Fix build and code structure improvements. New but essential UI functionality. CI improvements. Documentation improvements. AI module improvements.

This commit is contained in:
StellaOps Bot
2025-12-26 21:54:17 +02:00
parent 335ff7da16
commit c2b9cd8d1f
3717 changed files with 264714 additions and 48202 deletions

View File

@@ -0,0 +1,111 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using MicrosoftOptions = Microsoft.Extensions.Options;
using StellaOps.SbomService.Models;
using StellaOps.SbomService.Persistence.Postgres.Repositories;
using StellaOps.SbomService.Persistence.Postgres;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.SbomService.Persistence.Tests;
[Collection(SbomServicePostgresCollection.Name)]
public sealed class PostgresEntrypointRepositoryTests : IAsyncLifetime
{
private readonly SbomServicePostgresFixture _fixture;
private readonly PostgresEntrypointRepository _repository;
private readonly string _tenantId = "tenant-" + Guid.NewGuid().ToString("N")[..8];
public PostgresEntrypointRepositoryTests(SbomServicePostgresFixture fixture)
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new SbomServiceDataSource(MicrosoftOptions.Options.Create(options), NullLogger<SbomServiceDataSource>.Instance);
_repository = new PostgresEntrypointRepository(dataSource, NullLogger<PostgresEntrypointRepository>.Instance);
}
public async Task InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
}
public Task DisposeAsync() => Task.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpsertAndList_RoundTripsEntrypoint()
{
// Arrange
var entrypoint = new Entrypoint(
Artifact: "ghcr.io/test/api",
Service: "web",
Path: "/api",
Scope: "runtime",
RuntimeFlag: true);
// Act
await _repository.UpsertAsync(_tenantId, entrypoint, CancellationToken.None);
var fetched = await _repository.ListAsync(_tenantId, CancellationToken.None);
// Assert
fetched.Should().HaveCount(1);
fetched[0].Artifact.Should().Be("ghcr.io/test/api");
fetched[0].Service.Should().Be("web");
fetched[0].Path.Should().Be("/api");
fetched[0].RuntimeFlag.Should().BeTrue();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task UpsertAsync_UpdatesExistingEntrypoint()
{
// Arrange
var entrypoint1 = new Entrypoint("ghcr.io/test/api", "web", "/old", "runtime", false);
var entrypoint2 = new Entrypoint("ghcr.io/test/api", "web", "/new", "build", true);
// Act
await _repository.UpsertAsync(_tenantId, entrypoint1, CancellationToken.None);
await _repository.UpsertAsync(_tenantId, entrypoint2, CancellationToken.None);
var fetched = await _repository.ListAsync(_tenantId, CancellationToken.None);
// Assert
fetched.Should().HaveCount(1);
fetched[0].Path.Should().Be("/new");
fetched[0].Scope.Should().Be("build");
fetched[0].RuntimeFlag.Should().BeTrue();
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ListAsync_ReturnsOrderedByArtifactServicePath()
{
// Arrange
await _repository.UpsertAsync(_tenantId, new Entrypoint("z-api", "web", "/z", "runtime", true), CancellationToken.None);
await _repository.UpsertAsync(_tenantId, new Entrypoint("a-api", "web", "/a", "runtime", true), CancellationToken.None);
await _repository.UpsertAsync(_tenantId, new Entrypoint("a-api", "worker", "/b", "runtime", true), CancellationToken.None);
// Act
var fetched = await _repository.ListAsync(_tenantId, CancellationToken.None);
// Assert
fetched.Should().HaveCount(3);
fetched[0].Artifact.Should().Be("a-api");
fetched[0].Service.Should().Be("web");
fetched[1].Artifact.Should().Be("a-api");
fetched[1].Service.Should().Be("worker");
fetched[2].Artifact.Should().Be("z-api");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ListAsync_ReturnsEmptyForUnknownTenant()
{
// Act
var fetched = await _repository.ListAsync("unknown-tenant", CancellationToken.None);
// Assert
fetched.Should().BeEmpty();
}
}

View File

@@ -0,0 +1,108 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using MicrosoftOptions = Microsoft.Extensions.Options;
using StellaOps.SbomService.Services;
using StellaOps.SbomService.Persistence.Postgres.Repositories;
using StellaOps.SbomService.Persistence.Postgres;
using Xunit;
using StellaOps.TestKit;
namespace StellaOps.SbomService.Persistence.Tests;
[Collection(SbomServicePostgresCollection.Name)]
public sealed class PostgresOrchestratorControlRepositoryTests : IAsyncLifetime
{
private readonly SbomServicePostgresFixture _fixture;
private readonly PostgresOrchestratorControlRepository _repository;
private readonly string _tenantId = "tenant-" + Guid.NewGuid().ToString("N")[..8];
public PostgresOrchestratorControlRepositoryTests(SbomServicePostgresFixture fixture)
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new SbomServiceDataSource(MicrosoftOptions.Options.Create(options), NullLogger<SbomServiceDataSource>.Instance);
_repository = new PostgresOrchestratorControlRepository(dataSource, NullLogger<PostgresOrchestratorControlRepository>.Instance);
}
public async Task InitializeAsync()
{
await _fixture.TruncateAllTablesAsync();
}
public Task DisposeAsync() => Task.CompletedTask;
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task GetAsync_ReturnsDefaultStateForNewTenant()
{
// Act
var state = await _repository.GetAsync(_tenantId, CancellationToken.None);
// Assert
state.Should().NotBeNull();
state.TenantId.Should().Be(_tenantId);
state.Paused.Should().BeFalse();
state.ThrottlePercent.Should().Be(0);
state.Backpressure.Should().Be("normal");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SetAsync_PersistsControlState()
{
// Arrange
var state = new OrchestratorControlState(
TenantId: _tenantId,
Paused: true,
ThrottlePercent: 50,
Backpressure: "high",
UpdatedAtUtc: DateTimeOffset.UtcNow);
// Act
await _repository.SetAsync(state, CancellationToken.None);
var fetched = await _repository.GetAsync(_tenantId, CancellationToken.None);
// Assert
fetched.Paused.Should().BeTrue();
fetched.ThrottlePercent.Should().Be(50);
fetched.Backpressure.Should().Be("high");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task SetAsync_UpdatesExistingState()
{
// Arrange
var state1 = new OrchestratorControlState(_tenantId, false, 10, "low", DateTimeOffset.UtcNow);
var state2 = new OrchestratorControlState(_tenantId, true, 90, "critical", DateTimeOffset.UtcNow);
// Act
await _repository.SetAsync(state1, CancellationToken.None);
await _repository.SetAsync(state2, CancellationToken.None);
var fetched = await _repository.GetAsync(_tenantId, CancellationToken.None);
// Assert
fetched.Paused.Should().BeTrue();
fetched.ThrottlePercent.Should().Be(90);
fetched.Backpressure.Should().Be("critical");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task ListAsync_ReturnsAllStates()
{
// Arrange
var tenant1 = "tenant-a-" + Guid.NewGuid().ToString("N")[..4];
var tenant2 = "tenant-b-" + Guid.NewGuid().ToString("N")[..4];
await _repository.SetAsync(new OrchestratorControlState(tenant1, false, 0, "normal", DateTimeOffset.UtcNow), CancellationToken.None);
await _repository.SetAsync(new OrchestratorControlState(tenant2, true, 50, "high", DateTimeOffset.UtcNow), CancellationToken.None);
// Act
var states = await _repository.ListAsync(CancellationToken.None);
// Assert
states.Should().HaveCountGreaterThanOrEqualTo(2);
}
}

View File

@@ -0,0 +1,27 @@
using System.Reflection;
using StellaOps.Infrastructure.Postgres.Testing;
using StellaOps.SbomService.Persistence.Postgres;
using Xunit;
namespace StellaOps.SbomService.Persistence.Tests;
/// <summary>
/// PostgreSQL integration test fixture for the SbomService module.
/// </summary>
public sealed class SbomServicePostgresFixture : PostgresIntegrationFixture, ICollectionFixture<SbomServicePostgresFixture>
{
protected override Assembly? GetMigrationAssembly()
=> typeof(SbomServiceDataSource).Assembly;
protected override string GetModuleName() => "SbomService";
}
/// <summary>
/// Collection definition for SbomService PostgreSQL integration tests.
/// Tests in this collection share a single PostgreSQL container instance.
/// </summary>
[CollectionDefinition(Name)]
public sealed class SbomServicePostgresCollection : ICollectionFixture<SbomServicePostgresFixture>
{
public const string Name = "SbomServicePostgres";
}

View File

@@ -0,0 +1,27 @@
<?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>
<RootNamespace>StellaOps.SbomService.Persistence.Tests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="xunit.runner.visualstudio" >
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\__Libraries\StellaOps.SbomService.Persistence\StellaOps.SbomService.Persistence.csproj" />
<ProjectReference Include="..\..\..\__Tests\__Libraries\StellaOps.Infrastructure.Postgres.Testing\StellaOps.Infrastructure.Postgres.Testing.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.TestKit\StellaOps.TestKit.csproj" />
</ItemGroup>
</Project>