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