Skip to main content
Glama

mcp-adr-analysis-server

by tosin2013
hybrid-dag-kubernetes.test.ts19.5 kB
/** * End-to-End Integration Test for Hybrid DAG Architecture with Kubernetes Pattern * * This test validates the complete workflow: * 1. Loading validated patterns from YAML * 2. Converting patterns to executable DAG tasks * 3. Building and validating DAG structure * 4. Verifying dependency resolution and task ordering */ import { describe, it, expect, beforeAll } from '@jest/globals'; import { PatternLoader } from '../../src/utils/pattern-loader.js'; import { PatternToDAGConverter } from '../../src/utils/pattern-to-dag-converter.js'; import { DAGExecutor } from '../../src/utils/dag-executor.js'; describe('Hybrid DAG Architecture - Kubernetes E2E Test', () => { let patternLoader: PatternLoader; let patternConverter: PatternToDAGConverter; let dagExecutor: DAGExecutor; beforeAll(() => { patternLoader = new PatternLoader(); patternConverter = new PatternToDAGConverter(); dagExecutor = new DAGExecutor(3); // Max 3 parallel tasks for testing }); describe('Pattern Loading and Validation', () => { it('should load Kubernetes pattern from YAML', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); expect(pattern).toBeDefined(); expect(pattern.id).toBe('kubernetes-v1'); expect(pattern.name).toBe('Kubernetes'); expect(pattern.dependencies).toBeDefined(); expect(pattern.deploymentPhases).toBeDefined(); expect(pattern.validationChecks).toBeDefined(); }); it('should validate Kubernetes pattern structure', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); // Validate dependencies expect(pattern.dependencies.length).toBeGreaterThan(0); const kubectlDep = pattern.dependencies.find(d => d.name === 'kubectl'); expect(kubectlDep).toBeDefined(); expect(kubectlDep?.required).toBe(true); expect(kubectlDep?.installCommand).toBeDefined(); expect(kubectlDep?.verificationCommand).toBeDefined(); // Validate deployment phases expect(pattern.deploymentPhases.length).toBe(4); expect(pattern.deploymentPhases[0]?.name).toBe('Prerequisites Validation'); expect(pattern.deploymentPhases[1]?.name).toBe('Namespace Setup'); expect(pattern.deploymentPhases[2]?.name).toBe('Deploy Application Resources'); expect(pattern.deploymentPhases[3]?.name).toBe('Verify Deployment'); // Validate validation checks expect(pattern.validationChecks.length).toBe(3); const clusterCheck = pattern.validationChecks.find(c => c.id === 'cluster-connection'); expect(clusterCheck).toBeDefined(); expect(clusterCheck?.severity).toBe('critical'); }); it('should have proper authoritative sources', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); expect(pattern.authoritativeSources).toBeDefined(); expect(pattern.authoritativeSources.length).toBeGreaterThan(0); // Should have official Kubernetes documentation const officialDocs = pattern.authoritativeSources.find(s => s.url.includes('kubernetes.io/docs') ); expect(officialDocs).toBeDefined(); expect(officialDocs?.priority).toBe(10); expect(officialDocs?.requiredForDeployment).toBe(true); }); }); describe('Pattern to DAG Conversion', () => { it('should convert Kubernetes pattern to DAG tasks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); expect(dagTasks).toBeDefined(); expect(dagTasks.length).toBeGreaterThan(0); // Should have dependency install/verify tasks const installTasks = dagTasks.filter(t => t.id.includes('install')); expect(installTasks.length).toBeGreaterThan(0); // Should have deployment phase tasks const phaseTasks = dagTasks.filter(t => t.id.includes('phase')); expect(phaseTasks.length).toBeGreaterThan(0); // Should have validation tasks const validationTasks = dagTasks.filter(t => t.id.includes('validate')); expect(validationTasks.length).toBeGreaterThan(0); }); it('should create tasks with proper dependency chains', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find kubectl install and verify tasks const kubectlInstall = dagTasks.find(t => t.id === 'kubernetes-install-kubectl'); const kubectlVerify = dagTasks.find(t => t.id === 'kubernetes-verify-kubectl'); expect(kubectlInstall).toBeDefined(); expect(kubectlVerify).toBeDefined(); // Verify task should depend on install task expect(kubectlVerify?.dependsOn).toContain('kubernetes-install-kubectl'); }); it('should create tasks with infrastructure category and proper severity', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // All tasks should be infrastructure category expect(dagTasks.every(t => t.category === 'infrastructure')).toBe(true); // Critical tasks (first phase, required dependencies) const criticalTasks = dagTasks.filter(t => t.severity === 'critical'); expect(criticalTasks.length).toBeGreaterThan(0); // Dependency tasks should be critical const kubectlInstall = dagTasks.find(t => t.id === 'kubernetes-install-kubectl'); expect(kubectlInstall?.severity).toBe('critical'); }); it('should map deployment phase prerequisites to task dependencies', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find phase 2 tasks (Namespace Setup) - should depend on phase 1 (Prerequisites Validation) const phase2Tasks = dagTasks.filter(t => t.id.includes('phase-2')); const phase1Tasks = dagTasks.filter(t => t.id.includes('phase-1')); if (phase2Tasks.length > 0 && phase1Tasks.length > 0) { const phase2Task = phase2Tasks[0]; const phase1TaskIds = phase1Tasks.map(t => t.id); // Phase 2 should depend on at least one phase 1 task const hasPhase1Dependency = phase2Task?.dependsOn.some(dep => phase1TaskIds.includes(dep)); expect(hasPhase1Dependency).toBe(true); } }); it('should create validation check tasks that depend on deployment tasks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find validation tasks const validationTasks = dagTasks.filter(t => t.id.includes('validate')); if (validationTasks.length > 0) { const validationTask = validationTasks[0]; // Validation tasks should depend on deployment/phase tasks expect(validationTask?.dependsOn.length).toBeGreaterThan(0); // Should not depend on other validation tasks const dependsOnValidation = validationTask?.dependsOn.some(dep => dep.includes('validate')); expect(dependsOnValidation).toBe(false); } }); it('should generate correct task count based on pattern structure', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Expected task count: // - 2 tasks per required dependency (install + verify) = kubectl + kubeconfig = 4 tasks // - Commands from phase 1, 2, 3, 4 = multiple tasks // - 3 validation checks = 3 tasks // Total should be significant expect(dagTasks.length).toBeGreaterThanOrEqual(10); // Log task breakdown for debugging console.log('Task breakdown:'); console.log(` Total tasks: ${dagTasks.length}`); console.log(` Install tasks: ${dagTasks.filter(t => t.id.includes('install')).length}`); console.log(` Verify tasks: ${dagTasks.filter(t => t.id.includes('verify')).length}`); console.log(` Phase tasks: ${dagTasks.filter(t => t.id.includes('phase')).length}`); console.log(` Validation tasks: ${dagTasks.filter(t => t.id.includes('validate')).length}`); }); }); describe('DAG Structure Validation', () => { it('should create a valid DAG without cycles', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // DAGExecutor.validateDAG will throw if there are cycles expect(() => { // Access private method through type casting for testing const executor = dagExecutor as any; executor.validateDAG(dagTasks); }).not.toThrow(); }); it('should have no duplicate task IDs', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); const taskIds = dagTasks.map(t => t.id); const uniqueIds = new Set(taskIds); expect(taskIds.length).toBe(uniqueIds.size); }); it('should have all dependencies exist as tasks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); const taskIds = new Set(dagTasks.map(t => t.id)); for (const task of dagTasks) { for (const depId of task.dependsOn) { expect(taskIds.has(depId)).toBe(true); } } }); it('should have proper topological order', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Build dependency graph and get topological sort const executor = dagExecutor as any; const graph = executor.buildDependencyGraph(dagTasks); const layers = executor.topologicalSort(graph); expect(layers.length).toBeGreaterThan(0); // First layer should have no dependencies or only dependencies within the layer const firstLayer = layers[0]; if (firstLayer) { for (const task of firstLayer) { const allDepsInFirstLayer = task.dependsOn.every(depId => firstLayer.some(t => t.id === depId) ); expect(task.dependsOn.length === 0 || allDepsInFirstLayer).toBe(true); } } // Each subsequent layer should only depend on previous layers for (let i = 1; i < layers.length; i++) { const layer = layers[i]; const previousLayerIds = new Set(layers.slice(0, i).flatMap(l => l?.map(t => t.id) || [])); if (layer) { for (const task of layer) { const allDepsInPreviousLayers = task.dependsOn.every( depId => previousLayerIds.has(depId) || layer.some(t => t.id === depId) ); expect(allDepsInPreviousLayers).toBe(true); } } } }); it('should identify critical path tasks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Critical path should include: // 1. Required dependency installations // 2. Phase 1 (Prerequisites Validation) // 3. Critical validation checks const criticalTasks = dagTasks.filter(t => t.severity === 'critical'); expect(criticalTasks.length).toBeGreaterThan(0); // Should include kubectl installation const kubectlInstall = criticalTasks.find(t => t.id.includes('kubectl')); expect(kubectlInstall).toBeDefined(); }); it('should properly layer tasks for parallel execution', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); const executor = dagExecutor as any; const graph = executor.buildDependencyGraph(dagTasks); const layers = executor.topologicalSort(graph); // Should have multiple layers expect(layers.length).toBeGreaterThan(1); // Log layer information console.log('\nDAG Layer Structure:'); for (let i = 0; i < layers.length; i++) { const layer = layers[i]; if (layer) { console.log(` Layer ${i + 1}: ${layer.length} tasks`); console.log(` Tasks: ${layer.map(t => t.name).join(', ')}`); } } }); }); describe('Validation Check Integration', () => { it('should create validation functions from validation checks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find validation tasks const validationTasks = dagTasks.filter(t => t.validationCheck); expect(validationTasks.length).toBeGreaterThan(0); // Each validation task should have a validation function for (const task of validationTasks) { expect(task.validationCheck).toBeDefined(); expect(typeof task.validationCheck).toBe('function'); } }); it('should validate task output using custom validation functions', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find a validation task const validationTask = dagTasks.find(t => t.validationCheck); if (validationTask?.validationCheck) { // Test validation function with success output const successOutput = 'Pods are running and ready'; expect(validationTask.validationCheck(successOutput)).toBe(true); // Test validation function with failure output const failureOutput = 'Error: pod not found'; expect(validationTask.validationCheck(failureOutput)).toBe(false); } }); it('should detect failure keywords in validation output', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); const validationTask = dagTasks.find(t => t.validationCheck); if (validationTask?.validationCheck) { // Test various failure scenarios const failureOutputs = [ 'error: connection refused', 'failed to connect', 'not found: cluster', 'cannot access cluster', 'unable to authenticate', 'access denied', ]; for (const output of failureOutputs) { expect(validationTask.validationCheck(output)).toBe(false); } } }); it('should detect success indicators in validation output', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); // Find deployment/ready validation task const deploymentTask = dagTasks.find( t => t.id.includes('deployment-ready') || t.id.includes('ready') ); if (deploymentTask?.validationCheck) { // Test success outputs expect(deploymentTask.validationCheck('deployment is ready')).toBe(true); expect(deploymentTask.validationCheck('pods are running')).toBe(true); } }); }); describe('Task Configuration Verification', () => { it('should have proper command structure for all tasks', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); for (const task of dagTasks) { // Task should have either a command or be marked as skippable if (!task.canFailSafely) { expect(task.command || task.commandArgs).toBeDefined(); } // If command exists, it should be a string if (task.command) { expect(typeof task.command).toBe('string'); expect(task.command.length).toBeGreaterThan(0); } // Command args should be an array if present if (task.commandArgs) { expect(Array.isArray(task.commandArgs)).toBe(true); } } }); it('should have reasonable timeout values', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); for (const task of dagTasks) { if (task.timeout) { // Timeout should be between 1 second and 10 minutes expect(task.timeout).toBeGreaterThanOrEqual(1000); expect(task.timeout).toBeLessThanOrEqual(600000); } } }); it('should have proper task naming conventions', async () => { const pattern = await patternLoader.loadPattern('kubernetes'); const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); for (const task of dagTasks) { // ID should start with platform name expect(task.id).toMatch(/^kubernetes-/); // Name should be descriptive expect(task.name.length).toBeGreaterThan(0); // Description should be provided expect(task.description.length).toBeGreaterThan(0); } }); }); describe('Complete Workflow Integration', () => { it('should demonstrate complete pattern-to-DAG workflow', async () => { // This test demonstrates the complete workflow: // 1. Load pattern // 2. Convert to DAG // 3. Validate structure // 4. Verify execution order // Step 1: Load pattern const pattern = await patternLoader.loadPattern('kubernetes'); expect(pattern).toBeDefined(); expect(pattern.id).toBe('kubernetes-v1'); // Step 2: Convert to DAG const dagTasks = patternConverter.buildInfrastructureTasksFromPattern(pattern, 'kubernetes'); expect(dagTasks.length).toBeGreaterThan(0); // Step 3: Validate DAG structure const executor = dagExecutor as any; expect(() => executor.validateDAG(dagTasks)).not.toThrow(); // Step 4: Verify execution order const graph = executor.buildDependencyGraph(dagTasks); const layers = executor.topologicalSort(graph); expect(layers.length).toBeGreaterThan(0); // Log workflow summary console.log('\n=== Kubernetes Pattern Workflow Summary ==='); console.log(`Pattern: ${pattern.name} (${pattern.id})`); console.log(`Generated Tasks: ${dagTasks.length}`); console.log(`Execution Layers: ${layers.length}`); console.log(`Max Parallelism: 3 tasks per layer`); console.log(`Critical Tasks: ${dagTasks.filter(t => t.severity === 'critical').length}`); console.log('==========================================\n'); }, 30000); // 30 second timeout for complete workflow }); });

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