using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; namespace ScadaLink.SiteEventLogging.Tests; public class EventLogPurgeServiceTests : IDisposable { private readonly SiteEventLogger _eventLogger; private readonly string _dbPath; private readonly SiteEventLogOptions _options; public EventLogPurgeServiceTests() { _dbPath = Path.Combine(Path.GetTempPath(), $"test_purge_{Guid.NewGuid()}.db"); _options = new SiteEventLogOptions { DatabasePath = _dbPath, RetentionDays = 30, MaxStorageMb = 1024 }; _eventLogger = new SiteEventLogger( Options.Create(_options), NullLogger.Instance); } public void Dispose() { _eventLogger.Dispose(); if (File.Exists(_dbPath)) File.Delete(_dbPath); } private EventLogPurgeService CreatePurgeService(SiteEventLogOptions? optionsOverride = null) { var opts = optionsOverride ?? _options; return new EventLogPurgeService( _eventLogger, Options.Create(opts), NullLogger.Instance); } private void InsertEventWithTimestamp(DateTimeOffset timestamp) { using var cmd = _eventLogger.Connection.CreateCommand(); cmd.CommandText = """ INSERT INTO site_events (timestamp, event_type, severity, source, message) VALUES ($ts, 'script', 'Info', 'Test', 'Test message') """; cmd.Parameters.AddWithValue("$ts", timestamp.ToString("o")); cmd.ExecuteNonQuery(); } private long GetEventCount() { using var cmd = _eventLogger.Connection.CreateCommand(); cmd.CommandText = "SELECT COUNT(*) FROM site_events"; return (long)cmd.ExecuteScalar()!; } [Fact] public void PurgeByRetention_DeletesOldEvents() { // Insert an old event (31 days ago) and a recent one InsertEventWithTimestamp(DateTimeOffset.UtcNow.AddDays(-31)); InsertEventWithTimestamp(DateTimeOffset.UtcNow); var purge = CreatePurgeService(); purge.RunPurge(); Assert.Equal(1, GetEventCount()); } [Fact] public void PurgeByRetention_KeepsRecentEvents() { InsertEventWithTimestamp(DateTimeOffset.UtcNow.AddDays(-29)); InsertEventWithTimestamp(DateTimeOffset.UtcNow.AddDays(-1)); InsertEventWithTimestamp(DateTimeOffset.UtcNow); var purge = CreatePurgeService(); purge.RunPurge(); Assert.Equal(3, GetEventCount()); } [Fact] public void PurgeByStorageCap_DeletesOldestWhenOverCap() { // Insert enough events to have some data for (int i = 0; i < 100; i++) { InsertEventWithTimestamp(DateTimeOffset.UtcNow); } // Set an artificially small cap to trigger purge var smallCapOptions = new SiteEventLogOptions { DatabasePath = _dbPath, RetentionDays = 30, MaxStorageMb = 0 // 0 MB cap forces purge }; var purge = CreatePurgeService(smallCapOptions); purge.RunPurge(); // All events should be purged since cap is 0 Assert.Equal(0, GetEventCount()); } [Fact] public void GetDatabaseSizeBytes_ReturnsPositiveValue() { InsertEventWithTimestamp(DateTimeOffset.UtcNow); var purge = CreatePurgeService(); var size = purge.GetDatabaseSizeBytes(); Assert.True(size > 0); } }