// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.TestCommon; using Moq; namespace System.Net.Http.Handlers { public class ProgressStreamTest { [Fact] public async Task Read_ReportsBytesRead() { // Arrange HttpResponseMessage response = CreateResponse(); Stream innerStream = await response.Content.ReadAsStreamAsync(); long? expectedLength = response.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: false); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, response: response); // Act/Assert int totalBytesRead = 0; int bytesRead = 0; do { byte[] buffer = new byte[8]; bytesRead = progressStream.Read(buffer, 0, buffer.Length); totalBytesRead += bytesRead; Assert.Equal(totalBytesRead, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesRead) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } while (bytesRead > 0); Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } [Fact] public async Task ReadByte_ReportsBytesRead() { // Arrange HttpResponseMessage response = CreateResponse(); Stream innerStream = await response.Content.ReadAsStreamAsync(); long? expectedLength = response.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: false); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, response: response); // Act/Assert int totalBytesRead = 0; while (progressStream.ReadByte() != -1) { totalBytesRead += 1; Assert.Equal(totalBytesRead, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesRead) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } #if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries [Fact] public async Task BeginEndRead_ReportsBytesRead() { // Arrange HttpResponseMessage response = CreateResponse(); Stream innerStream = await response.Content.ReadAsStreamAsync(); long? expectedLength = response.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: false); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, response: response); object userState = new object(); // Act/Assert int totalBytesRead = 0; int bytesRead = 0; do { byte[] buffer = new byte[8]; IAsyncResult result = progressStream.BeginRead(buffer, 0, buffer.Length, null, userState); bytesRead = progressStream.EndRead(result); totalBytesRead += bytesRead; Assert.Same(userState, mockProgressEventHandler.EventArgs.UserState); Assert.Equal(totalBytesRead, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesRead) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } while (bytesRead > 0); Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } #endif [Fact] public async Task ReadAsync_ReportsBytesRead() { // Arrange HttpResponseMessage response = CreateResponse(); Stream innerStream = await response.Content.ReadAsStreamAsync(); long? expectedLength = response.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: false); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, response: response); object userState = new object(); // Act/Assert int totalBytesRead = 0; int bytesRead = 0; do { byte[] buffer = new byte[8]; bytesRead = await progressStream.ReadAsync(buffer, 0, buffer.Length); totalBytesRead += bytesRead; Assert.Equal(totalBytesRead, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesRead) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } while (bytesRead > 0); Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } [Fact] public void Write_ReportsBytesWritten() { // Arrange HttpRequestMessage request = CreateRequest(); Stream innerStream = new MemoryStream(); byte[] buffer = CreateBufferContent(); long? expectedLength = request.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: true); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, request: request); // Act/Assert int totalBytesWritten = 0; int bytesWritten = 0; while (totalBytesWritten < expectedLength) { bytesWritten = Math.Min(8, (int)expectedLength - totalBytesWritten); progressStream.Write(buffer, totalBytesWritten, bytesWritten); totalBytesWritten += bytesWritten; Assert.Equal(totalBytesWritten, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesWritten) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } [Fact] public void WriteByte_ReportsBytesWritten() { // Arrange HttpRequestMessage request = CreateRequest(); Stream innerStream = new MemoryStream(); byte[] buffer = CreateBufferContent(); long? expectedLength = request.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: true); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, request: request); // Act/Assert int totalBytesWritten = 0; while (totalBytesWritten < expectedLength) { progressStream.WriteByte(buffer[totalBytesWritten]); totalBytesWritten += 1; Assert.Equal(totalBytesWritten, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesWritten) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } #if !NETFX_CORE // BeginX and EndX not supported on Streams in portable libraries [Fact] public void BeginEndWrite_ReportsBytesWritten() { // Arrange using (ManualResetEvent writeComplete = new ManualResetEvent(false)) { HttpRequestMessage request = CreateRequest(); Stream innerStream = new MemoryStream(); byte[] buffer = CreateBufferContent(); long? expectedLength = request.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: true); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, request: request); object userState = new object(); // Act/Assert int totalBytesWritten = 0; int bytesWritten = 0; while (totalBytesWritten < expectedLength) { bytesWritten = Math.Min(8, (int)expectedLength - totalBytesWritten); IAsyncResult result = progressStream.BeginWrite(buffer, totalBytesWritten, bytesWritten, ia => { progressStream.EndWrite(ia); writeComplete.Set(); }, userState); writeComplete.WaitOne(); writeComplete.Reset(); totalBytesWritten += bytesWritten; Assert.Same(userState, mockProgressEventHandler.EventArgs.UserState); Assert.Equal(totalBytesWritten, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesWritten) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } } #endif [Fact] public async Task WriteAsync_ReportsBytesWritten() { // Arrange using (ManualResetEvent writeComplete = new ManualResetEvent(false)) { HttpRequestMessage request = CreateRequest(); Stream innerStream = new MemoryStream(); byte[] buffer = CreateBufferContent(); long? expectedLength = request.Content.Headers.ContentLength; MockProgressEventHandler mockProgressEventHandler; ProgressMessageHandler progressMessageHandler = MockProgressEventHandler.CreateProgressMessageHandler(out mockProgressEventHandler, sendProgress: true); ProgressStream progressStream = CreateProgressStream(innerStream: innerStream, progressMessageHandler: progressMessageHandler, request: request); object userState = new object(); // Act/Assert int totalBytesWritten = 0; int bytesWritten = 0; while (totalBytesWritten < expectedLength) { bytesWritten = Math.Min(8, (int)expectedLength - totalBytesWritten); await progressStream.WriteAsync(buffer, totalBytesWritten, bytesWritten); totalBytesWritten += bytesWritten; Assert.Equal(totalBytesWritten, mockProgressEventHandler.EventArgs.BytesTransferred); Assert.Equal((100L * totalBytesWritten) / expectedLength, mockProgressEventHandler.EventArgs.ProgressPercentage); } Assert.Equal(expectedLength, mockProgressEventHandler.EventArgs.TotalBytes); Assert.Equal(100, mockProgressEventHandler.EventArgs.ProgressPercentage); } } internal static ProgressStream CreateProgressStream( Stream innerStream = null, ProgressMessageHandler progressMessageHandler = null, HttpRequestMessage request = null, HttpResponseMessage response = null) { Stream iStream = innerStream ?? new Mock().Object; ProgressMessageHandler pHandler = progressMessageHandler ?? new ProgressMessageHandler(); HttpRequestMessage req = request ?? new HttpRequestMessage(); HttpResponseMessage rsp = response ?? new HttpResponseMessage(); return new ProgressStream(iStream, pHandler, req, rsp); } private static HttpRequestMessage CreateRequest() { return new HttpRequestMessage { Content = CreateStringContent() }; } private static HttpResponseMessage CreateResponse() { return new HttpResponseMessage { Content = CreateStringContent() }; } private static String CreateContent() { StringBuilder content = new StringBuilder(); for (int count = 0; count < 100; count++) { content.Append("1234567890"); } return content.ToString(); } private static HttpContent CreateStringContent() { return new StringContent(CreateContent()); } private static byte[] CreateBufferContent() { return Encoding.UTF8.GetBytes(CreateContent()); } } }