diff --git a/src/JobEngine/StellaOps.Scheduler.WebService/Configuration/SchedulerStorageConfiguration.cs b/src/JobEngine/StellaOps.Scheduler.WebService/Configuration/SchedulerStorageConfiguration.cs new file mode 100644 index 000000000..6baa06340 --- /dev/null +++ b/src/JobEngine/StellaOps.Scheduler.WebService/Configuration/SchedulerStorageConfiguration.cs @@ -0,0 +1,32 @@ +using Microsoft.Extensions.Configuration; + +namespace StellaOps.Scheduler.WebService.Configuration; + +public static class SchedulerStorageConfiguration +{ + public const string FlatSectionPath = "Scheduler:Storage"; + public const string ComposeNestedSectionPath = "Scheduler:Storage:Postgres:Scheduler"; + public const string LegacySectionPath = "Postgres:Scheduler"; + + public static string? ResolveSectionPath(IConfiguration configuration) + { + foreach (var sectionPath in GetCandidateSectionPaths()) + { + if (!string.IsNullOrWhiteSpace(configuration[$"{sectionPath}:ConnectionString"])) + { + return sectionPath; + } + } + + return null; + } + + public static string? ResolveConnectionString(IConfiguration configuration) + { + var sectionPath = ResolveSectionPath(configuration); + return sectionPath is null ? null : configuration[$"{sectionPath}:ConnectionString"]; + } + + private static string[] GetCandidateSectionPaths() + => [FlatSectionPath, ComposeNestedSectionPath, LegacySectionPath]; +} diff --git a/src/JobEngine/StellaOps.Scheduler.__Tests/StellaOps.Scheduler.WebService.Tests/SchedulerStorageConfigurationTests.cs b/src/JobEngine/StellaOps.Scheduler.__Tests/StellaOps.Scheduler.WebService.Tests/SchedulerStorageConfigurationTests.cs new file mode 100644 index 000000000..20fb1a9d8 --- /dev/null +++ b/src/JobEngine/StellaOps.Scheduler.__Tests/StellaOps.Scheduler.WebService.Tests/SchedulerStorageConfigurationTests.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Configuration; +using StellaOps.Scheduler.WebService.Configuration; + +namespace StellaOps.Scheduler.WebService.Tests; + +public sealed class SchedulerStorageConfigurationTests +{ + [Fact] + public void ResolveConnectionString_PrefersFlatSchedulerStorage() + { + var configuration = BuildConfiguration( + [ + new("Scheduler:Storage:ConnectionString", "Host=flat;Database=scheduler"), + new("Scheduler:Storage:Postgres:Scheduler:ConnectionString", "Host=nested;Database=scheduler"), + ]); + + Assert.Equal(SchedulerStorageConfiguration.FlatSectionPath, SchedulerStorageConfiguration.ResolveSectionPath(configuration)); + Assert.Equal("Host=flat;Database=scheduler", SchedulerStorageConfiguration.ResolveConnectionString(configuration)); + } + + [Fact] + public void ResolveConnectionString_AcceptsComposeNestedStorage() + { + var configuration = BuildConfiguration( + [ + new("Scheduler:Storage:Postgres:Scheduler:ConnectionString", "Host=nested;Database=scheduler"), + ]); + + Assert.Equal(SchedulerStorageConfiguration.ComposeNestedSectionPath, SchedulerStorageConfiguration.ResolveSectionPath(configuration)); + Assert.Equal("Host=nested;Database=scheduler", SchedulerStorageConfiguration.ResolveConnectionString(configuration)); + } + + [Fact] + public void ResolveConnectionString_FallsBackToLegacyPostgresScheduler() + { + var configuration = BuildConfiguration( + [ + new("Postgres:Scheduler:ConnectionString", "Host=legacy;Database=scheduler"), + ]); + + Assert.Equal(SchedulerStorageConfiguration.LegacySectionPath, SchedulerStorageConfiguration.ResolveSectionPath(configuration)); + Assert.Equal("Host=legacy;Database=scheduler", SchedulerStorageConfiguration.ResolveConnectionString(configuration)); + } + + private static IConfiguration BuildConfiguration(IEnumerable> values) + => new ConfigurationBuilder() + .AddInMemoryCollection(values) + .Build(); +}