feat: Add tests for RichGraphPublisher and RichGraphWriter
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled

- Implement unit tests for RichGraphPublisher to verify graph publishing to CAS.
- Implement unit tests for RichGraphWriter to ensure correct writing of canonical graphs and metadata.

feat: Implement AOC Guard validation logic

- Add AOC Guard validation logic to enforce document structure and field constraints.
- Introduce violation codes for various validation errors.
- Implement tests for AOC Guard to validate expected behavior.

feat: Create Console Status API client and service

- Implement ConsoleStatusClient for fetching console status and streaming run events.
- Create ConsoleStatusService to manage console status polling and event subscriptions.
- Add tests for ConsoleStatusClient to verify API interactions.

feat: Develop Console Status component

- Create ConsoleStatusComponent for displaying console status and run events.
- Implement UI for showing status metrics and handling user interactions.
- Add styles for console status display.

test: Add tests for Console Status store

- Implement tests for ConsoleStatusStore to verify event handling and state management.
This commit is contained in:
StellaOps Bot
2025-12-01 07:34:50 +02:00
parent 7df0677e34
commit c11d87d252
108 changed files with 4773 additions and 351 deletions

View File

@@ -1,3 +1,4 @@
using System.Linq;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -136,6 +137,70 @@ public sealed class RefreshTokenRepositoryTests : IAsyncLifetime
tokens.Should().AllSatisfy(t => t.RevokedAt.Should().NotBeNull());
}
[Fact]
public async Task GetByUserId_IsDeterministic_WhenIssuedAtTies()
{
// Arrange: fixed IDs with same IssuedAt to assert stable ordering
var userId = Guid.NewGuid();
var issuedAt = new DateTimeOffset(2025, 11, 30, 12, 0, 0, TimeSpan.Zero);
var tokens = new[]
{
new RefreshTokenEntity
{
Id = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "rhash1-" + Guid.NewGuid().ToString("N"),
AccessTokenId = Guid.Parse("10000000-0000-0000-0000-000000000000"),
ClientId = "web-app",
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddDays(30)
},
new RefreshTokenEntity
{
Id = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "rhash2-" + Guid.NewGuid().ToString("N"),
AccessTokenId = Guid.Parse("20000000-0000-0000-0000-000000000000"),
ClientId = "web-app",
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddDays(30)
},
new RefreshTokenEntity
{
Id = Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "rhash3-" + Guid.NewGuid().ToString("N"),
AccessTokenId = Guid.Parse("30000000-0000-0000-0000-000000000000"),
ClientId = "web-app",
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddDays(30)
}
};
foreach (var token in tokens.Reverse())
{
await _repository.CreateAsync(_tenantId, token);
}
// Act
var first = await _repository.GetByUserIdAsync(_tenantId, userId);
var second = await _repository.GetByUserIdAsync(_tenantId, userId);
var expectedOrder = tokens
.OrderByDescending(t => t.IssuedAt)
.ThenBy(t => t.Id)
.Select(t => t.Id)
.ToArray();
// Assert
first.Select(t => t.Id).Should().ContainInOrder(expectedOrder);
second.Should().BeEquivalentTo(first, o => o.WithStrictOrdering());
}
private RefreshTokenEntity CreateRefreshToken(Guid userId) => new()
{
Id = Guid.NewGuid(),

View File

@@ -1,3 +1,4 @@
using System.Linq;
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
@@ -121,6 +122,71 @@ public sealed class TokenRepositoryTests : IAsyncLifetime
tokens.Should().AllSatisfy(t => t.RevokedAt.Should().NotBeNull());
}
[Fact]
public async Task GetByUserId_IsDeterministic_WhenIssuedAtTies()
{
// Arrange: same IssuedAt, fixed IDs to validate ordering
var userId = Guid.NewGuid();
var issuedAt = new DateTimeOffset(2025, 11, 30, 12, 0, 0, TimeSpan.Zero);
var tokens = new[]
{
new TokenEntity
{
Id = Guid.Parse("11111111-1111-1111-1111-111111111111"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "hash1-" + Guid.NewGuid().ToString("N"),
TokenType = TokenType.Access,
Scopes = ["a"],
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddHours(1)
},
new TokenEntity
{
Id = Guid.Parse("22222222-2222-2222-2222-222222222222"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "hash2-" + Guid.NewGuid().ToString("N"),
TokenType = TokenType.Access,
Scopes = ["a"],
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddHours(1)
},
new TokenEntity
{
Id = Guid.Parse("33333333-3333-3333-3333-333333333333"),
TenantId = _tenantId,
UserId = userId,
TokenHash = "hash3-" + Guid.NewGuid().ToString("N"),
TokenType = TokenType.Access,
Scopes = ["a"],
IssuedAt = issuedAt,
ExpiresAt = issuedAt.AddHours(1)
}
};
// Insert out of order to ensure repository enforces deterministic ordering
foreach (var token in tokens.Reverse())
{
await _repository.CreateAsync(_tenantId, token);
}
// Act
var first = await _repository.GetByUserIdAsync(_tenantId, userId);
var second = await _repository.GetByUserIdAsync(_tenantId, userId);
var expectedOrder = tokens
.OrderByDescending(t => t.IssuedAt)
.ThenBy(t => t.Id)
.Select(t => t.Id)
.ToArray();
// Assert
first.Select(t => t.Id).Should().ContainInOrder(expectedOrder);
second.Should().BeEquivalentTo(first, o => o.WithStrictOrdering());
}
private TokenEntity CreateToken(Guid userId) => new()
{
Id = Guid.NewGuid(),