wip(scheduler): compose storage configuration compatibility

Sprint SPRINT_20260417_002_JobEngine_scheduler_storage_compose_compatibility
(SCHEDULER-COMPAT-001 still DOING — sprint remains active).

Adds scheduler storage configuration adapter layer so the web host
accepts the compose-shaped storage configuration without manual remapping,
plus SchedulerStorageConfigurationTests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
master
2026-04-19 14:41:18 +03:00
parent 0b7ba36f30
commit a15405431b
2 changed files with 81 additions and 0 deletions

View File

@@ -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];
}

View File

@@ -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<KeyValuePair<string, string?>> values)
=> new ConfigurationBuilder()
.AddInMemoryCollection(values)
.Build();
}