feat(audit): multi-value filters across ManagementService, CLI and Central UI
This commit is contained in:
@@ -58,10 +58,10 @@ public class AuditQueryCommandTests
|
||||
{
|
||||
Since = "1h",
|
||||
Until = "2026-05-20T12:00:00Z",
|
||||
Channel = "ApiOutbound",
|
||||
Kind = "ApiCallCached",
|
||||
Status = "Delivered",
|
||||
Site = "site-1",
|
||||
Channel = new[] { "ApiOutbound" },
|
||||
Kind = new[] { "ApiCallCached" },
|
||||
Status = new[] { "Delivered" },
|
||||
Site = new[] { "site-1" },
|
||||
Target = "weather-api",
|
||||
Actor = "multi-role",
|
||||
CorrelationId = "abc-123",
|
||||
@@ -96,6 +96,43 @@ public class AuditQueryCommandTests
|
||||
Assert.Equal("Failed", parsed["status"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildQueryString_MultiValueChannel_EmitsOneKeyPerValue()
|
||||
{
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var args = new AuditQueryArgs
|
||||
{
|
||||
Channel = new[] { "ApiOutbound", "DbOutbound" },
|
||||
Status = new[] { "Failed", "Parked" },
|
||||
Site = new[] { "site-1", "site-2" },
|
||||
};
|
||||
|
||||
var qs = AuditQueryHelpers.BuildQueryString(args, now, null, null);
|
||||
var parsed = HttpUtility.ParseQueryString(qs.TrimStart('?'));
|
||||
|
||||
Assert.Equal(new[] { "ApiOutbound", "DbOutbound" }, parsed.GetValues("channel"));
|
||||
Assert.Equal(new[] { "Failed", "Parked" }, parsed.GetValues("status"));
|
||||
Assert.Equal(new[] { "site-1", "site-2" }, parsed.GetValues("sourceSiteId"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildQueryString_ErrorsOnly_OverridesExplicitStatusValues()
|
||||
{
|
||||
// --errors-only stays a single-status override: it pins status=Failed and
|
||||
// supersedes any explicit (multi-value) --status selection.
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var args = new AuditQueryArgs
|
||||
{
|
||||
ErrorsOnly = true,
|
||||
Status = new[] { "Delivered", "Parked" },
|
||||
};
|
||||
|
||||
var qs = AuditQueryHelpers.BuildQueryString(args, now, null, null);
|
||||
var parsed = HttpUtility.ParseQueryString(qs.TrimStart('?'));
|
||||
|
||||
Assert.Equal(new[] { "Failed" }, parsed.GetValues("status"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildQueryString_Cursor_AppendsAfterParameters()
|
||||
{
|
||||
@@ -254,6 +291,38 @@ public class AuditQueryCommandTests
|
||||
Assert.Empty(parse.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Query_MultipleChannelValues_SingleToken_AreAccepted()
|
||||
{
|
||||
// AllowMultipleArgumentsPerToken: --channel A B parses as two values.
|
||||
var root = AuditCommandTestHarness.BuildRoot();
|
||||
var parse = root.Parse(new[] { "audit", "query", "--channel", "ApiOutbound", "DbOutbound" });
|
||||
Assert.Empty(parse.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Query_MultipleChannelValues_RepeatedFlag_AreAccepted()
|
||||
{
|
||||
// --channel A --channel B parses as two values.
|
||||
var root = AuditCommandTestHarness.BuildRoot();
|
||||
var parse = root.Parse(new[]
|
||||
{
|
||||
"audit", "query", "--channel", "ApiOutbound", "--channel", "Notification",
|
||||
});
|
||||
Assert.Empty(parse.Errors);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Query_MultiValueChannel_WithOneInvalidName_FailsFast()
|
||||
{
|
||||
// AcceptOnlyFromAmong validates EACH value of the multi-value option.
|
||||
var root = AuditCommandTestHarness.BuildRoot();
|
||||
var (exit, _, err) = AuditCommandTestHarness.Invoke(
|
||||
root, "audit", "query", "--channel", "ApiOutbound", "OutboundApi");
|
||||
Assert.NotEqual(0, exit);
|
||||
Assert.NotEqual("", err);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Query_ChannelWithInvalidName_FailsFast_NonZeroExit()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user