Files
obsidian_ollama/tests/semantic-cache.test.ts
fegger 771db09d24 Refactor chat view and add conversation state management
Introduce ConversationStateManager to handle short, medium, and long-term
context for improved conversation flow. Update ChatView to use this manager
and refactor input handling to accept values directly for better testability.

Update OllamaClient with non-streaming chat support and improved error
handling for malformed chunks. Enhance vault indexer with caching, better
scoring, and stop word filtering. Refactor main plugin entry point and
semantic cache initialization for robustness.
2026-05-08 11:52:31 +02:00

166 lines
5.1 KiB
TypeScript

// tests/semantic-cache.test.ts
import { ChromaClient } from 'chromadb';
import { CacheConfig } from '../src/types';
// Mock ChromaDB module
jest.mock('chromadb', () => ({
ChromaClient: jest.fn().mockImplementation(() => {
return {
getOrCreateCollection: jest.fn().mockResolvedValue({
query: jest.fn(),
add: jest.fn(),
reset: jest.fn(),
}),
deleteCollection: jest.fn(),
};
}),
IncludeEnum: {
Documents: 'documents',
Embeddings: 'embeddings',
Metadatas: 'metadatas',
Distances: 'distances',
},
}));
import { SemanticCacheService } from '../src/semantic-cache';
describe('SemanticCacheService', () => {
const mockOllamaUrl = 'http://localhost:11434';
const mockCacheConfig: CacheConfig = {
enabled: true,
similarityThreshold: 0.85,
collectionName: 'test_cache',
embeddingModel: 'nomic-embed-text',
chromaURL: 'http://localhost:8000',
};
let cacheService: SemanticCacheService;
let mockChromaClient: any;
let mockCollection: any;
beforeEach(async () => {
// Reset all mocks
jest.clearAllMocks();
// Create a fresh instance for each test
cacheService = new SemanticCacheService(mockOllamaUrl, mockCacheConfig);
await cacheService.initialize();
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ embedding: [0.1, 0.2, 0.3] }),
});
// Access the internal mocks
mockChromaClient = (ChromaClient as jest.Mock).mock.results[0].value;
mockCollection = await mockChromaClient.getOrCreateCollection.mock.results[0].value;
});
describe('constructor', () => {
it('should initialize with correct configuration', () => {
expect(mockChromaClient).toBeDefined();
expect(mockChromaClient.getOrCreateCollection).toHaveBeenCalledWith({
name: mockCacheConfig.collectionName,
metadata: { 'hnsw:space': 'cosine' },
});
});
});
describe('initialize', () => {
it('should initialize the cache collection', async () => {
await cacheService.initialize();
expect(mockChromaClient.getOrCreateCollection).toHaveBeenCalledWith({
name: mockCacheConfig.collectionName,
metadata: { 'hnsw:space': 'cosine' },
});
});
it('should not initialize when cache is disabled', async () => {
jest.clearAllMocks();
const disabledConfig: CacheConfig = { ...mockCacheConfig, enabled: false };
const disabledCacheService = new SemanticCacheService(mockOllamaUrl, disabledConfig);
await disabledCacheService.initialize();
expect(mockChromaClient.getOrCreateCollection).not.toHaveBeenCalled();
});
});
describe('getCache', () => {
it('should return null when cache is disabled', async () => {
jest.clearAllMocks();
const disabledConfig: CacheConfig = { ...mockCacheConfig, enabled: false };
const disabledCacheService = new SemanticCacheService(mockOllamaUrl, disabledConfig);
const result = await disabledCacheService.getCache('test query');
expect(result).toBeNull();
expect(mockCollection.query).not.toHaveBeenCalled();
});
it('should return null when no cache hit', async () => {
mockCollection.query.mockResolvedValue({
ids: [[]],
documents: [[]],
distances: [[]],
});
const result = await cacheService.getCache('test query');
expect(result).toBeNull();
expect(mockCollection.query).toHaveBeenCalled();
});
it('should return cached content when hit', async () => {
const cachedContent = 'cached response';
mockCollection.query.mockResolvedValue({
ids: [['test-id']],
documents: [[cachedContent]],
distances: [[0.9]], // Above threshold
});
const result = await cacheService.getCache('test query');
expect(result).toBe(cachedContent);
expect(mockCollection.query).toHaveBeenCalled();
});
});
describe('setCache', () => {
it('should not set cache when disabled', async () => {
jest.clearAllMocks();
const disabledConfig: CacheConfig = { ...mockCacheConfig, enabled: false };
const disabledCacheService = new SemanticCacheService(mockOllamaUrl, disabledConfig);
await disabledCacheService.setCache('test query', 'test response');
expect(mockCollection.add).not.toHaveBeenCalled();
});
it('should add content to cache', async () => {
await cacheService.setCache('test query', 'test response');
expect(mockCollection.add).toHaveBeenCalled();
});
});
describe('clearCache', () => {
it('should not clear when cache is disabled', async () => {
jest.clearAllMocks();
const disabledConfig: CacheConfig = { ...mockCacheConfig, enabled: false };
const disabledCacheService = new SemanticCacheService(mockOllamaUrl, disabledConfig);
await disabledCacheService.clearCache();
expect(mockCollection.reset).not.toHaveBeenCalled();
});
it('should clear the cache collection', async () => {
await cacheService.clearCache();
expect(mockCollection.reset).toHaveBeenCalled();
});
});
});