Tests fixes, audit progress, UI completions

This commit is contained in:
StellaOps Bot
2025-12-30 09:03:22 +02:00
parent 7a5210e2aa
commit 82e55c206a
318 changed files with 7232 additions and 1256 deletions

View File

@@ -0,0 +1,22 @@
# Authority Core Tests AGENTS
## Purpose & Scope
- Working directory: `src/Authority/__Tests/StellaOps.Authority.Core.Tests/`.
- Roles: QA automation, backend engineer.
- Focus: verdict manifests, serialization, replay verification, and store behaviors.
## Required Reading (treat as read before DOING)
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/modules/authority/architecture.md`
- Relevant sprint files.
## Working Agreements
- Keep tests deterministic (fixed time/IDs, stable ordering).
- Avoid live network calls; use fakes for signing and evaluation.
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
## Testing
- Use xUnit + FluentAssertions + Moq.
- Cover manifest builder/serializer, replay verification, and store pagination/filters.

View File

@@ -0,0 +1,10 @@
# Authority Core Tests Task Board
This board mirrors active sprint tasks for this module.
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
| Task ID | Status | Notes |
| --- | --- | --- |
| AUDIT-0087-M | DONE | Maintainability audit for StellaOps.Authority.Core.Tests. |
| AUDIT-0087-T | DONE | Test coverage audit for StellaOps.Authority.Core.Tests. |
| AUDIT-0087-A | TODO | Pending approval for changes. |

View File

@@ -0,0 +1,22 @@
# Authority Persistence Tests AGENTS
## Purpose & Scope
- Working directory: `src/Authority/__Tests/StellaOps.Authority.Persistence.Tests/`.
- Roles: QA automation, backend engineer.
- Focus: PostgreSQL repository behavior, migrations, concurrency, and storage correctness.
## Required Reading (treat as read before DOING)
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/modules/authority/architecture.md`
- Relevant sprint files.
## Working Agreements
- Keep tests deterministic (fixed time/IDs); tag integration tests correctly.
- Avoid network calls beyond local Postgres fixtures.
- Update `docs/implplan/SPRINT_*.md` and local `TASKS.md` when starting or completing work.
## Testing
- Use xUnit + FluentAssertions + Moq + TestKit fixtures.
- Cover repository CRUD, migrations, concurrency, and pagination edge cases.

View File

