Increase AI host test coverage

This commit is contained in:
Sipke Schoorstra 2026-06-27 04:04:39 +02:00
parent 869aecfd7e
commit 5336f9ea06
No known key found for this signature in database
GPG key ID: 5C10502B28A4268F
2 changed files with 79 additions and 0 deletions

View file

@ -253,6 +253,25 @@ public class AIToolRegistryTests
Assert.True(enablement.IsEnabled(definition));
}
[Fact(DisplayName = "Tool enablement disables administrative tools by name")]
public void ToolEnablementDisablesAdministrativeToolsByName()
{
var enablement = new AIToolEnablementService();
var definition = new AIToolDefinition
{
Name = "admin",
DisplayName = "Admin",
Mutability = AIToolMutability.Administrative
};
enablement.EnableAdministrative("ADMIN");
Assert.True(enablement.IsEnabled(definition));
enablement.Disable("admin");
Assert.False(enablement.IsEnabled(definition));
}
[Fact(DisplayName = "Tool registry filters agent-scoped tools by agent")]
public async Task ToolRegistryFiltersAgentScopedToolsByAgent()
{

View file

@ -59,6 +59,44 @@ public class AIContextResolverTests
Assert.Equal("visible", context.Data["displayName"]!.GetValue<string>());
}
[Fact(DisplayName = "Context resolver redacts nested context payloads")]
public async Task ContextResolverRedactsNestedContextPayloads()
{
using var provider = CreateProvider(services => services.AddSingleton<IAIContextProvider, NestedSensitiveContextProvider>());
var resolver = provider.GetRequiredService<AIContextResolver>();
var result = await resolver.ResolveAsync(new AIChatRequest
{
UserId = "user-1",
Attachments = [new AIContextAttachment { Kind = "NestedSensitive" }]
});
var context = Assert.Single(result);
var profile = Assert.IsType<JsonObject>(context.Data["profile"]);
var history = Assert.IsType<JsonArray>(context.Data["history"]);
Assert.Equal("[redacted]", profile["password"]!.GetValue<string>());
Assert.Equal("visible", profile["displayName"]!.GetValue<string>());
Assert.Equal("[redacted]", history[0]!.GetValue<string>());
Assert.Equal(42, history[1]!.GetValue<int>());
Assert.True(history[2]!.GetValue<bool>());
}
[Fact(DisplayName = "Context resolver ignores attachments without providers")]
public async Task ContextResolverIgnoresAttachmentsWithoutProviders()
{
using var provider = CreateProvider(_ => { });
var resolver = provider.GetRequiredService<AIContextResolver>();
var result = await resolver.ResolveAsync(new AIChatRequest
{
UserId = "user-1",
Attachments = [new AIContextAttachment { Kind = "Unknown" }]
});
Assert.Empty(result);
}
[Fact(DisplayName = "Context resolver uses the last provider for duplicate provider kinds")]
public async Task ContextResolverUsesTheLastProviderForDuplicateProviderKinds()
{
@ -148,6 +186,28 @@ public class AIContextResolverTests
}
}
private class NestedSensitiveContextProvider : IAIContextProvider
{
public string Kind => "NestedSensitive";
public ValueTask<AIResolvedContext> ResolveAsync(AIContextResolutionRequest request, CancellationToken cancellationToken = default)
{
return ValueTask.FromResult(new AIResolvedContext
{
Kind = Kind,
Data = new JsonObject
{
["profile"] = new JsonObject
{
["password"] = "secret-value",
["displayName"] = "visible"
},
["history"] = new JsonArray("Bearer abcdefgh", 42, true)
}
});
}
}
private class DuplicateContextProvider(string summary, string kind = "Duplicate") : IAIContextProvider
{
public string Kind => kind;