Restructure solution layout by module
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
using System.Text.Json;
|
||||
using StellaOps.Scheduler.Models;
|
||||
|
||||
namespace StellaOps.Scheduler.Models.Tests;
|
||||
|
||||
public sealed class ScheduleSerializationTests
|
||||
{
|
||||
[Fact]
|
||||
public void ScheduleSerialization_IsDeterministicRegardlessOfInputOrdering()
|
||||
{
|
||||
var selectionA = new Selector(
|
||||
SelectorScope.ByNamespace,
|
||||
tenantId: "tenant-alpha",
|
||||
namespaces: new[] { "team-b", "team-a" },
|
||||
repositories: new[] { "app/service-api", "app/service-web" },
|
||||
digests: new[] { "sha256:bb", "sha256:aa" },
|
||||
includeTags: new[] { "prod", "canary" },
|
||||
labels: new[]
|
||||
{
|
||||
new LabelSelector("env", new[] { "prod", "staging" }),
|
||||
new LabelSelector("app", new[] { "web", "api" }),
|
||||
},
|
||||
resolvesTags: true);
|
||||
|
||||
var selectionB = new Selector(
|
||||
scope: SelectorScope.ByNamespace,
|
||||
tenantId: "tenant-alpha",
|
||||
namespaces: new[] { "team-a", "team-b" },
|
||||
repositories: new[] { "app/service-web", "app/service-api" },
|
||||
digests: new[] { "sha256:aa", "sha256:bb" },
|
||||
includeTags: new[] { "canary", "prod" },
|
||||
labels: new[]
|
||||
{
|
||||
new LabelSelector("app", new[] { "api", "web" }),
|
||||
new LabelSelector("env", new[] { "staging", "prod" }),
|
||||
},
|
||||
resolvesTags: true);
|
||||
|
||||
var scheduleA = new Schedule(
|
||||
id: "sch_001",
|
||||
tenantId: "tenant-alpha",
|
||||
name: "Nightly Prod",
|
||||
enabled: true,
|
||||
cronExpression: "0 2 * * *",
|
||||
timezone: "UTC",
|
||||
mode: ScheduleMode.AnalysisOnly,
|
||||
selection: selectionA,
|
||||
onlyIf: new ScheduleOnlyIf(lastReportOlderThanDays: 7, policyRevision: "policy@42"),
|
||||
notify: new ScheduleNotify(onNewFindings: true, SeverityRank.High, includeKev: true),
|
||||
limits: new ScheduleLimits(maxJobs: 1000, ratePerSecond: 25, parallelism: 4),
|
||||
createdAt: DateTimeOffset.Parse("2025-10-18T23:00:00Z"),
|
||||
createdBy: "svc_scheduler",
|
||||
updatedAt: DateTimeOffset.Parse("2025-10-18T23:00:00Z"),
|
||||
updatedBy: "svc_scheduler");
|
||||
|
||||
var scheduleB = new Schedule(
|
||||
id: scheduleA.Id,
|
||||
tenantId: scheduleA.TenantId,
|
||||
name: scheduleA.Name,
|
||||
enabled: scheduleA.Enabled,
|
||||
cronExpression: scheduleA.CronExpression,
|
||||
timezone: scheduleA.Timezone,
|
||||
mode: scheduleA.Mode,
|
||||
selection: selectionB,
|
||||
onlyIf: scheduleA.OnlyIf,
|
||||
notify: scheduleA.Notify,
|
||||
limits: scheduleA.Limits,
|
||||
createdAt: scheduleA.CreatedAt,
|
||||
createdBy: scheduleA.CreatedBy,
|
||||
updatedAt: scheduleA.UpdatedAt,
|
||||
updatedBy: scheduleA.UpdatedBy,
|
||||
subscribers: scheduleA.Subscribers);
|
||||
|
||||
var jsonA = CanonicalJsonSerializer.Serialize(scheduleA);
|
||||
var jsonB = CanonicalJsonSerializer.Serialize(scheduleB);
|
||||
|
||||
Assert.Equal(jsonA, jsonB);
|
||||
|
||||
using var doc = JsonDocument.Parse(jsonA);
|
||||
var root = doc.RootElement;
|
||||
Assert.Equal(SchedulerSchemaVersions.Schedule, root.GetProperty("schemaVersion").GetString());
|
||||
Assert.Equal("analysis-only", root.GetProperty("mode").GetString());
|
||||
Assert.Equal("tenant-alpha", root.GetProperty("tenantId").GetString());
|
||||
|
||||
var namespaces = root.GetProperty("selection").GetProperty("namespaces").EnumerateArray().Select(e => e.GetString()).ToArray();
|
||||
Assert.Equal(new[] { "team-a", "team-b" }, namespaces);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData("not-a-timezone")]
|
||||
public void Schedule_ThrowsWhenTimezoneInvalid(string timezone)
|
||||
{
|
||||
var selection = new Selector(SelectorScope.AllImages, tenantId: "tenant-alpha");
|
||||
|
||||
Assert.ThrowsAny<Exception>(() => new Schedule(
|
||||
id: "sch_002",
|
||||
tenantId: "tenant-alpha",
|
||||
name: "Invalid timezone",
|
||||
enabled: true,
|
||||
cronExpression: "0 3 * * *",
|
||||
timezone: timezone,
|
||||
mode: ScheduleMode.AnalysisOnly,
|
||||
selection: selection,
|
||||
onlyIf: null,
|
||||
notify: null,
|
||||
limits: null,
|
||||
createdAt: DateTimeOffset.UtcNow,
|
||||
createdBy: "svc",
|
||||
updatedAt: DateTimeOffset.UtcNow,
|
||||
updatedBy: "svc"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user