Some checks failed
Deploy / deploy (push) Has been cancelled
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>
339 lines
12 KiB
JavaScript
339 lines
12 KiB
JavaScript
const { expect } = require('chai');
|
|
const TestSetup = require('../setup');
|
|
const RiskStrategyService = require('../../src/service/RiskStrategyService');
|
|
|
|
describe('RiskStrategyService', function() {
|
|
let riskService;
|
|
let testDb;
|
|
|
|
before(async function() {
|
|
this.timeout(10000);
|
|
|
|
await TestSetup.setupDatabase();
|
|
await TestSetup.setupRedis();
|
|
await TestSetup.createTestData();
|
|
|
|
testDb = TestSetup.getTestDb();
|
|
riskService = new RiskStrategyService();
|
|
await riskService.initialize();
|
|
});
|
|
|
|
after(async function() {
|
|
await TestSetup.cleanup();
|
|
});
|
|
|
|
describe('Initialization', function() {
|
|
it('should initialize with default rules', function() {
|
|
expect(riskService.isInitialized).to.be.true;
|
|
expect(riskService.activeRules.size).to.be.greaterThan(0);
|
|
});
|
|
|
|
it('should load rules from database', async function() {
|
|
const rules = await riskService.getAllRules();
|
|
expect(rules).to.be.an('array');
|
|
expect(rules.length).to.be.greaterThan(0);
|
|
});
|
|
});
|
|
|
|
describe('Risk Evaluation', function() {
|
|
const mockExecutionContext = {
|
|
account: { accountId: 1, healthScore: 85, status: 'active' },
|
|
target: { id: 'test_group', type: 'group' },
|
|
message: { content: 'Test message', length: 12 },
|
|
task: { id: 1, strategy: 'sequential' },
|
|
timing: { hour: 14, dayOfWeek: 3 }
|
|
};
|
|
|
|
it('should evaluate overall risk level', async function() {
|
|
const riskLevel = await riskService.evaluateOverallRisk(mockExecutionContext);
|
|
|
|
expect(riskLevel).to.be.oneOf(['low', 'medium', 'high', 'critical']);
|
|
});
|
|
|
|
it('should identify specific risks', async function() {
|
|
const risks = await riskService.identifyRisks(mockExecutionContext);
|
|
|
|
expect(risks).to.be.an('array');
|
|
risks.forEach(risk => {
|
|
expect(risk).to.have.property('ruleId');
|
|
expect(risk).to.have.property('severity');
|
|
expect(risk).to.have.property('action');
|
|
expect(risk).to.have.property('reason');
|
|
});
|
|
});
|
|
|
|
it('should handle account health risk', async function() {
|
|
const lowHealthContext = {
|
|
...mockExecutionContext,
|
|
account: { accountId: 2, healthScore: 30, status: 'warning' }
|
|
};
|
|
|
|
const risks = await riskService.identifyRisks(lowHealthContext);
|
|
const healthRisk = risks.find(r => r.type === 'account' && r.category === 'health');
|
|
|
|
if (healthRisk) {
|
|
expect(healthRisk.severity).to.be.oneOf(['medium', 'high']);
|
|
expect(healthRisk.action).to.be.oneOf(['switched', 'delayed', 'blocked']);
|
|
}
|
|
});
|
|
|
|
it('should handle frequency limits', async function() {
|
|
// Simulate high frequency context
|
|
const highFreqContext = {
|
|
...mockExecutionContext,
|
|
frequency: { recentCount: 15, timeWindow: 3600 }
|
|
};
|
|
|
|
const risks = await riskService.identifyRisks(highFreqContext);
|
|
const freqRisk = risks.find(r => r.category === 'frequency');
|
|
|
|
if (freqRisk) {
|
|
expect(freqRisk.action).to.be.oneOf(['delayed', 'blocked']);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Risk Action Execution', function() {
|
|
it('should execute delayed action', async function() {
|
|
const risk = {
|
|
ruleId: 1,
|
|
action: 'delayed',
|
|
severity: 'medium',
|
|
parameters: { minDelay: 5000, maxDelay: 15000 }
|
|
};
|
|
|
|
const result = await riskService.executeRiskAction(risk, {});
|
|
|
|
expect(result).to.have.property('action', 'delayed');
|
|
expect(result).to.have.property('delay');
|
|
expect(result.delay).to.be.at.least(5000);
|
|
expect(result.delay).to.be.at.most(15000);
|
|
});
|
|
|
|
it('should execute switch account action', async function() {
|
|
const risk = {
|
|
ruleId: 2,
|
|
action: 'switched',
|
|
severity: 'high',
|
|
parameters: { reason: 'account_health_low' }
|
|
};
|
|
|
|
const result = await riskService.executeRiskAction(risk, {
|
|
account: { accountId: 1 }
|
|
});
|
|
|
|
expect(result).to.have.property('action', 'switched');
|
|
expect(result).to.have.property('originalAccount', 1);
|
|
expect(result).to.have.property('reason');
|
|
});
|
|
|
|
it('should execute block action', async function() {
|
|
const risk = {
|
|
ruleId: 3,
|
|
action: 'blocked',
|
|
severity: 'critical',
|
|
parameters: { reason: 'critical_risk_detected' }
|
|
};
|
|
|
|
const result = await riskService.executeRiskAction(risk, {});
|
|
|
|
expect(result).to.have.property('action', 'blocked');
|
|
expect(result).to.have.property('reason');
|
|
expect(result.success).to.be.false;
|
|
});
|
|
});
|
|
|
|
describe('Rule Management', function() {
|
|
it('should create new rule', async function() {
|
|
const ruleData = {
|
|
name: 'Test Rule',
|
|
type: 'behavior',
|
|
category: 'test',
|
|
conditions: { testCondition: true },
|
|
action: 'warned',
|
|
severity: 'low',
|
|
priority: 50,
|
|
enabled: true
|
|
};
|
|
|
|
const rule = await riskService.createRule(ruleData);
|
|
|
|
expect(rule).to.have.property('id');
|
|
expect(rule.name).to.equal('Test Rule');
|
|
expect(rule.enabled).to.be.true;
|
|
});
|
|
|
|
it('should update existing rule', async function() {
|
|
const rules = await riskService.getAllRules();
|
|
const ruleToUpdate = rules[0];
|
|
|
|
const updateData = {
|
|
priority: 90,
|
|
enabled: false
|
|
};
|
|
|
|
const updatedRule = await riskService.updateRule(ruleToUpdate.id, updateData);
|
|
|
|
expect(updatedRule.priority).to.equal(90);
|
|
expect(updatedRule.enabled).to.be.false;
|
|
});
|
|
|
|
it('should delete rule', async function() {
|
|
const rules = await riskService.getAllRules();
|
|
const ruleToDelete = rules.find(r => r.name === 'Test Rule');
|
|
|
|
if (ruleToDelete) {
|
|
const result = await riskService.deleteRule(ruleToDelete.id);
|
|
expect(result).to.be.true;
|
|
|
|
const updatedRules = await riskService.getAllRules();
|
|
const deletedRule = updatedRules.find(r => r.id === ruleToDelete.id);
|
|
expect(deletedRule).to.be.undefined;
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Risk Statistics', function() {
|
|
it('should provide risk statistics', async function() {
|
|
const stats = await riskService.getRiskStatistics('24h');
|
|
|
|
expect(stats).to.have.property('totalEvaluations');
|
|
expect(stats).to.have.property('riskDistribution');
|
|
expect(stats).to.have.property('actionDistribution');
|
|
expect(stats).to.have.property('topTriggeredRules');
|
|
|
|
expect(stats.riskDistribution).to.have.property('low');
|
|
expect(stats.riskDistribution).to.have.property('medium');
|
|
expect(stats.riskDistribution).to.have.property('high');
|
|
expect(stats.riskDistribution).to.have.property('critical');
|
|
});
|
|
|
|
it('should track rule performance', async function() {
|
|
const performance = await riskService.getRulePerformance();
|
|
|
|
expect(performance).to.be.an('array');
|
|
performance.forEach(rule => {
|
|
expect(rule).to.have.property('ruleId');
|
|
expect(rule).to.have.property('triggerCount');
|
|
expect(rule).to.have.property('avgProcessingTime');
|
|
expect(rule).to.have.property('successRate');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Configuration Management', function() {
|
|
it('should update risk thresholds', async function() {
|
|
const newThresholds = {
|
|
low: { min: 0, max: 30 },
|
|
medium: { min: 31, max: 60 },
|
|
high: { min: 61, max: 85 },
|
|
critical: { min: 86, max: 100 }
|
|
};
|
|
|
|
await riskService.updateRiskThresholds(newThresholds);
|
|
|
|
const config = riskService.getConfiguration();
|
|
expect(config.riskThresholds).to.deep.equal(newThresholds);
|
|
});
|
|
|
|
it('should enable/disable rule categories', async function() {
|
|
await riskService.enableRuleCategory('behavior', false);
|
|
|
|
const config = riskService.getConfiguration();
|
|
expect(config.enabledCategories.behavior).to.be.false;
|
|
|
|
// Re-enable for other tests
|
|
await riskService.enableRuleCategory('behavior', true);
|
|
});
|
|
});
|
|
|
|
describe('Integration Tests', function() {
|
|
it('should work with message queue for async processing', async function() {
|
|
const mockContext = {
|
|
account: { accountId: 1, healthScore: 85 },
|
|
target: { id: 'test_group' },
|
|
message: { content: 'Test message' }
|
|
};
|
|
|
|
// This would normally interact with Redis queue
|
|
const queueResult = await riskService.queueRiskEvaluation(mockContext);
|
|
expect(queueResult).to.have.property('queued', true);
|
|
expect(queueResult).to.have.property('jobId');
|
|
});
|
|
|
|
it('should provide real-time risk monitoring data', async function() {
|
|
const monitoringData = await riskService.getRealTimeRiskData();
|
|
|
|
expect(monitoringData).to.have.property('currentRiskLevel');
|
|
expect(monitoringData).to.have.property('activeThreats');
|
|
expect(monitoringData).to.have.property('recentEvaluations');
|
|
expect(monitoringData).to.have.property('systemHealth');
|
|
});
|
|
});
|
|
|
|
describe('Error Handling', function() {
|
|
it('should handle malformed rule conditions', async function() {
|
|
const invalidContext = {
|
|
account: null, // Invalid account
|
|
target: { id: 'test' },
|
|
message: { content: 'test' }
|
|
};
|
|
|
|
const risks = await riskService.identifyRisks(invalidContext);
|
|
expect(risks).to.be.an('array'); // Should not throw error
|
|
});
|
|
|
|
it('should handle database connection errors', async function() {
|
|
// Mock database error
|
|
const originalQuery = testDb.query;
|
|
testDb.query = () => Promise.reject(new Error('Database error'));
|
|
|
|
try {
|
|
await riskService.getAllRules();
|
|
expect.fail('Should have thrown an error');
|
|
} catch (error) {
|
|
expect(error.message).to.include('Database error');
|
|
}
|
|
|
|
// Restore
|
|
testDb.query = originalQuery;
|
|
});
|
|
});
|
|
|
|
describe('Performance Tests', function() {
|
|
it('should evaluate risks quickly', async function() {
|
|
const context = {
|
|
account: { accountId: 1, healthScore: 85 },
|
|
target: { id: 'test_group' },
|
|
message: { content: 'Test message' }
|
|
};
|
|
|
|
const startTime = Date.now();
|
|
await riskService.identifyRisks(context);
|
|
const endTime = Date.now();
|
|
|
|
const duration = endTime - startTime;
|
|
expect(duration).to.be.at.most(50); // Should complete within 50ms
|
|
});
|
|
|
|
it('should handle concurrent evaluations', async function() {
|
|
const promises = [];
|
|
const context = {
|
|
account: { accountId: 1, healthScore: 85 },
|
|
target: { id: 'test_group' },
|
|
message: { content: 'Test message' }
|
|
};
|
|
|
|
// Create 10 concurrent evaluations
|
|
for (let i = 0; i < 10; i++) {
|
|
promises.push(riskService.identifyRisks({ ...context, requestId: i }));
|
|
}
|
|
|
|
const results = await Promise.all(promises);
|
|
expect(results).to.have.length(10);
|
|
results.forEach(result => {
|
|
expect(result).to.be.an('array');
|
|
});
|
|
});
|
|
});
|
|
}); |