Skip to main content
Glama
NeDBStorageAdapter.test.ts11.8 kB
import { NeDBStorageAdapter } from './NeDBStorageAdapter'; import { OperationResult, OperationStatus } from '../types'; import fs from 'fs'; import path from 'path'; describe('NeDBStorageAdapter', () => { // Use a unique test DB path for each test run to avoid file permission issues const testDbPath = path.join(__dirname, `test-db-${Date.now()}-${Math.floor(Math.random() * 10000)}`); let adapter: NeDBStorageAdapter; beforeEach(async () => { // Create a new adapter for each test with a clean database adapter = new NeDBStorageAdapter(testDbPath); await adapter.initialize(); }); afterEach(async () => { // Close the adapter and clean up the test database await adapter.close(); // Give the file system a moment to release file handles await new Promise(resolve => setTimeout(resolve, 100)); try { // Remove the test database files if they exist if (fs.existsSync(testDbPath)) { // Get all files in the directory const files = fs.readdirSync(testDbPath); // Try to delete each file for (const file of files) { try { fs.unlinkSync(path.join(testDbPath, file)); } catch (e) { // Ignore errors when deleting individual files } } // Try to remove the directory try { fs.rmdirSync(testDbPath); } catch (e) { // Ignore errors when removing the directory } } } catch (error) { // Just log the error but don't fail the test console.warn(`Error cleaning up test database: ${error instanceof Error ? error.message : String(error)}`); } }); describe('storeResult', () => { it('should store a result by log ID', async () => { // Create a test result const result: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; // Store the result await adapter.storeResult(result.logId, result); // Retrieve the result const retrievedResult = await adapter.getResult(result.logId); // Verify the result was stored correctly expect(retrievedResult).not.toBeNull(); expect(retrievedResult?.logId).toBe(result.logId); expect(retrievedResult?.status).toBe(result.status); expect(retrievedResult?.result).toEqual(result.result); expect(retrievedResult?.isComplete).toBe(result.isComplete); }); it('should store a result with just the result object', async () => { // Create a test result const result: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-2', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; // Store the result await adapter.storeResult(result); // Retrieve the result const retrievedResult = await adapter.getResult(result.logId); // Verify the result was stored correctly expect(retrievedResult).not.toBeNull(); expect(retrievedResult?.logId).toBe(result.logId); expect(retrievedResult?.status).toBe(result.status); expect(retrievedResult?.result).toEqual(result.result); expect(retrievedResult?.isComplete).toBe(result.isComplete); }); it('should update an existing result', async () => { // Create a test result const result: OperationResult = { status: OperationStatus.RUNNING, logId: 'test-log-id-3', partialResult: { progress: 50 }, isComplete: false, startTime: Date.now() }; // Store the result await adapter.storeResult(result); // Update the result const updatedResult: OperationResult = { ...result, status: OperationStatus.SUCCESS, result: { value: 42 }, partialResult: undefined, isComplete: true, endTime: Date.now() }; // Store the updated result await adapter.storeResult(updatedResult); // Retrieve the result const retrievedResult = await adapter.getResult(result.logId); // Verify the result was updated correctly expect(retrievedResult).not.toBeNull(); expect(retrievedResult?.logId).toBe(result.logId); expect(retrievedResult?.status).toBe(OperationStatus.SUCCESS); expect(retrievedResult?.result).toEqual({ value: 42 }); expect(retrievedResult?.isComplete).toBe(true); expect(retrievedResult?.endTime).toBeDefined(); }); }); describe('getResult', () => { it('should return null for an unknown log ID', async () => { // Retrieve a result with an unknown log ID const result = await adapter.getResult('unknown-log-id'); // Verify the result is null expect(result).toBeNull(); }); it('should retrieve a stored result', async () => { // Create a test result const result: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-4', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; // Store the result await adapter.storeResult(result); // Retrieve the result const retrievedResult = await adapter.getResult(result.logId); // Verify the result was retrieved correctly expect(retrievedResult).not.toBeNull(); expect(retrievedResult?.logId).toBe(result.logId); expect(retrievedResult?.status).toBe(result.status); expect(retrievedResult?.result).toEqual(result.result); expect(retrievedResult?.isComplete).toBe(result.isComplete); }); }); describe('registerRunningOperation and cancelOperation', () => { it('should register and cancel an operation', async () => { // Create a mock cancel function const cancelFn = jest.fn(); // Register the operation await adapter.registerRunningOperation('test-log-id-5', cancelFn); // Cancel the operation const cancelled = await adapter.cancelOperation('test-log-id-5'); // Verify the operation was cancelled expect(cancelled).toBe(true); expect(cancelFn).toHaveBeenCalled(); }); it('should return false when cancelling an unknown operation', async () => { // Cancel an operation with an unknown log ID const cancelled = await adapter.cancelOperation('unknown-log-id'); // Verify the operation was not cancelled expect(cancelled).toBe(false); }); it('should unregister a running operation', async () => { // Create a mock cancel function const cancelFn = jest.fn(); // Register the operation await adapter.registerRunningOperation('test-log-id-6', cancelFn); // Unregister the operation await adapter.unregisterRunningOperation('test-log-id-6'); // Try to cancel the operation const cancelled = await adapter.cancelOperation('test-log-id-6'); // Verify the operation was not cancelled expect(cancelled).toBe(false); expect(cancelFn).not.toHaveBeenCalled(); }); }); describe('listOperations', () => { it('should list all operations', async () => { // Create some test results const result1: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-7', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; const result2: OperationResult = { status: OperationStatus.RUNNING, logId: 'test-log-id-8', partialResult: { progress: 50 }, isComplete: false, startTime: Date.now() }; // Store the results await adapter.storeResult(result1); await adapter.storeResult(result2); // List all operations const operations = await adapter.listOperations(); // Verify the operations list expect(operations.length).toBe(2); expect(operations.some(op => op.logId === result1.logId)).toBe(true); expect(operations.some(op => op.logId === result2.logId)).toBe(true); }); }); describe('cleanupCompletedOperations', () => { it('should clean up old completed operations', async () => { // Create a test result that's "old" const oldResult: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-9', result: { value: 42 }, isComplete: true, startTime: Date.now() - 2000, // 2 seconds ago endTime: Date.now() - 1000 // 1 second ago }; // Create a test result that's "new" const newResult: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-10', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; // Store the results await adapter.storeResult(oldResult); await adapter.storeResult(newResult); // Clean up operations older than 500ms await adapter.cleanupCompletedOperations(500); // Verify the old result was cleaned up const retrievedOldResult = await adapter.getResult(oldResult.logId); expect(retrievedOldResult).toBeNull(); // Verify the new result was not cleaned up const retrievedNewResult = await adapter.getResult(newResult.logId); expect(retrievedNewResult).not.toBeNull(); }); it('should not clean up incomplete operations', async () => { // Create a test result that's "old" but incomplete const oldIncompleteResult: OperationResult = { status: OperationStatus.RUNNING, logId: 'test-log-id-11', partialResult: { progress: 50 }, isComplete: false, startTime: Date.now() - 2000 // 2 seconds ago }; // Store the result await adapter.storeResult(oldIncompleteResult); // Clean up operations older than 500ms await adapter.cleanupCompletedOperations(500); // Verify the incomplete result was not cleaned up const retrievedResult = await adapter.getResult(oldIncompleteResult.logId); expect(retrievedResult).not.toBeNull(); }); }); describe('persistence', () => { it('should persist data across adapter instances', async () => { // Create a test result const result: OperationResult = { status: OperationStatus.SUCCESS, logId: 'test-log-id-12', result: { value: 42 }, isComplete: true, startTime: Date.now(), endTime: Date.now() }; // Store the result await adapter.storeResult(result); // Close the adapter await adapter.close(); // Give the file system a moment to release file handles await new Promise(resolve => setTimeout(resolve, 100)); // Create a new adapter instance with the same path const newAdapter = new NeDBStorageAdapter(testDbPath); await newAdapter.initialize(); try { // Retrieve the result from the new adapter const retrievedResult = await newAdapter.getResult(result.logId); // Verify the result was retrieved correctly expect(retrievedResult).not.toBeNull(); expect(retrievedResult?.logId).toBe(result.logId); expect(retrievedResult?.status).toBe(result.status); expect(retrievedResult?.result).toEqual(result.result); expect(retrievedResult?.isComplete).toBe(result.isComplete); } finally { // Close the new adapter await newAdapter.close(); // Give the file system a moment to release file handles await new Promise(resolve => setTimeout(resolve, 100)); } }); }); });

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/TSavo/Unity-MCP'

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