up
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

This commit is contained in:
StellaOps Bot
2025-12-14 15:50:38 +02:00
parent f1a39c4ce3
commit 233873f620
249 changed files with 29746 additions and 154 deletions

View File

@@ -0,0 +1,164 @@
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");
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" ?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.4">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\StellaOps.TaskRunner.Storage.Postgres\StellaOps.TaskRunner.Storage.Postgres.csproj" />
<ProjectReference Include="..\StellaOps.TaskRunner\StellaOps.TaskRunner.Core\StellaOps.TaskRunner.Core.csproj" />
<ProjectReference Include="..\..\__Libraries\StellaOps.Infrastructure.Postgres.Testing\StellaOps.Infrastructure.Postgres.Testing.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,30 @@
using System.Reflection;
using StellaOps.TaskRunner.Storage.Postgres;
using StellaOps.Infrastructure.Postgres.Testing;
using Xunit;
namespace StellaOps.TaskRunner.Storage.Postgres.Tests;
/// <summary>
/// PostgreSQL integration test fixture for the TaskRunner module.
/// Runs migrations from embedded resources and provides test isolation.
/// </summary>
public sealed class TaskRunnerPostgresFixture : PostgresIntegrationFixture, ICollectionFixture<TaskRunnerPostgresFixture>
{
protected override Assembly? GetMigrationAssembly()
=> typeof(TaskRunnerDataSource).Assembly;
protected override string GetModuleName() => "TaskRunner";
protected override string? GetResourcePrefix() => "Migrations";
}
/// <summary>
/// Collection definition for TaskRunner PostgreSQL integration tests.
/// Tests in this collection share a single PostgreSQL container instance.
/// </summary>
[CollectionDefinition(Name)]
public sealed class TaskRunnerPostgresCollection : ICollectionFixture<TaskRunnerPostgresFixture>
{
public const string Name = "TaskRunnerPostgres";
}