/** * contentSecurityService.test.js * Unit tests for server-side content security service. */ const { describe, it, before, after, beforeEach } = require('node:test'); const assert = require('node:assert/strict'); const ContentSecurityService = require('../services/contentSecurityService'); describe('ContentSecurityService', () => { let service; before(() => { service = new ContentSecurityService(); }); after(() => { // Clean up rate limiter state service._requestTimestamps = []; service._requestQueue.forEach(resolve => resolve()); service._requestQueue = []; service._isProcessingQueue = false; }); it('should initialize with rate limiter', () => { assert.ok(service._requestTimestamps); assert.ok(Array.isArray(service._requestTimestamps)); assert.ok(service._requestQueue); assert.ok(Array.isArray(service._requestQueue)); }); it('should have checkTextContent method', () => { assert.strictEqual(typeof service.checkTextContent, 'function'); }); it('should have checkImageContent method', () => { assert.strictEqual(typeof service.checkImageContent, 'function'); }); it('should reject checkTextContent when token manager is unavailable', async () => { // Override token manager to be unavailable if (service.tokenManager) { service.tokenManager._accessToken = ''; service.tokenManager._isAvailable = false; } try { const result = await service.checkTextContent('test_openid', 'hello', 1); // When token is unavailable, should return error or risky assert.ok(result); assert.strictEqual(result.pass, false); } catch (e) { // Also acceptable - throws when service unavailable assert.ok(e); } }); it('should respect rate limiting', async () => { // Test rate limiter concept const now = Date.now(); service._requestTimestamps = []; // Should allow first request await service._enforceRateLimit(); assert.ok(service._requestTimestamps.length > 0); // Fill up rate limit for (let i = 0; i < 5000; i++) { service._requestTimestamps.push(now); } // Should queue when limit reached (returns a pending Promise) const limited = service._enforceRateLimit(); assert.ok(limited instanceof Promise); // Clean up: clear the queue to avoid hanging service._requestQueue.forEach(resolve => resolve()); service._requestQueue = []; service._requestTimestamps = []; service._isProcessingQueue = false; }); }); describe('ViolationService', () => { let violationService; before(() => { const ViolationService = require('../services/violationService'); const AuditLogger = require('../services/auditLogger'); violationService = new ViolationService({ logger: new AuditLogger() }); }); after(() => { // Clean up any timers using destroy method if (violationService.destroy) { violationService.destroy(); } }); it('should initialize without errors', () => { assert.ok(violationService); }); it('should have recordViolation method', () => { assert.strictEqual(typeof violationService.recordViolation, 'function'); }); it('should have getMuteStatus method', () => { assert.strictEqual(typeof violationService.getMuteStatus, 'function'); }); it('should record a violation and increment count', () => { const testUserId = 'test_user_' + Date.now(); violationService.recordViolation({ userId: testUserId, violationType: 'text_violation', contentSummary: '测试违规内容', scene: 2, }); const status = violationService.getMuteStatus(testUserId); assert.ok(status); assert.strictEqual(typeof status.isMuted, 'boolean'); // Check violation count via internal records const record = violationService._records.get(testUserId); assert.ok(record); assert.strictEqual(typeof record.count, 'number'); assert.strictEqual(record.count, 1); }); it('should apply mute penalty at 3 violations', () => { const testUserId = 'mute_test_' + Date.now(); // Record 3 violations for (let i = 0; i < 3; i++) { violationService.recordViolation({ userId: testUserId, violationType: 'pornography', contentSummary: `violation ${i}`, scene: 2, }); } const status = violationService.getMuteStatus(testUserId); assert.strictEqual(status.isMuted, true); assert.ok(status.remainingMs > 0); }); it('should escalate mute at 5 violations', () => { const testUserId = 'escalate_test_' + Date.now(); // Record 5 violations for (let i = 0; i < 5; i++) { violationService.recordViolation({ userId: testUserId, violationType: 'gambling', contentSummary: `violation ${i}`, scene: 2, }); } const status = violationService.getMuteStatus(testUserId); assert.strictEqual(status.isMuted, true); }); }); describe('ReportService', () => { let reportService; before(() => { const ReportService = require('../services/reportService'); const AuditLogger = require('../services/auditLogger'); reportService = new ReportService({ logger: new AuditLogger() }); }); it('should initialize without errors', () => { assert.ok(reportService); }); it('should have submitReport method', () => { assert.strictEqual(typeof reportService.submitReport, 'function'); }); it('should accept a report submission', () => { const result = reportService.submitReport({ contentId: 'test_content_' + Date.now(), targetUserId: 'target_user_123', contentType: 'chat', contentSummary: 'test content', reporterId: 'reporter_user_456', reason: 'politics', }); assert.ok(result); assert.strictEqual(typeof result.success, 'boolean'); }); });