Add unit tests for SBOM ingestion and transformation
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Implement `SbomIngestServiceCollectionExtensionsTests` to verify the SBOM ingestion pipeline exports snapshots correctly.
- Create `SbomIngestTransformerTests` to ensure the transformation produces expected nodes and edges, including deduplication of license nodes and normalization of timestamps.
- Add `SbomSnapshotExporterTests` to test the export functionality for manifest, adjacency, nodes, and edges.
- Introduce `VexOverlayTransformerTests` to validate the transformation of VEX nodes and edges.
- Set up project file for the test project with necessary dependencies and configurations.
- Include JSON fixture files for testing purposes.
This commit is contained in:
master
2025-11-04 07:49:39 +02:00
parent f72c5c513a
commit 2eb6852d34
491 changed files with 39445 additions and 3917 deletions

View File

@@ -56,10 +56,11 @@ public sealed class GraphJobEventPublisherTests
await publisher.PublishAsync(notification, CancellationToken.None);
var message = Assert.Single(loggerProvider.Messages);
Assert.Contains("\"kind\":\"scheduler.graph.job.completed\"", message);
Assert.Contains("\"tenant\":\"tenant-alpha\"", message);
Assert.Contains("\"resultUri\":\"oras://result\"", message);
Assert.Contains(loggerProvider.Messages, message => message.Contains("unsupported driver", StringComparison.OrdinalIgnoreCase));
var eventPayload = loggerProvider.Messages.FirstOrDefault(message => message.Contains("\"kind\":\"scheduler.graph.job.completed\"", StringComparison.Ordinal));
Assert.NotNull(eventPayload);
Assert.Contains("\"tenant\":\"tenant-alpha\"", eventPayload);
Assert.Contains("\"resultUri\":\"oras://result\"", eventPayload);
}
[Fact]

View File

