using AyCode.Core.Serializers.Binaries; using static AyCode.Core.Tests.TestModels.AcSerializerModels; namespace AyCode.Core.Tests.Serialization; [TestClass] public class AcBinarySerializerPipeParallelTests { [TestMethod] public async Task SerializeAndDeserialize_InParallelOnTwoTasks_ThroughPipe_RoundTrip() { var original = CreatePayload(200); var options = AcBinarySerializerOptions.Default; using var reader = new SegmentBufferReader(64); var deserializeTask = Task.Run(() => (TestParentWithDateTimeItemCollection?)AcBinaryDeserializer.Deserialize(reader, typeof(TestParentWithDateTimeItemCollection), options)); var serializeTask = Task.Run(async () => { try { var binary = AcBinarySerializer.Serialize(original, options); var offset = 0; var chunkSizes = new[] { 7, 31, 13, 64, 5, 29 }; for (var chunkIndex = 0; offset < binary.Length; chunkIndex++) { var chunkSize = Math.Min(chunkSizes[chunkIndex % chunkSizes.Length], binary.Length - offset); reader.Write(binary.AsSpan(offset, chunkSize)); offset += chunkSize; if (chunkIndex % 4 == 0) await Task.Yield(); } } finally { reader.Complete(); } }); await Task.WhenAll(serializeTask, deserializeTask); var result = deserializeTask.Result; Assert.IsNotNull(result); AssertPayloadEquals(original, result); } [TestMethod] public async Task SerializeAndDeserialize_InParallelOnTwoTasks_WithMultiplePipelines_RoundTrip() { var options = AcBinarySerializerOptions.Default; var pipelines = Enumerable.Range(1, 8).Select(async seed => { var original = CreatePayload(80 + seed * 10); using var reader = new SegmentBufferReader(32); var deserializeTask = Task.Run(() => (TestParentWithDateTimeItemCollection?)AcBinaryDeserializer.Deserialize(reader, typeof(TestParentWithDateTimeItemCollection), options)); var serializeTask = Task.Run(async () => { try { var binary = AcBinarySerializer.Serialize(original, options); var offset = 0; var chunkSize = (seed % 5) + 1; while (offset < binary.Length) { var take = Math.Min(chunkSize, binary.Length - offset); reader.Write(binary.AsSpan(offset, take)); offset += take; await Task.Yield(); } } finally { reader.Complete(); } }); await Task.WhenAll(serializeTask, deserializeTask); var result = deserializeTask.Result; Assert.IsNotNull(result); AssertPayloadEquals(original, result); }); await Task.WhenAll(pipelines); } private static TestParentWithDateTimeItemCollection CreatePayload(int itemCount) { var now = DateTime.UtcNow; var items = new List(itemCount); for (var i = 0; i < itemCount; i++) { items.Add(new TestEntityWithDateTimeAndInt { Id = i + 1, IntValue = i * 3, Created = now.AddMinutes(-i), Modified = now.AddMinutes(i), StatusCode = i % 4, Name = $"item-{i}" }); } return new TestParentWithDateTimeItemCollection { Id = 11, Name = "pipe-parallel-test", Created = now, Items = items }; } private static void AssertPayloadEquals(TestParentWithDateTimeItemCollection expected, TestParentWithDateTimeItemCollection actual) { Assert.AreEqual(expected.Id, actual.Id); Assert.AreEqual(expected.Name, actual.Name); Assert.AreEqual(expected.Created, actual.Created); Assert.IsNotNull(expected.Items); Assert.IsNotNull(actual.Items); Assert.AreEqual(expected.Items.Count, actual.Items.Count); for (var i = 0; i < expected.Items.Count; i++) { var e = expected.Items[i]; var a = actual.Items[i]; Assert.AreEqual(e.Id, a.Id); Assert.AreEqual(e.IntValue, a.IntValue); Assert.AreEqual(e.Created, a.Created); Assert.AreEqual(e.Modified, a.Modified); Assert.AreEqual(e.StatusCode, a.StatusCode); Assert.AreEqual(e.Name, a.Name); } } }