Skip to main content
Glama
adrs-review-resource.test.ts12.1 kB
/** * Unit tests for adrs-review-resource.ts * Tests ADR review resource generation, caching, and parameter handling */ import { URLSearchParams } from 'url'; import { describe, it, expect, beforeAll, _beforeEach, _afterEach, _jest } from 'vitest'; // Mock conditional-request (needed for generateETag) vi.mock('../../src/utils/conditional-request.js', () => ({ generateStrongETag: vi.fn((data: any) => `etag-${JSON.stringify(data).length}`), })); // Mock ResourceCache const mockCacheGet = vi.fn(); const mockCacheSet = vi.fn(); vi.mock('../../src/resources/resource-cache.js', () => ({ resourceCache: { get: mockCacheGet, set: mockCacheSet, }, generateETag: (data: any) => `etag-${JSON.stringify(data).length}`, ResourceCache: vi.fn(), })); // Mock reviewExistingAdrs tool const mockReviewExistingAdrs = vi.fn(); vi.mock('../../src/tools/review-existing-adrs-tool.js', () => ({ reviewExistingAdrs: mockReviewExistingAdrs, })); describe('ADR Review Resource', () => { let generateAdrsReviewResource: any; beforeAll(async () => { const module = await import('../../src/resources/adrs-review-resource.js'); generateAdrsReviewResource = module.generateAdrsReviewResource; }); beforeEach(() => { vi.clearAllMocks(); // Default: no cache hit mockCacheGet.mockResolvedValue(null); // Default: successful review mockReviewExistingAdrs.mockResolvedValue({ content: [ { type: 'text', text: ` ### ADR 001 - Database Architecture **Status**: Accepted ## Compliance Score: 8.5/10 ## Evidence Found - Database schema matches ADR specification - Connection pooling implemented as described - Migration scripts follow defined patterns ## Gaps Identified - Backup strategy not fully implemented - Monitoring dashboards missing ## Recommendations - Implement automated backups - Add performance monitoring - Update ADR with current configuration `, }, ], }); }); afterEach(() => { vi.restoreAllMocks(); }); describe('Basic Resource Generation', () => { it('should generate ADR review with required id parameter', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result).toBeDefined(); expect(result.data).toBeDefined(); expect(result.data.adrId).toBe('001'); expect(result.contentType).toBe('application/json'); expect(result.cacheKey).toBe('adr-review:001:detailed'); expect(result.ttl).toBe(180); }); it('should throw error when id parameter is missing', async () => { await expect(generateAdrsReviewResource({}, new URLSearchParams())).rejects.toThrow( 'Missing required parameter: id' ); }); it('should include timestamp in response', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.timestamp).toBeDefined(); expect(new Date(result.data.timestamp).getTime()).toBeGreaterThan(0); }); it('should call reviewExistingAdrs with correct parameters', async () => { await generateAdrsReviewResource( { id: '001' }, new URLSearchParams('analysisDepth=comprehensive&projectPath=/test/project') ); expect(mockReviewExistingAdrs).toHaveBeenCalledWith({ projectPath: '/test/project', specificAdr: '001', analysisDepth: 'comprehensive', includeTreeSitter: true, generateUpdatePlan: true, }); }); }); describe('Query Parameter Handling', () => { it('should respect analysisDepth parameter', async () => { const result = await generateAdrsReviewResource( { id: '001' }, new URLSearchParams('analysisDepth=basic') ); expect(result.data.analysisDepth).toBe('basic'); expect(result.cacheKey).toBe('adr-review:001:basic'); expect(mockReviewExistingAdrs).toHaveBeenCalledWith( expect.objectContaining({ analysisDepth: 'basic', }) ); }); it('should default analysisDepth to detailed', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.analysisDepth).toBe('detailed'); }); it('should respect includeTreeSitter parameter', async () => { await generateAdrsReviewResource( { id: '001' }, new URLSearchParams('includeTreeSitter=false') ); expect(mockReviewExistingAdrs).toHaveBeenCalledWith( expect.objectContaining({ includeTreeSitter: false, }) ); }); it('should use custom projectPath when provided', async () => { const customPath = '/custom/project/path'; const result = await generateAdrsReviewResource( { id: '001' }, new URLSearchParams(`projectPath=${customPath}`) ); expect(result.data.projectPath).toBe(customPath); }); it('should use process.cwd() as default projectPath', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.projectPath).toBe(process.cwd()); }); }); describe('Compliance Score Extraction', () => { it('should extract compliance score from review text', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.complianceScore).toBe(8.5); }); it('should default to 5 when score not found', async () => { mockReviewExistingAdrs.mockResolvedValue({ content: [{ type: 'text', text: 'Review without score' }], }); const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.complianceScore).toBe(5); }); it('should determine implementation status based on score', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.codeCompliance.implemented).toBe(true); expect(result.data.codeCompliance.partiallyImplemented).toBe(false); expect(result.data.codeCompliance.notImplemented).toBe(false); }); it('should mark as partially implemented for medium scores', async () => { mockReviewExistingAdrs.mockResolvedValue({ content: [{ type: 'text', text: 'Compliance Score: 6.5/10' }], }); const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.codeCompliance.implemented).toBe(false); expect(result.data.codeCompliance.partiallyImplemented).toBe(true); expect(result.data.codeCompliance.notImplemented).toBe(false); }); it('should mark as not implemented for low scores', async () => { mockReviewExistingAdrs.mockResolvedValue({ content: [{ type: 'text', text: 'Compliance Score: 3/10' }], }); const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.codeCompliance.implemented).toBe(false); expect(result.data.codeCompliance.partiallyImplemented).toBe(false); expect(result.data.codeCompliance.notImplemented).toBe(true); }); }); describe('Evidence and Gaps Extraction', () => { it('should extract evidence from review text', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.codeCompliance.evidence).toBeInstanceOf(Array); expect(result.data.codeCompliance.evidence.length).toBeGreaterThan(0); }); it('should extract gaps from review text', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.codeCompliance.gaps).toBeInstanceOf(Array); expect(result.data.codeCompliance.gaps.length).toBeGreaterThan(0); }); it('should extract recommendations from review text', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.recommendations.actions).toBeInstanceOf(Array); expect(result.data.recommendations.actions.length).toBeGreaterThan(0); }); }); describe('Caching', () => { it('should return cached result when available', async () => { const cachedResult = { data: { adrId: '001', title: 'Cached ADR', complianceScore: 9, timestamp: new Date().toISOString(), }, contentType: 'application/json', cacheKey: 'adr-review:001:detailed', }; mockCacheGet.mockResolvedValue(cachedResult); const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result).toBe(cachedResult); expect(mockReviewExistingAdrs).not.toHaveBeenCalled(); }); it('should cache result after generation', async () => { await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(mockCacheSet).toHaveBeenCalledWith( 'adr-review:001:detailed', expect.objectContaining({ data: expect.any(Object), contentType: 'application/json', cacheKey: 'adr-review:001:detailed', ttl: 180, }), 180 ); }); it('should use different cache keys for different analysis depths', async () => { mockCacheGet.mockResolvedValue(null); await generateAdrsReviewResource({ id: '001' }, new URLSearchParams('analysisDepth=basic')); expect(mockCacheSet).toHaveBeenCalledWith('adr-review:001:basic', expect.any(Object), 180); }); }); describe('Error Handling', () => { it('should throw error when review fails', async () => { mockReviewExistingAdrs.mockRejectedValue(new Error('Review failed')); await expect( generateAdrsReviewResource({ id: '001' }, new URLSearchParams()) ).rejects.toThrow('Failed to generate ADR review'); }); it('should handle empty review result', async () => { mockReviewExistingAdrs.mockResolvedValue({ content: [], }); const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.data.analysis).toBe(''); expect(result.data.complianceScore).toBe(5); // default }); }); describe('Response Structure', () => { it('should return properly structured ResourceGenerationResult', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result).toMatchObject({ data: expect.objectContaining({ adrId: '001', title: expect.any(String), status: expect.any(String), complianceScore: expect.any(Number), codeCompliance: expect.objectContaining({ implemented: expect.any(Boolean), partiallyImplemented: expect.any(Boolean), notImplemented: expect.any(Boolean), evidence: expect.any(Array), gaps: expect.any(Array), }), recommendations: expect.objectContaining({ updateAdr: expect.any(Boolean), updateCode: expect.any(Boolean), createPlan: expect.any(Boolean), actions: expect.any(Array), }), analysis: expect.any(String), timestamp: expect.any(String), projectPath: expect.any(String), analysisDepth: expect.any(String), }), contentType: 'application/json', lastModified: expect.any(String), cacheKey: expect.any(String), ttl: 180, etag: expect.any(String), }); }); it('should generate valid etag', async () => { const result = await generateAdrsReviewResource({ id: '001' }, new URLSearchParams()); expect(result.etag).toBeDefined(); expect(typeof result.etag).toBe('string'); expect(result.etag.length).toBeGreaterThan(0); }); }); });

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/tosin2013/mcp-adr-analysis-server'

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