using System.Net; using System.Net.Http.Json; using StellaOps.TestKit; namespace StellaOps.Scanner.WebService.Tests; public sealed class RegistryEndpointsTests { [Trait("Category", TestCategories.Unit)] [Fact] public async Task RegistrySearchAndDigestEndpoints_ReturnExpectedResults() { await using var factory = ScannerApplicationFactory.CreateLightweight(); await factory.InitializeAsync(); using var client = factory.CreateClient(); var searchResponse = await client.GetAsync( "/api/v1/registries/images/search?q=nginx", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, searchResponse.StatusCode); var searchPayload = await searchResponse.Content.ReadFromJsonAsync( cancellationToken: TestContext.Current.CancellationToken); Assert.NotNull(searchPayload); Assert.Contains(searchPayload!.Items, item => item.Repository == "library/nginx"); var digestResponse = await client.GetAsync( "/api/v1/registries/images/digests?repository=library/nginx", TestContext.Current.CancellationToken); Assert.Equal(HttpStatusCode.OK, digestResponse.StatusCode); var digestPayload = await digestResponse.Content.ReadFromJsonAsync( cancellationToken: TestContext.Current.CancellationToken); Assert.NotNull(digestPayload); Assert.Equal("library/nginx", digestPayload!.Repository); Assert.NotEmpty(digestPayload.Digests); Assert.All(digestPayload.Digests, item => Assert.StartsWith("sha256:", item.Digest, StringComparison.Ordinal)); } [Trait("Category", TestCategories.Unit)] [Fact] public async Task UnknownRepositoryDigest_IsDeterministicAcrossRequests() { await using var factory = ScannerApplicationFactory.CreateLightweight(); await factory.InitializeAsync(); using var client = factory.CreateClient(); var first = await client.GetFromJsonAsync( "/api/v1/registries/images/digests?repository=example/custom-service", TestContext.Current.CancellationToken); var second = await client.GetFromJsonAsync( "/api/v1/registries/images/digests?repository=example/custom-service", TestContext.Current.CancellationToken); Assert.NotNull(first); Assert.NotNull(second); Assert.Equal(first!.Digests[0].Digest, second!.Digests[0].Digest); } public sealed class RegistrySearchResponse { public RegistryImageDto[] Items { get; set; } = []; public int TotalCount { get; set; } public string? RegistryId { get; set; } } public sealed class RegistryDigestResponse { public string Name { get; set; } = string.Empty; public string Repository { get; set; } = string.Empty; public string[] Tags { get; set; } = []; public RegistryDigestEntry[] Digests { get; set; } = []; } public sealed class RegistryImageDto { public string Name { get; set; } = string.Empty; public string Repository { get; set; } = string.Empty; public string[] Tags { get; set; } = []; public RegistryDigestEntry[] Digests { get; set; } = []; public string LastPushed { get; set; } = string.Empty; } public sealed class RegistryDigestEntry { public string Tag { get; set; } = string.Empty; public string Digest { get; set; } = string.Empty; public string PushedAt { get; set; } = string.Empty; } }