|
- using Campaign_Tracker.Server.Seed;
- using Campaign_Tracker.Server.Seed.Models;
-
- namespace Campaign_Tracker.Server.Tests;
-
- public sealed class SeedServiceTests
- {
- private static readonly DateTimeOffset FixedNow =
- new(2026, 5, 6, 12, 0, 0, TimeSpan.Zero);
-
- [Fact]
- public async Task IsSeededAsync_ReportsFalseBeforeSeedAndTrueAfterSeed_AC1_AC4()
- {
- var store = new InMemorySeedDataStore();
- var sut = BuildSut(store);
-
- Assert.False(await sut.IsSeededAsync());
-
- await sut.SeedAsync();
-
- Assert.True(await sut.IsSeededAsync());
- }
-
- [Fact]
- public async Task SeedAsync_PopulatesReferenceValuesRequiredRulesAndEscalationDefaults_AC1_AC2_AC3()
- {
- var store = new InMemorySeedDataStore();
- var sut = BuildSut(store);
-
- await sut.SeedAsync();
-
- var referenceValues = await store.GetReferenceValuesAsync();
- var requiredRules = await store.GetRequiredFieldRulesAsync();
- var escalationRules = await store.GetEscalationRulesAsync();
-
- Assert.Contains(referenceValues, value =>
- value.Category == "OperationalStatus" && value.Value == "blocked");
- Assert.Contains(referenceValues, value =>
- value.Category == "ServiceTemplate" && value.Value == "transportation");
- Assert.Contains(referenceValues, value =>
- value.Category == "ElectionCycleType" && value.Value == "general");
-
- Assert.Contains(requiredRules, rule =>
- rule.EntityType == "ElectionCycleJob" &&
- rule.FieldPath == "electionDate" &&
- rule.ReadinessFeatureKey == "FR29.ReadinessStatus" &&
- rule.IsRequired);
-
- Assert.Contains(escalationRules, rule =>
- rule.Scenario == "OverdueMilestoneAlert" &&
- rule.Action == "NotifyOperationsLead" &&
- rule.TriggerCondition.Contains("dueDate", StringComparison.OrdinalIgnoreCase));
- }
-
- [Fact]
- public async Task SeedAsync_IsFullyIdempotentAndCreatesNoDuplicateSeedKeys_AC4()
- {
- var store = new InMemorySeedDataStore();
- var sut = BuildSut(store);
-
- await sut.SeedAsync();
- await sut.SeedAsync();
-
- var referenceValues = await store.GetReferenceValuesAsync();
- var requiredRules = await store.GetRequiredFieldRulesAsync();
- var escalationRules = await store.GetEscalationRulesAsync();
-
- Assert.Equal(referenceValues.Count, referenceValues.Select(value => value.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
- Assert.Equal(requiredRules.Count, requiredRules.Select(rule => rule.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
- Assert.Equal(escalationRules.Count, escalationRules.Select(rule => rule.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
- }
-
- [Fact]
- public async Task SeedAsync_DoesNotOverwriteAdminManagedValuesOnRerun_AC5()
- {
- var store = new InMemorySeedDataStore();
- var sut = BuildSut(store);
-
- await sut.SeedAsync();
- var template = (await store.GetReferenceValuesAsync())
- .Single(value => value.SeedKey == "service-template.addressing");
- template.Name = "Custom Addressing Template";
- template.Value = "custom-addressing";
- template.Source = SeedRecordSource.AdminManaged;
- template.UpdatedAt = FixedNow.AddHours(1);
- await store.SaveReferenceValueAsync(template);
-
- await sut.SeedAsync();
-
- var persisted = (await store.GetReferenceValuesAsync())
- .Single(value => value.SeedKey == "service-template.addressing");
- Assert.Equal("Custom Addressing Template", persisted.Name);
- Assert.Equal("custom-addressing", persisted.Value);
- Assert.Equal(SeedRecordSource.AdminManaged, persisted.Source);
- Assert.Equal(FixedNow.AddHours(1), persisted.UpdatedAt);
- }
-
- [Fact]
- public async Task RequiredFieldRules_AreScopedForEpicTwoReadinessEvaluation_AC2()
- {
- var store = new InMemorySeedDataStore();
- var sut = BuildSut(store);
-
- await sut.SeedAsync();
-
- var rules = await store.GetRequiredFieldRulesAsync();
-
- Assert.All(rules, rule =>
- {
- Assert.Equal("ElectionCycleJob", rule.EntityType);
- Assert.Equal("FR29.ReadinessStatus", rule.ReadinessFeatureKey);
- Assert.False(string.IsNullOrWhiteSpace(rule.FieldPath));
- });
- Assert.Contains(rules, rule => rule.FieldPath == "mailDate");
- Assert.Contains(rules, rule => rule.FieldPath == "legacyJurisdictionJCode");
- }
-
- [Fact]
- public async Task FileSeedDataStore_PersistsSeededDefaultsAcrossInstances_AC1()
- {
- var path = Path.Combine(Path.GetTempPath(), $"campaign-tracker-seed-{Guid.NewGuid():N}.json");
- try
- {
- var firstStore = new FileSeedDataStore(path);
- var firstService = BuildSut(firstStore);
- await firstService.SeedAsync();
-
- var secondStore = new FileSeedDataStore(path);
- var secondService = BuildSut(secondStore);
-
- Assert.True(await secondService.IsSeededAsync());
- Assert.Contains(await secondStore.GetEscalationRulesAsync(), rule =>
- rule.SeedKey == "escalation.overdue-milestone.operations-lead");
- }
- finally
- {
- if (File.Exists(path))
- {
- File.Delete(path);
- }
- }
- }
-
- private static SeedService BuildSut(ISeedDataStore store) =>
- new(store, new FakeTimeProvider(FixedNow));
-
- private sealed class FakeTimeProvider(DateTimeOffset utcNow) : TimeProvider
- {
- public override DateTimeOffset GetUtcNow() => utcNow;
- }
- }
|