Skip to content

Commit fabaa0a

Browse files
committed
Clean up and formatting
1 parent d71862e commit fabaa0a

2 files changed

Lines changed: 53 additions & 45 deletions

File tree

src/Ramstack.FileSystem.Amazon/S3UploadStream.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,11 @@ namespace Ramstack.FileSystem.Amazon;
1010

1111
/// <summary>
1212
/// Represents a stream for uploading data to Amazon S3 using multipart upload.
13-
/// This stream accumulates data in a temporary buffer and uploads it to S3 in parts
14-
/// once the buffer reaches a predefined size.
1513
/// </summary>
1614
internal sealed class S3UploadStream : Stream
1715
{
1816
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/qfacts.html
19-
private const long PartSize = 5L * 1024 * 1024;
17+
private const long MinPartSize = 5L * 1024 * 1024;
2018

2119
private readonly IAmazonS3 _client;
2220
private readonly string _bucketName;
@@ -82,7 +80,7 @@ public S3UploadStream(IAmazonS3 client, string bucketName, string key, string up
8280
FileShare.None,
8381
bufferSize: 4096,
8482
FileOptions.DeleteOnClose
85-
| FileOptions.Asynchronous);
83+
| FileOptions.Asynchronous);
8684
}
8785

8886
/// <inheritdoc />
@@ -103,7 +101,7 @@ public override void Write(ReadOnlySpan<byte> buffer)
103101
{
104102
_stream.Write(buffer);
105103

106-
if (_stream.Length >= PartSize)
104+
if (_stream.Length >= MinPartSize)
107105
UploadPart();
108106
}
109107
catch (Exception exception)
@@ -123,7 +121,7 @@ public override async ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, Cancella
123121
try
124122
{
125123
await _stream.WriteAsync(buffer, cancellationToken).ConfigureAwait(false);
126-
if (_stream.Length >= PartSize)
124+
if (_stream.Length >= MinPartSize)
127125
await UploadPartAsync(cancellationToken).ConfigureAwait(false);
128126
}
129127
catch (Exception exception)

tests/Ramstack.FileSystem.Amazon.Tests/WritableAmazonFileSystemTests.cs

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -193,82 +193,92 @@ await reader.ReadToEndAsync(),
193193
await destination.DeleteAsync();
194194
}
195195

196-
197196
[Test]
198197
public async Task File_OpenWrite_FlushDoesNotCauseUndersizedParts()
199198
{
200199
using var fs = GetFileSystem();
201200

202-
var content = "Hello, World!";
201+
const string Content = "Hello, World!";
203202

204203
{
205204
await using var stream = await fs.OpenWriteAsync("/flush-test.txt");
206205
await using var writer = new StreamWriter(stream);
207206

208207
// Write small data and flush multiple times.
209208
// Flush should be a no-op and not upload undersized parts.
210-
await writer.WriteAsync(content[..5]);
211-
await writer.FlushAsync();
212-
await writer.WriteAsync(content[5..]);
213-
await writer.FlushAsync();
209+
foreach (var ch in Content)
210+
{
211+
await writer.WriteAsync(ch);
212+
await writer.FlushAsync();
213+
}
214214
}
215-
216215
{
217-
var file = fs.GetFile("/flush-test.txt");
218-
Assert.That(await file.ExistsAsync(), Is.True);
219-
220216
// ReSharper disable once UseAwaitUsing
221-
using var stream = await file.OpenReadAsync();
217+
using var stream = await fs.OpenReadAsync("/flush-test.txt");
222218
using var reader = new StreamReader(stream);
223-
Assert.That(await reader.ReadToEndAsync(), Is.EqualTo(content));
224219

225-
await file.DeleteAsync();
220+
Assert.That(await reader.ReadToEndAsync(), Is.EqualTo(Content));
226221
}
222+
223+
await fs.DeleteFileAsync("/flush-test.txt");
227224
}
228225

229226
[Test]
230227
public async Task File_OpenWrite_FlushWithMultipartUpload()
231228
{
232229
using var fs = GetFileSystem();
233230

234-
// Write more than 5 MiB to trigger multipart upload,
235-
// with Flush calls between writes.
236-
var chunk = new byte[2 * 1024 * 1024];
231+
const int Count = 5;
232+
const string FileName = "/flush-multipart-test.bin";
233+
234+
var chunk = new byte[3 * 1024 * 1024];
237235
Random.Shared.NextBytes(chunk);
238236

239237
{
240-
await using var stream = await fs.OpenWriteAsync("/flush-multipart-test.bin");
238+
await using var stream = await fs.OpenWriteAsync(FileName);
239+
for (var i = 0; i < Count; i++)
240+
await stream.WriteAsync(chunk);
241+
}
242+
243+
{
244+
var file = fs.GetFile(FileName);
245+
246+
Assert.That(await file.ExistsAsync(), Is.True);
247+
Assert.That(await file.GetLengthAsync(), Is.EqualTo(chunk.Length * Count));
241248

242-
// Write 4 chunks (8 MiB total) with flushes in between.
243-
// Without the fix, each flush would upload an undersized part
244-
// and CompleteMultipartUpload would fail.
245-
for (var i = 0; i < 4; i++)
249+
// ReSharper disable once UseAwaitUsing
250+
using var stream = await file.OpenReadAsync();
251+
252+
var bytes = new byte[chunk.Length];
253+
254+
for (var i = 0; i < Count; i++)
246255
{
247-
await stream.WriteAsync(chunk);
248-
await stream.FlushAsync();
256+
var n = await ReadBlockAsync(stream, bytes);
257+
Assert.That(n, Is.EqualTo(bytes.Length));
258+
259+
Assert.That(
260+
bytes.AsSpan().SequenceEqual(chunk),
261+
Is.True);
249262
}
250263
}
251264

252-
var file = fs.GetFile("/flush-multipart-test.bin");
253-
Assert.That(await file.ExistsAsync(), Is.True);
254-
Assert.That(await file.GetLengthAsync(), Is.EqualTo(chunk.Length * 4));
255-
256-
await file.DeleteAsync();
257-
}
265+
await fs.DeleteFileAsync(FileName);
258266

259-
[Test]
260-
public async Task File_OpenWrite_EmptyFileWithFlush()
261-
{
262-
using var fs = GetFileSystem();
267+
static async Task<int> ReadBlockAsync(Stream stream, Memory<byte> memory)
268+
{
269+
var count = memory.Length;
263270

264-
await using (var stream = await fs.OpenWriteAsync("/empty-flush-test.txt"))
265-
await stream.FlushAsync();
271+
while (!memory.IsEmpty)
272+
{
273+
var n = await stream.ReadAsync(memory);
274+
if (n == 0)
275+
return 0;
266276

267-
var file = fs.GetFile("/empty-flush-test.txt");
268-
Assert.That(await file.ExistsAsync(), Is.True);
269-
Assert.That(await file.GetLengthAsync(), Is.EqualTo(0));
277+
memory = memory[n..];
278+
}
270279

271-
await file.DeleteAsync();
280+
return count;
281+
}
272282
}
273283

274284
[Test]

0 commit comments

Comments
 (0)