#!/usr/bin/env bun /** * Production Deployment Integration Test * * Tests the complete deployment flow with real Dokploy API: * - Project creation * - Environment retrieval * - Application creation * - Configuration * - Domain setup * - Deployment * - Health verification * - Cleanup/Rollback */ import { createProductionDokployClient } from './api/dokploy-production.js'; import { ProductionDeployer } from './orchestrator/production-deployer.js'; console.log('═══════════════════════════════════════'); console.log(' Production Deployment Integration Test'); console.log('═══════════════════════════════════════\n'); const TEST_STACK_NAME = `test-prod-${Date.now()}`; const DOCKER_IMAGE = process.env.STACK_IMAGE || 'nginx:alpine'; const DOMAIN_SUFFIX = process.env.STACK_DOMAIN_SUFFIX || 'ai.flexinit.nl'; console.log(`Test Configuration:`); console.log(` Stack Name: ${TEST_STACK_NAME}`); console.log(` Docker Image: ${DOCKER_IMAGE}`); console.log(` Domain: ${TEST_STACK_NAME}.${DOMAIN_SUFFIX}`); console.log(); async function main() { const client = createProductionDokployClient(); const deployer = new ProductionDeployer(client); console.log('🚀 Starting deployment...\n'); const result = await deployer.deploy({ stackName: TEST_STACK_NAME, dockerImage: DOCKER_IMAGE, domainSuffix: DOMAIN_SUFFIX, port: 80, // nginx default port healthCheckTimeout: 120000, // 2 minutes healthCheckInterval: 5000, // 5 seconds }); console.log('\n═══════════════════════════════════════'); console.log(' Deployment Result'); console.log('═══════════════════════════════════════\n'); console.log(`Status: ${result.success ? '✅ SUCCESS' : '❌ FAILURE'}`); console.log(`Deployment ID: ${result.state.id}`); console.log(`Final Phase: ${result.state.phase}`); console.log(`Progress: ${result.state.progress}%`); console.log(`Message: ${result.state.message}`); if (result.state.url) { console.log(`URL: ${result.state.url}`); } console.log(`\nResources Created:`); console.log(` Project ID: ${result.state.resources.projectId || 'N/A'}`); console.log(` Environment ID: ${result.state.resources.environmentId || 'N/A'}`); console.log(` Application ID: ${result.state.resources.applicationId || 'N/A'}`); console.log(` Domain ID: ${result.state.resources.domainId || 'N/A'}`); console.log(`\nTimestamps:`); console.log(` Started: ${result.state.timestamps.started}`); console.log(` Completed: ${result.state.timestamps.completed || 'N/A'}`); if (result.state.error) { console.log(`\nError Details:`); console.log(` Phase: ${result.state.error.phase}`); console.log(` Message: ${result.state.error.message}`); if (result.state.error.code) { console.log(` Code: ${result.state.error.code}`); } } console.log(`\nCircuit Breaker State: ${client.getCircuitBreakerState()}`); console.log(`\n═══════════════════════════════════════`); console.log(' Deployment Logs'); console.log('═══════════════════════════════════════\n'); const logs = client.getLogs(); logs.forEach(log => { const level = log.level.toUpperCase().padEnd(5); const phase = log.phase.padEnd(15); const action = log.action.padEnd(10); const duration = log.duration_ms ? ` (${log.duration_ms}ms)` : ''; console.log(`[${level}] ${phase} ${action} ${log.message}${duration}`); if (log.error) { console.log(` Error: ${log.error.message}`); } }); // Cleanup test resources if (result.success && result.state.resources.applicationId) { console.log('\n🧹 Cleaning up test resources...'); try { await client.deleteApplication(result.state.resources.applicationId); console.log('✅ Test application deleted'); if (result.state.resources.projectId) { await client.deleteProject(result.state.resources.projectId); console.log('✅ Test project deleted'); } } catch (error) { console.error('❌ Cleanup failed:', error); } } console.log('\n═══════════════════════════════════════'); console.log(result.success ? ' ✅ Test PASSED' : ' ❌ Test FAILED'); console.log('═══════════════════════════════════════\n'); process.exit(result.success ? 0 : 1); } main().catch(error => { console.error('\n❌ Test execution failed:', error); process.exit(1); });