Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

152 řádky
5.6KB

  1. using Campaign_Tracker.Server.Seed;
  2. using Campaign_Tracker.Server.Seed.Models;
  3. namespace Campaign_Tracker.Server.Tests;
  4. public sealed class SeedServiceTests
  5. {
  6. private static readonly DateTimeOffset FixedNow =
  7. new(2026, 5, 6, 12, 0, 0, TimeSpan.Zero);
  8. [Fact]
  9. public async Task IsSeededAsync_ReportsFalseBeforeSeedAndTrueAfterSeed_AC1_AC4()
  10. {
  11. var store = new InMemorySeedDataStore();
  12. var sut = BuildSut(store);
  13. Assert.False(await sut.IsSeededAsync());
  14. await sut.SeedAsync();
  15. Assert.True(await sut.IsSeededAsync());
  16. }
  17. [Fact]
  18. public async Task SeedAsync_PopulatesReferenceValuesRequiredRulesAndEscalationDefaults_AC1_AC2_AC3()
  19. {
  20. var store = new InMemorySeedDataStore();
  21. var sut = BuildSut(store);
  22. await sut.SeedAsync();
  23. var referenceValues = await store.GetReferenceValuesAsync();
  24. var requiredRules = await store.GetRequiredFieldRulesAsync();
  25. var escalationRules = await store.GetEscalationRulesAsync();
  26. Assert.Contains(referenceValues, value =>
  27. value.Category == "OperationalStatus" && value.Value == "blocked");
  28. Assert.Contains(referenceValues, value =>
  29. value.Category == "ServiceTemplate" && value.Value == "transportation");
  30. Assert.Contains(referenceValues, value =>
  31. value.Category == "ElectionCycleType" && value.Value == "general");
  32. Assert.Contains(requiredRules, rule =>
  33. rule.EntityType == "ElectionCycleJob" &&
  34. rule.FieldPath == "electionDate" &&
  35. rule.ReadinessFeatureKey == "FR29.ReadinessStatus" &&
  36. rule.IsRequired);
  37. Assert.Contains(escalationRules, rule =>
  38. rule.Scenario == "OverdueMilestoneAlert" &&
  39. rule.Action == "NotifyOperationsLead" &&
  40. rule.TriggerCondition.Contains("dueDate", StringComparison.OrdinalIgnoreCase));
  41. }
  42. [Fact]
  43. public async Task SeedAsync_IsFullyIdempotentAndCreatesNoDuplicateSeedKeys_AC4()
  44. {
  45. var store = new InMemorySeedDataStore();
  46. var sut = BuildSut(store);
  47. await sut.SeedAsync();
  48. await sut.SeedAsync();
  49. var referenceValues = await store.GetReferenceValuesAsync();
  50. var requiredRules = await store.GetRequiredFieldRulesAsync();
  51. var escalationRules = await store.GetEscalationRulesAsync();
  52. Assert.Equal(referenceValues.Count, referenceValues.Select(value => value.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
  53. Assert.Equal(requiredRules.Count, requiredRules.Select(rule => rule.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
  54. Assert.Equal(escalationRules.Count, escalationRules.Select(rule => rule.SeedKey).Distinct(StringComparer.OrdinalIgnoreCase).Count());
  55. }
  56. [Fact]
  57. public async Task SeedAsync_DoesNotOverwriteAdminManagedValuesOnRerun_AC5()
  58. {
  59. var store = new InMemorySeedDataStore();
  60. var sut = BuildSut(store);
  61. await sut.SeedAsync();
  62. var template = (await store.GetReferenceValuesAsync())
  63. .Single(value => value.SeedKey == "service-template.addressing");
  64. template.Name = "Custom Addressing Template";
  65. template.Value = "custom-addressing";
  66. template.Source = SeedRecordSource.AdminManaged;
  67. template.UpdatedAt = FixedNow.AddHours(1);
  68. await store.SaveReferenceValueAsync(template);
  69. await sut.SeedAsync();
  70. var persisted = (await store.GetReferenceValuesAsync())
  71. .Single(value => value.SeedKey == "service-template.addressing");
  72. Assert.Equal("Custom Addressing Template", persisted.Name);
  73. Assert.Equal("custom-addressing", persisted.Value);
  74. Assert.Equal(SeedRecordSource.AdminManaged, persisted.Source);
  75. Assert.Equal(FixedNow.AddHours(1), persisted.UpdatedAt);
  76. }
  77. [Fact]
  78. public async Task RequiredFieldRules_AreScopedForEpicTwoReadinessEvaluation_AC2()
  79. {
  80. var store = new InMemorySeedDataStore();
  81. var sut = BuildSut(store);
  82. await sut.SeedAsync();
  83. var rules = await store.GetRequiredFieldRulesAsync();
  84. Assert.All(rules, rule =>
  85. {
  86. Assert.Equal("ElectionCycleJob", rule.EntityType);
  87. Assert.Equal("FR29.ReadinessStatus", rule.ReadinessFeatureKey);
  88. Assert.False(string.IsNullOrWhiteSpace(rule.FieldPath));
  89. });
  90. Assert.Contains(rules, rule => rule.FieldPath == "mailDate");
  91. Assert.Contains(rules, rule => rule.FieldPath == "legacyJurisdictionJCode");
  92. }
  93. [Fact]
  94. public async Task FileSeedDataStore_PersistsSeededDefaultsAcrossInstances_AC1()
  95. {
  96. var path = Path.Combine(Path.GetTempPath(), $"campaign-tracker-seed-{Guid.NewGuid():N}.json");
  97. try
  98. {
  99. var firstStore = new FileSeedDataStore(path);
  100. var firstService = BuildSut(firstStore);
  101. await firstService.SeedAsync();
  102. var secondStore = new FileSeedDataStore(path);
  103. var secondService = BuildSut(secondStore);
  104. Assert.True(await secondService.IsSeededAsync());
  105. Assert.Contains(await secondStore.GetEscalationRulesAsync(), rule =>
  106. rule.SeedKey == "escalation.overdue-milestone.operations-lead");
  107. }
  108. finally
  109. {
  110. if (File.Exists(path))
  111. {
  112. File.Delete(path);
  113. }
  114. }
  115. }
  116. private static SeedService BuildSut(ISeedDataStore store) =>
  117. new(store, new FakeTimeProvider(FixedNow));
  118. private sealed class FakeTimeProvider(DateTimeOffset utcNow) : TimeProvider
  119. {
  120. public override DateTimeOffset GetUtcNow() => utcNow;
  121. }
  122. }

Powered by TurnKey Linux.