@@ -0,0 +1,332 @@
using System.Net;
using System.Net.Http.Headers;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Mongo2Go;
using StellaOps.Scheduler.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Scheduler.WebService.PolicySimulations;
using System.Collections.Generic;
using System.Threading;
namespace StellaOps.Scheduler.WebService.Tests;
public sealed class PolicySimulationEndpointTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _factory;
public PolicySimulationEndpointTests(WebApplicationFactory<Program> factory)
{
_factory = factory;
}
[Fact]
public async Task CreateListGetSimulation()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var createResponse = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-alpha",
policyVersion = 3,
metadata = new Dictionary<string, string> { ["requestedBy"] = "unit-test" },
inputs = new
{
sbomSet = new[] { "sbom://alpha", "sbom://bravo" },
captureExplain = true
}
});
createResponse.EnsureSuccessStatusCode();
Assert.Equal(System.Net.HttpStatusCode.Created, createResponse.StatusCode);
var created = await createResponse.Content.ReadFromJsonAsync<JsonElement>();
var runId = created.GetProperty("simulation").GetProperty("runId").GetString();
Assert.False(string.IsNullOrEmpty(runId));
Assert.Equal("simulate", created.GetProperty("simulation").GetProperty("mode").GetString());
var listResponse = await client.GetAsync("/api/v1/scheduler/policies/simulations?limit=5");
listResponse.EnsureSuccessStatusCode();
var list = await listResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.True(list.GetProperty("simulations").EnumerateArray().Any());
var getResponse = await client.GetAsync($"/api/v1/scheduler/policies/simulations/{runId}");
getResponse.EnsureSuccessStatusCode();
var simulation = await getResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal(runId, simulation.GetProperty("simulation").GetProperty("runId").GetString());
}
[Fact]
public async Task MetricsEndpointWithoutProviderReturns501()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-metrics-missing");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var response = await client.GetAsync("/api/v1/scheduler/policies/simulations/metrics");
Assert.Equal(HttpStatusCode.NotImplemented, response.StatusCode);
}
[Fact]
public async Task MetricsEndpointReturnsSummary()
{
var stub = new StubPolicySimulationMetricsProvider
{
Response = new PolicySimulationMetricsResponse(
new PolicySimulationQueueDepth(
3,
new Dictionary<string, long>
{
["pending"] = 2,
["dispatching"] = 1
}),
new PolicySimulationLatencyMetrics(
Samples: 2,
P50: 1.5,
P90: 2.5,
P95: 3.5,
P99: 4.0,
Mean: 2.0))
};
await using var factory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IPolicySimulationMetricsProvider>(stub);
services.AddSingleton<IPolicySimulationMetricsRecorder>(stub);
});
});
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-metrics");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var response = await client.GetAsync("/api/v1/scheduler/policies/simulations/metrics");
response.EnsureSuccessStatusCode();
var payload = await response.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal(3, payload.GetProperty("policy_simulation_queue_depth").GetProperty("total").GetInt32());
Assert.Equal(2, payload.GetProperty("policy_simulation_latency").GetProperty("samples").GetInt32());
Assert.Equal(2.0, payload.GetProperty("policy_simulation_latency").GetProperty("mean_seconds").GetDouble());
}
[Fact]
public async Task CreateSimulationRequiresScopeHeader()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-auth");
var response = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-auth",
policyVersion = 1
});
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task CreateSimulationRequiresPolicySimulateScope()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-authz");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:run");
var response = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-authz",
policyVersion = 2
});
Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode);
}
[Fact]
public async Task CancelSimulationMarksStatus()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-cancel");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var create = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-bravo",
policyVersion = 2
});
create.EnsureSuccessStatusCode();
var runId = (await create.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("simulation").GetProperty("runId").GetString();
var cancel = await client.PostAsJsonAsync($"/api/v1/scheduler/policies/simulations/{runId}/cancel", new
{
reason = "user-request"
});
cancel.EnsureSuccessStatusCode();
var cancelled = await cancel.Content.ReadFromJsonAsync<JsonElement>();
Assert.True(cancelled.GetProperty("simulation").GetProperty("cancellationRequested").GetBoolean());
}
[Fact]
public async Task RetrySimulationCreatesNewRun()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-retry");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var create = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-charlie",
policyVersion = 5
});
create.EnsureSuccessStatusCode();
var runId = (await create.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("simulation").GetProperty("runId").GetString();
// Mark as cancelled to allow retry
await client.PostAsJsonAsync($"/api/v1/scheduler/policies/simulations/{runId}/cancel", new { reason = "cleanup" });
var retry = await client.PostAsync($"/api/v1/scheduler/policies/simulations/{runId}/retry", content: null);
retry.EnsureSuccessStatusCode();
Assert.Equal(System.Net.HttpStatusCode.Created, retry.StatusCode);
var retried = await retry.Content.ReadFromJsonAsync<JsonElement>();
var newRunId = retried.GetProperty("simulation").GetProperty("runId").GetString();
Assert.False(string.IsNullOrEmpty(newRunId));
Assert.NotEqual(runId, newRunId);
var metadata = retried.GetProperty("simulation").GetProperty("metadata");
Assert.True(metadata.TryGetProperty("retry-of", out var retryOf));
Assert.Equal(runId, retryOf.GetString());
}
[Fact]
public async Task StreamSimulationEmitsCoreEvents()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-stream");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var create = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-delta",
policyVersion = 7
});
create.EnsureSuccessStatusCode();
var runId = (await create.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("simulation").GetProperty("runId").GetString();
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/scheduler/policies/simulations/{runId}/stream");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
var seenRetry = false;
var seenInitial = false;
var seenQueueLag = false;
var seenHeartbeat = false;
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
while (!cts.Token.IsCancellationRequested && !(seenRetry && seenInitial && seenQueueLag && seenHeartbeat))
{
var readTask = reader.ReadLineAsync();
var completed = await Task.WhenAny(readTask, Task.Delay(200, cts.Token));
if (completed != readTask)
{
continue;
}
var line = await readTask;
if (line is null)
{
break;
}
if (line.Length == 0)
{
continue;
}
if (line.StartsWith("retry:", StringComparison.Ordinal))
{
seenRetry = true;
}
else if (line.StartsWith("event: initial", StringComparison.Ordinal))
{
seenInitial = true;
}
else if (line.StartsWith("event: queueLag", StringComparison.Ordinal))
{
seenQueueLag = true;
}
else if (line.StartsWith("event: heartbeat", StringComparison.Ordinal))
{
seenHeartbeat = true;
}
}
Assert.True(seenRetry, "Retry directive should be emitted before events.");
Assert.True(seenInitial, "Initial event was not observed.");
Assert.True(seenQueueLag, "Queue lag event was not observed.");
Assert.True(seenHeartbeat, "Heartbeat event was not observed.");
}
[Fact]
public async Task MongoBackedCreateSimulationPersists()
{
using var runner = MongoDbRunner.Start(additionalMongodArguments: "--quiet");
await using var factory = _factory.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration((_, configuration) =>
{
configuration.AddInMemoryCollection(new[]
{
new KeyValuePair<string, string?>("Scheduler:Storage:ConnectionString", runner.ConnectionString),
new KeyValuePair<string, string?>("Scheduler:Storage:Database", $"scheduler_web_tests_{Guid.NewGuid():N}")
});
});
});
using var client = factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-sim-mongo");
client.DefaultRequestHeaders.Add("X-Scopes", "policy:simulate");
var createResponse = await client.PostAsJsonAsync("/api/v1/scheduler/policies/simulations", new
{
policyId = "policy-mongo",
policyVersion = 11
});
createResponse.EnsureSuccessStatusCode();
var runId = (await createResponse.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("simulation").GetProperty("runId").GetString();
Assert.False(string.IsNullOrEmpty(runId));
var fetched = await client.GetAsync($"/api/v1/scheduler/policies/simulations/{runId}");
fetched.EnsureSuccessStatusCode();
var payload = await fetched.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal(runId, payload.GetProperty("simulation").GetProperty("runId").GetString());
}
private sealed class StubPolicySimulationMetricsProvider : IPolicySimulationMetricsProvider, IPolicySimulationMetricsRecorder
{
public PolicySimulationMetricsResponse Response { get; set; } = new(
new PolicySimulationQueueDepth(0, new Dictionary<string, long>()),
new PolicySimulationLatencyMetrics(0, null, null, null, null, null));
public List<double> RecordedLatencies { get; } = new();
public Task<PolicySimulationMetricsResponse> CaptureAsync(string tenantId, CancellationToken cancellationToken)
=> Task.FromResult(Response);
public void RecordLatency(PolicyRunStatus status, DateTimeOffset observedAt)
{
var finishedAt = status.FinishedAt ?? observedAt;
var latency = (finishedAt - status.QueuedAt).TotalSeconds;
if (latency >= 0)
{
RecordedLatencies.Add(latency);
}
}
}
}

