Files
telegram-management-system/backend/test/integration/TaskWorkflow.test.js
你的用户名 237c7802e5
Some checks failed
Deploy / deploy (push) Has been cancelled
Initial commit: Telegram Management System
Full-stack web application for Telegram management
- Frontend: Vue 3 + Vben Admin
- Backend: NestJS
- Features: User management, group broadcast, statistics

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 15:37:50 +08:00

638 lines
24 KiB
JavaScript

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();
});
});
});