Skip to content

Commit 8ef2c7d

Browse files
committed
test: cover priced cache probe branch
1 parent d83c67a commit 8ef2c7d

1 file changed

Lines changed: 43 additions & 4 deletions

File tree

tests/AiRouter.AspNetCore.Tests/CacheProbeBranchCoverageTests.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ public async Task Probe_reports_zero_cache_ratio_when_usage_is_known_and_uncache
5050
Assert.Contains("cache_ratio_zero", result.Diagnostics);
5151
}
5252

53+
[Fact]
54+
public async Task Probe_resolves_provider_pricing_when_target_is_known()
55+
{
56+
var providers = await PricedProvidersAsync();
57+
var router = new RecordingRouter(Result("priced", new ProviderUsage(10, 2, 12, 5, null, null)));
58+
var request = new CacheProbeRequest("coding", JsonDocument.Parse("{}").RootElement.Clone(), 1);
59+
60+
var result = await CacheProbe.RunAsync(router, providers, request);
61+
62+
Assert.NotNull(result.Attempts[0].Cost);
63+
Assert.Equal("estimated", result.Attempts[0].CostSource);
64+
}
65+
5366
[Fact]
5467
public async Task Probe_null_arguments_are_rejected()
5568
{
@@ -96,6 +109,34 @@ private static async Task<IProviderManager> EmptyProvidersAsync()
96109
return manager;
97110
}
98111

112+
private static async Task<IProviderManager> PricedProvidersAsync()
113+
{
114+
var factory = new FakeFactory();
115+
var manager = new ProviderManager(new InMemoryProviderStore(), [factory]);
116+
await manager.InitializeAsync();
117+
await manager.AddAsync(new ProviderDefinition(
118+
"priced", "priced", "fake", "https://example.test", "key",
119+
Models: ["model"], DefaultModel: "model",
120+
InputPricePerMillion: 1m, CachedInputPricePerMillion: 0.1m, OutputPricePerMillion: 2m));
121+
return manager;
122+
}
123+
124+
private sealed class FakeFactory : IAiProviderFactory
125+
{
126+
public bool CanCreate(ProviderDefinition definition) => definition.Type == "fake";
127+
public IAiProvider Create(ProviderDefinition definition) => new FakeProvider(definition);
128+
}
129+
130+
private sealed class FakeProvider(ProviderDefinition definition) : IAiProvider
131+
{
132+
public ProviderDefinition Definition { get; } = definition;
133+
public ProviderHealth Health { get; } = new();
134+
public Task<ProviderResponse> SendChatAsync(string model, JsonElement requestBody, bool stream, CancellationToken ct = default) => Task.FromResult(new ProviderResponse { Success = true, StatusCode = 200 });
135+
public Task<ProviderResponse> SendResponsesAsync(string model, JsonElement requestBody, bool stream, CancellationToken ct = default) => SendChatAsync(model, requestBody, stream, ct);
136+
public Task<IReadOnlyList<string>> ListModelsAsync(CancellationToken ct = default) => Task.FromResult<IReadOnlyList<string>>(Definition.Models ?? []);
137+
public Task<ProviderConnectivityResult> CheckHealthAsync(CancellationToken ct = default) => Task.FromResult(new ProviderConnectivityResult(true));
138+
}
139+
99140
private sealed class RecordingRouter(RouterResult result) : IAiRouter
100141
{
101142
public int ChatCalls { get; private set; }
@@ -107,16 +148,14 @@ public Task<RouterResult> ChatAsync(string model, JsonElement body, bool stream
107148
return Task.FromResult(result);
108149
}
109150

110-
public Task<RouterResult> ChatAsync(string model, JsonElement body, RouterRequestContext? requestContext, bool stream = false, CancellationToken ct = default) =>
111-
ChatAsync(model, body, stream, ct);
151+
public Task<RouterResult> ChatAsync(string model, JsonElement body, RouterRequestContext? requestContext, bool stream = false, CancellationToken ct = default) => ChatAsync(model, body, stream, ct);
112152

113153
public Task<RouterResult> ResponsesAsync(string model, JsonElement body, bool stream = false, CancellationToken ct = default)
114154
{
115155
ResponsesCalls++;
116156
return Task.FromResult(result);
117157
}
118158

119-
public Task<RouterResult> ResponsesAsync(string model, JsonElement body, RouterRequestContext? requestContext, bool stream = false, CancellationToken ct = default) =>
120-
ResponsesAsync(model, body, stream, ct);
159+
public Task<RouterResult> ResponsesAsync(string model, JsonElement body, RouterRequestContext? requestContext, bool stream = false, CancellationToken ct = default) => ResponsesAsync(model, body, stream, ct);
121160
}
122161
}

0 commit comments

Comments
 (0)