From a41e3a0577e7981e339cf8601c5d31cb7a04560a Mon Sep 17 00:00:00 2001 From: rameel Date: Thu, 26 Mar 2026 00:37:34 +0500 Subject: [PATCH 1/2] Clean up and formatting --- .../S3UploadStream.cs | 13 +++++---- .../GcsWriteStream.cs | 27 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/Ramstack.FileSystem.Amazon/S3UploadStream.cs b/src/Ramstack.FileSystem.Amazon/S3UploadStream.cs index e1cdf42..929c64d 100644 --- a/src/Ramstack.FileSystem.Amazon/S3UploadStream.cs +++ b/src/Ramstack.FileSystem.Amazon/S3UploadStream.cs @@ -100,14 +100,13 @@ public override void Write(ReadOnlySpan buffer) try { _stream.Write(buffer); - if (_stream.Length >= MinPartSize) UploadPart(); } - catch (Exception exception) + catch { Abort(); - ExceptionDispatchInfo.Throw(exception); + throw; } } @@ -124,10 +123,10 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella if (_stream.Length >= MinPartSize) await UploadPartAsync(cancellationToken).ConfigureAwait(false); } - catch (Exception exception) + catch { await AbortAsync(cancellationToken).ConfigureAwait(false); - ExceptionDispatchInfo.Throw(exception); + throw; } } @@ -254,10 +253,10 @@ private async ValueTask UploadPartAsync(CancellationToken cancellationToken) _stream.Position = 0; _stream.SetLength(0); } - catch (Exception exception) + catch { await AbortAsync(cancellationToken).ConfigureAwait(false); - ExceptionDispatchInfo.Throw(exception); + throw; } } } diff --git a/src/Ramstack.FileSystem.Google/GcsWriteStream.cs b/src/Ramstack.FileSystem.Google/GcsWriteStream.cs index 146b709..9a6fa15 100644 --- a/src/Ramstack.FileSystem.Google/GcsWriteStream.cs +++ b/src/Ramstack.FileSystem.Google/GcsWriteStream.cs @@ -3,14 +3,14 @@ namespace Ramstack.FileSystem.Google; /// -/// Represents a temporary write-only stream for Google Cloud Storage operations, redirecting all write operations to a temporary file. -/// Upon disposing or closing the stream, the data is transferred to the Azure Blob storage. +/// Represents a temporary write-only stream that buffers data to a temporary file before uploading it to Google Cloud Storage. +/// Data is committed to the storage bucket when the stream is disposed or closed. /// internal sealed class GcsWriteStream : Stream { private readonly GoogleFileSystem _fs; private readonly string _objectName; - private readonly FileStream _stream = CreateTempFileStream(); + private readonly FileStream _stream; private bool _disposed; /// @@ -53,6 +53,16 @@ public GcsWriteStream(GoogleFileSystem fs, string objectName) { _fs = fs; _objectName = objectName; + _stream = new FileStream( + Path.Combine( + Path.GetTempPath(), + Path.GetRandomFileName()), + FileMode.CreateNew, + FileAccess.ReadWrite, + FileShare.None, + bufferSize: 4096, + FileOptions.DeleteOnClose + | FileOptions.Asynchronous); } /// @@ -84,7 +94,6 @@ public override void Write(ReadOnlySpan buffer) { _disposed = true; _stream.Close(); - throw; } } @@ -104,7 +113,6 @@ public override async ValueTask WriteAsync(ReadOnlyMemory buffer, Cancella { _disposed = true; _stream.Close(); - throw; } } @@ -176,15 +184,6 @@ await _fs.StorageClient } } - private static FileStream CreateTempFileStream() - { - const int BufferSize = 4096; - const FileOptions Options = FileOptions.DeleteOnClose | FileOptions.Asynchronous; - - var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - return new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, BufferSize, Options); - } - [DoesNotReturn] private static void Error_NotSupported() => throw new NotSupportedException(); From c04c4996ce5f9961c4e06d9ed2f676958bb19258 Mon Sep 17 00:00:00 2001 From: rameel Date: Thu, 26 Mar 2026 00:44:54 +0500 Subject: [PATCH 2/2] Clean up and formatting --- .../WritableAmazonFileSystemTests.cs | 16 ++++++------- .../WritableGoogleFileSystemTests.cs | 23 +++++++++++-------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/tests/Ramstack.FileSystem.Amazon.Tests/WritableAmazonFileSystemTests.cs b/tests/Ramstack.FileSystem.Amazon.Tests/WritableAmazonFileSystemTests.cs index 7d2e8c4..2d89780 100644 --- a/tests/Ramstack.FileSystem.Amazon.Tests/WritableAmazonFileSystemTests.cs +++ b/tests/Ramstack.FileSystem.Amazon.Tests/WritableAmazonFileSystemTests.cs @@ -14,7 +14,7 @@ namespace Ramstack.FileSystem.Amazon; [Category("Cloud:Amazon")] public class WritableAmazonFileSystemTests : VirtualFileSystemSpecificationTests { - private readonly HashSet _list = []; + private readonly HashSet _buckets = []; private readonly TempFileStorage _storage = new TempFileStorage(); [OneTimeSetUp] @@ -35,7 +35,7 @@ public async Task Cleanup() { _storage.Dispose(); - foreach (var name in _list.ToArray()) + foreach (var name in _buckets.ToArray()) { using var fs = CreateFileSystem(name); @@ -43,9 +43,9 @@ public async Task Cleanup() { await fs.DeleteDirectoryAsync("/"); } - catch (Exception exception) + catch (Exception e) { - Console.WriteLine(exception); + Console.WriteLine(e); } } } @@ -61,14 +61,15 @@ public async Task File_OpenWrite_InternalBufferWriteError_DoesNotCreateFile() Assert.That(underlying, Is.Not.Null); // Write enough data to trigger automatic part upload (>= 5 MiB). - await stream.WriteAsync(new ReadOnlyMemory(new byte[6 * 1024 * 1024])); + await stream.WriteAsync(new byte[6 * 1024 * 1024]); // Simulates an internal buffer write error. await underlying.DisposeAsync(); try { - await stream.WriteAsync(new ReadOnlyMemory(new byte[1024])); + await stream.WriteAsync(new byte[1024]); + Assert.Fail(); } catch { @@ -239,7 +240,6 @@ public async Task File_OpenWrite_FlushWithMultipartUpload() for (var i = 0; i < Count; i++) await stream.WriteAsync(chunk); } - { var file = fs.GetFile(FileName); @@ -314,7 +314,7 @@ protected override DirectoryInfo GetDirectoryInfo() => private AmazonS3FileSystem CreateFileSystem(string storageName) { - _list.Add(storageName); + _buckets.Add(storageName); return new AmazonS3FileSystem( new BasicAWSCredentials("rustfsadmin", "rustfsadmin"), diff --git a/tests/Ramstack.FileSystem.Google.Tests/WritableGoogleFileSystemTests.cs b/tests/Ramstack.FileSystem.Google.Tests/WritableGoogleFileSystemTests.cs index 00280ea..da61f77 100644 --- a/tests/Ramstack.FileSystem.Google.Tests/WritableGoogleFileSystemTests.cs +++ b/tests/Ramstack.FileSystem.Google.Tests/WritableGoogleFileSystemTests.cs @@ -43,9 +43,9 @@ public async Task Cleanup() { await fs.DeleteDirectoryAsync("/"); } - catch (Exception exception) + catch (Exception e) { - Console.WriteLine(exception); + Console.WriteLine(e); } } } @@ -60,22 +60,19 @@ public async Task File_OpenWrite_InternalBufferWriteError_DoesNotCreateFile() var underlying = (FileStream)stream.GetType().GetField("_stream", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(stream)!; Assert.That(underlying, Is.Not.Null); - await stream.WriteAsync(new ReadOnlyMemory(new byte[1024])); - - // Forces to upload buffer. - await stream.FlushAsync(); + await stream.WriteAsync(new byte[1024]); // Simulates an internal buffer write error. await underlying.DisposeAsync(); try { - await stream.WriteAsync(new ReadOnlyMemory(new byte[1024])); + await stream.WriteAsync(new byte[1024]); + Assert.Fail(); } - catch (Exception exception) + catch { - Console.WriteLine("Exception expected!"); - Console.WriteLine(exception); + // Ignore } } @@ -160,6 +157,9 @@ public async Task File_CopyTo_File_DifferentFileSystems() Assert.That( await reader.ReadToEndAsync(), Is.EqualTo(content)); + + await source.DeleteAsync(); + await destination.DeleteAsync(); } [Test] @@ -189,6 +189,9 @@ public async Task File_CopyTo_File_DifferentStorages() Assert.That( await reader.ReadToEndAsync(), Is.EqualTo(content)); + + await source.DeleteAsync(); + await destination.DeleteAsync(); } protected override GoogleFileSystem GetFileSystem() =>