Skip to main content
Glama
deployment-task-integration.test.ts15.5 kB
/** * Tests for Deployment Task Integration * * Validates the MCP Tasks integration for deployment readiness tool, * implementing ADR-020: MCP Tasks Integration Strategy. * * @see ADR-020: MCP Tasks Integration Strategy */ import { DeploymentTaskManager, getDeploymentTaskManager, resetDeploymentTaskManager, executeDeploymentWithTaskTracking, DEPLOYMENT_PHASES, type CreateDeploymentTaskOptions, type DeploymentTaskResult, } from '../../src/utils/deployment-task-integration.js'; import { resetTaskManager } from '../../src/utils/task-manager.js'; describe('DeploymentTaskManager', () => { let dtm: DeploymentTaskManager; beforeEach(async () => { // Reset both task managers before each test await resetTaskManager(); await resetDeploymentTaskManager(); dtm = getDeploymentTaskManager(); await dtm.initialize(); }); afterEach(async () => { await resetDeploymentTaskManager(); await resetTaskManager(); }); describe('Task Creation', () => { it('should create a deployment task with phases', async () => { const options: CreateDeploymentTaskOptions = { projectPath: '/path/to/project', targetEnvironment: 'production', operation: 'full_audit', strictMode: true, enableMemoryIntegration: true, }; const { task, context } = await dtm.createDeploymentTask(options); expect(task).toBeDefined(); expect(task.taskId).toBeDefined(); expect(task.status).toBe('working'); expect(task.metadata?.type).toBe('deployment'); expect(task.metadata?.tool).toBe('deployment_readiness'); expect(task.metadata?.phases).toHaveLength(DEPLOYMENT_PHASES.length); expect(context).toBeDefined(); expect(context.taskId).toBe(task.taskId); expect(context.currentPhase).toBe('initialization'); expect(context.operation).toBe('full_audit'); expect(context.targetEnvironment).toBe('production'); expect(context.cancelled).toBe(false); }); it('should include project path and environment in metadata', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/my/project', targetEnvironment: 'staging', operation: 'test_validation', }); expect(task.metadata?.projectPath).toBe('/my/project'); }); }); describe('Phase Management', () => { it('should start and complete phases', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); // Start test validation phase await dtm.startPhase(task.taskId, 'test_validation', 'Running tests...'); const { task: updatedTask } = await dtm.getTaskStatus(task.taskId); const phase = updatedTask?.metadata?.phases?.find(p => p.name === 'test_validation'); expect(phase?.status).toBe('running'); // Complete the phase await dtm.completePhase(task.taskId, 'test_validation', 'Tests completed'); const { task: completedTask } = await dtm.getTaskStatus(task.taskId); const completedPhase = completedTask?.metadata?.phases?.find( p => p.name === 'test_validation' ); expect(completedPhase?.status).toBe('completed'); expect(completedPhase?.progress).toBe(100); }); it('should fail a phase with error', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.startPhase(task.taskId, 'code_quality_analysis'); await dtm.failPhase(task.taskId, 'code_quality_analysis', 'Security vulnerabilities found'); const { task: failedTask } = await dtm.getTaskStatus(task.taskId); const phase = failedTask?.metadata?.phases?.find(p => p.name === 'code_quality_analysis'); expect(phase?.status).toBe('failed'); expect(phase?.error).toBe('Security vulnerabilities found'); }); it('should update phase progress', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.startPhase(task.taskId, 'test_validation'); await dtm.updatePhaseProgress(task.taskId, 'test_validation', 50, 'Halfway through tests'); const { task: updatedTask } = await dtm.getTaskStatus(task.taskId); const phase = updatedTask?.metadata?.phases?.find(p => p.name === 'test_validation'); expect(phase?.progress).toBe(50); }); }); describe('Result Storage', () => { it('should store test validation result', async () => { const { task, context } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'test_validation', }); await dtm.storeTestValidationResult(task.taskId, { passed: true, failureCount: 0, coveragePercentage: 85, }); expect(context.testValidationResult).toBeDefined(); expect(context.testValidationResult?.passed).toBe(true); expect(context.testValidationResult?.failureCount).toBe(0); expect(context.testValidationResult?.coveragePercentage).toBe(85); }); it('should store code quality result', async () => { const { task, context } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.storeCodeQualityResult(task.taskId, { score: 92, securityIssues: 2, complexity: 8.5, }); expect(context.codeQualityResult).toBeDefined(); expect(context.codeQualityResult?.score).toBe(92); expect(context.codeQualityResult?.securityIssues).toBe(2); }); it('should store deployment history analysis result', async () => { const { task, context } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'deployment_history', }); await dtm.storeHistoryAnalysisResult(task.taskId, { successRate: 95, rollbackRate: 5, recommendedAction: 'proceed', }); expect(context.historyAnalysisResult).toBeDefined(); expect(context.historyAnalysisResult?.successRate).toBe(95); expect(context.historyAnalysisResult?.rollbackRate).toBe(5); expect(context.historyAnalysisResult?.recommendedAction).toBe('proceed'); }); it('should store ADR compliance result', async () => { const { task, context } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.storeAdrComplianceResult(task.taskId, { score: 88, compliantAdrs: 15, totalAdrs: 17, }); expect(context.adrComplianceResult).toBeDefined(); expect(context.adrComplianceResult?.score).toBe(88); expect(context.adrComplianceResult?.compliantAdrs).toBe(15); expect(context.adrComplianceResult?.totalAdrs).toBe(17); }); it('should store blocker count', async () => { const { task, context } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.storeBlockerCount(task.taskId, 3); expect(context.blockerCount).toBe(3); }); }); describe('Cancellation', () => { it('should check if task is cancelled', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); expect(await dtm.isCancelled(task.taskId)).toBe(false); await dtm.cancelTask(task.taskId, 'User cancelled'); // Context is removed after cancellation expect(dtm.getContext(task.taskId)).toBeUndefined(); }); it('should throw error when starting phase on cancelled task', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); // Set cancelled flag in context const context = dtm.getContext(task.taskId); if (context) { context.cancelled = true; } await expect(dtm.startPhase(task.taskId, 'test_validation')).rejects.toThrow('cancelled'); }); }); describe('Task Completion', () => { it('should complete task successfully', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); const result: DeploymentTaskResult = { success: true, data: { isDeploymentReady: true, overallScore: 95, confidence: 90, blockerCount: 0, testsPassed: true, gitPushStatus: 'allowed', }, }; await dtm.completeTask(task.taskId, result); const { task: completedTask } = await dtm.getTaskStatus(task.taskId); expect(completedTask?.status).toBe('completed'); expect(completedTask?.result).toEqual(result); // Context should be cleaned up expect(dtm.getContext(task.taskId)).toBeUndefined(); }); it('should fail task with error', async () => { const { task } = await dtm.createDeploymentTask({ projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }); await dtm.failTask(task.taskId, 'Critical security vulnerability detected'); const { task: failedTask } = await dtm.getTaskStatus(task.taskId); expect(failedTask?.status).toBe('failed'); // Context should be cleaned up expect(dtm.getContext(task.taskId)).toBeUndefined(); }); }); }); describe('executeDeploymentWithTaskTracking', () => { beforeEach(async () => { await resetTaskManager(); await resetDeploymentTaskManager(); }); afterEach(async () => { await resetDeploymentTaskManager(); await resetTaskManager(); }); it('should execute deployment workflow with task tracking', async () => { const options: CreateDeploymentTaskOptions = { projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }; const { taskId, result } = await executeDeploymentWithTaskTracking<DeploymentTaskResult>( options, async tracker => { // Test validation phase await tracker.startPhase('test_validation'); await tracker.storeTestValidationResult({ passed: true, failureCount: 0, coveragePercentage: 90, }); await tracker.completePhase('test_validation'); // Code quality phase await tracker.startPhase('code_quality_analysis'); await tracker.storeCodeQualityResult({ score: 95, securityIssues: 0, complexity: 5.2, }); await tracker.completePhase('code_quality_analysis'); // ADR compliance phase await tracker.startPhase('adr_compliance_check'); await tracker.storeAdrComplianceResult({ score: 100, compliantAdrs: 20, totalAdrs: 20, }); await tracker.completePhase('adr_compliance_check'); // Store blocker count await tracker.storeBlockerCount(0); // Return result return { isDeploymentReady: true, overallScore: 95, confidence: 90, blockerCount: 0, testsPassed: true, gitPushStatus: 'allowed', }; } ); expect(taskId).toBeDefined(); expect(result.success).toBe(true); expect(result.data?.isDeploymentReady).toBe(true); expect(result.data?.gitPushStatus).toBe('allowed'); }); it('should handle errors in executor', async () => { const options: CreateDeploymentTaskOptions = { projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }; const { taskId, result } = await executeDeploymentWithTaskTracking<DeploymentTaskResult>( options, async () => { throw new Error('Critical test failures'); } ); expect(taskId).toBeDefined(); expect(result.success).toBe(false); expect(result.error?.code).toBe('DEPLOYMENT_READINESS_ERROR'); expect(result.error?.message).toBe('Critical test failures'); }); it('should check cancellation during execution', async () => { const options: CreateDeploymentTaskOptions = { projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }; const { taskId: _taskId, result } = await executeDeploymentWithTaskTracking<DeploymentTaskResult>(options, async tracker => { // Check cancellation at start if (await tracker.isCancelled()) { throw new Error('Task was cancelled'); } await tracker.startPhase('test_validation'); await tracker.completePhase('test_validation'); return { isDeploymentReady: true, overallScore: 100, confidence: 100, blockerCount: 0, testsPassed: true, gitPushStatus: 'allowed', }; }); expect(result.success).toBe(true); }); it('should handle blocked deployment scenario', async () => { const options: CreateDeploymentTaskOptions = { projectPath: '/project', targetEnvironment: 'production', operation: 'full_audit', }; const { taskId, result } = await executeDeploymentWithTaskTracking<DeploymentTaskResult>( options, async tracker => { // Test validation phase - with failures await tracker.startPhase('test_validation'); await tracker.storeTestValidationResult({ passed: false, failureCount: 5, coveragePercentage: 60, }); await tracker.completePhase('test_validation'); // Store blocker count await tracker.storeBlockerCount(3); // Return blocked result return { isDeploymentReady: false, overallScore: 45, confidence: 80, blockerCount: 3, testsPassed: false, gitPushStatus: 'blocked', }; } ); expect(taskId).toBeDefined(); expect(result.success).toBe(false); expect(result.data?.isDeploymentReady).toBe(false); expect(result.data?.gitPushStatus).toBe('blocked'); expect(result.data?.blockerCount).toBe(3); }); }); describe('Global DeploymentTaskManager', () => { beforeEach(async () => { await resetDeploymentTaskManager(); await resetTaskManager(); }); afterEach(async () => { await resetDeploymentTaskManager(); await resetTaskManager(); }); it('should return singleton instance', () => { const dtm1 = getDeploymentTaskManager(); const dtm2 = getDeploymentTaskManager(); expect(dtm1).toBe(dtm2); }); it('should reset global instance', async () => { const dtm1 = getDeploymentTaskManager(); await resetDeploymentTaskManager(); const dtm2 = getDeploymentTaskManager(); expect(dtm1).not.toBe(dtm2); }); });

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