Skip to content

Commit

Permalink
Zero byte reads support for FileBufferingReadStream #41287 (#41309)
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher authored Apr 21, 2022
1 parent cf513d3 commit f041d49
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 2 deletions.
6 changes: 4 additions & 2 deletions src/Http/WebUtilities/src/FileBufferingReadStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ public override int Read(Span<byte> buffer)
{
_buffer.Write(buffer.Slice(0, read));
}
else
// Allow zero-byte reads
else if (buffer.Length > 0)
{
_completelyBuffered = true;
}
Expand Down Expand Up @@ -388,7 +389,8 @@ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, Cancellation
{
await _buffer.WriteAsync(buffer.Slice(0, read), cancellationToken);
}
else
// Allow zero-byte reads
else if (buffer.Length > 0)
{
_completelyBuffered = true;
}
Expand Down
107 changes: 107 additions & 0 deletions src/Http/WebUtilities/test/FileBufferingReadStreamTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,39 @@ public void FileBufferingReadStream_Properties_ExpectedValues()
Assert.True(inner.CanSeek);
}

[Fact]
public void FileBufferingReadStream_Sync0ByteReadUnderThreshold_DoesntCreateFile()
{
var inner = MakeStream(1024);
using (var stream = new FileBufferingReadStream(inner, 1024 * 2, null, Directory.GetCurrentDirectory()))
{
var bytes = new byte[1000];
var read0 = stream.Read(bytes, 0, 0);
Assert.Equal(0, read0);
Assert.Equal(read0, stream.Length);
Assert.Equal(read0, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read1 = stream.Read(bytes, 0, bytes.Length);
Assert.Equal(bytes.Length, read1);
Assert.Equal(read0 + read1, stream.Length);
Assert.Equal(read0 + read1, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read2 = stream.Read(bytes, 0, bytes.Length);
Assert.Equal(inner.Length - read0 - read1, read2);
Assert.Equal(read0 + read1 + read2, stream.Length);
Assert.Equal(read0 + read1 + read2, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read3 = stream.Read(bytes, 0, bytes.Length);
Assert.Equal(0, read3);
}
}

[Fact]
public void FileBufferingReadStream_SyncReadUnderThreshold_DoesntCreateFile()
{
Expand Down Expand Up @@ -165,6 +198,39 @@ public void FileBufferingReadStream_SyncReadWithOnDiskLimit_EnforcesLimit()

///////////////////

[Fact]
public async Task FileBufferingReadStream_Async0ByteReadUnderThreshold_DoesntCreateFile()
{
var inner = MakeStream(1024);
using (var stream = new FileBufferingReadStream(inner, 1024 * 2, null, Directory.GetCurrentDirectory()))
{
var bytes = new byte[1000];
var read0 = await stream.ReadAsync(bytes, 0, 0);
Assert.Equal(0, read0);
Assert.Equal(read0, stream.Length);
Assert.Equal(read0, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read1 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(bytes.Length, read1);
Assert.Equal(read0 + read1, stream.Length);
Assert.Equal(read0 + read1, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read2 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(inner.Length - read0 - read1, read2);
Assert.Equal(read0 + read1 + read2, stream.Length);
Assert.Equal(read0 + read1 + read2, stream.Position);
Assert.True(stream.InMemory);
Assert.Null(stream.TempFileName);

var read3 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(0, read3);
}
}

[Fact]
public async Task FileBufferingReadStream_AsyncReadUnderThreshold_DoesntCreateFile()
{
Expand Down Expand Up @@ -237,6 +303,47 @@ public async Task FileBufferingReadStream_AsyncReadOverThreshold_CreatesFile()
Assert.False(File.Exists(tempFileName));
}

[Fact]
public async Task FileBufferingReadStream_Async0ByteReadAfterBuffering_ReadsFromFile()
{
var inner = MakeStream(1024 * 2);
string tempFileName;
using (var stream = new FileBufferingReadStream(inner, 1024, null, GetCurrentDirectory()))
{
await stream.DrainAsync(default);
stream.Position = 0;
Assert.Equal(inner.Length, stream.Length);
Assert.Equal(0, stream.Position);
Assert.False(stream.InMemory);
Assert.NotNull(stream.TempFileName);
tempFileName = stream.TempFileName!;
Assert.True(File.Exists(tempFileName));

var bytes = new byte[1000];
var read0 = await stream.ReadAsync(bytes, 0, 0);
Assert.Equal(0, read0);
Assert.Equal(read0, stream.Position);

var read1 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(bytes.Length, read1);
Assert.Equal(read0 + read1, stream.Position);

var read2 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(bytes.Length, read2);
Assert.Equal(read0 + read1 + read2, stream.Position);

var read3 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(inner.Length - read0 - read1 - read2, read3);
Assert.Equal(read0 + read1 + read2 + read3, stream.Length);
Assert.Equal(read0 + read1 + read2 + read3, stream.Position);

var read4 = await stream.ReadAsync(bytes, 0, bytes.Length);
Assert.Equal(0, read4);
}

Assert.False(File.Exists(tempFileName));
}

[Fact]
public async Task FileBufferingReadStream_AsyncReadWithInMemoryLimit_EnforcesLimit()
{
Expand Down

0 comments on commit f041d49

Please sign in to comment.