@@ -31,6 +31,7 @@ public sealed class ApiKeyConcurrencyTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private ApiKeyRepository _repository = null!;
private AuthorityDataSource? _dataSource;
private NpgsqlDataSource _npgsqlDataSource = null!;
private readonly string _tenantId = Guid.NewGuid().ToString();
private readonly Guid _userId = Guid.NewGuid();
@@ -44,10 +45,9 @@ public sealed class ApiKeyConcurrencyTests : IAsyncLifetime
{
await _fixture.TruncateAllTablesAsync();
var options = _fixture.Fixture.CreateOptions();
options.SchemaName = _fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(dataSource, NullLogger<ApiKeyRepository>.Instance);
var options = _fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(_dataSource, NullLogger<ApiKeyRepository>.Instance);
_npgsqlDataSource = NpgsqlDataSource.Create(_fixture.ConnectionString);
await SeedTenantAsync();
@@ -57,6 +57,10 @@ public sealed class ApiKeyConcurrencyTests : IAsyncLifetime
public async ValueTask DisposeAsync()
{
await _npgsqlDataSource.DisposeAsync();
if (_dataSource is not null)
{
await _dataSource.DisposeAsync();
}
}
[Trait("Category", TestCategories.Unit)]

View File

@@ -31,6 +31,7 @@ public sealed class ApiKeyIdempotencyTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private ApiKeyRepository _repository = null!;
private AuthorityDataSource? _dataSource;
private NpgsqlDataSource _npgsqlDataSource = null!;
private readonly string _tenantId = Guid.NewGuid().ToString();
private readonly Guid _userId = Guid.NewGuid();
@@ -44,10 +45,9 @@ public sealed class ApiKeyIdempotencyTests : IAsyncLifetime
{
await _fixture.TruncateAllTablesAsync();
var options = _fixture.Fixture.CreateOptions();
options.SchemaName = _fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(dataSource, NullLogger<ApiKeyRepository>.Instance);
var options = _fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(_dataSource, NullLogger<ApiKeyRepository>.Instance);
_npgsqlDataSource = NpgsqlDataSource.Create(_fixture.ConnectionString);
await SeedTenantAsync();
@@ -57,6 +57,10 @@ public sealed class ApiKeyIdempotencyTests : IAsyncLifetime
public async ValueTask DisposeAsync()
{
await _npgsqlDataSource.DisposeAsync();
if (_dataSource is not null)
{
await _dataSource.DisposeAsync();
}
}
[Trait("Category", TestCategories.Unit)]

View File

@@ -12,6 +12,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class ApiKeyRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly ApiKeyRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -19,10 +20,9 @@ public sealed class ApiKeyRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(dataSource, NullLogger<ApiKeyRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new ApiKeyRepository(_dataSource, NullLogger<ApiKeyRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -31,7 +31,7 @@ public sealed class ApiKeyRepositoryTests : IAsyncLifetime
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -12,6 +12,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class AuditRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly AuditRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -19,14 +20,13 @@ public sealed class AuditRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new AuditRepository(dataSource, NullLogger<AuditRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new AuditRepository(_dataSource, NullLogger<AuditRepository>.Instance);
}
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -8,6 +8,7 @@
using System.Reflection;
using StellaOps.Authority.Persistence.Postgres;
using StellaOps.Infrastructure.Postgres.Testing;
using StellaOps.Infrastructure.Postgres.Options;
using StellaOps.TestKit;
using StellaOps.TestKit.Fixtures;
using Xunit;
@@ -28,6 +29,15 @@ public sealed class AuthorityPostgresFixture : PostgresIntegrationFixture, IColl
=> typeof(AuthorityDataSource).Assembly;
protected override string GetModuleName() => "Authority";
public PostgresOptions CreateOptions()
{
var options = Fixture.CreateOptions();
options.SchemaName = SchemaName;
options.MaxPoolSize = 10;
options.MinPoolSize = 0;
return options;
}
}
/// <summary>

View File

@@ -13,19 +13,19 @@ public sealed class OfflineKitAuditRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly OfflineKitAuditRepository _repository;
private readonly AuthorityDataSource _dataSource;
public OfflineKitAuditRepositoryTests(AuthorityPostgresFixture fixture)
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new OfflineKitAuditRepository(dataSource, NullLogger<OfflineKitAuditRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new OfflineKitAuditRepository(_dataSource, NullLogger<OfflineKitAuditRepository>.Instance);
}
public ValueTask InitializeAsync() => new(_fixture.TruncateAllTablesAsync());
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -12,6 +12,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class PermissionRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly PermissionRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -19,10 +20,9 @@ public sealed class PermissionRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new PermissionRepository(dataSource, NullLogger<PermissionRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new PermissionRepository(_dataSource, NullLogger<PermissionRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -31,7 +31,7 @@ public sealed class PermissionRepositoryTests : IAsyncLifetime
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -13,6 +13,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class RefreshTokenRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly RefreshTokenRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -20,10 +21,9 @@ public sealed class RefreshTokenRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new RefreshTokenRepository(dataSource, NullLogger<RefreshTokenRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new RefreshTokenRepository(_dataSource, NullLogger<RefreshTokenRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -32,7 +32,7 @@ public sealed class RefreshTokenRepositoryTests : IAsyncLifetime
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -28,6 +28,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class RoleBasedAccessTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private AuthorityDataSource? _dataSource;
private RoleRepository _roleRepository = null!;
private PermissionRepository _permissionRepository = null!;
private UserRepository _userRepository = null!;
@@ -42,18 +43,23 @@ public sealed class RoleBasedAccessTests : IAsyncLifetime
{
await _fixture.TruncateAllTablesAsync();
var options = _fixture.Fixture.CreateOptions();
options.SchemaName = _fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
var options = _fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_roleRepository = new RoleRepository(dataSource, NullLogger<RoleRepository>.Instance);
_permissionRepository = new PermissionRepository(dataSource, NullLogger<PermissionRepository>.Instance);
_userRepository = new UserRepository(dataSource, NullLogger<UserRepository>.Instance);
_roleRepository = new RoleRepository(_dataSource, NullLogger<RoleRepository>.Instance);
_permissionRepository = new PermissionRepository(_dataSource, NullLogger<PermissionRepository>.Instance);
_userRepository = new UserRepository(_dataSource, NullLogger<UserRepository>.Instance);
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public async ValueTask DisposeAsync()
{
if (_dataSource is not null)
{
await _dataSource.DisposeAsync();
}
}
#region User-Role Assignment Tests

View File

@@ -12,6 +12,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class RoleRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly RoleRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -19,10 +20,9 @@ public sealed class RoleRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new RoleRepository(dataSource, NullLogger<RoleRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new RoleRepository(_dataSource, NullLogger<RoleRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -31,7 +31,7 @@ public sealed class RoleRepositoryTests : IAsyncLifetime
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -12,6 +12,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class SessionRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly SessionRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -19,10 +20,9 @@ public sealed class SessionRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new SessionRepository(dataSource, NullLogger<SessionRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new SessionRepository(_dataSource, NullLogger<SessionRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -31,7 +31,7 @@ public sealed class SessionRepositoryTests : IAsyncLifetime
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]

View File

@@ -0,0 +1,10 @@
# Authority Persistence Tests Task Board
This board mirrors active sprint tasks for this module.
Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.md`.
| Task ID | Status | Notes |
| --- | --- | --- |
| AUDIT-0089-M | DONE | Maintainability audit for StellaOps.Authority.Persistence.Tests. |
| AUDIT-0089-T | DONE | Test coverage audit for StellaOps.Authority.Persistence.Tests. |
| AUDIT-0089-A | TODO | Pending approval for changes. |

View File

@@ -13,6 +13,7 @@ namespace StellaOps.Authority.Persistence.Tests;
public sealed class TokenRepositoryTests : IAsyncLifetime
{
private readonly AuthorityPostgresFixture _fixture;
private readonly AuthorityDataSource _dataSource;
private readonly TokenRepository _repository;
private readonly string _tenantId = Guid.NewGuid().ToString();
@@ -20,10 +21,9 @@ public sealed class TokenRepositoryTests : IAsyncLifetime
{
_fixture = fixture;
var options = fixture.Fixture.CreateOptions();
options.SchemaName = fixture.SchemaName;
var dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new TokenRepository(dataSource, NullLogger<TokenRepository>.Instance);
var options = fixture.CreateOptions();
_dataSource = new AuthorityDataSource(Options.Create(options), NullLogger<AuthorityDataSource>.Instance);
_repository = new TokenRepository(_dataSource, NullLogger<TokenRepository>.Instance);
}
public async ValueTask InitializeAsync()
@@ -31,7 +31,7 @@ public sealed class TokenRepositoryTests : IAsyncLifetime
await _fixture.TruncateAllTablesAsync();
await SeedTenantAsync();
}
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
public ValueTask DisposeAsync() => _dataSource.DisposeAsync();
[Trait("Category", TestCategories.Unit)]
[Fact]