diff --git a/cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj b/cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj index 8ac9a0d..10500cf 100644 --- a/cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj +++ b/cadente/Sisk.Cadente.CoreEngine/Sisk.Cadente.CoreEngine.csproj @@ -2,7 +2,7 @@ - net9.0 + net8.0;net9.0 Sisk.Cadente.CoreEngine Debug;Release diff --git a/cadente/Sisk.Cadente/Sisk.Cadente.csproj b/cadente/Sisk.Cadente/Sisk.Cadente.csproj index 82459a8..f8ae95b 100644 --- a/cadente/Sisk.Cadente/Sisk.Cadente.csproj +++ b/cadente/Sisk.Cadente/Sisk.Cadente.csproj @@ -2,8 +2,9 @@ - net9.0 + net8.0;net9.0 Sisk.Cadente + preview Debug;Release diff --git a/tests/Sisk.Core/Tests/LargePayloadTests.cs b/tests/Sisk.Core/Tests/LargePayloadTests.cs new file mode 100644 index 0000000..d04f60f --- /dev/null +++ b/tests/Sisk.Core/Tests/LargePayloadTests.cs @@ -0,0 +1,120 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using System.Net.Http; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Sisk.Cadente; +using Sisk.Cadente.CoreEngine; +using Sisk.Core.Http; +using Sisk.Core.Http.Hosting; +using Sisk.Core.Routing; + +namespace tests; + +[TestClass] +public class LargePayloadTests +{ + private HttpServerHostContext? _server; + private int _port; + + private static int GetRandomPort() + { + using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0); + listener.Start(); + return ((System.Net.IPEndPoint)listener.LocalEndpoint).Port; + } + + private async Task CalculateHashAsync(Stream stream) + { + byte[] hashBytes = await SHA1.HashDataAsync(stream); + return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant(); + } + + [TestInitialize] + public void Setup() + { + _port = GetRandomPort(); + } + + [TestCleanup] + public void Cleanup() + { + _server?.Dispose(); + } + + private async Task RunPayloadTest(long size) + { + var router = new Router(); + router.SetRoute(RouteMethod.Post, "/payload", async (HttpRequest req) => + { + using var stream = req.GetRequestStream(); + string hash = await CalculateHashAsync(stream); + return new HttpResponse(200) { Content = new StringContent(hash) }; + }); + + var engine = new CadenteHttpServerEngine(host => { + // Configure large timeouts for the test + host.TimeoutManager.BodyDrainTimeout = TimeSpan.FromMinutes(10); + host.TimeoutManager.ClientReadTimeout = TimeSpan.FromMinutes(10); + host.TimeoutManager.ClientWriteTimeout = TimeSpan.FromMinutes(10); + }); + + _server = HttpServer.CreateBuilder() + .UseListeningPort((ushort)_port) + .UseRouter(router) + .UseEngine(engine) + .UseConfiguration(config => + { + config.AccessLogsStream = null; + config.ErrorsLogsStream = LogStream.ConsoleOutput; + }) + .Build(); + + _server.Start(verbose: false, preventHault: false); + + using var client = new HttpClient(); + client.Timeout = TimeSpan.FromMinutes(10); + + int seed = 12345; + using var payloadStream = new RandomStream(size, seed); + using var content = new StreamContent(payloadStream); + content.Headers.ContentLength = size; + + // Calculate expected hash + using var calculationStream = new RandomStream(size, seed); + string expectedHash = await CalculateHashAsync(calculationStream); + + var response = await client.PostAsync($"http://localhost:{_port}/payload", content); + response.EnsureSuccessStatusCode(); + + string serverHash = await response.Content.ReadAsStringAsync(); + Assert.AreEqual(expectedHash, serverHash, $"Hash mismatch for payload size {size}"); + } + + [TestMethod] + public async Task TestPayload_10MB() + { + await RunPayloadTest(10 * 1024 * 1024); + } + + [TestMethod] + public async Task TestPayload_100MB() + { + await RunPayloadTest(100 * 1024 * 1024); + } + + [TestMethod] + public async Task TestPayload_500MB() + { + await RunPayloadTest(500 * 1024 * 1024); + } + + [TestMethod] + [Timeout(600000)] // 10 minutes + public async Task TestPayload_1_5GB() + { + long size = (long)(1.5 * 1024 * 1024 * 1024); + await RunPayloadTest(size); + } +} diff --git a/tests/Sisk.Core/Tests/RandomStream.cs b/tests/Sisk.Core/Tests/RandomStream.cs new file mode 100644 index 0000000..4b8ac64 --- /dev/null +++ b/tests/Sisk.Core/Tests/RandomStream.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; + +namespace tests; + +public class RandomStream : Stream +{ + private readonly long _length; + private long _position; + private readonly Random _random; + + public RandomStream(long length, int seed) + { + _length = length; + _random = new Random(seed); + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => _length; + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override void Flush() { } + + public override int Read(byte[] buffer, int offset, int count) + { + return Read(buffer.AsSpan(offset, count)); + } + + public override int Read(Span buffer) + { + long remaining = _length - _position; + if (remaining <= 0) return 0; + + int toRead = (int)Math.Min(buffer.Length, remaining); + _random.NextBytes(buffer.Slice(0, toRead)); + _position += toRead; + return toRead; + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); +} diff --git a/tests/Sisk.Core/tests.csproj b/tests/Sisk.Core/tests.csproj index 081a603..283d5f3 100644 --- a/tests/Sisk.Core/tests.csproj +++ b/tests/Sisk.Core/tests.csproj @@ -1,7 +1,7 @@ - net9.0 + net8.0 latest enable enable @@ -15,6 +15,7 @@ +