Skip to main content
Glama
lazy-initialization.test.ts5.24 kB
// Lazy initialization tests for Embedder // TDD Red phase: These tests should fail initially import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { Embedder, EmbeddingError } from '../index.js' import type { EmbedderConfig } from '../index.js' describe('Embedder - Lazy Initialization', () => { let testConfig: EmbedderConfig beforeEach(() => { testConfig = { modelPath: 'Xenova/all-MiniLM-L6-v2', batchSize: 8, cacheDir: './tmp/models-lazy-test', } }) afterEach(() => { vi.restoreAllMocks() }) // Test 1: Lazy initialization on first embed() call it('should initialize on first embed() call without explicit initialize()', async () => { const embedder = new Embedder(testConfig) // Note: NOT calling await embedder.initialize() const result = await embedder.embed('test text for lazy initialization') expect(result).toBeDefined() expect(Array.isArray(result)).toBe(true) expect(result.length).toBe(384) expect(result.every((value) => typeof value === 'number')).toBe(true) }, 180000) // 3 minute timeout for model download // Test 2: Lazy initialization on first embedBatch() call it('should initialize on first embedBatch() call without explicit initialize()', async () => { const embedder = new Embedder(testConfig) // Note: NOT calling await embedder.initialize() const texts = ['first text', 'second text', 'third text'] const results = await embedder.embedBatch(texts) expect(results).toBeDefined() expect(Array.isArray(results)).toBe(true) expect(results.length).toBe(3) expect(results.every((embedding) => embedding.length === 384)).toBe(true) }, 180000) // Test 3: Initialization should happen only once for concurrent calls it('should initialize only once for concurrent embed() calls', async () => { const embedder = new Embedder(testConfig) // Spy on the initialize method to count how many times it's called const initializeSpy = vi.spyOn(embedder as any, 'initialize') // Make 5 concurrent embed() calls const promises = Array.from({ length: 5 }, (_, i) => embedder.embed(`concurrent test ${i}`)) const results = await Promise.all(promises) // Verify all calls succeeded expect(results).toHaveLength(5) expect(results.every((result) => result.length === 384)).toBe(true) // Verify initialize was called only once expect(initializeSpy).toHaveBeenCalledTimes(1) }, 180000) // Test 4: Retry should be possible after initialization failure it('should allow retry after initialization failure', async () => { // First attempt with invalid model path const embedderWithInvalidPath = new Embedder({ ...testConfig, modelPath: 'invalid/nonexistent-model', }) // First call should fail await expect(embedderWithInvalidPath.embed('test')).rejects.toThrow() // Second attempt with valid model path const embedderWithValidPath = new Embedder(testConfig) // This should succeed (retry with new instance) const result = await embedderWithValidPath.embed('test after retry') expect(result).toBeDefined() expect(result.length).toBe(384) }, 180000) // Test 5: Error message should provide detailed guidance it('should provide detailed error message with guidance on initialization failure', async () => { const embedderWithInvalidPath = new Embedder({ ...testConfig, modelPath: 'invalid/nonexistent-model', }) try { await embedderWithInvalidPath.embed('test') // Should not reach here expect.fail('Expected embed() to throw an error') } catch (error) { expect(error).toBeInstanceOf(EmbeddingError) const errorMessage = (error as EmbeddingError).message // Verify error message contains helpful guidance expect(errorMessage).toContain('Possible causes') expect(errorMessage).toContain('Recommended actions') expect(errorMessage).toContain(testConfig.cacheDir) expect(errorMessage).toContain('Check your internet connection') expect(errorMessage).toContain('delete cache') } }, 30000) // Test 6: Explicit initialize() should still work (backward compatibility) it('should still work with explicit initialize() call for backward compatibility', async () => { const embedder = new Embedder(testConfig) // Explicit initialize (existing behavior) await embedder.initialize() const result = await embedder.embed('test with explicit initialize') expect(result).toBeDefined() expect(result.length).toBe(384) }, 180000) // Test 7: Multiple calls to embed() after lazy initialization should not reinitialize it('should not reinitialize on subsequent embed() calls', async () => { const embedder = new Embedder(testConfig) // First call triggers lazy initialization await embedder.embed('first call') // Spy on initialize after first call const initializeSpy = vi.spyOn(embedder as any, 'initialize') // Second and third calls should not trigger initialization await embedder.embed('second call') await embedder.embed('third call') expect(initializeSpy).not.toHaveBeenCalled() }, 180000) })

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shinpr/mcp-local-rag'

If you have feedback or need assistance with the MCP directory API, please join our Discord server