// Orchestration Integration Tests const TestEnvironment = require('./setup'); const TestHelpers = require('./helpers'); const apiGatewayApp = require('../../services/api-gateway/src/app'); const orchestratorApp = require('../../services/orchestrator/src/app'); const claudeAgentApp = require('../../services/claude-agent/src/app'); const gramjsAdapterApp = require('../../services/gramjs-adapter/src/app'); describe('Orchestration Integration Tests', () => { let testEnv; let helpers; let apiClient; let testUser; const SERVICES = { 'api-gateway': { app: apiGatewayApp, port: 13000 }, 'orchestrator': { app: orchestratorApp, port: 13001 }, 'claude-agent': { app: claudeAgentApp, port: 13002 }, 'gramjs-adapter': { app: gramjsAdapterApp, port: 13003 } }; beforeAll(async () => { testEnv = new TestEnvironment(); helpers = new TestHelpers(testEnv); // Setup test environment await testEnv.setup(); // Setup mocks helpers.setupMocks(); // Start all services for (const [name, config] of Object.entries(SERVICES)) { await testEnv.startService(name, config.app, config.port); } // Wait for services to be ready await helpers.sleep(2000); // Create test user testUser = await testEnv.createTestUser(); // Create authenticated client apiClient = await helpers.createAuthenticatedClient( `http://localhost:${SERVICES['api-gateway'].port}`, testUser ); }); afterAll(async () => { helpers.cleanupMocks(); await testEnv.cleanup(); }); describe('Campaign Orchestration', () => { test('should create and execute a campaign', async () => { // Create campaign const campaignData = { name: 'Integration Test Campaign', description: 'Testing full orchestration flow', targetAudience: { groups: ['test-group-1'], tags: ['integration-test'] }, messages: [ { content: 'Hello from integration test!', type: 'text', delay: 0 }, { content: 'This is the second message', type: 'text', delay: 1000 } ], schedule: { startTime: new Date(), endTime: new Date(Date.now() + 3600000), timezone: 'UTC' }, goals: { impressions: 100, clicks: 10 } }; const createResponse = await apiClient.post('/api/v1/campaigns', campaignData); const { campaign } = helpers.expectApiSuccess(createResponse, 201); expect(campaign.campaignId).toBeDefined(); expect(campaign.status).toBe('draft'); // Start campaign const startResponse = await apiClient.post( `/api/v1/campaigns/${campaign.campaignId}/start` ); helpers.expectApiSuccess(startResponse); // Wait for campaign to start processing await helpers.sleep(2000); // Check campaign status const statusResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}` ); const updatedCampaign = helpers.expectApiSuccess(statusResponse).campaign; expect(['active', 'completed']).toContain(updatedCampaign.status); // Check that tasks were created const tasksResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}/tasks` ); const { tasks } = helpers.expectApiSuccess(tasksResponse); expect(tasks).toBeDefined(); expect(tasks.length).toBeGreaterThan(0); expect(tasks[0].type).toBe('SEND_MESSAGE'); }); test('should handle campaign pause and resume', async () => { // Create and start campaign const campaign = await helpers.createTestCampaign({ status: 'active' }); // Pause campaign const pauseResponse = await apiClient.post( `/api/v1/campaigns/${campaign.campaignId}/pause` ); helpers.expectApiSuccess(pauseResponse); // Verify paused status const pausedResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}` ); const pausedCampaign = helpers.expectApiSuccess(pausedResponse).campaign; expect(pausedCampaign.status).toBe('paused'); // Resume campaign const resumeResponse = await apiClient.post( `/api/v1/campaigns/${campaign.campaignId}/resume` ); helpers.expectApiSuccess(resumeResponse); // Verify active status const activeResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}` ); const activeCampaign = helpers.expectApiSuccess(activeResponse).campaign; expect(activeCampaign.status).toBe('active'); }); test('should handle campaign cancellation', async () => { // Create and start campaign const campaign = await helpers.createTestCampaign({ status: 'active' }); // Cancel campaign const cancelResponse = await apiClient.post( `/api/v1/campaigns/${campaign.campaignId}/cancel` ); helpers.expectApiSuccess(cancelResponse); // Verify cancelled status const cancelledResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}` ); const cancelledCampaign = helpers.expectApiSuccess(cancelledResponse).campaign; expect(cancelledCampaign.status).toBe('cancelled'); }); }); describe('Task Execution', () => { test('should execute message sending task', async () => { // Create a message task const task = await helpers.createTestTask({ type: 'SEND_MESSAGE', payload: { message: 'Test message from integration test', chatId: 'test-chat-123', options: { parseMode: 'HTML' } } }); // Execute task const executeResponse = await apiClient.post( `/api/v1/tasks/${task.taskId}/execute` ); helpers.expectApiSuccess(executeResponse); // Wait for execution await helpers.sleep(1000); // Check task status const statusResponse = await apiClient.get( `/api/v1/tasks/${task.taskId}` ); const executedTask = helpers.expectApiSuccess(statusResponse).task; expect(['completed', 'processing']).toContain(executedTask.status); expect(executedTask.result).toBeDefined(); }); test('should handle task retry on failure', async () => { // Create a task that will fail const task = await helpers.createTestTask({ type: 'SEND_MESSAGE', payload: { message: 'Test message', chatId: 'invalid-chat-id', // This should cause a failure options: {} }, maxRetries: 3 }); // Execute task const executeResponse = await apiClient.post( `/api/v1/tasks/${task.taskId}/execute` ); helpers.expectApiSuccess(executeResponse); // Wait for retries await helpers.sleep(3000); // Check task status const statusResponse = await apiClient.get( `/api/v1/tasks/${task.taskId}` ); const retriedTask = helpers.expectApiSuccess(statusResponse).task; expect(retriedTask.retryCount).toBeGreaterThan(0); expect(['failed', 'pending']).toContain(retriedTask.status); }); }); describe('Claude Agent Integration', () => { test('should generate campaign strategy using Claude', async () => { const strategyRequest = { goal: 'Increase user engagement', targetAudience: { demographics: { age: '25-35', interests: ['technology', 'startups'] }, size: 1000 }, constraints: { budget: 1000, duration: '7 days' } }; const response = await apiClient.post( '/api/v1/ai/strategy/generate', strategyRequest ); const { strategy } = helpers.expectApiSuccess(response); expect(strategy).toBeDefined(); expect(strategy.messages).toBeDefined(); expect(strategy.schedule).toBeDefined(); expect(strategy.expectedOutcomes).toBeDefined(); }); test('should analyze campaign performance', async () => { // Create a completed campaign with some metrics const campaign = await helpers.createTestCampaign({ status: 'completed', metrics: { impressions: 500, clicks: 50, conversions: 5 } }); const analysisRequest = { campaignId: campaign.campaignId, metrics: campaign.metrics }; const response = await apiClient.post( '/api/v1/ai/analysis/campaign', analysisRequest ); const { analysis } = helpers.expectApiSuccess(response); expect(analysis).toBeDefined(); expect(analysis.performance).toBeDefined(); expect(analysis.recommendations).toBeDefined(); expect(analysis.insights).toBeDefined(); }); }); describe('Message Queue Integration', () => { test('should process messages through RabbitMQ', async () => { if (!testEnv.getRabbitChannel()) { console.log('Skipping RabbitMQ test - not available'); return; } const channel = testEnv.getRabbitChannel(); const testQueue = 'test-integration-queue'; const testMessage = { type: 'TEST_MESSAGE', data: { value: 'Integration test message', timestamp: new Date().toISOString() } }; // Create queue await channel.assertQueue(testQueue, { durable: false }); // Set up consumer const receivedMessages = []; await channel.consume(testQueue, (msg) => { if (msg) { receivedMessages.push(JSON.parse(msg.content.toString())); channel.ack(msg); } }); // Send message channel.sendToQueue( testQueue, Buffer.from(JSON.stringify(testMessage)) ); // Wait for message to be processed await helpers.sleep(1000); // Verify message was received expect(receivedMessages).toHaveLength(1); expect(receivedMessages[0]).toEqual(testMessage); // Cleanup await channel.deleteQueue(testQueue); }); }); describe('End-to-End Workflow', () => { test('should complete full marketing workflow', async () => { // 1. Generate strategy with Claude const strategyResponse = await apiClient.post('/api/v1/ai/strategy/generate', { goal: 'Product launch announcement', targetAudience: { demographics: { interests: ['tech'] }, size: 500 } }); const { strategy } = helpers.expectApiSuccess(strategyResponse); // 2. Create campaign based on strategy const campaignData = { name: 'Product Launch Campaign', description: 'Generated from AI strategy', targetAudience: strategy.targetAudience, messages: strategy.messages, schedule: strategy.schedule, goals: strategy.expectedOutcomes }; const createResponse = await apiClient.post('/api/v1/campaigns', campaignData); const { campaign } = helpers.expectApiSuccess(createResponse, 201); // 3. Start campaign await apiClient.post(`/api/v1/campaigns/${campaign.campaignId}/start`); // 4. Wait for some execution await helpers.sleep(3000); // 5. Get analytics const analyticsResponse = await apiClient.get( `/api/v1/analytics/campaigns/${campaign.campaignId}/metrics` ); const { metrics } = helpers.expectApiSuccess(analyticsResponse); expect(metrics).toBeDefined(); expect(metrics.totalMessages).toBeGreaterThanOrEqual(0); // 6. Get AI analysis const analysisResponse = await apiClient.post('/api/v1/ai/analysis/campaign', { campaignId: campaign.campaignId, metrics: metrics }); const { analysis } = helpers.expectApiSuccess(analysisResponse); expect(analysis).toBeDefined(); expect(analysis.performance).toBeDefined(); // 7. Stop campaign await apiClient.post(`/api/v1/campaigns/${campaign.campaignId}/cancel`); // Verify final state const finalResponse = await apiClient.get( `/api/v1/campaigns/${campaign.campaignId}` ); const finalCampaign = helpers.expectApiSuccess(finalResponse).campaign; expect(finalCampaign.status).toBe('cancelled'); }); }); });