feat(ui): server-side streaming CSV export of Audit Log (#23 M7)
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using ScadaLink.Commons.Types.Audit;
|
||||
using ScadaLink.Commons.Types.Enums;
|
||||
using AuditLogPage = ScadaLink.CentralUI.Components.Pages.Audit.AuditLogPage;
|
||||
|
||||
namespace ScadaLink.CentralUI.Tests.Pages;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="AuditLogPage.BuildExportUrl"/> (#23 M7-T14 /
|
||||
/// Bundle F). Builds the <c>?...</c> querystring the Export-CSV link points
|
||||
/// at; the same conversion is round-tripped on the server side by
|
||||
/// <see cref="ScadaLink.CentralUI.Audit.AuditExportEndpoints.ParseFilter"/>.
|
||||
/// These tests pin the no-filter base path + the round-trip back through
|
||||
/// <see cref="QueryHelpers.ParseQuery"/> so the link contract stays stable.
|
||||
/// </summary>
|
||||
public class AuditLogPageExportUrlTests
|
||||
{
|
||||
[Fact]
|
||||
public void BuildExportUrl_NullFilter_ReturnsBasePath()
|
||||
{
|
||||
var url = AuditLogPage.BuildExportUrl(null);
|
||||
Assert.Equal("/api/centralui/audit/export", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildExportUrl_EmptyFilter_ReturnsBasePath()
|
||||
{
|
||||
// Defensive: a filter where every column is null should still render
|
||||
// as the bare path — no trailing "?" so the URL stays clean.
|
||||
var url = AuditLogPage.BuildExportUrl(new AuditLogQueryFilter());
|
||||
Assert.Equal("/api/centralui/audit/export", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildExportUrl_AllFiltersSet_RoundTrips()
|
||||
{
|
||||
var corr = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
|
||||
var filter = new AuditLogQueryFilter(
|
||||
Channel: AuditChannel.ApiOutbound,
|
||||
Kind: AuditKind.ApiCall,
|
||||
Status: AuditStatus.Failed,
|
||||
SourceSiteId: "plant-a",
|
||||
Target: "PaymentApi",
|
||||
Actor: "apikey-1",
|
||||
CorrelationId: corr,
|
||||
FromUtc: new DateTime(2026, 5, 20, 0, 0, 0, DateTimeKind.Utc),
|
||||
ToUtc: new DateTime(2026, 5, 20, 23, 59, 59, DateTimeKind.Utc));
|
||||
|
||||
var url = AuditLogPage.BuildExportUrl(filter);
|
||||
|
||||
Assert.StartsWith("/api/centralui/audit/export?", url);
|
||||
var query = QueryHelpers.ParseQuery(new Uri("http://x" + url).Query);
|
||||
|
||||
Assert.Equal("ApiOutbound", query["channel"]);
|
||||
Assert.Equal("ApiCall", query["kind"]);
|
||||
Assert.Equal("Failed", query["status"]);
|
||||
Assert.Equal("plant-a", query["site"]);
|
||||
Assert.Equal("PaymentApi", query["target"]);
|
||||
Assert.Equal("apikey-1", query["actor"]);
|
||||
Assert.Equal(corr.ToString(), query["correlationId"]);
|
||||
Assert.Equal("2026-05-20T00:00:00.0000000Z", query["from"]);
|
||||
Assert.Equal("2026-05-20T23:59:59.0000000Z", query["to"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildExportUrl_OnlyChannelSet_OmitsOtherParams()
|
||||
{
|
||||
var filter = new AuditLogQueryFilter(Channel: AuditChannel.Notification);
|
||||
|
||||
var url = AuditLogPage.BuildExportUrl(filter);
|
||||
|
||||
Assert.StartsWith("/api/centralui/audit/export?", url);
|
||||
var query = QueryHelpers.ParseQuery(new Uri("http://x" + url).Query);
|
||||
Assert.Single(query);
|
||||
Assert.Equal("Notification", query["channel"]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user