Skip to main content
Glama

Scratchpad MCP

by pc035860
critical-fixes-validation-v2.test.tsโ€ข16.9 kB
/** * Phase 3: Critical Issue Fixes Validation Tests (Updated) * Tests for WAL checkpoint strategy and type safety enhancements */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; import { existsSync, unlinkSync } from 'fs'; import { ScratchpadDatabase } from '../src/database/index.js'; import { isScratchpad, isWorkflowDbRow, isVersionQueryResult } from '../src/database/types.js'; describe('Critical Issue Fixes Validation (Updated)', () => { let db: ScratchpadDatabase; const testDbPath = 'test-critical-fixes-v2.db'; beforeEach(() => { // Clean up any existing test database if (existsSync(testDbPath)) { unlinkSync(testDbPath); } }); afterEach(() => { if (db) { db.close(); } // Clean up test database file if (existsSync(testDbPath)) { unlinkSync(testDbPath); } }); describe('Phase 1: WAL Checkpoint Strategy Validation', () => { it('should complete TRUNCATE checkpoint successfully on startup', () => { const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => {}); // Create database with WAL mode db = new ScratchpadDatabase({ filename: testDbPath }); // Verify that debug message indicates successful TRUNCATE expect(consoleSpy).toHaveBeenCalledWith('WAL checkpoint (TRUNCATE) completed successfully'); consoleSpy.mockRestore(); }); it('should handle database initialization robustly', () => { const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => {}); db = new ScratchpadDatabase({ filename: testDbPath }); // Database should initialize successfully expect(consoleSpy).toHaveBeenCalledWith('WAL checkpoint (TRUNCATE) completed successfully'); // Database should be functional expect(() => { db.createWorkflow({ name: 'Test Workflow' }); }).not.toThrow(); consoleSpy.mockRestore(); }); it('should maintain data consistency after multiple operations', () => { db = new ScratchpadDatabase({ filename: testDbPath }); // Create test data const workflow = db.createWorkflow({ name: 'Consistency Test' }); const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: 'Test Scratchpad', content: 'Initial content for consistency test', }); // Close and reopen database to trigger checkpoint again db.close(); db = new ScratchpadDatabase({ filename: testDbPath }); // Verify data integrity const retrievedWorkflow = db.getWorkflowById(workflow.id); const retrievedScratchpad = db.getScratchpadById(scratchpad.id); expect(retrievedWorkflow).toBeTruthy(); expect(retrievedWorkflow?.name).toBe('Consistency Test'); expect(retrievedScratchpad).toBeTruthy(); expect(retrievedScratchpad?.content).toBe('Initial content for consistency test'); }); it('should have minimal impact on startup performance (<100ms)', () => { const startTime = performance.now(); db = new ScratchpadDatabase({ filename: testDbPath }); const endTime = performance.now(); const initTime = endTime - startTime; // Startup should be under 100ms even with checkpoint operations expect(initTime).toBeLessThan(100); // Database should be fully functional expect(() => { db.getStats(); }).not.toThrow(); }); it('should handle rapid database operations successfully', () => { db = new ScratchpadDatabase({ filename: testDbPath }); const workflow = db.createWorkflow({ name: 'Rapid Operations Test' }); // Rapidly create multiple scratchpads const scratchpads = []; for (let i = 0; i < 10; i++) { scratchpads.push( db.createScratchpad({ workflow_id: workflow.id, title: `Rapid ${i}`, content: `Rapid test content ${i}`, }) ); } // Verify all operations completed successfully expect(scratchpads).toHaveLength(10); const listed = db.listScratchpads({ workflow_id: workflow.id }); expect(listed).toHaveLength(10); // Search should work properly after rapid operations const searchResults = db.searchScratchpads({ query: 'rapid' }); expect(searchResults.length).toBeGreaterThan(0); }); }); describe('Phase 2: Type Safety Enhancement Validation', () => { beforeEach(() => { db = new ScratchpadDatabase({ filename: testDbPath }); }); describe('Type Guard Functions', () => { it('should validate Scratchpad objects correctly', () => { const validScratchpad = { id: 'test-id', workflow_id: 'workflow-id', title: 'Test Title', content: 'Test Content', created_at: 1234567890, updated_at: 1234567890, size_bytes: 1024, }; expect(isScratchpad(validScratchpad)).toBe(true); // Test invalid cases expect(isScratchpad(null)).toBe(false); expect(isScratchpad(undefined)).toBe(false); expect(isScratchpad('string')).toBe(false); expect(isScratchpad(123)).toBe(false); expect(isScratchpad({})).toBe(false); // Test partial objects expect(isScratchpad({ id: 'test-id' })).toBe(false); expect(isScratchpad({ ...validScratchpad, id: null })).toBe(false); expect(isScratchpad({ ...validScratchpad, created_at: 'invalid' })).toBe(false); }); it('should validate WorkflowDbRow objects correctly', () => { const validWorkflowRow = { id: 'workflow-id', name: 'Test Workflow', description: 'Test Description', project_scope: null, created_at: 1234567890, updated_at: 1234567890, is_active: 1, scratchpad_count: 0, }; expect(isWorkflowDbRow(validWorkflowRow)).toBe(true); // Test invalid cases expect(isWorkflowDbRow(null)).toBe(false); expect(isWorkflowDbRow(undefined)).toBe(false); expect(isWorkflowDbRow({ id: 'test' })).toBe(false); expect(isWorkflowDbRow({ ...validWorkflowRow, is_active: 'invalid' })).toBe(false); }); it('should validate version query results correctly', () => { // Based on type definition: checks for 'value' field const validVersionResult = { value: '( t+e+s+t* OR test* )' }; expect(isVersionQueryResult(validVersionResult)).toBe(true); // Test invalid cases expect(isVersionQueryResult(null)).toBe(false); expect(isVersionQueryResult({})).toBe(false); expect(isVersionQueryResult({ value: 123 })).toBe(false); expect(isVersionQueryResult({ result: '1.0' })).toBe(false); // Wrong field name }); }); describe('Database Operations Type Safety', () => { it('should handle getScratchpadById with type safety', () => { const workflow = db.createWorkflow({ name: 'Type Safety Test' }); const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: 'Type Test', content: 'Content for type safety testing', }); const retrieved = db.getScratchpadById(scratchpad.id); expect(retrieved).toBeTruthy(); expect(isScratchpad(retrieved)).toBe(true); // Test with non-existent ID (returns null for safety, doesn't throw) const nonExistent = db.getScratchpadById('non-existent-id'); expect(nonExistent).toBeNull(); }); it('should handle getWorkflowById with type safety', () => { const workflow = db.createWorkflow({ name: 'Workflow Type Test' }); const retrieved = db.getWorkflowById(workflow.id); expect(retrieved).toBeTruthy(); // Verify the workflow has the expected structure expect(retrieved?.id).toBe(workflow.id); expect(retrieved?.name).toBe('Workflow Type Test'); // Test with non-existent ID (returns null for safety, doesn't throw) const nonExistent = db.getWorkflowById('non-existent-id'); expect(nonExistent).toBeNull(); }); it('should validate scratchpad structure in real database operations', () => { const workflow = db.createWorkflow({ name: 'Structure Test' }); const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: 'Structure Test Scratchpad', content: 'Content for structure validation', }); // All returned scratchpads should pass type validation expect(isScratchpad(scratchpad)).toBe(true); const retrieved = db.getScratchpadById(scratchpad.id); expect(isScratchpad(retrieved)).toBe(true); const listed = db.listScratchpads({ workflow_id: workflow.id }); expect(listed).toHaveLength(1); expect(isScratchpad(listed[0])).toBe(true); }); }); describe('Error Handling and Recovery', () => { it('should maintain system stability under type validation stress', () => { const workflow = db.createWorkflow({ name: 'Stress Test' }); // Multiple operations to ensure type safety doesn't impact performance (within limits) const operations = []; for (let i = 0; i < 25; i++) { // Reduced to stay within MAX_SCRATCHPADS_PER_WORKFLOW limit operations.push( db.createScratchpad({ workflow_id: workflow.id, title: `Stress Test ${i}`, content: `Content for stress test iteration ${i}`, }) ); } // All operations should complete successfully expect(operations).toHaveLength(25); operations.forEach((scratchpad) => { expect(isScratchpad(scratchpad)).toBe(true); }); // Search should still work with type safety const searchResults = db.searchScratchpads({ query: 'stress' }); expect(searchResults.length).toBeGreaterThan(0); searchResults.forEach((result) => { expect(isScratchpad(result.scratchpad)).toBe(true); }); }); it('should handle append operations with type validation', () => { const workflow = db.createWorkflow({ name: 'Append Safety Test' }); const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: 'Append Test', content: 'Initial content', }); // Multiple append operations for (let i = 0; i < 5; i++) { const updated = db.appendToScratchpad({ id: scratchpad.id, content: `\nAppended content ${i}`, }); expect(isScratchpad(updated)).toBe(true); } // Final validation const final = db.getScratchpadById(scratchpad.id); expect(isScratchpad(final)).toBe(true); expect(final?.content).toContain('Appended content 4'); }); }); }); describe('Integration: WAL + Type Safety Combined', () => { it('should maintain type safety during checkpoint operations', () => { db = new ScratchpadDatabase({ filename: testDbPath }); const workflow = db.createWorkflow({ name: 'Integration Test' }); const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: 'Integration Scratchpad', content: 'Content for integration testing', }); // Verify type safety is maintained const retrieved = db.getScratchpadById(scratchpad.id); expect(isScratchpad(retrieved)).toBe(true); expect(retrieved?.content).toBe('Content for integration testing'); }); it('should handle concurrent operations with WAL and type validation', () => { db = new ScratchpadDatabase({ filename: testDbPath }); const workflow = db.createWorkflow({ name: 'Concurrent Test' }); // Create and immediately append to scratchpads const scratchpads = []; for (let i = 0; i < 10; i++) { const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: `Concurrent ${i}`, content: `Content ${i}`, }); const updated = db.appendToScratchpad({ id: scratchpad.id, content: `\nAppended content ${i}`, }); scratchpads.push(updated); } // All operations should complete successfully with type safety scratchpads.forEach((result) => { expect(isScratchpad(result)).toBe(true); expect(result.content).toContain('Appended content'); }); // Final verification const allScratchpads = db.listScratchpads({ workflow_id: workflow.id }); expect(allScratchpads).toHaveLength(10); allScratchpads.forEach((scratchpad) => { expect(isScratchpad(scratchpad)).toBe(true); }); }); it('should demonstrate combined performance improvements', () => { const startTime = performance.now(); db = new ScratchpadDatabase({ filename: testDbPath }); // Create substantial test data within reasonable limits const workflow = db.createWorkflow({ name: 'Performance Test' }); for (let i = 0; i < 20; i++) { db.createScratchpad({ workflow_id: workflow.id, title: `Performance Test ${i}`, content: `Content for performance testing iteration ${i}. This includes various operations.`, }); } // Search operations (benefits from WAL performance) const searchStart = performance.now(); const searchResults = db.searchScratchpads({ query: 'performance' }); const searchEnd = performance.now(); expect(searchResults.length).toBeGreaterThan(0); expect(searchEnd - searchStart).toBeLessThan(100); // Should be under 100ms // List operations (benefits from type safety) const listStart = performance.now(); const listResults = db.listScratchpads({ workflow_id: workflow.id }); const listEnd = performance.now(); expect(listResults).toHaveLength(20); expect(listEnd - listStart).toBeLessThan(50); // Should be under 50ms // All results should have proper type validation listResults.forEach((result) => { expect(isScratchpad(result)).toBe(true); }); const totalTime = performance.now() - startTime; expect(totalTime).toBeLessThan(300); // Total operation time should be reasonable }); it('should maintain reliability under mixed workloads', () => { db = new ScratchpadDatabase({ filename: testDbPath }); // Create multiple workflows const workflows = []; for (let i = 0; i < 3; i++) { workflows.push(db.createWorkflow({ name: `Mixed Workload ${i}` })); } // Create scratchpads across workflows const allScratchpads = []; workflows.forEach((workflow, workflowIndex) => { for (let i = 0; i < 5; i++) { const scratchpad = db.createScratchpad({ workflow_id: workflow.id, title: `WF${workflowIndex}-SP${i}`, content: `Content for workflow ${workflowIndex}, scratchpad ${i}`, }); allScratchpads.push(scratchpad); } }); // Verify all operations maintain type safety expect(allScratchpads).toHaveLength(15); allScratchpads.forEach((scratchpad) => { expect(isScratchpad(scratchpad)).toBe(true); }); // Cross-workflow searches should work const searchResults = db.searchScratchpads({ query: 'Content' }); expect(searchResults.length).toBeGreaterThanOrEqual(15); searchResults.forEach((result) => { expect(isScratchpad(result.scratchpad)).toBe(true); }); }); }); describe('Performance Benchmarks', () => { it('should meet performance targets with enhanced safety', () => { db = new ScratchpadDatabase({ filename: testDbPath }); const workflow = db.createWorkflow({ name: 'Benchmark Test' }); // Creation performance const createStart = performance.now(); for (let i = 0; i < 10; i++) { db.createScratchpad({ workflow_id: workflow.id, title: `Benchmark ${i}`, content: `Performance benchmark content ${i}`, }); } const createEnd = performance.now(); expect(createEnd - createStart).toBeLessThan(100); // 10 creations under 100ms // Search performance const searchStart = performance.now(); const results = db.searchScratchpads({ query: 'benchmark' }); const searchEnd = performance.now(); expect(searchEnd - searchStart).toBeLessThan(50); // Search under 50ms expect(results.length).toBeGreaterThan(0); // Type validation doesn't significantly impact performance results.forEach((result) => { expect(isScratchpad(result.scratchpad)).toBe(true); }); }); }); });

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/pc035860/scratchpad-mcp'

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