Skip to main content
Glama
storage.test.ts7.16 kB
/** * Agent Synch MCP Server - Storage Layer Tests * TDD First: These tests define the expected behavior before implementation. */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { AgentSynchStorage } from './storage'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as os from 'os'; describe('AgentSynchStorage', () => { let storage: AgentSynchStorage; let testDir: string; beforeEach(async () => { // Use a temp directory for isolated tests testDir = path.join(os.tmpdir(), `agent-synch-test-${Date.now()}`); storage = new AgentSynchStorage(testDir); await storage.initialize(); }); afterEach(async () => { // Cleanup try { await fs.rm(testDir, { recursive: true, force: true }); } catch (e) { // Ignore cleanup errors (SQLite file might be locked) } }); describe('Active Context', () => { it('should get null for new project', async () => { const context = await storage.getActiveContext('test-project'); expect(context).toBeNull(); }); it('should set and get active context', async () => { const projectId = 'test-project'; const contextData = { summary: 'Working on auth module', lastUpdated: new Date().toISOString(), focus: 'Implementing login flow', taskGraph: { nodes: [] } }; await storage.setActiveContext(projectId, contextData); const retrieved = await storage.getActiveContext(projectId); expect(retrieved).toEqual(contextData); }); // Global context is just a project_id = 'global' it('should get global context when no project specified', async () => { const globalContext = { summary: 'Global state', lastUpdated: new Date().toISOString() }; await storage.setActiveContext('global', globalContext); const retrieved = await storage.getActiveContext('global'); expect(retrieved).toEqual(globalContext); }); }); describe('Filing Cabinet', () => { it('should file a document to the cabinet', async () => { const projectId = 'test-project'; const filePath = '/src/main.ts'; const content = { originalPath: filePath, summary: 'Main entry point', keyExports: ['main', 'init'], dependencies: ['./config', './utils'], }; await storage.indexFile(projectId, content); const retrieved = await storage.getFileFromCabinet(projectId, filePath); expect(retrieved).toMatchObject(content); expect(retrieved?.indexedAt).toBeDefined(); }); it('should list all files in cabinet', async () => { const projectId = 'test-project'; await storage.indexFile(projectId, { originalPath: '/src/a.ts', summary: 'A' }); await storage.indexFile(projectId, { originalPath: '/src/b.ts', summary: 'B' }); const files = await storage.listCabinet(projectId); expect(files).toHaveLength(2); expect(files).toContain('/src/a.ts'); expect(files).toContain('/src/b.ts'); }); it('should return null for non-existent file', async () => { const result = await storage.getFileFromCabinet('test-project', '/nonexistent.ts'); expect(result).toBeNull(); }); }); describe('Project Profile (Legacy JSON Support)', () => { it('should set and get project profile', async () => { const projectId = 'test-project'; const profile = { name: 'My Project', standards: { codeStyle: 'StandardJS' }, workflow: { start: 'npm run dev', build: 'npm run build' }, }; await storage.setProjectProfile(projectId, profile); const retrieved = await storage.getProjectProfile(projectId); expect(retrieved).toEqual(profile); }); }); describe('Spatial Map', () => { it('should add a room to the spatial map', async () => { const projectId = 'test-project'; const room = { path: 'src/components', description: 'UI components', depth: 2, connectedRooms: [], keyItems: ['Button.tsx'], }; await storage.addRoom(projectId, room); const map = await storage.getSpatialMap(projectId); expect(map.rooms['src/components']).toEqual(room); }); it('should link two rooms', async () => { const projectId = 'test-project'; await storage.addRoom(projectId, { path: 'src/components', description: 'Components', depth: 2, connectedRooms: [], keyItems: [] }); await storage.addRoom(projectId, { path: 'src/hooks', description: 'Hooks', depth: 2, connectedRooms: [], keyItems: [] }); await storage.linkRooms(projectId, 'src/components', 'src/hooks'); const map = await storage.getSpatialMap(projectId); expect(map.rooms['src/components'].connectedRooms).toContain('src/hooks'); // JSON stringify match might be order dependent if strict equal, but toContain checks array expect(map.rooms['src/hooks'].connectedRooms).toContain('src/components'); }); }); describe('Search', () => { it('should search across all indexed content', async () => { const projectId = 'test-project'; await storage.indexFile(projectId, { originalPath: '/src/auth.ts', summary: 'Authentication module with login and logout' }); await storage.indexFile(projectId, { originalPath: '/src/db.ts', summary: 'Database connection handler' }); const results = await storage.searchMemory('login', projectId); expect(results).toHaveLength(1); expect(results[0].path).toBe('/src/auth.ts'); }); it('should search globally when no project specified', async () => { await storage.indexFile('project-a', { originalPath: '/src/utils.ts', summary: 'Utility functions' }); await storage.indexFile('project-b', { originalPath: '/lib/helpers.ts', summary: 'Helper utilities' }); const results = await storage.searchMemory('util'); expect(results.length).toBeGreaterThanOrEqual(2); }); }); describe('Project Management', () => { it('should list all projects', async () => { await storage.setActiveContext('project-a', { summary: 'A', lastUpdated: new Date().toISOString() }); await storage.setActiveContext('project-b', { summary: 'B', lastUpdated: new Date().toISOString() }); const projects = await storage.listProjects(); expect(projects).toContain('project-a'); expect(projects).toContain('project-b'); }); }); describe('Bug Logging', () => { it('should log and resolve a bug', async () => { const projectId = 'test-project'; const bugId = await storage.logBug({ projectId, title: 'Test Bug', description: 'Testing bug logging', severity: 'high' }); const bugs = await storage.getBugs(projectId, 'open'); expect(bugs).toHaveLength(1); expect(bugs[0].id).toBe(bugId); await storage.resolveBug(bugId, projectId, 'Fixed it'); const resolvedBugs = await storage.getBugs(projectId, 'resolved'); expect(resolvedBugs).toHaveLength(1); expect(resolvedBugs[0].resolution).toBe('Fixed it'); }); }); });

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/Mnehmos/mnehmos.synch.mcp'

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