diff options
Diffstat (limited to 'tests/Agent.Core.Tests/SharedFakeOllamaServer.cs')
| -rw-r--r-- | tests/Agent.Core.Tests/SharedFakeOllamaServer.cs | 55 |
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(); + } +} |
