Skip to main content
Glama
manage-observations.test.ts9.94 kB
/** * Manage Observations Use Case Tests - FULL PIPELINE COVERAGE * Single responsibility: Test observation management that keeps memory intact * Focus: Cover the 17.39% gap that could leave production observation pipelines broken */ import { describe, it, expect, beforeEach, vi } from 'vitest'; import { ManageObservationsUseCase, ObservationRequest } from '../../../src/application/use-cases/manage-observations'; import { MemoryRepository } from '../../../src/domain/repositories/memory-repository'; describe('ManageObservationsUseCase - The Observation Pipeline', () => { let useCase: ManageObservationsUseCase; let mockRepository: MemoryRepository; beforeEach(() => { vi.clearAllMocks(); // Mock the repository that actually handles the data operations mockRepository = { findById: vi.fn(), addObservations: vi.fn(), deleteObservations: vi.fn(), // Add other required methods as stubs create: vi.fn(), findByIds: vi.fn(), findByType: vi.fn(), update: vi.fn(), delete: vi.fn(), exists: vi.fn(), findWithFilters: vi.fn(), createRelation: vi.fn(), createEnhancedRelation: vi.fn(), deleteRelation: vi.fn() } as any; useCase = new ManageObservationsUseCase(mockRepository); }); describe('Adding Observations', () => { it('should add observations to existing memory', async () => { // Setup: Mock memory exists const mockMemory = { id: 'mem123', name: 'Test Memory' }; mockRepository.findById = vi.fn().mockResolvedValue(mockMemory); mockRepository.addObservations = vi.fn().mockResolvedValue(undefined); const request: ObservationRequest = { memoryId: 'mem123', contents: ['First observation', 'Second observation'] }; // Execute await useCase.addObservations(request); // Verify expect(mockRepository.findById).toHaveBeenCalledWith('mem123'); expect(mockRepository.addObservations).toHaveBeenCalledWith('mem123', [ 'First observation', 'Second observation' ]); }); it('should fail when memory does not exist', async () => { // Setup: Memory not found mockRepository.findById = vi.fn().mockResolvedValue(null); const request: ObservationRequest = { memoryId: 'nonexistent1234567', contents: ['Observation for missing memory'] }; // Execute & Verify await expect(useCase.addObservations(request)) .rejects.toThrow('Memory not found: nonexistent1234567'); expect(mockRepository.findById).toHaveBeenCalledWith('nonexistent1234567'); expect(mockRepository.addObservations).not.toHaveBeenCalled(); }); it('should handle empty observation list', async () => { // Setup: Mock memory exists const mockMemory = { id: 'mem123', name: 'Test Memory' }; mockRepository.findById = vi.fn().mockResolvedValue(mockMemory); mockRepository.addObservations = vi.fn().mockResolvedValue(undefined); const request: ObservationRequest = { memoryId: 'mem123', contents: [] // Empty array should still work }; // Execute await useCase.addObservations(request); // Verify - should still call repository with empty array expect(mockRepository.addObservations).toHaveBeenCalledWith('mem123', []); }); }); describe('Deleting Observations', () => { it('should delete observations from existing memory', async () => { // Setup: Mock memory exists const mockMemory = { id: 'mem456', name: 'Memory with Observations' }; mockRepository.findById = vi.fn().mockResolvedValue(mockMemory); mockRepository.deleteObservations = vi.fn().mockResolvedValue(undefined); const request: ObservationRequest = { memoryId: 'mem456', contents: [ 'abcd1234efgh5678AB', // Valid 18-char BASE85 ID 'wxyz9876mnop5432CD' // Valid 18-char BASE85 ID ] }; // Execute await useCase.deleteObservations(request); // Verify expect(mockRepository.findById).toHaveBeenCalledWith('mem456'); expect(mockRepository.deleteObservations).toHaveBeenCalledWith('mem456', [ 'abcd1234efgh5678AB', 'wxyz9876mnop5432CD' ]); }); it('should fail when memory does not exist for deletion', async () => { // Setup: Memory not found mockRepository.findById = vi.fn().mockResolvedValue(null); const request: ObservationRequest = { memoryId: 'missing$memory0001', contents: ['abcd1234efgh5678AB'] // Valid observation ID }; // Execute & Verify await expect(useCase.deleteObservations(request)) .rejects.toThrow('Memory not found: missing$memory0001'); expect(mockRepository.findById).toHaveBeenCalledWith('missing$memory0001'); expect(mockRepository.deleteObservations).not.toHaveBeenCalled(); }); it('should handle repository errors during deletion', async () => { // Setup: Memory exists but deletion fails const mockMemory = { id: 'mem789', name: 'Test Memory' }; mockRepository.findById = vi.fn().mockResolvedValue(mockMemory); mockRepository.deleteObservations = vi.fn().mockRejectedValue( new Error('Database connection lost') ); const request: ObservationRequest = { memoryId: 'mem789', contents: ['abcd1234efgh5678AB'] // Valid observation ID }; // Execute & Verify await expect(useCase.deleteObservations(request)) .rejects.toThrow('Database connection lost'); }); }); describe('Batch Operations', () => { it('should process multiple add operations successfully', async () => { // Setup: Mock all memories exist mockRepository.findById = vi.fn().mockResolvedValue({ id: 'test', name: 'Test Memory' }); mockRepository.addObservations = vi.fn().mockResolvedValue(undefined); const requests: ObservationRequest[] = [ { memoryId: 'mem1', contents: ['Observation 1'] }, { memoryId: 'mem2', contents: ['Observation 2', 'Observation 3'] }, { memoryId: 'mem3', contents: ['Observation 4'] } ]; // Execute const result = await useCase.executeMany('add', requests); // Verify - count actual observations: 2 + 1 + 1 = 4 expect(result.processed).toBe(4); expect(result.errors).toHaveLength(0); expect(mockRepository.findById).toHaveBeenCalledTimes(3); expect(mockRepository.addObservations).toHaveBeenCalledTimes(3); }); it('should process multiple delete operations successfully', async () => { // Setup: Mock all memories exist mockRepository.findById = vi.fn().mockResolvedValue({ id: 'test', name: 'Test Memory' }); mockRepository.deleteObservations = vi.fn().mockResolvedValue(undefined); const requests: ObservationRequest[] = [ { memoryId: 'mem1', contents: ['abcd1234efgh5678AB'] }, // 1 valid ID { memoryId: 'mem2', contents: ['wxyz9876mnop5432CD', 'efgh1234ijkl5678EF'] } // 2 valid IDs ]; // Execute const result = await useCase.executeMany('delete', requests); // Verify - count actual observations: 1 + 2 = 3 expect(result.processed).toBe(3); expect(result.errors).toHaveLength(0); expect(mockRepository.deleteObservations).toHaveBeenCalledTimes(2); }); it('should handle mixed success and failure scenarios', async () => { // Setup: First memory exists, second doesn't, third exists mockRepository.findById = vi.fn() .mockResolvedValueOnce({ id: 'mem1', name: 'Memory 1' }) .mockResolvedValueOnce(null) // Memory not found .mockResolvedValueOnce({ id: 'mem3', name: 'Memory 3' }); mockRepository.addObservations = vi.fn().mockResolvedValue(undefined); const requests: ObservationRequest[] = [ { memoryId: 'mem1', contents: ['Success observation'] }, { memoryId: 'nonexistent1234567', contents: ['Failed observation'] }, { memoryId: 'mem3', contents: ['Another success'] } ]; // Execute const result = await useCase.executeMany('add', requests); // Verify expect(result.processed).toBe(2); // Two successful expect(result.errors).toHaveLength(1); // One failed expect(result.errors[0]).toContain('Memory not found: nonexistent1234567'); expect(mockRepository.addObservations).toHaveBeenCalledTimes(2); }); it('should handle repository errors in batch operations', async () => { // Setup: Memory exists but operations fail randomly mockRepository.findById = vi.fn().mockResolvedValue({ id: 'test', name: 'Test Memory' }); mockRepository.addObservations = vi.fn() .mockResolvedValueOnce(undefined) // First succeeds .mockRejectedValueOnce(new Error('Database timeout')) // Second fails .mockResolvedValueOnce(undefined); // Third succeeds const requests: ObservationRequest[] = [ { memoryId: 'mem1', contents: ['Success 1'] }, { memoryId: 'mem2', contents: ['Will fail'] }, { memoryId: 'mem3', contents: ['Success 2'] } ]; // Execute const result = await useCase.executeMany('add', requests); // Verify expect(result.processed).toBe(2); // Two successful expect(result.errors).toHaveLength(1); // One failed expect(result.errors[0]).toContain('Database timeout'); }); it('should handle empty batch operations', async () => { // Execute with empty requests const result = await useCase.executeMany('add', []); // Verify expect(result.processed).toBe(0); expect(result.errors).toHaveLength(0); expect(mockRepository.findById).not.toHaveBeenCalled(); expect(mockRepository.addObservations).not.toHaveBeenCalled(); }); }); });

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/sylweriusz/mcp-neo4j-memory-server'

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