From 2a2d7fb5d7950403b6bee4ca4c272e5b66d1f08a Mon Sep 17 00:00:00 2001 From: imariom Date: Wed, 1 May 2024 20:44:47 +0200 Subject: [PATCH 01/12] Added the synchronize with barrier main program --- .../ChunkUploadServer.cs | 85 +++++++++++++++++++ .../SynchronizeWithBarrier/Program.cs | 14 +++ .../SynchronizeWithBarrier.csproj | 10 +++ .../SynchronizingOperationsWithBarrier.sln | 22 +++++ 4 files changed, 131 insertions(+) create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.csproj create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs new file mode 100644 index 0000000000..31a5aa60bd --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -0,0 +1,85 @@ +using System.Net; +using System.Text; + +namespace SimpleHTTPServer; + +public class ChunkUploadServer +{ + readonly int chunkSize; + readonly int threadCount; + + public ChunkUploadServer(int chunkSize, int threadCount) + { + this.chunkSize = chunkSize; + this.threadCount = threadCount; + } + + public async Task StartServer(int port) + { + var uri = $"http://localhost:{port}/upload/"; + + var listener = new HttpListener(); + listener.Prefixes.Add(uri); + listener.Start(); + + Console.WriteLine($"Server started listening at {uri}"); + + // Wait for a client request + var context = await listener.GetContextAsync(); + if (context.Request.HttpMethod == HttpMethod.Post.Method) + { + await ProcessUpload(context); + } + else + { + context.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; + context.Response.Close(); + } + } + + public async Task ProcessUpload(HttpListenerContext context) + { + // Get the name of the file being uploaded from the request + var fileName = Path.GetFileName(context.Request.Headers["X-Filename"]); + + // If the file size is larger than total chunk size, handle appropriately + if (context.Request.ContentLength64 > chunkSize * threadCount) + { + Console.WriteLine("File size exceeds chunk capacity."); + context.Response.Abort(); + return; + } + + var barrier = new Barrier(threadCount + 1); + + for (int i = 0; i < threadCount; i++) + { + int chunkNumber = i + 1; + var threadTask = Task.Run(() => + { + var buffer = new byte[chunkSize]; + + int bytesRead = context.Request.InputStream.Read(buffer, 0, buffer.Length); + if (bytesRead > 0) + { + // Logic to process the chunk + Console.WriteLine($"Thread {chunkNumber} processed {bytesRead} bytes of chunk {chunkNumber}."); + } + + barrier.SignalAndWait(); + }); + } + + barrier.SignalAndWait(); + + // Respond to request + var message = $"File '{fileName}' uploaded successfully..."; + + context.Response.ContentLength64 = Encoding.UTF8.GetByteCount(message); + context.Response.StatusCode = (int)HttpStatusCode.Created; + + using (Stream s = context.Response.OutputStream) + using (StreamWriter writer = new StreamWriter(s)) + await writer.WriteAsync(message); + } +} \ No newline at end of file diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs new file mode 100644 index 0000000000..f8135962c2 --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs @@ -0,0 +1,14 @@ +using SimpleHTTPServer; + +class Program +{ + public static void Main(string[] args) + { + int port = 8080; + int chunkSize = 1024 * 1024; // 1 MB chunk size + int threadCount = 4; // 4 participant threads + + var server = new ChunkUploadServer(chunkSize, threadCount); + server.StartServer(port).Wait(); + } +} diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.csproj b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.csproj new file mode 100644 index 0000000000..2150e3797b --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln new file mode 100644 index 0000000000..a9101525de --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SynchronizeWithBarrier", "SynchronizeWithBarrier\SynchronizeWithBarrier.csproj", "{68F96422-6D64-41BD-8F49-1EE10CFE34E1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal From bdaadd8808b242dba8f55b643033615c215ac241 Mon Sep 17 00:00:00 2001 From: imariom Date: Wed, 1 May 2024 20:48:32 +0200 Subject: [PATCH 02/12] Added tests for the synchronize with barrier project --- .../SynchronizingOperationsWithBarrier.sln | 6 ++ .../Tests/ChunkUploadServerUnitTest.cs | 87 +++++++++++++++++++ .../Tests/Tests.csproj | 27 ++++++ 3 files changed, 120 insertions(+) create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/Tests.csproj diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln index a9101525de..534265c0c8 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizingOperationsWithBarrier.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SynchronizeWithBarrier", "SynchronizeWithBarrier\SynchronizeWithBarrier.csproj", "{68F96422-6D64-41BD-8F49-1EE10CFE34E1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{AC241346-1198-4A49-93BB-A2D62D01326C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +20,9 @@ Global {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Debug|Any CPU.Build.0 = Debug|Any CPU {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Release|Any CPU.ActiveCfg = Release|Any CPU {68F96422-6D64-41BD-8F49-1EE10CFE34E1}.Release|Any CPU.Build.0 = Release|Any CPU + {AC241346-1198-4A49-93BB-A2D62D01326C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AC241346-1198-4A49-93BB-A2D62D01326C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AC241346-1198-4A49-93BB-A2D62D01326C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AC241346-1198-4A49-93BB-A2D62D01326C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs new file mode 100644 index 0000000000..2c447abdda --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs @@ -0,0 +1,87 @@ +using System.Net; +using System.Text; +using SimpleHTTPServer; + +[TestClass] +public class ChunkUploadServerTests +{ + [TestMethod] + public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHTTPMethods() + { + // Arrange + int chunkSize = 1024 * 1024; + int threadCount = 4; + int port = 8080; + var server = new ChunkUploadServer(chunkSize, threadCount); + + // Act + Task serverTask = server.StartServer(port); + await Task.Delay(2000); // Allow some time for server to start + + // Assert + using (var client = new HttpClient()) + { + var response = await client.GetAsync($"http://localhost:{port}/upload/"); + Assert.AreEqual((int)HttpStatusCode.MethodNotAllowed, (int)response.StatusCode); + } + + // Clean up + serverTask.Dispose(); + } + + [TestMethod] + [ExpectedException(typeof(HttpRequestException))] + public async Task WhenUploadingLargeFiles_ShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() + { + // Arrange + int chunkSize = 1024 * 1024; + int threadCount = 4; + int port = 8080; + long fileSize = (chunkSize * threadCount) + 1; // Exceeds total chunk size + + var server = new ChunkUploadServer(chunkSize, threadCount); + _ = server.StartServer(port); + await Task.Delay(2000); // Allow some time for server to start + + // Act + using var client = new HttpClient(); + using var content = new ByteArrayContent(new byte[fileSize]); + content.Headers.Add("X-Filename", "test.txt"); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + } + + [TestMethod] + public async Task WhenUploadingAFile_ShouldProcessChunksWithMultipleThreads() + { + // Arrange + int chunkSize = 1024 * 1024; + int threadCount = 4; + int port = 8080; + long fileSize = chunkSize * threadCount; + + var server = new ChunkUploadServer(chunkSize, threadCount); + Task serverTask = server.StartServer(port); + await Task.Delay(2000); // Allow some time for server to start + + // Act + using (var client = new HttpClient()) + using (var content = new ByteArrayContent(new byte[fileSize])) + { + content.Headers.Add("X-Filename", "test.txt"); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + + // Assert + Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); + + // Assert + using var result = response.Content.ReadAsStream(); + using var reader = new StreamReader(result); + var message = reader.ReadToEnd(); + Assert.AreEqual($"File 'test.txt' uploaded successfully...", message); + } + + // Wait for the server task to complete + await Task.Delay(2000); + serverTask.Wait(); + } +} \ No newline at end of file diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/Tests.csproj b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/Tests.csproj new file mode 100644 index 0000000000..3398e8b1cc --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/Tests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + From 655531584ebd687252f1239ebe322d3b977f4b24 Mon Sep 17 00:00:00 2001 From: imariom Date: Thu, 2 May 2024 00:44:53 +0200 Subject: [PATCH 03/12] Added HttpClientHandler to fix SSL connection failure --- .../Tests/ChunkUploadServerUnitTest.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs index 2c447abdda..6680e0bd0e 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs @@ -1,10 +1,20 @@ using System.Net; -using System.Text; using SimpleHTTPServer; [TestClass] public class ChunkUploadServerTests { + private HttpClientHandler clientHandler; + + [TestInitialize] + public void TestInitialize() + { + clientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; } + }; + } + [TestMethod] public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHTTPMethods() { @@ -19,7 +29,7 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHT await Task.Delay(2000); // Allow some time for server to start // Assert - using (var client = new HttpClient()) + using (var client = new HttpClient(clientHandler)) { var response = await client.GetAsync($"http://localhost:{port}/upload/"); Assert.AreEqual((int)HttpStatusCode.MethodNotAllowed, (int)response.StatusCode); @@ -44,7 +54,7 @@ public async Task WhenUploadingLargeFiles_ShouldRejectLargeFilesExceedingChunkCa await Task.Delay(2000); // Allow some time for server to start // Act - using var client = new HttpClient(); + using var client = new HttpClient(clientHandler); using var content = new ByteArrayContent(new byte[fileSize]); content.Headers.Add("X-Filename", "test.txt"); var response = await client.PostAsync($"http://localhost:{port}/upload/", content); @@ -64,7 +74,7 @@ public async Task WhenUploadingAFile_ShouldProcessChunksWithMultipleThreads() await Task.Delay(2000); // Allow some time for server to start // Act - using (var client = new HttpClient()) + using (var client = new HttpClient(clientHandler)) using (var content = new ByteArrayContent(new byte[fileSize])) { content.Headers.Add("X-Filename", "test.txt"); From 030f5c2ae47c052102c18a1cb4313aadcc01c292 Mon Sep 17 00:00:00 2001 From: imariom Date: Thu, 2 May 2024 08:37:36 +0200 Subject: [PATCH 04/12] Fixed file name to use live tests --- ...nkUploadServerUnitTest.cs => ChunkUploadServerLiveTest.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/{ChunkUploadServerUnitTest.cs => ChunkUploadServerLiveTest.cs} (93%) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs similarity index 93% rename from csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs rename to csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index 6680e0bd0e..2eb1e5c0e0 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerUnitTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -41,7 +41,7 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHT [TestMethod] [ExpectedException(typeof(HttpRequestException))] - public async Task WhenUploadingLargeFiles_ShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() + public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() { // Arrange int chunkSize = 1024 * 1024; @@ -61,7 +61,7 @@ public async Task WhenUploadingLargeFiles_ShouldRejectLargeFilesExceedingChunkCa } [TestMethod] - public async Task WhenUploadingAFile_ShouldProcessChunksWithMultipleThreads() + public async Task WhenUploadingAFile_ThenShouldProcessChunksWithMultipleThreads() { // Arrange int chunkSize = 1024 * 1024; From 198a0ba79cf1a0ff0d96985cc42aaef962ac06bd Mon Sep 17 00:00:00 2001 From: imariom Date: Thu, 2 May 2024 11:34:06 +0200 Subject: [PATCH 05/12] Fixed open HTTPListner instances by closing the connection --- .../SynchronizeWithBarrier/ChunkUploadServer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index 31a5aa60bd..cb10106e6f 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -35,6 +35,8 @@ public async Task StartServer(int port) context.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; context.Response.Close(); } + + listener.Close(); } public async Task ProcessUpload(HttpListenerContext context) From fc576958d960524fe0d83165d30377bc94a34aae Mon Sep 17 00:00:00 2001 From: imariom Date: Thu, 2 May 2024 12:16:41 +0200 Subject: [PATCH 06/12] Fixed unit test to catch exception thrown --- .../ChunkUploadServer.cs | 3 ++- .../Tests/ChunkUploadServerLiveTest.cs | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index cb10106e6f..4dd8e2f487 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -48,7 +48,8 @@ public async Task ProcessUpload(HttpListenerContext context) if (context.Request.ContentLength64 > chunkSize * threadCount) { Console.WriteLine("File size exceeds chunk capacity."); - context.Response.Abort(); + context.Response.StatusCode = (int)HttpStatusCode.BadRequest; + context.Response.Close(); return; } diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index 2eb1e5c0e0..7685c66902 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -36,7 +36,9 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHT } // Clean up - serverTask.Dispose(); + // Wait for the server task to complete + await Task.Delay(2000); + serverTask.Wait(); } [TestMethod] @@ -46,18 +48,24 @@ public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChu // Arrange int chunkSize = 1024 * 1024; int threadCount = 4; - int port = 8080; + int port = 8082; long fileSize = (chunkSize * threadCount) + 1; // Exceeds total chunk size var server = new ChunkUploadServer(chunkSize, threadCount); - _ = server.StartServer(port); + Task serverTask = server.StartServer(port); await Task.Delay(2000); // Allow some time for server to start // Act - using var client = new HttpClient(clientHandler); - using var content = new ByteArrayContent(new byte[fileSize]); - content.Headers.Add("X-Filename", "test.txt"); - var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + using (var client = new HttpClient(clientHandler)) + using (var content = new ByteArrayContent(new byte[fileSize])) + { + content.Headers.Add("X-Filename", "test.txt"); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + } + + // Wait for the server task to complete + await Task.Delay(2000); + serverTask.Wait(); } [TestMethod] @@ -66,7 +74,7 @@ public async Task WhenUploadingAFile_ThenShouldProcessChunksWithMultipleThreads( // Arrange int chunkSize = 1024 * 1024; int threadCount = 4; - int port = 8080; + int port = 8084; long fileSize = chunkSize * threadCount; var server = new ChunkUploadServer(chunkSize, threadCount); From a85266f97ffc056072d31dbddc2856c5a99a45f9 Mon Sep 17 00:00:00 2001 From: imariom Date: Thu, 2 May 2024 12:22:50 +0200 Subject: [PATCH 07/12] Fixed properly closing of HTTPListner connection --- .../SynchronizeWithBarrier/ChunkUploadServer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index 4dd8e2f487..00106848e2 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -29,14 +29,13 @@ public async Task StartServer(int port) if (context.Request.HttpMethod == HttpMethod.Post.Method) { await ProcessUpload(context); + listener.Close(); } else { context.Response.StatusCode = (int)HttpStatusCode.MethodNotAllowed; context.Response.Close(); } - - listener.Close(); } public async Task ProcessUpload(HttpListenerContext context) From cd6acfd935568b6d7aeb3bcc838e76fa2e4d3c63 Mon Sep 17 00:00:00 2001 From: imariom Date: Sun, 5 May 2024 18:46:44 +0200 Subject: [PATCH 08/12] Fixed logic to read from input stream --- .../ChunkUploadServer.cs | 13 ++-- .../SynchronizeWithBarrier/Program.cs | 2 +- .../Tests/ChunkUploadServerLiveTest.cs | 72 +++++++------------ 3 files changed, 29 insertions(+), 58 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index 00106848e2..c71d3d0382 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -29,7 +29,6 @@ public async Task StartServer(int port) if (context.Request.HttpMethod == HttpMethod.Post.Method) { await ProcessUpload(context); - listener.Close(); } else { @@ -59,14 +58,8 @@ public async Task ProcessUpload(HttpListenerContext context) int chunkNumber = i + 1; var threadTask = Task.Run(() => { - var buffer = new byte[chunkSize]; - - int bytesRead = context.Request.InputStream.Read(buffer, 0, buffer.Length); - if (bytesRead > 0) - { - // Logic to process the chunk - Console.WriteLine($"Thread {chunkNumber} processed {bytesRead} bytes of chunk {chunkNumber}."); - } + // Logic to process the chunk from the request stream + Console.WriteLine($"Thread {chunkNumber} processed stream chunk."); barrier.SignalAndWait(); }); @@ -83,5 +76,7 @@ public async Task ProcessUpload(HttpListenerContext context) using (Stream s = context.Response.OutputStream) using (StreamWriter writer = new StreamWriter(s)) await writer.WriteAsync(message); + + context.Response.Close(); } } \ No newline at end of file diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs index f8135962c2..c13d2dc18c 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs @@ -4,7 +4,7 @@ class Program { public static void Main(string[] args) { - int port = 8080; + int port = 8090; int chunkSize = 1024 * 1024; // 1 MB chunk size int threadCount = 4; // 4 participant threads diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index 7685c66902..c4784de1dd 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -16,56 +16,44 @@ public void TestInitialize() } [TestMethod] - public async Task WhenCreatingAServer_ThenItStartsSuccessfullyAndRejectInvalidHTTPMethods() + public async Task WhenCreatingAServer_ThenItStartsSuccessfully() { // Arrange int chunkSize = 1024 * 1024; int threadCount = 4; - int port = 8080; + int port = 8090; var server = new ChunkUploadServer(chunkSize, threadCount); - // Act - Task serverTask = server.StartServer(port); + _ = server.StartServer(port); await Task.Delay(2000); // Allow some time for server to start - // Assert - using (var client = new HttpClient(clientHandler)) - { - var response = await client.GetAsync($"http://localhost:{port}/upload/"); - Assert.AreEqual((int)HttpStatusCode.MethodNotAllowed, (int)response.StatusCode); - } - - // Clean up - // Wait for the server task to complete - await Task.Delay(2000); - serverTask.Wait(); + // Act + using var client = new HttpClient(clientHandler); + var response = await client.GetAsync($"http://localhost:{port}/upload/"); + Assert.AreEqual(HttpStatusCode.MethodNotAllowed, response.StatusCode); } [TestMethod] - [ExpectedException(typeof(HttpRequestException))] public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() { // Arrange int chunkSize = 1024 * 1024; int threadCount = 4; - int port = 8082; + int port = 8091; long fileSize = (chunkSize * threadCount) + 1; // Exceeds total chunk size var server = new ChunkUploadServer(chunkSize, threadCount); - Task serverTask = server.StartServer(port); + _ = server.StartServer(port); await Task.Delay(2000); // Allow some time for server to start // Act - using (var client = new HttpClient(clientHandler)) - using (var content = new ByteArrayContent(new byte[fileSize])) - { - content.Headers.Add("X-Filename", "test.txt"); - var response = await client.PostAsync($"http://localhost:{port}/upload/", content); - } + using var client = new HttpClient(clientHandler); + using var content = new ByteArrayContent(new byte[fileSize]); + content.Headers.Add("X-Filename", "test.txt"); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); - // Wait for the server task to complete - await Task.Delay(2000); - serverTask.Wait(); + // Assert + Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); } [TestMethod] @@ -74,32 +62,20 @@ public async Task WhenUploadingAFile_ThenShouldProcessChunksWithMultipleThreads( // Arrange int chunkSize = 1024 * 1024; int threadCount = 4; - int port = 8084; + int port = 8092; long fileSize = chunkSize * threadCount; var server = new ChunkUploadServer(chunkSize, threadCount); - Task serverTask = server.StartServer(port); - await Task.Delay(2000); // Allow some time for server to start + _ = server.StartServer(port); + await Task.Delay(2000); // Allow some time for server to start // Act - using (var client = new HttpClient(clientHandler)) - using (var content = new ByteArrayContent(new byte[fileSize])) - { - content.Headers.Add("X-Filename", "test.txt"); - var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + using var client = new HttpClient(clientHandler); + using var content = new ByteArrayContent(new byte[fileSize]); + content.Headers.Add("X-Filename", "test.txt"); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); - // Assert - Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); - - // Assert - using var result = response.Content.ReadAsStream(); - using var reader = new StreamReader(result); - var message = reader.ReadToEnd(); - Assert.AreEqual($"File 'test.txt' uploaded successfully...", message); - } - - // Wait for the server task to complete - await Task.Delay(2000); - serverTask.Wait(); + // Assert + Assert.AreEqual(HttpStatusCode.Created, response.StatusCode); } } \ No newline at end of file From d2dea23c7a8fc24e685e876fc027ed0c548d7c1d Mon Sep 17 00:00:00 2001 From: imariom Date: Sun, 5 May 2024 18:52:07 +0200 Subject: [PATCH 09/12] Added check for thrown exception --- .../Tests/ChunkUploadServerLiveTest.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index c4784de1dd..327adb4570 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -34,6 +34,7 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfully() } [TestMethod] + [ExpectedException(typeof(HttpRequestException))] public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() { // Arrange From 3b1a14e80feaf75d14d15e2187463ea2953124c0 Mon Sep 17 00:00:00 2001 From: imariom Date: Sun, 19 May 2024 12:30:41 +0200 Subject: [PATCH 10/12] Unit test: Remove check for expected exception (no longer thrown). --- .../ChunkUploadServer.cs | 4 --- .../SynchronizeWithBarrier/Program.cs | 6 ++--- .../SynchronizeWithBarrier.sln | 25 +++++++++++++++++++ .../Tests/ChunkUploadServerLiveTest.cs | 12 +++------ 4 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.sln diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index c71d3d0382..2a3e2dfbdd 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -39,10 +39,8 @@ public async Task StartServer(int port) public async Task ProcessUpload(HttpListenerContext context) { - // Get the name of the file being uploaded from the request var fileName = Path.GetFileName(context.Request.Headers["X-Filename"]); - // If the file size is larger than total chunk size, handle appropriately if (context.Request.ContentLength64 > chunkSize * threadCount) { Console.WriteLine("File size exceeds chunk capacity."); @@ -58,7 +56,6 @@ public async Task ProcessUpload(HttpListenerContext context) int chunkNumber = i + 1; var threadTask = Task.Run(() => { - // Logic to process the chunk from the request stream Console.WriteLine($"Thread {chunkNumber} processed stream chunk."); barrier.SignalAndWait(); @@ -67,7 +64,6 @@ public async Task ProcessUpload(HttpListenerContext context) barrier.SignalAndWait(); - // Respond to request var message = $"File '{fileName}' uploaded successfully..."; context.Response.ContentLength64 = Encoding.UTF8.GetByteCount(message); diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs index c13d2dc18c..0e7809bd37 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/Program.cs @@ -4,9 +4,9 @@ class Program { public static void Main(string[] args) { - int port = 8090; - int chunkSize = 1024 * 1024; // 1 MB chunk size - int threadCount = 4; // 4 participant threads + var port = 8090; + var chunkSize = 1024 * 1024; + var threadCount = 4; var server = new ChunkUploadServer(chunkSize, threadCount); server.StartServer(port).Wait(); diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.sln b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.sln new file mode 100644 index 0000000000..7696faac31 --- /dev/null +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/SynchronizeWithBarrier.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.002.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SynchronizeWithBarrier", "SynchronizeWithBarrier.csproj", "{7C32891D-EBC5-4C45-B844-D6EE099CD459}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7C32891D-EBC5-4C45-B844-D6EE099CD459}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C32891D-EBC5-4C45-B844-D6EE099CD459}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C32891D-EBC5-4C45-B844-D6EE099CD459}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C32891D-EBC5-4C45-B844-D6EE099CD459}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C587068E-4DEC-419F-9213-3B21A0DA8046} + EndGlobalSection +EndGlobal diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index 327adb4570..be3497561d 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -22,10 +22,9 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfully() int chunkSize = 1024 * 1024; int threadCount = 4; int port = 8090; - var server = new ChunkUploadServer(chunkSize, threadCount); - _ = server.StartServer(port); - await Task.Delay(2000); // Allow some time for server to start + var server = new ChunkUploadServer(chunkSize, threadCount); + server.StartServer(port); // Act using var client = new HttpClient(clientHandler); @@ -34,7 +33,6 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfully() } [TestMethod] - [ExpectedException(typeof(HttpRequestException))] public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() { // Arrange @@ -44,8 +42,7 @@ public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChu long fileSize = (chunkSize * threadCount) + 1; // Exceeds total chunk size var server = new ChunkUploadServer(chunkSize, threadCount); - _ = server.StartServer(port); - await Task.Delay(2000); // Allow some time for server to start + server.StartServer(port); // Act using var client = new HttpClient(clientHandler); @@ -67,8 +64,7 @@ public async Task WhenUploadingAFile_ThenShouldProcessChunksWithMultipleThreads( long fileSize = chunkSize * threadCount; var server = new ChunkUploadServer(chunkSize, threadCount); - _ = server.StartServer(port); - await Task.Delay(2000); // Allow some time for server to start + server.StartServer(port); // Act using var client = new HttpClient(clientHandler); From b76be9cc0ad0a170ad5d8f3a7843b5714cded913 Mon Sep 17 00:00:00 2001 From: imariom Date: Tue, 21 May 2024 19:27:21 +0200 Subject: [PATCH 11/12] Changed PostAsync call to normal HTTP send request to avoid exceptions --- .../Tests/ChunkUploadServerLiveTest.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index be3497561d..912b780f01 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -33,7 +33,7 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfully() } [TestMethod] - public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() + public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacity() { // Arrange int chunkSize = 1024 * 1024; @@ -48,7 +48,11 @@ public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChu using var client = new HttpClient(clientHandler); using var content = new ByteArrayContent(new byte[fileSize]); content.Headers.Add("X-Filename", "test.txt"); - var response = await client.PostAsync($"http://localhost:{port}/upload/", content); + + var request = new HttpRequestMessage(HttpMethod.Post, new Uri($"http://localhost:{port}/upload/")); + request.Content = content; + + var response = client.Send(request); // Assert Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); From 0abb857d792faa81f804d0f588304bd935636734 Mon Sep 17 00:00:00 2001 From: imariom Date: Tue, 21 May 2024 20:22:58 +0200 Subject: [PATCH 12/12] Unit test can now capture exception thrown when uploading large files --- .../SynchronizeWithBarrier/ChunkUploadServer.cs | 3 +-- .../Tests/ChunkUploadServerLiveTest.cs | 12 +++--------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs index 2a3e2dfbdd..f5201a6d44 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/SynchronizeWithBarrier/ChunkUploadServer.cs @@ -44,8 +44,7 @@ public async Task ProcessUpload(HttpListenerContext context) if (context.Request.ContentLength64 > chunkSize * threadCount) { Console.WriteLine("File size exceeds chunk capacity."); - context.Response.StatusCode = (int)HttpStatusCode.BadRequest; - context.Response.Close(); + context.Response.Abort(); return; } diff --git a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs index 912b780f01..3c4b19bb0f 100644 --- a/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs +++ b/csharp-advanced-topics/SynchronizingOperationsWithBarrier/Tests/ChunkUploadServerLiveTest.cs @@ -33,7 +33,8 @@ public async Task WhenCreatingAServer_ThenItStartsSuccessfully() } [TestMethod] - public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacity() + [ExpectedException(typeof(HttpRequestException))] + public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChunkCapacityByThrowingException() { // Arrange int chunkSize = 1024 * 1024; @@ -48,14 +49,7 @@ public async Task WhenUploadingLargeFiles_ThenShouldRejectLargeFilesExceedingChu using var client = new HttpClient(clientHandler); using var content = new ByteArrayContent(new byte[fileSize]); content.Headers.Add("X-Filename", "test.txt"); - - var request = new HttpRequestMessage(HttpMethod.Post, new Uri($"http://localhost:{port}/upload/")); - request.Content = content; - - var response = client.Send(request); - - // Assert - Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); + var response = await client.PostAsync($"http://localhost:{port}/upload/", content); } [TestMethod]