Skip to main content
Glama
backup.test.ts8.63 kB
import { HeptabaseMcpServer } from '@/server'; import { BackupManager } from '@/services/BackupManager'; import { HeptabaseDataService } from '@/services/HeptabaseDataService'; import { z } from 'zod'; jest.mock('@/services/BackupManager'); jest.mock('@/services/HeptabaseDataService'); describe('Backup Management Tools', () => { let server: HeptabaseMcpServer; let mockBackupManager: jest.Mocked<BackupManager>; let mockDataService: jest.Mocked<HeptabaseDataService>; beforeEach(() => { jest.clearAllMocks(); // Create mock instances mockBackupManager = { config: { backupPath: '/test/path', extractionPath: '/test/extract', autoExtract: true, watchDirectory: false, keepExtracted: true }, listBackups: jest.fn(), loadBackup: jest.fn(), startWatching: jest.fn(), stopWatching: jest.fn(), cleanupOldBackups: jest.fn() } as any; mockDataService = { config: { dataPath: '/test/data', cacheEnabled: true, cacheTTL: 3600 }, loadData: jest.fn(), searchWhiteboards: jest.fn(), searchCards: jest.fn(), getWhiteboard: jest.fn(), getCard: jest.fn(), getCardsByArea: jest.fn(), getConnections: jest.fn(), getData: jest.fn() } as any; // Initialize server with mocked services server = new HeptabaseMcpServer(); server['backupManager'] = mockBackupManager; server['dataService'] = mockDataService; }); describe('configureBackupPath tool', () => { it('should configure backup path and update manager', async () => { const params = { path: '/new/backup/path', watchForChanges: true, autoExtract: false }; const result = await server.tools.configureBackupPath.handler(params); expect(result.content[0].text).toContain('Backup path configured successfully'); expect(server.config.backupPath).toBe('/new/backup/path'); expect(server.config.autoExtract).toBe(false); expect(server.config.watchDirectory).toBe(true); expect(mockBackupManager.startWatching).toHaveBeenCalled(); }); it('should validate path parameter', async () => { const schema = server.tools.configureBackupPath.inputSchema; expect(() => schema.parse({ path: '' })).toThrow(); expect(() => schema.parse({ path: '/valid/path' })).not.toThrow(); }); it('should stop watching when watchForChanges is false', async () => { const params = { path: '/new/backup/path', watchForChanges: false }; // Reset mocks since new BackupManager will be created mockBackupManager.stopWatching.mockClear(); mockBackupManager.startWatching.mockClear(); await server.tools.configureBackupPath.handler(params); expect(server.config.watchDirectory).toBe(false); }); }); describe('listBackups tool', () => { it('should list available backups', async () => { const mockBackups = [ { backupId: 'backup1', backupPath: '/path/backup1.zip', createdDate: new Date('2024-01-01'), fileSize: 1000000, isCompressed: true }, { backupId: 'backup2', backupPath: '/path/backup2.json', createdDate: new Date('2024-01-02'), fileSize: 500000, isCompressed: false } ]; mockBackupManager.listBackups.mockResolvedValue(mockBackups); const result = await server.tools.listBackups.handler({}); expect(result.content[0].text).toContain('2 backups'); expect(result.content[0].text).toContain('backup1'); expect(result.content[0].text).toContain('backup2'); }); it('should use custom path when provided', async () => { mockBackupManager.listBackups.mockResolvedValue([]); await server.tools.listBackups.handler({ path: '/custom/path' }); expect(mockBackupManager.listBackups).toHaveBeenCalledWith('/custom/path'); }); it('should sort by date when specified', async () => { const mockBackups = [ { backupId: 'backup1', backupPath: '/path/backup1.zip', createdDate: new Date('2024-01-01'), fileSize: 1000000, isCompressed: true } ]; mockBackupManager.listBackups.mockResolvedValue(mockBackups); await server.tools.listBackups.handler({ sortBy: 'date' }); expect(mockBackupManager.listBackups).toHaveBeenCalled(); }); it('should limit results when specified', async () => { const mockBackups = Array.from({ length: 10 }, (_, i) => ({ backupId: `backup${i}`, backupPath: `/path/backup${i}.zip`, createdDate: new Date(`2024-01-${i + 1}`), fileSize: 1000000, isCompressed: true })); mockBackupManager.listBackups.mockResolvedValue(mockBackups); const result = await server.tools.listBackups.handler({ limit: 5 }); expect(result.content[0].text).toContain('5 backups'); }); }); describe('loadBackup tool', () => { it('should load backup by path', async () => { const mockMetadata = { backupId: 'backup1', backupPath: '/path/backup1.zip', createdDate: new Date('2024-01-01'), fileSize: 1000000, isCompressed: true, extractedPath: '/extracted/backup1' }; mockBackupManager.loadBackup.mockResolvedValue(mockMetadata); mockDataService.loadData.mockResolvedValue(undefined); const result = await server.tools.loadBackup.handler({ backupPath: '/path/backup1.zip' }); expect(mockBackupManager.loadBackup).toHaveBeenCalledWith('/path/backup1.zip'); expect(mockDataService.loadData).toHaveBeenCalled(); expect(result.content[0].text).toContain('Backup loaded successfully'); }); it('should load backup by ID', async () => { const mockBackups = [ { backupId: 'backup1', backupPath: '/path/backup1.zip', createdDate: new Date('2024-01-01'), fileSize: 1000000, isCompressed: true } ]; mockBackupManager.listBackups.mockResolvedValue(mockBackups); mockBackupManager.loadBackup.mockResolvedValue(mockBackups[0]); mockDataService.loadData.mockResolvedValue(undefined); const result = await server.tools.loadBackup.handler({ backupId: 'backup1' }); expect(mockBackupManager.loadBackup).toHaveBeenCalledWith('/path/backup1.zip'); expect(result.content[0].text).toContain('Backup loaded successfully'); }); it('should extract if specified', async () => { const mockMetadata = { backupId: 'backup1', backupPath: '/path/backup1.zip', createdDate: new Date('2024-01-01'), fileSize: 1000000, isCompressed: true }; mockBackupManager.loadBackup.mockResolvedValue(mockMetadata); mockDataService.loadData.mockResolvedValue(undefined); await server.tools.loadBackup.handler({ backupPath: '/path/backup1.zip', extract: true }); expect(mockBackupManager.loadBackup).toHaveBeenCalled(); }); it('should throw error when backup not found', async () => { mockBackupManager.listBackups.mockResolvedValue([]); await expect( server.tools.loadBackup.handler({ backupId: 'nonexistent' }) ).rejects.toThrow('Backup not found'); }); it('should require either backupPath or backupId', async () => { await expect( server.tools.loadBackup.handler({}) ).rejects.toThrow(); }); }); describe('tool schemas', () => { it('should have valid configureBackupPath schema', () => { const schema = server.tools.configureBackupPath.inputSchema; expect(schema).toBeInstanceOf(z.ZodObject); const validInput = { path: '/test/path' }; expect(() => schema.parse(validInput)).not.toThrow(); }); it('should have valid listBackups schema', () => { const schema = server.tools.listBackups.inputSchema; expect(schema).toBeInstanceOf(z.ZodObject); const validInput = { sortBy: 'date', limit: 10 }; expect(() => schema.parse(validInput)).not.toThrow(); }); it('should have valid loadBackup schema', () => { const schema = server.tools.loadBackup.inputSchema; expect(schema).toBeDefined(); const validInput = { backupPath: '/test/backup.zip' }; expect(() => schema.parse(validInput)).not.toThrow(); }); }); });

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/LarryStanley/heptabase-mcp'

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