Files
telegram-management-system/backend/test/services/TaskExecutionEngine.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

472 lines
16 KiB
JavaScript

const { expect } = require('chai');
const sinon = require('sinon');
const TestSetup = require('../setup');
const TaskExecutionEngine = require('../../src/service/TaskExecutionEngine');
describe('TaskExecutionEngine', function() {
let taskEngine;
let testDb;
before(async function() {
this.timeout(15000);
await TestSetup.setupDatabase();
await TestSetup.setupRedis();
await TestSetup.createTestData();
testDb = TestSetup.getTestDb();
taskEngine = new TaskExecutionEngine();
await taskEngine.initialize();
});
after(async function() {
if (taskEngine) {
await taskEngine.shutdown();
}
await TestSetup.cleanup();
});
describe('Initialization', function() {
it('should initialize all components', function() {
expect(taskEngine.isInitialized).to.be.true;
expect(taskEngine.accountScheduler).to.not.be.null;
expect(taskEngine.riskService).to.not.be.null;
expect(taskEngine.behaviorSimulator).to.not.be.null;
expect(taskEngine.contentVariator).to.not.be.null;
});
it('should start and stop correctly', async function() {
await taskEngine.start();
expect(taskEngine.isRunning).to.be.true;
await taskEngine.stop();
expect(taskEngine.isRunning).to.be.false;
// Restart for other tests
await taskEngine.start();
});
});
describe('Task Execution Workflow', function() {
let mockTask;
beforeEach(function() {
mockTask = {
id: 1,
name: '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!',
type: 'text'
}),
sendingStrategy: JSON.stringify({
type: 'sequential',
interval: 2000,
batchSize: 1
}),
status: 'pending'
};
});
it('should execute task successfully', async function() {
this.timeout(10000);
// Mock the actual Telegram sending
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({
success: true,
messageId: 'msg_123',
timestamp: new Date()
});
const result = await taskEngine.executeTask(mockTask);
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');
sendStub.restore();
});
it('should handle task execution with risk controls', async function() {
this.timeout(10000);
// Mock risk evaluation that returns medium risk
const riskStub = sinon.stub(taskEngine.riskService, 'evaluateOverallRisk').resolves('medium');
const actionStub = sinon.stub(taskEngine.riskService, 'executeRiskAction').resolves({
action: 'delayed',
delay: 3000,
success: true
});
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({
success: true,
messageId: 'msg_123'
});
const result = await taskEngine.executeTask(mockTask);
expect(result.success).to.be.true;
expect(riskStub.called).to.be.true;
riskStub.restore();
actionStub.restore();
sendStub.restore();
});
it('should handle account switching on high risk', async function() {
this.timeout(10000);
// Mock high risk scenario requiring account switch
const riskStub = sinon.stub(taskEngine.riskService, 'evaluateOverallRisk').resolves('high');
const actionStub = sinon.stub(taskEngine.riskService, 'executeRiskAction').resolves({
action: 'switched',
originalAccount: 1,
newAccount: { accountId: 2, healthScore: 90 },
success: true
});
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({
success: true,
messageId: 'msg_124'
});
const result = await taskEngine.executeTask(mockTask);
expect(result.success).to.be.true;
expect(actionStub.called).to.be.true;
riskStub.restore();
actionStub.restore();
sendStub.restore();
});
});
describe('Message Processing', function() {
it('should apply content variation', async function() {
const originalMessage = 'Hello world! This is a test message.';
const context = {
account: { accountId: 1 },
target: { id: 'group1' },
variationLevel: 'medium'
};
// Mock content variation
const variationStub = sinon.stub(taskEngine.contentVariator, 'generateVariation').resolves({
content: 'Hi world! This is a test message.',
variationsApplied: ['greeting_variation']
});
const result = await taskEngine.processMessageContent(originalMessage, context);
expect(result).to.have.property('content');
expect(result).to.have.property('variationsApplied');
expect(variationStub.called).to.be.true;
variationStub.restore();
});
it('should apply behavior simulation', async function() {
const context = {
account: { accountId: 1, tier: 'normal' },
message: { content: 'Test message', length: 12 }
};
// Mock behavior simulation
const behaviorStub = sinon.stub(taskEngine.behaviorSimulator, 'simulateHumanBehavior').resolves({
typingTime: 1200,
readingTime: 800,
delay: 500,
patterns: ['natural_typing', 'reading_pause']
});
const result = await taskEngine.simulateBehavior(context);
expect(result).to.have.property('typingTime');
expect(result).to.have.property('readingTime');
expect(result).to.have.property('delay');
expect(behaviorStub.called).to.be.true;
behaviorStub.restore();
});
});
describe('Account Management Integration', function() {
it('should select optimal account for task', async function() {
const taskRequirements = {
tier: 'normal',
messageCount: 5,
urgency: 'medium'
};
// Mock account selection
const scheduleStub = sinon.stub(taskEngine.accountScheduler, 'selectOptimalAccount').resolves({
accountId: 1,
healthScore: 85,
status: 'active',
tier: 'normal'
});
const account = await taskEngine.selectAccount(taskRequirements);
expect(account).to.not.be.null;
expect(account).to.have.property('accountId');
expect(scheduleStub.called).to.be.true;
scheduleStub.restore();
});
it('should update account usage after successful send', async function() {
const accountId = 1;
const usageData = {
sentCount: 1,
success: true,
executionTime: 1500,
riskLevel: 'low'
};
// Mock usage update
const updateStub = sinon.stub(taskEngine.accountScheduler, 'updateAccountUsage').resolves(true);
await taskEngine.updateAccountUsage(accountId, usageData);
expect(updateStub.calledWith(accountId, usageData)).to.be.true;
updateStub.restore();
});
});
describe('Error Handling', function() {
it('should handle send failures gracefully', async function() {
const mockTask = {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Test message'
}),
sendingStrategy: JSON.stringify({
type: 'sequential',
interval: 1000
})
};
// Mock send failure
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').rejects(
new Error('Rate limit exceeded')
);
const result = await taskEngine.executeTask(mockTask);
expect(result).to.have.property('success', false);
expect(result).to.have.property('failureCount');
expect(result.failureCount).to.be.greaterThan(0);
sendStub.restore();
});
it('should handle account unavailability', async function() {
// Mock no available accounts
const scheduleStub = sinon.stub(taskEngine.accountScheduler, 'selectOptimalAccount').resolves(null);
const mockTask = {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Test message'
}),
sendingStrategy: JSON.stringify({
type: 'sequential'
})
};
const result = await taskEngine.executeTask(mockTask);
expect(result).to.have.property('success', false);
expect(result).to.have.property('error');
expect(result.error).to.include('account');
scheduleStub.restore();
});
it('should handle critical risk blocking', async function() {
// Mock critical risk that blocks execution
const riskStub = sinon.stub(taskEngine.riskService, 'evaluateOverallRisk').resolves('critical');
const actionStub = sinon.stub(taskEngine.riskService, 'executeRiskAction').resolves({
action: 'blocked',
reason: 'Critical security risk detected',
success: false
});
const mockTask = {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Test message'
}),
sendingStrategy: JSON.stringify({
type: 'sequential'
})
};
const result = await taskEngine.executeTask(mockTask);
expect(result).to.have.property('success', false);
expect(result).to.have.property('error');
expect(result.error).to.include('blocked');
riskStub.restore();
actionStub.restore();
});
});
describe('Performance Monitoring', function() {
it('should track execution metrics', async function() {
const mockTask = {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Test message'
}),
sendingStrategy: JSON.stringify({
type: 'sequential'
})
};
// Mock successful send
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({
success: true,
messageId: 'msg_123',
executionTime: 1200
});
const startTime = Date.now();
const result = await taskEngine.executeTask(mockTask);
const endTime = Date.now();
expect(result).to.have.property('executionTime');
expect(result.executionTime).to.be.at.most(endTime - startTime + 100); // Allow some margin
sendStub.restore();
});
it('should provide service statistics', function() {
const stats = taskEngine.getServiceStats();
expect(stats).to.have.property('isRunning');
expect(stats).to.have.property('totalTasksExecuted');
expect(stats).to.have.property('successRate');
expect(stats).to.have.property('avgExecutionTime');
expect(stats).to.have.property('activeConnections');
});
});
describe('Configuration Management', function() {
it('should update execution configuration', async function() {
const newConfig = {
maxConcurrentTasks: 10,
defaultTimeout: 30000,
retryAttempts: 3,
enableBehaviorSimulation: true
};
await taskEngine.updateConfiguration(newConfig);
const config = taskEngine.getConfiguration();
expect(config.maxConcurrentTasks).to.equal(10);
expect(config.defaultTimeout).to.equal(30000);
});
it('should validate configuration parameters', function() {
const invalidConfig = {
maxConcurrentTasks: -1, // Invalid
defaultTimeout: 'invalid' // Invalid type
};
expect(() => {
taskEngine.updateConfiguration(invalidConfig);
}).to.throw();
});
});
describe('Integration with Message Queue', function() {
it('should process queued tasks', async function() {
const queuedTask = {
id: 'queue_task_1',
taskData: {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Queued message'
}),
sendingStrategy: JSON.stringify({
type: 'sequential'
})
},
priority: 'normal'
};
// Mock queue processing
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').resolves({
success: true,
messageId: 'msg_queue_123'
});
const result = await taskEngine.processQueuedTask(queuedTask);
expect(result).to.have.property('success', true);
expect(result).to.have.property('jobId', queuedTask.id);
sendStub.restore();
});
it('should handle queue failures with retry', async function() {
const queuedTask = {
id: 'retry_task_1',
taskData: {
id: 1,
targetInfo: JSON.stringify({
targets: [{ id: 'group1', type: 'group' }]
}),
messageContent: JSON.stringify({
content: 'Retry message'
})
},
attempts: 0,
maxRetries: 3
};
// Mock failure on first attempt, success on second
let callCount = 0;
const sendStub = sinon.stub(taskEngine, 'sendTelegramMessage').callsFake(() => {
callCount++;
if (callCount === 1) {
return Promise.reject(new Error('Temporary failure'));
}
return Promise.resolve({ success: true, messageId: 'msg_retry_123' });
});
const result = await taskEngine.processQueuedTaskWithRetry(queuedTask);
expect(result).to.have.property('success', true);
expect(callCount).to.equal(2); // Failed once, succeeded on retry
sendStub.restore();
});
});
});