179 lines
7.2 KiB
C#
179 lines
7.2 KiB
C#
using System.Text.Json.Nodes;
|
|
using StellaOps.Scheduler.Models;
|
|
|
|
using StellaOps.TestKit;
|
|
namespace StellaOps.Scheduler.Models.Tests;
|
|
|
|
public sealed class SchedulerSchemaMigrationTests
|
|
{
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeSchedule_DefaultsSchemaVersionWhenMissing()
|
|
{
|
|
var schedule = new Schedule(
|
|
id: "sch-01",
|
|
tenantId: "tenant-alpha",
|
|
name: "Nightly",
|
|
enabled: true,
|
|
cronExpression: "0 2 * * *",
|
|
timezone: "UTC",
|
|
mode: ScheduleMode.AnalysisOnly,
|
|
selection: new Selector(SelectorScope.AllImages, tenantId: "tenant-alpha"),
|
|
onlyIf: null,
|
|
notify: null,
|
|
limits: null,
|
|
createdAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z"),
|
|
createdBy: "svc-scheduler",
|
|
updatedAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z"),
|
|
updatedBy: "svc-scheduler");
|
|
|
|
var json = JsonNode.Parse(CanonicalJsonSerializer.Serialize(schedule))!.AsObject();
|
|
json.Remove("schemaVersion");
|
|
|
|
var result = SchedulerSchemaMigration.UpgradeSchedule(json);
|
|
|
|
Assert.Equal(SchedulerSchemaVersions.Schedule, result.Value.SchemaVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.Schedule, result.ToVersion);
|
|
Assert.Empty(result.Warnings);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeRun_StrictModeRemovesUnknownProperties()
|
|
{
|
|
var run = new Run(
|
|
id: "run-01",
|
|
tenantId: "tenant-alpha",
|
|
trigger: RunTrigger.Manual,
|
|
state: RunState.Queued,
|
|
stats: RunStats.Empty,
|
|
createdAt: DateTimeOffset.Parse("2025-10-18T01:10:00Z"));
|
|
|
|
var json = JsonNode.Parse(CanonicalJsonSerializer.Serialize(run))!.AsObject();
|
|
json["extraField"] = "to-be-removed";
|
|
|
|
var result = SchedulerSchemaMigration.UpgradeRun(json, strict: true);
|
|
|
|
Assert.Contains(result.Warnings, warning => warning.Contains("extraField", StringComparison.Ordinal));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeImpactSet_ThrowsForUnsupportedVersion()
|
|
{
|
|
var impactSet = new ImpactSet(
|
|
selector: new Selector(SelectorScope.AllImages, "tenant-alpha"),
|
|
images: Array.Empty<ImpactImage>(),
|
|
usageOnly: false,
|
|
generatedAt: DateTimeOffset.Parse("2025-10-18T02:00:00Z"));
|
|
|
|
var json = JsonNode.Parse(CanonicalJsonSerializer.Serialize(impactSet))!.AsObject();
|
|
json["schemaVersion"] = "scheduler.impact-set@99";
|
|
|
|
var ex = Assert.Throws<NotSupportedException>(() => SchedulerSchemaMigration.UpgradeImpactSet(json));
|
|
Assert.Contains("Unsupported scheduler schema version", ex.Message, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeSchedule_Legacy0_UpgradesToLatestVersion()
|
|
{
|
|
var legacy = new JsonObject
|
|
{
|
|
["schemaVersion"] = SchedulerSchemaVersions.ScheduleLegacy0,
|
|
["id"] = "sch-legacy",
|
|
["tenantId"] = "tenant-alpha",
|
|
["name"] = "Legacy Nightly",
|
|
["enabled"] = true,
|
|
["cronExpression"] = "0 2 * * *",
|
|
["timezone"] = "UTC",
|
|
["mode"] = "analysis-only",
|
|
["selection"] = new JsonObject
|
|
{
|
|
["scope"] = "all-images",
|
|
["tenantId"] = "tenant-alpha",
|
|
},
|
|
["notify"] = new JsonObject
|
|
{
|
|
["onNewFindings"] = "true",
|
|
["minSeverity"] = "HIGH",
|
|
},
|
|
["limits"] = new JsonObject
|
|
{
|
|
["maxJobs"] = "5",
|
|
["parallelism"] = -2,
|
|
},
|
|
["subscribers"] = "ops-team",
|
|
["createdAt"] = "2025-10-10T00:00:00Z",
|
|
["createdBy"] = "system",
|
|
["updatedAt"] = "2025-10-10T01:00:00Z",
|
|
["updatedBy"] = "system",
|
|
};
|
|
|
|
var result = SchedulerSchemaMigration.UpgradeSchedule(legacy, strict: true);
|
|
|
|
Assert.Equal(SchedulerSchemaVersions.ScheduleLegacy0, result.FromVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.Schedule, result.ToVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.Schedule, result.Value.SchemaVersion);
|
|
Assert.True(result.Value.Notify.IncludeKev);
|
|
Assert.Empty(result.Value.Subscribers);
|
|
Assert.Contains(result.Warnings, warning => warning.Contains("schedule.limits.parallelism", StringComparison.Ordinal));
|
|
Assert.Contains(result.Warnings, warning => warning.Contains("schedule.subscribers", StringComparison.Ordinal));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeRun_Legacy0_BackfillsMissingStats()
|
|
{
|
|
var legacy = new JsonObject
|
|
{
|
|
["schemaVersion"] = SchedulerSchemaVersions.RunLegacy0,
|
|
["id"] = "run-legacy",
|
|
["tenantId"] = "tenant-alpha",
|
|
["trigger"] = "manual",
|
|
["state"] = "queued",
|
|
["stats"] = new JsonObject
|
|
{
|
|
["candidates"] = "4",
|
|
["queued"] = 2,
|
|
},
|
|
["createdAt"] = "2025-10-10T02:00:00Z",
|
|
};
|
|
|
|
var result = SchedulerSchemaMigration.UpgradeRun(legacy, strict: true);
|
|
|
|
Assert.Equal(SchedulerSchemaVersions.RunLegacy0, result.FromVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.Run, result.ToVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.Run, result.Value.SchemaVersion);
|
|
Assert.Equal(4, result.Value.Stats.Candidates);
|
|
Assert.Equal(0, result.Value.Stats.NewMedium);
|
|
Assert.Equal(RunState.Queued, result.Value.State);
|
|
Assert.Empty(result.Value.Deltas);
|
|
Assert.Contains(result.Warnings, warning => warning.Contains("run.stats.newMedium", StringComparison.Ordinal));
|
|
}
|
|
|
|
[Trait("Category", TestCategories.Unit)]
|
|
[Fact]
|
|
public void UpgradeImpactSet_Legacy0_ComputesTotal()
|
|
{
|
|
var legacy = new JsonObject
|
|
{
|
|
["schemaVersion"] = SchedulerSchemaVersions.ImpactSetLegacy0,
|
|
["selector"] = JsonNode.Parse("""{"scope":"all-images","tenantId":"tenant-alpha"}"""),
|
|
["images"] = new JsonArray(
|
|
JsonNode.Parse("""{"imageDigest":"sha256:1111111111111111111111111111111111111111111111111111111111111111","registry":"docker.io","repository":"library/nginx"}"""),
|
|
JsonNode.Parse("""{"imageDigest":"sha256:2222222222222222222222222222222222222222222222222222222222222222","registry":"docker.io","repository":"library/httpd"}""")),
|
|
["usageOnly"] = "false",
|
|
["generatedAt"] = "2025-10-10T03:00:00Z",
|
|
};
|
|
|
|
var result = SchedulerSchemaMigration.UpgradeImpactSet(legacy, strict: true);
|
|
|
|
Assert.Equal(SchedulerSchemaVersions.ImpactSetLegacy0, result.FromVersion);
|
|
Assert.Equal(SchedulerSchemaVersions.ImpactSet, result.ToVersion);
|
|
Assert.Equal(2, result.Value.Total);
|
|
Assert.Equal(2, result.Value.Images.Length);
|
|
Assert.Contains(result.Warnings, warning => warning.Contains("impact set total", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
}
|