public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Verification_Fails_Using_Single_Chunk() { // Checksum is for "hello world" const string incorrectChecksum = "Kq5sNclPz7QV2+lfQIuc6R7oRu0="; const string message = "Hello World 12345!!@@åäö"; var buffer = new UTF8Encoding(false).GetBytes(message); var bytesWritten = 0L; var fileId = await _fixture.Store.CreateFileAsync(buffer.Length, null, CancellationToken.None); // Emulate several requests do { // Create a new store and cancellation token source on each request as one would do in a real scenario. _fixture.CreateNewStore(); var cts = new CancellationTokenSource(); var requestStream = new RequestStreamFake( (stream, bufferToFill, offset, count, ct) => { // Emulate that the request completed if (bytesWritten == buffer.Length) { return(Task.FromResult(0)); } // Emulate client disconnect after two bytes read. if (stream.Position == 2) { cts.Cancel(); cts.Token.ThrowIfCancellationRequested(); } bytesWritten += 2; return(stream.ReadBackingStreamAsync(bufferToFill, offset, 2, ct)); }, buffer.Skip((int)bytesWritten).ToArray()); await ClientDisconnectGuard.ExecuteAsync( () => _fixture.Store.AppendDataAsync(fileId, requestStream, cts.Token), cts.Token); } while (bytesWritten < buffer.Length); var checksumOk = await _fixture.Store .VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(incorrectChecksum), CancellationToken.None); // File should not have been saved. checksumOk.ShouldBeFalse(); var filePath = Path.Combine(_fixture.Path, fileId); new FileInfo(filePath).Length.ShouldBe(0); }
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); } }
public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Verification_Fails_Using_Multiple_Chunks() { var chunks = new[] { new Tuple <string, string, bool>("Hello ", "lka6E6To6r7KT1JZv9faQdNooaY=", true), new Tuple <string, string, bool> ("World ", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", true), new Tuple <string, string, bool> ("12345!!@@åäö", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", false) }; var encoding = new UTF8Encoding(false); var totalSize = 0; var fileId = await _fixture.Store.CreateFileAsync(chunks.Sum(f => encoding.GetBytes(f.Item1).Length), null, CancellationToken.None); foreach (var chunk in chunks) { var data = chunk.Item1; var checksum = chunk.Item2; var isValidChecksum = chunk.Item3; var dataBuffer = encoding.GetBytes(data); var bytesWritten = 0L; // Emulate several requests do { // Create a new store and cancellation token source on each request as one would do in a real scenario. _fixture.CreateNewStore(); var cts = new CancellationTokenSource(); var buffer = new RequestStreamFake( (stream, bufferToFill, offset, count, ct) => { // Emulate that the request completed if (bytesWritten == dataBuffer.Length) { return(Task.FromResult(0)); } // Emulate client disconnect after two bytes read. if (stream.Position == 2) { cts.Cancel(); cts.Token.ThrowIfCancellationRequested(); } bytesWritten += 2; return(stream.ReadBackingStreamAsync(bufferToFill, offset, 2, ct)); }, dataBuffer.Skip((int)bytesWritten).ToArray()); await ClientDisconnectGuard.ExecuteAsync( () => _fixture.Store.AppendDataAsync(fileId, buffer, cts.Token), cts.Token); } while (bytesWritten < dataBuffer.Length); var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(checksum), CancellationToken.None); checksumOk.ShouldBe(isValidChecksum); totalSize += isValidChecksum ? dataBuffer.Length : 0; } var filePath = Path.Combine(_fixture.Path, fileId); new FileInfo(filePath).Length.ShouldBe(totalSize); }