summaryrefslogtreecommitdiff
path: root/tests/Agent.Core.Tests/SharedFakeOllamaServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Agent.Core.Tests/SharedFakeOllamaServer.cs')
-rw-r--r--tests/Agent.Core.Tests/SharedFakeOllamaServer.cs55
1 files changed, 55 insertions, 0 deletions
diff --git a/tests/Agent.Core.Tests/SharedFakeOllamaServer.cs b/tests/Agent.Core.Tests/SharedFakeOllamaServer.cs
new file mode 100644
index 0000000..3264c77
--- /dev/null
+++ b/tests/Agent.Core.Tests/SharedFakeOllamaServer.cs
@@ -0,0 +1,55 @@
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Agent.Core.Tests;
+
+internal sealed class SharedFakeOllamaServer : IAsyncDisposable
+{
+ private readonly TcpListener _listener = new(IPAddress.Loopback, 0);
+ private readonly CancellationTokenSource _stop = new();
+ private readonly Task _loop;
+
+ public SharedFakeOllamaServer()
+ {
+ _listener.Start();
+ Endpoint = new Uri($"http://127.0.0.1:{((IPEndPoint)_listener.LocalEndpoint).Port}/");
+ _loop = RunAsync();
+ }
+
+ public Uri Endpoint { get; }
+
+ private async Task RunAsync()
+ {
+ try
+ {
+ while (!_stop.IsCancellationRequested)
+ {
+ using TcpClient client = await _listener.AcceptTcpClientAsync(_stop.Token).ConfigureAwait(false);
+ NetworkStream stream = client.GetStream();
+ using var reader = new StreamReader(stream, Encoding.ASCII, false, 1024, true);
+ int contentLength = 0;
+ while (await reader.ReadLineAsync(_stop.Token).ConfigureAwait(false) is { } line && line.Length > 0)
+ if (line.StartsWith("Content-Length:", StringComparison.OrdinalIgnoreCase)) contentLength = int.Parse(line[15..].Trim(), System.Globalization.CultureInfo.InvariantCulture);
+ if (contentLength > 0)
+ {
+ char[] body = new char[contentLength];
+ await reader.ReadBlockAsync(body.AsMemory(), _stop.Token).ConfigureAwait(false);
+ }
+ byte[] payload = Encoding.UTF8.GetBytes("""{"message":{"role":"assistant","content":"done"},"prompt_eval_count":3,"eval_count":2}""");
+ byte[] header = Encoding.ASCII.GetBytes($"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {payload.Length}\r\nConnection: close\r\n\r\n");
+ await stream.WriteAsync(header, _stop.Token).ConfigureAwait(false);
+ await stream.WriteAsync(payload, _stop.Token).ConfigureAwait(false);
+ }
+ }
+ catch (OperationCanceledException) when (_stop.IsCancellationRequested) { }
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ await _stop.CancelAsync().ConfigureAwait(false);
+ _listener.Stop();
+ await _loop.ConfigureAwait(false);
+ _stop.Dispose();
+ }
+}