public async Task CreateFinalFileAsync_Deletes_Partial_Files_If_Configuration_Says_So() { // Use default constructor (implying cleanup = false) var store = new TusDiskStore(_fixture.Path); var p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); var p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue(); // Cleanup = true store = new TusDiskStore(_fixture.Path, true); p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeFalse(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeFalse(); // Assert that all files are gone (regression on bug) var p1Files = Directory.EnumerateFiles(_fixture.Path, p1 + "*"); p1Files.Any().ShouldBeFalse("Meta files for partial file 1 has not been deleted"); var p2Files = Directory.EnumerateFiles(_fixture.Path, p2 + "*"); p2Files.Any().ShouldBeFalse("Meta files for partial file 1 has not been deleted"); // Cleanup = false store = new TusDiskStore(_fixture.Path, false); p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); _ = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue(); }
public async Task CreateFinalFileAsync_Deletes_Partial_Files_If_Configuration_Says_So() { // Use default constructor. var store = new TusDiskStore(_fixture.Path); var p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); var p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); var f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); f.ShouldNotBeNullOrWhiteSpace(); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue(); // Cleanup = true store = new TusDiskStore(_fixture.Path, true); p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); p1.ShouldNotBeNullOrWhiteSpace(); p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); p2.ShouldNotBeNullOrWhiteSpace(); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); f.ShouldNotBeNullOrWhiteSpace(); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeFalse(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeFalse(); // Cleanup = false store = new TusDiskStore(_fixture.Path, false); p1 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); p2 = await store.CreatePartialFileAsync(1, null, CancellationToken.None); await store.AppendDataAsync(p1, new MemoryStream(new byte[] { 1 }), CancellationToken.None); await store.AppendDataAsync(p2, new MemoryStream(new byte[] { 2 }), CancellationToken.None); f = await store.CreateFinalFileAsync(new[] { p1, p2 }, null, CancellationToken.None); f.ShouldNotBeNullOrWhiteSpace(); (await store.FileExistAsync(p1, CancellationToken.None)).ShouldBeTrue(); (await store.FileExistAsync(p2, CancellationToken.None)).ShouldBeTrue(); }
public async Task AppendDataAsync_Uses_The_Read_And_Write_Buffers_Correctly(int readBufferSize, int writeBufferSize, int fileSize, int expectedNumberOfWrites, int expectedNumberOfReads) { int readsPerWrite = (int)Math.Ceiling((double)writeBufferSize / readBufferSize); var store = new TusDiskStore(_fixture.Path, false, new TusDiskBufferSize(writeBufferSize, readBufferSize)); var totalNumberOfWrites = 0; var totalNumberOfReads = 0; var numberOfReadsSinceLastWrite = 0; var firstWrite = true; int bytesWritten = 0; var fileId = await store.CreateFileAsync(fileSize, null, CancellationToken.None); var requestStream = new RequestStreamFake(async(RequestStreamFake stream, byte[] bufferToFill, int offset, int count, CancellationToken cancellationToken) => { count.ShouldBe(readBufferSize); numberOfReadsSinceLastWrite++; var bytesRead = await stream.ReadBackingStreamAsync(bufferToFill, offset, count, cancellationToken); // Need to subtract from readsPerWrite due to this expression being checked _after_ the write has happened. var previousReadShouldHaveTriggeredWrite = numberOfReadsSinceLastWrite == readsPerWrite - (firstWrite ? 0 : 1) + 1; if (bytesRead != 0 && previousReadShouldHaveTriggeredWrite) { numberOfReadsSinceLastWrite = 0; firstWrite = false; GetLengthFromFileOnDisk().ShouldBe(bytesWritten); totalNumberOfWrites++; } totalNumberOfReads++; bytesWritten += bytesRead; return(bytesRead); }, new byte[fileSize]); await store.AppendDataAsync(fileId, requestStream, CancellationToken.None); GetLengthFromFileOnDisk().ShouldBe(fileSize); totalNumberOfWrites++; // -1 due to the last read returning 0 bytes as the stream is then drained Assert.Equal(expectedNumberOfReads, totalNumberOfReads - 1); Assert.Equal(expectedNumberOfWrites, totalNumberOfWrites); long GetLengthFromFileOnDisk() { return(new FileInfo(Path.Combine(_fixture.Path, fileId)).Length); } }
public async Task CreateFileAsync_Throws_An_Exception_If_The_File_Id_Already_Exist() { var expectedFileId = Guid.NewGuid().ToString(); var nonUniqueFileIdProvider = Substitute.For <ITusFileIdProvider>(); nonUniqueFileIdProvider.CreateId(null).ReturnsForAnyArgs(expectedFileId); nonUniqueFileIdProvider.ValidateId(null).ReturnsForAnyArgs(true); var store = new TusDiskStore(_fixture.Path, false, TusDiskBufferSize.Default, nonUniqueFileIdProvider); var fileId = await store.CreateFileAsync(1, null, CancellationToken.None); fileId.ShouldBe(expectedFileId); await store.AppendDataAsync(fileId, new MemoryStream(new[] { (byte)1 }), CancellationToken.None); var filePath = Path.Combine(_fixture.Path, fileId); File.Exists(filePath).ShouldBeTrue(); new FileInfo(filePath).Length.ShouldBe(1); await Assert.ThrowsAnyAsync <Exception>(async() => await store.CreateFileAsync(1, null, CancellationToken.None)); File.Exists(filePath).ShouldBeTrue(); new FileInfo(filePath).Length.ShouldBe(1); }
public async Task AppendDataAsync_Uses_The_Read_And_Write_Buffers_Correctly(int readBufferSize, int writeBufferSize, int fileSize, int expectedNumberOfWrites, int expectedNumberOfReads) { int numberOfReadsPerWrite = (int)Math.Ceiling((double)writeBufferSize / readBufferSize); var store = new TusDiskStore(_fixture.Path, false, new TusDiskBufferSize(writeBufferSize, readBufferSize)); var totalNumberOfWrites = 0; var totalNumberOfReads = 0; var numberOfReadsSinceLastWrite = 0; int totalBytesWritten = 0; var fileId = await store.CreateFileAsync(fileSize, null, CancellationToken.None); var requestStream = new RequestStreamFake(async(RequestStreamFake stream, byte[] bufferToFill, int offset, int count, CancellationToken cancellationToken) => { count.ShouldBe(readBufferSize); var bytesReadFromStream = await stream.ReadBackingStreamAsync(bufferToFill, offset, count, cancellationToken); // There should have been a write after the previous read. if (numberOfReadsSinceLastWrite > numberOfReadsPerWrite) { // Calculate the amount of data that should have been written to disk so far. var expectedFileSizeRightNow = CalculateExpectedFileSize(totalNumberOfReads, readBufferSize, writeBufferSize); // Assert that the size on disk is correct. GetLengthFromFileOnDisk().ShouldBe(expectedFileSizeRightNow); totalNumberOfWrites++; // Set to one as the write happened on the previous write, making this the second read since that write. numberOfReadsSinceLastWrite = 1; } numberOfReadsSinceLastWrite++; totalNumberOfReads++; totalBytesWritten += bytesReadFromStream; return(bytesReadFromStream); }, new byte[fileSize]); await store.AppendDataAsync(fileId, requestStream, CancellationToken.None); GetLengthFromFileOnDisk().ShouldBe(fileSize); totalNumberOfWrites++; // -1 due to the last read returning 0 bytes as the stream is then drained Assert.Equal(expectedNumberOfReads, totalNumberOfReads - 1); Assert.Equal(expectedNumberOfWrites, totalNumberOfWrites); long GetLengthFromFileOnDisk() { return(new FileInfo(Path.Combine(_fixture.Path, fileId)).Length); } }