const { expect } = require('chai'); const sinon = require('sinon'); const TestSetup = require('../setup'); // Import all services for integration testing const TaskExecutionEngine = require('../../src/service/TaskExecutionEngine'); const AccountScheduler = require('../../src/service/AccountScheduler'); const RiskStrategyService = require('../../src/service/RiskStrategyService'); const BehaviorSimulationService = require('../../src/service/BehaviorSimulationService'); const ContentVariationService = require('../../src/service/ContentVariationService'); const AlertNotificationService = require('../../src/service/AlertNotificationService'); const MessageQueueService = require('../../src/service/MessageQueueService'); describe('Task Workflow Integration Tests', function() { let testDb; let testRedis; let taskEngine; let accountScheduler; let riskService; let behaviorService; let contentService; let alertService; let queueService; before(async function() { this.timeout(20000); // Setup test environment await TestSetup.setupDatabase(); await TestSetup.setupRedis(); await TestSetup.createTestData(); testDb = TestSetup.getTestDb(); testRedis = TestSetup.getTestRedis(); // Initialize all services taskEngine = new TaskExecutionEngine(); accountScheduler = new AccountScheduler(); riskService = new RiskStrategyService(); behaviorService = new BehaviorSimulationService(); contentService = new ContentVariationService(); alertService = new AlertNotificationService(); queueService = new MessageQueueService(); // Initialize services await taskEngine.initialize(); await accountScheduler.start(); await riskService.initialize(); await behaviorService.initialize(); await contentService.initialize(); await alertService.initialize(); await queueService.initialize(); }); after(async function() { // Cleanup all services if (taskEngine) await taskEngine.shutdown(); if (accountScheduler) await accountScheduler.stop(); if (riskService) await riskService.shutdown(); if (behaviorService) await behaviorService.shutdown(); if (contentService) await contentService.shutdown(); if (alertService) await alertService.shutdown(); if (queueService) await queueService.shutdown(); await TestSetup.cleanup(); }); describe('Complete Task Execution Workflow', function() { it('should execute a full task with all integrations', async function() { this.timeout(15000); const mockTask = { id: 1, name: 'Integration Test Task', targetInfo: JSON.stringify({ targets: [ { id: 'group1', name: 'Test Group 1', type: 'group' }, { id: 'group2', name: 'Test Group 2', type: 'group' } ] }), messageContent: JSON.stringify({ content: 'Hello! This is a test message for integration testing.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'sequential', interval: 2000, batchSize: 1, enableRiskControl: true, enableBehaviorSimulation: true, enableContentVariation: true }), status: 'pending' }; // Mock external Telegram API calls const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: `msg_${Date.now()}`, timestamp: new Date(), executionTime: 1200 }); // Execute the complete workflow const result = await taskEngine.executeTask(mockTask); // Verify overall execution success expect(result).to.have.property('success', true); expect(result).to.have.property('taskId', mockTask.id); expect(result).to.have.property('totalTargets', 2); expect(result).to.have.property('successCount'); expect(result).to.have.property('failureCount'); expect(result).to.have.property('executionTime'); // Verify all targets were processed expect(result.successCount + result.failureCount).to.equal(2); // Verify Telegram API was called for each target expect(telegramSendStub.callCount).to.equal(2); telegramSendStub.restore(); }); it('should handle risk-based task modification', async function() { this.timeout(10000); const riskTask = { id: 2, name: 'Risk Control Test Task', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This message should trigger risk controls.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate', enableRiskControl: true }), status: 'pending' }; // Mock medium risk scenario const riskEvalStub = sinon.stub(riskService, 'evaluateOverallRisk').resolves('medium'); const riskActionStub = sinon.stub(riskService, 'executeRiskAction').resolves({ action: 'delayed', delay: 5000, reason: 'Frequency threshold reached', success: true }); const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: 'msg_risk_test', timestamp: new Date() }); const startTime = Date.now(); const result = await taskEngine.executeTask(riskTask); const endTime = Date.now(); // Verify risk control was applied (should have been delayed) expect(result.success).to.be.true; expect(endTime - startTime).to.be.at.least(5000); // Should have been delayed // Verify risk evaluation was called expect(riskEvalStub.called).to.be.true; expect(riskActionStub.called).to.be.true; riskEvalStub.restore(); riskActionStub.restore(); telegramSendStub.restore(); }); it('should integrate account switching on health issues', async function() { this.timeout(10000); const accountTask = { id: 3, name: 'Account Health Test Task', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'Testing account health-based switching.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate', enableRiskControl: true }), status: 'pending' }; // Mock unhealthy account selection and switching const selectStub = sinon.stub(accountScheduler, 'selectOptimalAccount'); selectStub.onFirstCall().resolves({ accountId: 3, healthScore: 30, // Low health status: 'warning', tier: 'normal' }); selectStub.onSecondCall().resolves({ accountId: 1, healthScore: 85, // High health status: 'active', tier: 'normal' }); const riskEvalStub = sinon.stub(riskService, 'evaluateOverallRisk').resolves('high'); const riskActionStub = sinon.stub(riskService, 'executeRiskAction').resolves({ action: 'switched', originalAccount: 3, newAccount: { accountId: 1, healthScore: 85 }, reason: 'Account health too low', success: true }); const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: 'msg_health_test', timestamp: new Date() }); const result = await taskEngine.executeTask(accountTask); // Verify task succeeded with account switching expect(result.success).to.be.true; expect(riskActionStub.called).to.be.true; selectStub.restore(); riskEvalStub.restore(); riskActionStub.restore(); telegramSendStub.restore(); }); }); describe('Message Queue Integration', function() { it('should process tasks through message queue', async function() { this.timeout(10000); const queuedTask = { id: 'queue_integration_test', taskData: { id: 4, name: 'Queued Task Test', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This message was processed through the queue.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'queued', priority: 'normal' }) }, priority: 'normal', attempts: 0 }; // Mock queue processing methods on task engine const processQueuedStub = sinon.stub(taskEngine, 'processQueuedTask').resolves({ success: true, jobId: queuedTask.id, processedAt: new Date(), executionTime: 1500 }); // Add task to queue const jobId = await queueService.addJob('task_execution', queuedTask, { priority: queuedTask.priority }); expect(jobId).to.not.be.null; // Simulate queue processing const result = await taskEngine.processQueuedTask(queuedTask); expect(result).to.have.property('success', true); expect(result).to.have.property('jobId', queuedTask.id); processQueuedStub.restore(); }); it('should handle queue failures with retry mechanism', async function() { this.timeout(10000); const failingTask = { id: 'failing_queue_test', taskData: { id: 5, targetInfo: JSON.stringify({ targets: [{ id: 'group1', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This task will fail initially.', type: 'text' }) }, attempts: 0, maxRetries: 2 }; let callCount = 0; const processStub = sinon.stub(taskEngine, 'processQueuedTaskWithRetry').callsFake(async () => { callCount++; if (callCount === 1) { throw new Error('First attempt failed'); } return { success: true, jobId: failingTask.id, attempts: callCount, processedAt: new Date() }; }); const result = await taskEngine.processQueuedTaskWithRetry(failingTask); expect(result.success).to.be.true; expect(callCount).to.equal(2); // Failed once, succeeded on retry processStub.restore(); }); }); describe('Real-time Monitoring Integration', function() { it('should emit monitoring events during task execution', async function() { this.timeout(10000); const monitoringTask = { id: 6, name: 'Monitoring Integration Test', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This task tests monitoring integration.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'sequential', enableMonitoring: true }), status: 'pending' }; // Track monitoring events const monitoringEvents = []; taskEngine.on('taskStarted', (data) => { monitoringEvents.push({ event: 'taskStarted', data }); }); taskEngine.on('taskProgress', (data) => { monitoringEvents.push({ event: 'taskProgress', data }); }); taskEngine.on('taskCompleted', (data) => { monitoringEvents.push({ event: 'taskCompleted', data }); }); const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: 'msg_monitoring_test', timestamp: new Date() }); const result = await taskEngine.executeTask(monitoringTask); // Verify task execution expect(result.success).to.be.true; // Verify monitoring events were emitted expect(monitoringEvents.length).to.be.at.least(2); // At least start and complete const startEvent = monitoringEvents.find(e => e.event === 'taskStarted'); const completeEvent = monitoringEvents.find(e => e.event === 'taskCompleted'); expect(startEvent).to.not.be.undefined; expect(completeEvent).to.not.be.undefined; telegramSendStub.restore(); }); it('should send alerts on critical issues', async function() { this.timeout(10000); const alertTask = { id: 7, name: 'Alert Integration Test', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This task should trigger alerts.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate' }), status: 'pending' }; // Mock critical risk that should trigger alerts const riskEvalStub = sinon.stub(riskService, 'evaluateOverallRisk').resolves('critical'); const riskActionStub = sinon.stub(riskService, 'executeRiskAction').resolves({ action: 'blocked', reason: 'Critical security risk detected', success: false }); // Mock alert sending const alertStub = sinon.stub(alertService, 'sendAlert').resolves({ sent: true, channels: ['websocket'], timestamp: new Date() }); const result = await taskEngine.executeTask(alertTask); // Verify task was blocked expect(result.success).to.be.false; // Verify alert was sent expect(alertStub.called).to.be.true; riskEvalStub.restore(); riskActionStub.restore(); alertStub.restore(); }); }); describe('Content and Behavior Integration', function() { it('should apply content variation and behavior simulation', async function() { this.timeout(10000); const contentTask = { id: 8, name: 'Content Behavior Integration Test', targetInfo: JSON.stringify({ targets: [ { id: 'group1', name: 'Test Group 1', type: 'group' }, { id: 'group2', name: 'Test Group 2', type: 'group' } ] }), messageContent: JSON.stringify({ content: 'Hello world! This is a test message that should be varied.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'sequential', interval: 1000, enableContentVariation: true, enableBehaviorSimulation: true }), status: 'pending' }; // Mock content variation const variationStub = sinon.stub(contentService, 'generateVariation'); variationStub.onFirstCall().resolves({ content: 'Hi world! This is a test message that should be varied.', variationsApplied: ['greeting_variation'] }); variationStub.onSecondCall().resolves({ content: 'Hello there! This is a test message that should be varied.', variationsApplied: ['greeting_variation', 'casual_tone'] }); // Mock behavior simulation const behaviorStub = sinon.stub(behaviorService, 'simulateHumanBehavior').resolves({ typingTime: 1500, readingTime: 800, delay: 300, patterns: ['natural_typing', 'reading_pause'] }); const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: 'msg_content_test', timestamp: new Date() }); const result = await taskEngine.executeTask(contentTask); // Verify task execution expect(result.success).to.be.true; expect(result.totalTargets).to.equal(2); // Verify content variation was applied expect(variationStub.callCount).to.equal(2); // Verify behavior simulation was applied expect(behaviorStub.callCount).to.equal(2); variationStub.restore(); behaviorStub.restore(); telegramSendStub.restore(); }); }); describe('Error Propagation and Recovery', function() { it('should handle cascading service failures gracefully', async function() { this.timeout(10000); const errorTask = { id: 9, name: 'Error Handling Test', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This task tests error handling.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate' }), status: 'pending' }; // Mock service failures const schedulerErrorStub = sinon.stub(accountScheduler, 'selectOptimalAccount') .rejects(new Error('Account scheduler database connection failed')); const result = await taskEngine.executeTask(errorTask); // Verify graceful error handling expect(result.success).to.be.false; expect(result).to.have.property('error'); expect(result.error).to.include('account'); schedulerErrorStub.restore(); }); it('should recover from temporary service failures', async function() { this.timeout(10000); const recoveryTask = { id: 10, name: 'Recovery Test', targetInfo: JSON.stringify({ targets: [{ id: 'group1', name: 'Test Group', type: 'group' }] }), messageContent: JSON.stringify({ content: 'This task tests recovery mechanisms.', type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate', retryOnFailure: true, maxRetries: 2 }), status: 'pending' }; // Mock temporary failure followed by success let callCount = 0; const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').callsFake(() => { callCount++; if (callCount === 1) { return Promise.reject(new Error('Temporary network failure')); } return Promise.resolve({ success: true, messageId: 'msg_recovery_test', timestamp: new Date() }); }); const result = await taskEngine.executeTask(recoveryTask); // Verify recovery was successful expect(result.success).to.be.true; expect(callCount).to.equal(2); // Failed once, succeeded on retry telegramSendStub.restore(); }); }); describe('Performance Under Load', function() { it('should handle multiple concurrent tasks', async function() { this.timeout(20000); const concurrentTasks = []; // Create 5 concurrent tasks for (let i = 0; i < 5; i++) { concurrentTasks.push({ id: 100 + i, name: `Concurrent Task ${i + 1}`, targetInfo: JSON.stringify({ targets: [{ id: `group${i + 1}`, name: `Test Group ${i + 1}`, type: 'group' }] }), messageContent: JSON.stringify({ content: `Concurrent test message ${i + 1}`, type: 'text' }), sendingStrategy: JSON.stringify({ type: 'immediate' }), status: 'pending' }); } // Mock Telegram API const telegramSendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({ success: true, messageId: 'concurrent_msg', timestamp: new Date() }); const startTime = Date.now(); // Execute all tasks concurrently const promises = concurrentTasks.map(task => taskEngine.executeTask(task)); const results = await Promise.all(promises); const endTime = Date.now(); const totalTime = endTime - startTime; // Verify all tasks completed successfully results.forEach((result, index) => { expect(result.success).to.be.true; expect(result.taskId).to.equal(100 + index); }); // Verify reasonable performance (should complete within 10 seconds) expect(totalTime).to.be.at.most(10000); telegramSendStub.restore(); }); }); });