using System.Security.Cryptography; using VolcanicCore.Persistence; using VolcanicCore.Persistence.Encryption; using VolcanicCore.Persistence.Migrations; using VolcanicCore.Persistence.Repositories; namespace VolcanicCore.Tests; public class ExecutionRepositoryTests { private static ExecutionRepository Setup() { var path = Path.Combine(Path.GetTempPath(), $"vc-{Guid.NewGuid():N}.db"); var f = new SqliteConnectionFactory(path); using (var conn = f.Open()) new Migrator(new IMigration[] { new Migration001Initial(), new Migration002Connections(), new Migration003Workflows(), new Migration004Executions(), }).Apply(conn); return new ExecutionRepository(f); } [Fact] public void Create_and_get_round_trip() { var repo = Setup(); var id = repo.Create("wf1", "nats", "{\"subject\":\"foo\"}"); var row = repo.Get(id); Assert.NotNull(row); Assert.Equal("wf1", row!.WorkflowId); Assert.Equal("nats", row.Trigger); Assert.Equal("running", row.Status); Assert.Null(row.EndedAt); } [Fact] public void SetStatus_updates_row() { var repo = Setup(); var id = repo.Create("wf1", "manual", "{}"); repo.SetStatus(id, "completed", error: null, endedAt: DateTimeOffset.UtcNow); var row = repo.Get(id)!; Assert.Equal("completed", row.Status); Assert.NotNull(row.EndedAt); } [Fact] public void AbortAllRunning_flips_running_rows_to_aborted() { var repo = Setup(); var a = repo.Create("wf1", "nats", "{}"); var b = repo.Create("wf1", "manual", "{}"); repo.SetStatus(b, "completed", null, DateTimeOffset.UtcNow); var n = repo.AbortAllRunning(); Assert.Equal(1, n); Assert.Equal("aborted", repo.Get(a)!.Status); Assert.Equal("completed", repo.Get(b)!.Status); } [Fact] public void ListForWorkflow_returns_desc_by_started_at_capped_by_limit() { var repo = Setup(); var ids = new List(); for (var i = 0; i < 5; i++) { ids.Add(repo.Create("wf1", "manual", "{}")); Thread.Sleep(5); } var got = repo.ListForWorkflow("wf1", limit: 3); Assert.Equal(3, got.Count); Assert.Equal(ids[^1], got[0].Id); // newest first } [Fact] public void PruneOlderThan_deletes_by_ended_at_cutoff() { var repo = Setup(); var old = repo.Create("wf1", "manual", "{}"); repo.SetStatus(old, "completed", null, DateTimeOffset.UtcNow.AddDays(-30)); var young = repo.Create("wf1", "manual", "{}"); repo.SetStatus(young, "completed", null, DateTimeOffset.UtcNow); var deleted = repo.PruneOlderThan(DateTimeOffset.UtcNow.AddDays(-7)); Assert.Equal(1, deleted); Assert.Null(repo.Get(old)); Assert.NotNull(repo.Get(young)); } [Fact] public void PruneOldestPerWorkflow_keeps_last_N_per_workflow() { var repo = Setup(); for (var i = 0; i < 10; i++) { var id = repo.Create("wf1", "manual", "{}"); repo.SetStatus(id, "completed", null, DateTimeOffset.UtcNow.AddSeconds(i)); } var deleted = repo.PruneOldestPerWorkflow(keep: 3); Assert.Equal(7, deleted); Assert.Equal(3, repo.ListForWorkflow("wf1", limit: 100).Count); } }