Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
165 lines
5.1 KiB
C#
165 lines
5.1 KiB
C#
using FluentAssertions;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
using Microsoft.Extensions.Options;
|
|
using StellaOps.TaskRunner.Core.Execution;
|
|
using StellaOps.TaskRunner.Core.Planning;
|
|
using StellaOps.TaskRunner.Storage.Postgres;
|
|
using StellaOps.TaskRunner.Storage.Postgres.Repositories;
|
|
using StellaOps.Infrastructure.Postgres.Options;
|
|
using Xunit;
|
|
|
|
namespace StellaOps.TaskRunner.Storage.Postgres.Tests;
|
|
|
|
[Collection(TaskRunnerPostgresCollection.Name)]
|
|
public sealed class PostgresPackRunStateStoreTests : IAsyncLifetime
|
|
{
|
|
private readonly TaskRunnerPostgresFixture _fixture;
|
|
private readonly PostgresPackRunStateStore _store;
|
|
private readonly TaskRunnerDataSource _dataSource;
|
|
|
|
public PostgresPackRunStateStoreTests(TaskRunnerPostgresFixture fixture)
|
|
{
|
|
_fixture = fixture;
|
|
var options = Options.Create(new PostgresOptions
|
|
{
|
|
ConnectionString = fixture.ConnectionString,
|
|
SchemaName = TaskRunnerDataSource.DefaultSchemaName,
|
|
AutoMigrate = false
|
|
});
|
|
|
|
_dataSource = new TaskRunnerDataSource(options, NullLogger<TaskRunnerDataSource>.Instance);
|
|
_store = new PostgresPackRunStateStore(_dataSource, NullLogger<PostgresPackRunStateStore>.Instance);
|
|
}
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
await _fixture.TruncateAllTablesAsync();
|
|
}
|
|
|
|
public async Task DisposeAsync()
|
|
{
|
|
await _dataSource.DisposeAsync();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GetAsync_ReturnsNullForUnknownRunId()
|
|
{
|
|
// Act
|
|
var result = await _store.GetAsync("nonexistent-run-id", CancellationToken.None);
|
|
|
|
// Assert
|
|
result.Should().BeNull();
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveAndGet_RoundTripsState()
|
|
{
|
|
// Arrange
|
|
var runId = "run-" + Guid.NewGuid().ToString("N")[..8];
|
|
var state = CreateState(runId);
|
|
|
|
// Act
|
|
await _store.SaveAsync(state, CancellationToken.None);
|
|
var fetched = await _store.GetAsync(runId, CancellationToken.None);
|
|
|
|
// Assert
|
|
fetched.Should().NotBeNull();
|
|
fetched!.RunId.Should().Be(runId);
|
|
fetched.PlanHash.Should().Be("sha256:plan123");
|
|
fetched.Plan.Metadata.Name.Should().Be("test-pack");
|
|
fetched.Steps.Should().HaveCount(1);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SaveAsync_UpdatesExistingState()
|
|
{
|
|
// Arrange
|
|
var runId = "run-" + Guid.NewGuid().ToString("N")[..8];
|
|
var state1 = CreateState(runId, "sha256:hash1");
|
|
var state2 = CreateState(runId, "sha256:hash2");
|
|
|
|
// Act
|
|
await _store.SaveAsync(state1, CancellationToken.None);
|
|
await _store.SaveAsync(state2, CancellationToken.None);
|
|
var fetched = await _store.GetAsync(runId, CancellationToken.None);
|
|
|
|
// Assert
|
|
fetched.Should().NotBeNull();
|
|
fetched!.PlanHash.Should().Be("sha256:hash2");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ListAsync_ReturnsAllStates()
|
|
{
|
|
// Arrange
|
|
var state1 = CreateState("run-list-1");
|
|
var state2 = CreateState("run-list-2");
|
|
|
|
await _store.SaveAsync(state1, CancellationToken.None);
|
|
await _store.SaveAsync(state2, CancellationToken.None);
|
|
|
|
// Act
|
|
var states = await _store.ListAsync(CancellationToken.None);
|
|
|
|
// Assert
|
|
states.Should().HaveCountGreaterOrEqualTo(2);
|
|
states.Select(s => s.RunId).Should().Contain("run-list-1", "run-list-2");
|
|
}
|
|
|
|
private static PackRunState CreateState(string runId, string planHash = "sha256:plan123")
|
|
{
|
|
var now = DateTimeOffset.UtcNow;
|
|
|
|
var metadata = new TaskPackPlanMetadata(
|
|
Name: "test-pack",
|
|
Version: "1.0.0",
|
|
Description: "Test pack for integration tests",
|
|
Tags: ["test"]);
|
|
|
|
var plan = new TaskPackPlan(
|
|
metadata: metadata,
|
|
inputs: new Dictionary<string, System.Text.Json.Nodes.JsonNode?>(),
|
|
steps: [],
|
|
hash: planHash,
|
|
approvals: [],
|
|
secrets: [],
|
|
outputs: [],
|
|
failurePolicy: null);
|
|
|
|
var failurePolicy = new TaskPackPlanFailurePolicy(
|
|
MaxAttempts: 3,
|
|
BackoffSeconds: 30,
|
|
ContinueOnError: false);
|
|
|
|
var stepState = new PackRunStepStateRecord(
|
|
StepId: "step-1",
|
|
Kind: PackRunStepKind.Run,
|
|
Enabled: true,
|
|
ContinueOnError: false,
|
|
MaxParallel: null,
|
|
ApprovalId: null,
|
|
GateMessage: null,
|
|
Status: PackRunStepExecutionStatus.Pending,
|
|
Attempts: 0,
|
|
LastTransitionAt: null,
|
|
NextAttemptAt: null,
|
|
StatusReason: null);
|
|
|
|
var steps = new Dictionary<string, PackRunStepStateRecord>(StringComparer.Ordinal)
|
|
{
|
|
["step-1"] = stepState
|
|
};
|
|
|
|
return new PackRunState(
|
|
RunId: runId,
|
|
PlanHash: planHash,
|
|
Plan: plan,
|
|
FailurePolicy: failurePolicy,
|
|
RequestedAt: now,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
Steps: steps,
|
|
TenantId: "test-tenant");
|
|
}
|
|
}
|