Repository navigation
Expand file tree
/
Copy pathNativeWebSearchLifecycleIntegrationTests.cs
More file actions
132 lines (127 loc) · 6.95 KB
/
Copy pathNativeWebSearchLifecycleIntegrationTests.cs
File metadata and controls
132 lines (127 loc) · 6.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System.Net;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
using ManagedCode.LlmTestServer.Client;
using ManagedCode.LlmTestServer.Tests.TestSupport;
namespace ManagedCode.LlmTestServer.Tests.OpenAI;
public sealed partial class NativeWebSearchIntegrationTests
{
[Test]
[Arguments(false)]
[Arguments(true)]
public async Task InFlightNativeResponse_CancellationAndResetReleaseGraphReservationAsync(bool reset)
{
using var host = await LlmTestServerTestHost.StartAsync();
using var http = host.GetTestClient();
var control = new LlmTestServerClient(http);
await control.ConfigureAsync(config => config.UseGpt41Mini().UseConversation("native-inflight", graph => graph
.Step("search", step => step.RespondsWithItems(Items()).DelaysBy(800).Complete())));
using var cancellation = new CancellationTokenSource();
var pending = http.PostAsJsonAsync("/openai/v1/responses", Request(), cancellation.Token);
var busy = false;
for (var attempt = 0; attempt < 200; attempt++)
{
if ((await control.GetConversationsAsync()).Any(state => state.IsBusy)) { busy = true; break; }
if (pending.IsCompleted) { break; }
await Task.Delay(2);
}
await Assert.That(busy).IsTrue();
if (reset)
{
await control.ResetAsync();
using var superseded = await pending;
await Assert.That(superseded.StatusCode).IsEqualTo(HttpStatusCode.Conflict);
}
else
{
cancellation.Cancel();
var cancelled = false;
try { using var response = await pending; }
catch (OperationCanceledException) when (cancellation.IsCancellationRequested) { cancelled = true; }
await Assert.That(cancelled).IsTrue();
}
await Assert.That((await control.GetConversationsAsync()).Count).IsEqualTo(0);
await AssertWireAsync(await CompleteAsync(http));
await Assert.That((await control.GetConversationsAsync()).Single().ExecutedSteps).IsEqualTo(1);
}
[Test]
public async Task GraphReplay_PreservesOrderedNativeItemsAndDoesNotAdvanceTwiceAsync()
{
using var host = await LlmTestServerTestHost.StartAsync();
using var http = host.GetTestClient();
var control = new LlmTestServerClient(http);
await control.ConfigureAsync(config => config.UseGpt41Mini().UseDeterminism("native-replay", new DateTimeOffset(2026, 1, 2, 3, 4, 5, TimeSpan.Zero))
.UseConversation("native-replay", graph => graph.Step("search", step => step.RespondsWithItems(Items()).Complete())));
var first = await CompleteAsync(http);
var replay = await CompleteAsync(http);
await AssertWireAsync(replay);
await Assert.That(replay.GetProperty("id").GetString()).IsEqualTo(first.GetProperty("id").GetString());
await Assert.That(replay.GetProperty("output").GetRawText()).IsEqualTo(first.GetProperty("output").GetRawText());
await Assert.That((await control.GetConversationsAsync()).Single().ExecutedSteps).IsEqualTo(1);
var evidence = await control.GetRequestsAsync();
await Assert.That(evidence.Requests.Count(trace => trace.IsReplay)).IsEqualTo(1);
await control.ResetAsync();
var reset = await CompleteAsync(http);
await Assert.That(reset.GetProperty("output").GetRawText()).IsEqualTo(first.GetProperty("output").GetRawText());
await Assert.That(reset.GetProperty("created_at").GetInt64()).IsEqualTo(first.GetProperty("created_at").GetInt64());
}
[Test]
[Arguments("credential")]
[Arguments("provider")]
[Arguments("session")]
[Arguments("reset")]
[Arguments("storeFalse")]
public async Task StoredNativeHistory_PreservesExistingOwnershipBoundariesAsync(string boundary)
{
using var host = await LlmTestServerTestHost.StartAsync();
using var http = host.GetTestClient();
var control = new LlmTestServerClient(http);
await control.ConfigureAsync(Configuration(2));
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "first-key");
var initial = Request();
if (boundary == "storeFalse") { initial["store"] = false; }
var first = await CompleteAsync(http, initial);
await AssertWireAsync(first);
var follow = new JsonObject
{
["model"] = "gpt-4.1-mini",
["input"] = "follow",
["previous_response_id"] = first.GetProperty("id").GetString(),
};
if (boundary == "credential") { http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "second-key"); }
if (boundary == "reset") { await control.ResetAsync(); }
var path = boundary == "provider" ? "/azure-openai/openai/v1/responses" : "/openai/v1/responses";
if (boundary == "session")
{
await using var session = await control.CreateSessionAsync(config => config.UseGpt41Mini()
.UseChatScenario("session-native", scenario => scenario.RespondsWithItems(Items())));
using var rejected = await session.HttpClient.PostAsJsonAsync(path, follow);
await Assert.That(rejected.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
await Assert.That((await rejected.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("error").GetProperty("code").GetString()).IsEqualTo("response_not_found");
await AssertWireAsync(await CompleteAsync(session.HttpClient));
}
else
{
using var rejected = await http.PostAsJsonAsync(path, follow);
await Assert.That(rejected.StatusCode).IsEqualTo(HttpStatusCode.NotFound);
await Assert.That((await rejected.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("error").GetProperty("code").GetString()).IsEqualTo("response_not_found");
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "first-key");
await AssertWireAsync(await CompleteAsync(http));
}
}
[Test]
public async Task NativeFixtureSourcesAndCitations_RespectAllowedDomainsWithoutConsumingResponseAsync()
{
using var host = await LlmTestServerTestHost.StartAsync();
using var http = host.GetTestClient();
await new LlmTestServerClient(http).ConfigureAsync(Configuration());
var body = Request();
body["tools"]![0]!["filters"] = new JsonObject { ["allowed_domains"] = new JsonArray("unrelated.example.org") };
using var rejected = await http.PostAsJsonAsync("/openai/v1/responses", body);
await Assert.That(rejected.StatusCode).IsEqualTo(HttpStatusCode.Conflict);
await Assert.That((await rejected.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("error").GetProperty("code").GetString()).IsEqualTo("llm_test_server_fixture_mismatch");
await AssertWireAsync(await CompleteAsync(http));
}
}