View File

@@ -1,5 +1,16 @@
using System.Linq;
using System.Text.Json;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Queue;
using StellaOps.Scheduler.Storage.Mongo.Repositories;
namespace StellaOps.Scheduler.WebService.Tests;
@@ -17,7 +28,7 @@ public sealed class RunEndpointTests : IClassFixture<WebApplicationFactory<Progr
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-runs");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview scheduler.runs.manage");
var scheduleResponse = await client.PostAsJsonAsync("/api/v1/scheduler/schedules", new
{
@@ -66,11 +77,11 @@ public sealed class RunEndpointTests : IClassFixture<WebApplicationFactory<Progr
}
[Fact]
public async Task PreviewImpactForSchedule()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-preview");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview");
public async Task PreviewImpactForSchedule()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-preview");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview scheduler.runs.manage");
var scheduleResponse = await client.PostAsJsonAsync("/api/v1/scheduler/schedules", new
{
@@ -96,9 +107,224 @@ public sealed class RunEndpointTests : IClassFixture<WebApplicationFactory<Progr
sampleSize = 3
});
previewResponse.EnsureSuccessStatusCode();
var preview = await previewResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.True(preview.GetProperty("total").GetInt32() >= 0);
Assert.True(preview.GetProperty("sample").GetArrayLength() <= 3);
}
}
previewResponse.EnsureSuccessStatusCode();
var preview = await previewResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.True(preview.GetProperty("total").GetInt32() >= 0);
Assert.True(preview.GetProperty("sample").GetArrayLength() <= 3);
}
[Fact]
public async Task RetryRunCreatesNewRun()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-retry");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview scheduler.runs.manage");
var scheduleId = await CreateScheduleAsync(client, "RetrySchedule");
var createRun = await client.PostAsJsonAsync("/api/v1/scheduler/runs", new
{
scheduleId,
trigger = "manual"
});
createRun.EnsureSuccessStatusCode();
var runJson = await createRun.Content.ReadFromJsonAsync<JsonElement>();
var runId = runJson.GetProperty("run").GetProperty("id").GetString();
Assert.False(string.IsNullOrEmpty(runId));
var cancelResponse = await client.PostAsync($"/api/v1/scheduler/runs/{runId}/cancel", null);
cancelResponse.EnsureSuccessStatusCode();
var retryResponse = await client.PostAsync($"/api/v1/scheduler/runs/{runId}/retry", content: null);
retryResponse.EnsureSuccessStatusCode();
Assert.Equal(System.Net.HttpStatusCode.Created, retryResponse.StatusCode);
var retryJson = await retryResponse.Content.ReadFromJsonAsync<JsonElement>();
var retryRun = retryJson.GetProperty("run");
Assert.Equal("planning", retryRun.GetProperty("state").GetString());
Assert.Equal(runId, retryRun.GetProperty("retryOf").GetString());
Assert.Equal("manual", retryRun.GetProperty("trigger").GetString());
Assert.Contains("retry-of:", retryRun.GetProperty("reason").GetProperty("manualReason").GetString());
}
[Fact]
public async Task GetRunDeltasReturnsMetadata()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-deltas");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview scheduler.runs.manage");
var scheduleId = await CreateScheduleAsync(client, "DeltaSchedule");
var runResponse = await client.PostAsJsonAsync("/api/v1/scheduler/runs", new
{
scheduleId,
trigger = "manual"
});
runResponse.EnsureSuccessStatusCode();
var runJson = await runResponse.Content.ReadFromJsonAsync<JsonElement>();
var runId = runJson.GetProperty("run").GetProperty("id").GetString()!;
using (var scope = _factory.Services.CreateScope())
{
var repository = scope.ServiceProvider.GetRequiredService<IRunRepository>();
var existing = await repository.GetAsync("tenant-deltas", runId);
Assert.NotNull(existing);
var deltas = ImmutableArray.Create(new DeltaSummary(
"sha256:" + new string('a', 64),
newFindings: 2,
newCriticals: 1,
newHigh: 1,
newMedium: 0,
newLow: 0));
var updated = new Run(
existing!.Id,
existing.TenantId,
existing.Trigger,
existing.State,
existing.Stats,
existing.CreatedAt,
existing.Reason,
existing.ScheduleId,
existing.StartedAt,
existing.FinishedAt,
existing.Error,
deltas,
existing.RetryOf,
existing.SchemaVersion);
await repository.UpdateAsync(updated);
}
var deltasResponse = await client.GetAsync($"/api/v1/scheduler/runs/{runId}/deltas");
deltasResponse.EnsureSuccessStatusCode();
var deltasJson = await deltasResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.Equal(1, deltasJson.GetProperty("deltas").GetArrayLength());
}
[Fact]
public async Task QueueLagSummaryReturnsDepth()
{
SchedulerQueueMetrics.RecordDepth("redis", "scheduler-runner", 7);
try
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-queue");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.runs.read scheduler.runs.manage");
var queueResponse = await client.GetAsync("/api/v1/scheduler/runs/queue/lag");
queueResponse.EnsureSuccessStatusCode();
var summary = await queueResponse.Content.ReadFromJsonAsync<JsonElement>();
Assert.True(summary.GetProperty("totalDepth").GetInt64() >= 7);
Assert.True(summary.GetProperty("queues").EnumerateArray().Any());
}
finally
{
SchedulerQueueMetrics.RemoveDepth("redis", "scheduler-runner");
}
}
[Fact]
public async Task StreamRunEmitsInitialEvent()
{
using var client = _factory.CreateClient();
client.DefaultRequestHeaders.Add("X-Tenant-Id", "tenant-stream");
client.DefaultRequestHeaders.Add("X-Scopes", "scheduler.schedules.write scheduler.schedules.read scheduler.runs.write scheduler.runs.read scheduler.runs.preview scheduler.runs.manage");
var scheduleId = await CreateScheduleAsync(client, "StreamSchedule");
var runResponse = await client.PostAsJsonAsync("/api/v1/scheduler/runs", new
{
scheduleId,
trigger = "manual"
});
runResponse.EnsureSuccessStatusCode();
var runJson = await runResponse.Content.ReadFromJsonAsync<JsonElement>();
var runId = runJson.GetProperty("run").GetProperty("id").GetString();
Assert.False(string.IsNullOrEmpty(runId));
using var request = new HttpRequestMessage(HttpMethod.Get, $"/api/v1/scheduler/runs/{runId}/stream");
request.Headers.Accept.ParseAdd("text/event-stream");
using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
await using var stream = await response.Content.ReadAsStreamAsync();
using var reader = new StreamReader(stream);
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));
var seenRetry = false;
var seenInitial = false;
var seenQueueLag = false;
var seenHeartbeat = false;
while (!cts.IsCancellationRequested && !(seenRetry && seenInitial && seenQueueLag && seenHeartbeat))
{
var readTask = reader.ReadLineAsync();
var completed = await Task.WhenAny(readTask, Task.Delay(200, cts.Token));
if (completed != readTask)
{
continue;
}
var line = await readTask;
if (line is null)
{
break;
}
if (line.Length == 0)
{
continue;
}
if (line.StartsWith("retry:", StringComparison.Ordinal))
{
seenRetry = true;
}
else if (line.StartsWith("event: initial", StringComparison.Ordinal))
{
seenInitial = true;
}
else if (line.StartsWith("event: queueLag", StringComparison.Ordinal))
{
seenQueueLag = true;
}
else if (line.StartsWith("event: heartbeat", StringComparison.Ordinal))
{
seenHeartbeat = true;
}
}
Assert.True(seenRetry, "Retry directive was not observed.");
Assert.True(seenInitial, "Initial snapshot was not observed.");
Assert.True(seenQueueLag, "Queue lag event was not observed.");
Assert.True(seenHeartbeat, "Heartbeat event was not observed.");
}
private static async Task<string> CreateScheduleAsync(HttpClient client, string name)
{
var scheduleResponse = await client.PostAsJsonAsync("/api/v1/scheduler/schedules", new
{
name,
cronExpression = "0 1 * * *",
timezone = "UTC",
mode = "analysis-only",
selection = new { scope = "all-images" }
});
scheduleResponse.EnsureSuccessStatusCode();
var scheduleJson = await scheduleResponse.Content.ReadFromJsonAsync<JsonElement>();
var scheduleId = scheduleJson.GetProperty("schedule").GetProperty("id").GetString();
Assert.False(string.IsNullOrEmpty(scheduleId));
return scheduleId!;
}
}

View File

@@ -1,9 +1,11 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Scheduler.WebService.Options;
using StellaOps.Scheduler.WebService.Runs;
namespace StellaOps.Scheduler.WebService.Tests;
@@ -41,6 +43,13 @@ public sealed class SchedulerWebApplicationFactory : WebApplicationFactory<Progr
options.Webhooks.Excitor.HmacSecret = "excitor-secret";
options.Webhooks.Excitor.Enabled = true;
});
services.PostConfigure<RunStreamOptions>(options =>
{
options.PollInterval = TimeSpan.FromMilliseconds(100);
options.QueueLagInterval = TimeSpan.FromMilliseconds(200);
options.HeartbeatInterval = TimeSpan.FromMilliseconds(150);
});
});
}
}

View File

@@ -8,6 +8,7 @@
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Mongo2Go" Version="4.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="xunit" Version="2.9.2" />
@@ -17,4 +18,4 @@
<ItemGroup>
<ProjectReference Include="../../StellaOps.Scheduler.WebService/StellaOps.Scheduler.WebService.csproj" />
</ItemGroup>
</Project>
</Project>