partly or unimplemented features - now implemented

This commit is contained in:
master
2026-02-09 08:53:51 +02:00
parent 1bf6bbf395
commit 4bdc298ec1
674 changed files with 90194 additions and 2271 deletions

View File

@@ -0,0 +1,372 @@
// -----------------------------------------------------------------------------
// BaselineResolverTests.cs
// Sprint: SPRINT_20260208_029_Cli_baseline_selection_logic
// Description: Unit tests for baseline resolution service.
// -----------------------------------------------------------------------------
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Time.Testing;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using StellaOps.Cli.Configuration;
using StellaOps.Cli.Services;
using StellaOps.Cli.Services.Models;
namespace StellaOps.Cli.Tests.Services;
public sealed class BaselineResolverTests
{
private readonly IForensicSnapshotClient _forensicClient;
private readonly StellaOpsCliOptions _options;
private readonly ILogger<BaselineResolver> _logger;
private readonly FakeTimeProvider _timeProvider;
private readonly BaselineResolver _resolver;
public BaselineResolverTests()
{
_forensicClient = Substitute.For<IForensicSnapshotClient>();
_options = new StellaOpsCliOptions { DefaultTenant = "test-tenant" };
_logger = Substitute.For<ILogger<BaselineResolver>>();
_timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow);
_resolver = new BaselineResolver(
_forensicClient,
_options,
_logger,
_timeProvider);
}
[Fact]
public async Task ResolveAsync_ExplicitStrategy_ReturnsProvidedDigest()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp@sha256:abc123",
Strategy = BaselineStrategy.Explicit,
ExplicitDigest = "sha256:cafebabe"
};
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.True(result.Success);
Assert.Equal("sha256:cafebabe", result.Digest);
Assert.Equal(BaselineStrategy.Explicit, result.Strategy);
Assert.Null(result.Error);
}
[Fact]
public async Task ResolveAsync_ExplicitStrategy_WithoutDigest_ReturnsFalse()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp@sha256:abc123",
Strategy = BaselineStrategy.Explicit,
ExplicitDigest = null
};
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.False(result.Success);
Assert.Null(result.Digest);
Assert.Contains("requires a digest", result.Error);
}
[Fact]
public async Task ResolveAsync_LastGreen_ReturnsLatestPassingSnapshot()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.LastGreen
};
var snapshot = new ForensicSnapshotDocument
{
SnapshotId = "snap-001",
CaseId = "case-001",
Tenant = "test-tenant",
Status = ForensicSnapshotStatus.Ready,
CreatedAt = DateTimeOffset.UtcNow.AddDays(-1),
Tags = ["verdict:pass", "artifact:pkg%3Aoci%2Fmyapp"],
Manifest = new ForensicSnapshotManifest
{
ManifestId = "manifest-001",
Digest = "sha256:lastgreen123"
}
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse
{
Snapshots = [snapshot],
Total = 1
});
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.True(result.Success);
Assert.Equal("sha256:lastgreen123", result.Digest);
Assert.Equal(BaselineStrategy.LastGreen, result.Strategy);
}
[Fact]
public async Task ResolveAsync_LastGreen_NoPassingSnapshots_ReturnsFalse()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.LastGreen
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse
{
Snapshots = [],
Total = 0
});
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.False(result.Success);
Assert.Null(result.Digest);
Assert.Contains("No passing snapshot found", result.Error);
Assert.NotNull(result.Suggestion);
}
[Fact]
public async Task ResolveAsync_PreviousRelease_ReturnsOlderRelease()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.PreviousRelease,
CurrentVersion = "v2.0.0"
};
var v2Snapshot = new ForensicSnapshotDocument
{
SnapshotId = "snap-002",
CaseId = "case-001",
Tenant = "test-tenant",
Status = ForensicSnapshotStatus.Ready,
CreatedAt = DateTimeOffset.UtcNow,
Tags = ["release:true", "version:v2.0.0", "artifact:pkg%3Aoci%2Fmyapp"],
Manifest = new ForensicSnapshotManifest
{
ManifestId = "manifest-002",
Digest = "sha256:v2digest"
}
};
var v1Snapshot = new ForensicSnapshotDocument
{
SnapshotId = "snap-001",
CaseId = "case-001",
Tenant = "test-tenant",
Status = ForensicSnapshotStatus.Ready,
CreatedAt = DateTimeOffset.UtcNow.AddDays(-7),
Tags = ["release:true", "version:v1.0.0", "artifact:pkg%3Aoci%2Fmyapp"],
Manifest = new ForensicSnapshotManifest
{
ManifestId = "manifest-001",
Digest = "sha256:v1digest"
}
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse
{
Snapshots = [v2Snapshot, v1Snapshot],
Total = 2
});
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.True(result.Success);
Assert.Equal("sha256:v1digest", result.Digest);
Assert.Equal(BaselineStrategy.PreviousRelease, result.Strategy);
}
[Fact]
public async Task ResolveAsync_PreviousRelease_NoReleases_ReturnsFalse()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.PreviousRelease
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse
{
Snapshots = [],
Total = 0
});
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.False(result.Success);
Assert.Null(result.Digest);
Assert.Contains("No release snapshots found", result.Error);
}
[Fact]
public async Task ResolveAsync_ClientException_ReturnsFalseWithError()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.LastGreen
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.ThrowsAsync(new HttpRequestException("Connection refused"));
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.False(result.Success);
Assert.Null(result.Digest);
Assert.Contains("Connection refused", result.Error);
}
[Fact]
public async Task GetSuggestionsAsync_ReturnsSuggestionsFromMultipleSources()
{
// Arrange
var passingSnapshot = new ForensicSnapshotDocument
{
SnapshotId = "snap-pass-001",
CaseId = "case-001",
Tenant = "test-tenant",
Status = ForensicSnapshotStatus.Ready,
CreatedAt = DateTimeOffset.UtcNow.AddDays(-1),
Tags = ["verdict:pass", "version:v1.0.0", "artifact:pkg%3Aoci%2Fmyapp"],
Manifest = new ForensicSnapshotManifest
{
ManifestId = "manifest-001",
Digest = "sha256:passing123"
}
};
var releaseSnapshot = new ForensicSnapshotDocument
{
SnapshotId = "snap-rel-001",
CaseId = "case-001",
Tenant = "test-tenant",
Status = ForensicSnapshotStatus.Ready,
CreatedAt = DateTimeOffset.UtcNow.AddDays(-2),
Tags = ["release:true", "version:v0.9.0", "artifact:pkg%3Aoci%2Fmyapp"],
Manifest = new ForensicSnapshotManifest
{
ManifestId = "manifest-002",
Digest = "sha256:release123"
}
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(
new ForensicSnapshotListResponse { Snapshots = [passingSnapshot], Total = 1 },
new ForensicSnapshotListResponse { Snapshots = [releaseSnapshot], Total = 1 });
// Act
var suggestions = await _resolver.GetSuggestionsAsync("pkg:oci/myapp");
// Assert
Assert.Equal(2, suggestions.Count);
Assert.Contains(suggestions, s => s.Digest == "sha256:passing123" && s.RecommendedStrategy == BaselineStrategy.LastGreen);
Assert.Contains(suggestions, s => s.Digest == "sha256:release123" && s.RecommendedStrategy == BaselineStrategy.PreviousRelease);
}
[Fact]
public async Task ResolveAsync_UsesDefaultTenant_WhenNotProvided()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.LastGreen,
TenantId = null
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse { Snapshots = [], Total = 0 });
// Act
await _resolver.ResolveAsync(request);
// Assert
await _forensicClient.Received(1).ListSnapshotsAsync(
Arg.Is<ForensicSnapshotListQuery>(q => q.Tenant == "test-tenant"),
Arg.Any<CancellationToken>());
}
[Fact]
public async Task ResolveAsync_UsesTenantFromRequest_WhenProvided()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = BaselineStrategy.LastGreen,
TenantId = "custom-tenant"
};
_forensicClient
.ListSnapshotsAsync(Arg.Any<ForensicSnapshotListQuery>(), Arg.Any<CancellationToken>())
.Returns(new ForensicSnapshotListResponse { Snapshots = [], Total = 0 });
// Act
await _resolver.ResolveAsync(request);
// Assert
await _forensicClient.Received(1).ListSnapshotsAsync(
Arg.Is<ForensicSnapshotListQuery>(q => q.Tenant == "custom-tenant"),
Arg.Any<CancellationToken>());
}
[Fact]
public async Task ResolveAsync_UnknownStrategy_ReturnsFalse()
{
// Arrange
var request = new BaselineResolutionRequest
{
ArtifactId = "pkg:oci/myapp",
Strategy = (BaselineStrategy)99 // Invalid strategy
};
// Act
var result = await _resolver.ResolveAsync(request);
// Assert
Assert.False(result.Success);
Assert.Contains("Unknown baseline strategy", result.Error);
}
}