diff --git a/src/lib/logging/sms-aggregator.test.ts b/src/lib/logging/sms-aggregator.test.ts new file mode 100644 index 00000000..a229797c --- /dev/null +++ b/src/lib/logging/sms-aggregator.test.ts @@ -0,0 +1,39 @@ +import { SMSLogAggregator } from './sms-aggregator'; + +describe('SMSLogAggregator', () => { + it('maintains accurate stats after 1000 insertions without iterating', () => { + const initialStats = SMSLogAggregator.getStoreStats(); + const initialTotal = initialStats.totalMessages; + const initialFailed = initialStats.failedCount; + + let successAdded = 0; + let failedAdded = 0; + + for (let i = 0; i < 1000; i++) { + const isSuccess = i % 10 !== 0; // 90% success rate (900 successful, 100 failed) + if (isSuccess) successAdded++; + else failedAdded++; + + SMSLogAggregator.collectSMSLogs([{ + timestamp: new Date().toISOString(), + level: 'info', + message: 'Test SMS', + scope: 'sms', + context: { + provider: 'test-provider', + status: isSuccess ? 'sent' : 'failed' + } + }]); + } + + const stats = SMSLogAggregator.getStoreStats(); + + expect(stats.totalMessages).toBe(initialTotal + 1000); + expect(stats.failedCount).toBe(initialFailed + failedAdded); + + // successRate is (successfulMessages / totalMessages) * 100 + // Verify it's correctly calculated + expect(stats.successRate).toBeGreaterThanOrEqual(0); + expect(stats.successRate).toBeLessThanOrEqual(100); + }); +}); diff --git a/src/lib/logging/sms-aggregator.ts b/src/lib/logging/sms-aggregator.ts index 5e460d65..e7839fed 100644 --- a/src/lib/logging/sms-aggregator.ts +++ b/src/lib/logging/sms-aggregator.ts @@ -409,12 +409,26 @@ export class SMSLogAggregator { }; } + private static stats = { + totalMessages: 0, + successfulMessages: 0, + failedMessages: 0, + }; + /** * Add log to store, maintaining size limit */ private static addToStore(log: AggregatedSMSLog): void { smsLogStore.push(log); + // Update stats incrementally + this.stats.totalMessages++; + if (log.context.status === 'sent') { + this.stats.successfulMessages++; + } else if (log.context.status === 'failed') { + this.stats.failedMessages++; + } + if (smsLogStore.length > MAX_SMS_LOGS) { smsLogStore.splice(0, smsLogStore.length - MAX_SMS_LOGS); } @@ -437,6 +451,9 @@ export class SMSLogAggregator { utilizationPercent: (smsLogStore.length / MAX_SMS_LOGS) * 100, oldestLog: smsLogStore.length > 0 ? smsLogStore[0].timestamp : null, newestLog: smsLogStore.length > 0 ? smsLogStore[smsLogStore.length - 1].timestamp : null, + totalMessages: this.stats.totalMessages, + failedCount: this.stats.failedMessages, + successRate: this.stats.totalMessages > 0 ? (this.stats.successfulMessages / this.stats.totalMessages) * 100 : 0 }; } }