|
| 1 | +using LantanaGroup.Link.Sdk.ApiClient; |
| 2 | +using LantanaGroup.Link.Sdk.Clients; |
| 3 | +using LantanaGroup.Link.Shared.Application.Models; |
| 4 | +using LantanaGroup.Link.Shared.Application.Models.Integration.Normalization; |
| 5 | +using LantanaGroup.Link.Shared.Application.Models.Kafka; |
| 6 | +using LantanaGroup.Link.Shared.Application.Models.Tenant; |
| 7 | +using LantanaGroup.Link.Tenant.Business.Managers; |
| 8 | +using Microsoft.AspNetCore.Http; |
| 9 | +using Microsoft.Extensions.DependencyInjection; |
| 10 | +using Moq; |
| 11 | +using Task = System.Threading.Tasks.Task; |
| 12 | + |
| 13 | +namespace IntegrationTests.Tenant; |
| 14 | + |
| 15 | +[Collection("IntegrationTests")] |
| 16 | +[Trait("Category", "IntegrationTests")] |
| 17 | +public class VendorAuditTests : IDisposable |
| 18 | +{ |
| 19 | + private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(5); |
| 20 | + |
| 21 | + private readonly IServiceScope _scope; |
| 22 | + private readonly IVendorManager _vendorManager; |
| 23 | + private readonly TenantIntegrationTestFixture.RecordingAuditProducer _auditProducer; |
| 24 | + |
| 25 | + public VendorAuditTests(TenantIntegrationTestFixture fixture) |
| 26 | + { |
| 27 | + _scope = fixture.ServiceProvider.CreateScope(); |
| 28 | + var serviceProvider = _scope.ServiceProvider; |
| 29 | + |
| 30 | + _vendorManager = serviceProvider.GetRequiredService<IVendorManager>(); |
| 31 | + _auditProducer = serviceProvider.GetRequiredService<TenantIntegrationTestFixture.RecordingAuditProducer>(); |
| 32 | + _auditProducer.Clear(); |
| 33 | + |
| 34 | + // Deleting a vendor checks Normalization for references to each of its versions. |
| 35 | + var normalizationServiceClient = serviceProvider.GetRequiredService<Mock<INormalizationServiceClient>>(); |
| 36 | + normalizationServiceClient.Reset(); |
| 37 | + normalizationServiceClient |
| 38 | + .Setup(client => client.GetVendorVersionOperationPresetsAsync( |
| 39 | + It.IsAny<Guid>(), null, It.IsAny<CancellationToken>())) |
| 40 | + .ReturnsAsync(new LinkApiResponse<List<NormalizationVendorVersionOperationPresetApiModel>> |
| 41 | + { |
| 42 | + StatusCode = StatusCodes.Status200OK, |
| 43 | + Body = [] |
| 44 | + }); |
| 45 | + } |
| 46 | + |
| 47 | + public void Dispose() => _scope.Dispose(); |
| 48 | + |
| 49 | + [Fact] |
| 50 | + public async Task CreateVendor_EmitsACreateAuditEvent() |
| 51 | + { |
| 52 | + var created = await _vendorManager.CreateVendorAsync(new VendorModel { Name = $"Vendor-{Guid.NewGuid():N}" }); |
| 53 | + |
| 54 | + var events = await _auditProducer.WaitForAsync(1, Timeout); |
| 55 | + |
| 56 | + var audit = Assert.Single(events); |
| 57 | + Assert.Equal(AuditEventType.Create, audit.Value.Action); |
| 58 | + Assert.Equal("Vendor", audit.Value.Resource); |
| 59 | + Assert.Equal(created.Id.ToString(), audit.Key); |
| 60 | + } |
| 61 | + |
| 62 | + [Fact] |
| 63 | + public async Task UpdateVendor_RecordsTheSigningKeySecretIdChange() |
| 64 | + { |
| 65 | + var created = await _vendorManager.CreateVendorAsync(new VendorModel { Name = $"Vendor-{Guid.NewGuid():N}" }); |
| 66 | + _auditProducer.Clear(); |
| 67 | + |
| 68 | + await _vendorManager.UpdateVendorAsync(created.Id!.Value, new VendorModel |
| 69 | + { |
| 70 | + Name = created.Name, |
| 71 | + Authentication = new VendorAuthenticationSettings { SigningKeySecretId = "epic-signing-key" } |
| 72 | + }); |
| 73 | + |
| 74 | + var events = await _auditProducer.WaitForAsync(1, Timeout); |
| 75 | + |
| 76 | + var audit = Assert.Single(events); |
| 77 | + Assert.Equal(AuditEventType.Update, audit.Value.Action); |
| 78 | + var change = Assert.Single(audit.Value.PropertyChanges!, |
| 79 | + c => c.PropertyName == nameof(VendorAuthenticationSettings.SigningKeySecretId)); |
| 80 | + Assert.Null(change.InitialPropertyValue); |
| 81 | + Assert.Equal("epic-signing-key", change.NewPropertyValue); |
| 82 | + } |
| 83 | + |
| 84 | + [Fact] |
| 85 | + public async Task UpdateVendor_RecordsAClearedSigningKeySecretId() |
| 86 | + { |
| 87 | + var created = await _vendorManager.CreateVendorAsync(new VendorModel |
| 88 | + { |
| 89 | + Name = $"Vendor-{Guid.NewGuid():N}", |
| 90 | + Authentication = new VendorAuthenticationSettings { SigningKeySecretId = "epic-signing-key" } |
| 91 | + }); |
| 92 | + _auditProducer.Clear(); |
| 93 | + |
| 94 | + await _vendorManager.UpdateVendorAsync(created.Id!.Value, new VendorModel |
| 95 | + { |
| 96 | + Name = created.Name, |
| 97 | + Authentication = new VendorAuthenticationSettings { SigningKeySecretId = null } |
| 98 | + }); |
| 99 | + |
| 100 | + var events = await _auditProducer.WaitForAsync(1, Timeout); |
| 101 | + |
| 102 | + var change = Assert.Single(Assert.Single(events).Value.PropertyChanges!, |
| 103 | + c => c.PropertyName == nameof(VendorAuthenticationSettings.SigningKeySecretId)); |
| 104 | + Assert.Equal("epic-signing-key", change.InitialPropertyValue); |
| 105 | + Assert.Null(change.NewPropertyValue); |
| 106 | + } |
| 107 | + |
| 108 | + [Fact] |
| 109 | + public async Task UpdateVendor_ThatChangesNothing_EmitsNoAuditEvent() |
| 110 | + { |
| 111 | + var created = await _vendorManager.CreateVendorAsync(new VendorModel { Name = $"Vendor-{Guid.NewGuid():N}" }); |
| 112 | + _auditProducer.Clear(); |
| 113 | + |
| 114 | + await _vendorManager.UpdateVendorAsync(created.Id!.Value, new VendorModel { Name = created.Name }); |
| 115 | + |
| 116 | + await Task.Delay(200); |
| 117 | + |
| 118 | + Assert.Empty(_auditProducer.Produced); |
| 119 | + } |
| 120 | + |
| 121 | + [Fact] |
| 122 | + public async Task DeleteVendor_EmitsADeleteAuditEvent() |
| 123 | + { |
| 124 | + var created = await _vendorManager.CreateVendorAsync(new VendorModel { Name = $"Vendor-{Guid.NewGuid():N}" }); |
| 125 | + _auditProducer.Clear(); |
| 126 | + |
| 127 | + await _vendorManager.DeleteVendorAsync(created.Id!.Value); |
| 128 | + |
| 129 | + var events = await _auditProducer.WaitForAsync(1, Timeout); |
| 130 | + |
| 131 | + Assert.Equal(AuditEventType.Delete, Assert.Single(events).Value.Action); |
| 132 | + } |
| 133 | +} |
0 commit comments