public void TestUploadProgress() { int chunkSize = 200; var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(true, ServerError.None, payload.Length, chunkSize); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = new MemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.ChunkSize = chunkSize; var progressEvents = new List <IUploadProgress>(); upload.ProgressChanged += (progress) => { progressEvents.Add(progress); }; upload.Upload(); // Starting (1) + Uploading (2) + Completed (1) Assert.That(progressEvents.Count, Is.EqualTo(4)); Assert.That(progressEvents[0].Status, Is.EqualTo(UploadStatus.Starting)); Assert.That(progressEvents[1].Status, Is.EqualTo(UploadStatus.Uploading)); Assert.That(progressEvents[2].Status, Is.EqualTo(UploadStatus.Uploading)); Assert.That(progressEvents[3].Status, Is.EqualTo(UploadStatus.Completed)); } }
public void Download_Error_PlaintextResponse(string responseText) { var downloadUri = "http://www.sample.com"; var chunkSize = 100; var handler = new MultipleChunksMessageHandler { ErrorResponse = responseText }; handler.StatusCode = HttpStatusCode.NotFound; handler.ChunkSize = chunkSize; // The media downloader adds the parameter... handler.DownloadUri = new Uri(downloadUri + "?alt=media"); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList <IDownloadProgress> progressList = new List <IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); downloader.Download(downloadUri, outputStream); var lastProgress = progressList.LastOrDefault(); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); GoogleApiException exception = (GoogleApiException)lastProgress.Exception; Assert.That(exception.HttpStatusCode, Is.EqualTo(handler.StatusCode)); Assert.That(exception.Message, Is.EqualTo(responseText)); Assert.IsNull(exception.Error); } }
/// <summary> Test helper to test a fail uploading by with the given server error.</summary> private void SubtestChunkUploadFail(ServerError error) { int chunkSize = 100; var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(true, error, payload.Length, chunkSize, true); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = new MemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.ChunkSize = chunkSize; IUploadProgress lastProgressStatus = null; upload.ProgressChanged += (p) => { lastProgressStatus = p; }; upload.Upload(); var exepctedCalls = MultipleChunksMessageHandler.ErrorOnCall + service.HttpClient.MessageHandler.NumTries - 1; Assert.That(handler.Calls, Is.EqualTo(exepctedCalls)); Assert.NotNull(lastProgressStatus); Assert.NotNull(lastProgressStatus.Exception); Assert.That(lastProgressStatus.Status, Is.EqualTo(UploadStatus.Failed)); } }
/// <summary> Helper test to test canceling media upload in the middle.</summary> /// <param name="cancelRequest">The request index to cancel.</param> private void TestChunkUploadFail_Cancel(int cancelRequest) { int chunkSize = 100; var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(true, ServerError.None, payload.Length, chunkSize, false); handler.CancellationTokenSource = new CancellationTokenSource(); handler.CancelRequestNum = cancelRequest; using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = new MemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.ChunkSize = chunkSize; try { var result = upload.UploadAsync(handler.CancellationTokenSource.Token).Result; Assert.Fail(); } catch (AggregateException ae) { Assert.IsInstanceOf <TaskCanceledException>(ae.InnerException); } Assert.That(handler.Calls, Is.EqualTo(cancelRequest)); } }
public void Download_Error() { var downloadUri = "http://www.sample.com?alt=media"; var chunkSize = 100; // reset the steam StreamContent.Position = 0; var handler = new MultipleChunksMessageHandler(); handler.StatusCode = HttpStatusCode.BadRequest; handler.ChunkSize = chunkSize; handler.DownloadUri = new Uri(downloadUri); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList <IDownloadProgress> progressList = new List <IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); downloader.Download(downloadUri, outputStream); var lastProgress = progressList.LastOrDefault(); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); } }
private void SubtestTestChunkUpload(bool knownSize, ServerError error = ServerError.None) { // -If error is none - there isn't any error, so there should be 6 calls (1 to initialize and 5 successful // upload requests. // -If error isn't supported by the media upload (4xx) - the upload fails. // Otherwise, we simulate server 503 error or exception, as following: // On the 4th chunk (when server received bytes 300-399), we mimic an error. // In the next request we expect the client to send the content range header with "bytes */[size]", and // server return that the upload was interrupted after 299 bytes. From that point the server works as // expected, and received the last chunks successfully int chunkSize = 100; var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(knownSize, error, payload.Length, chunkSize); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = knownSize ? new MemoryStream(payload) : new UnknownSizeMemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.ChunkSize = chunkSize; IUploadProgress lastProgress = null; upload.ProgressChanged += (p) => lastProgress = p; upload.Upload(); Assert.NotNull(lastProgress); if (error == ServerError.NotFound) { // upload fails Assert.That(lastProgress.Status, Is.EqualTo(UploadStatus.Failed)); Assert.That(handler.Calls, Is.EqualTo(MultipleChunksMessageHandler.ErrorOnCall)); Assert.True(lastProgress.Exception.Message.Contains( @"Message[Login Required] Location[Authorization - header] Reason[required] Domain[global]"), "Error message is invalid"); } else { Assert.That(lastProgress.Status, Is.EqualTo(UploadStatus.Completed)); Assert.That(payload, Is.EqualTo(handler.ReceivedData.ToArray())); // if server doesn't supports errors there should be 6 request - 1 initialize request and 5 // requests to upload data (the whole data send is divided to 5 chunks). // if server supports errors, there should be an additional 2 requests (1 to query where the upload // was interrupted and 1 to resend the data) Assert.That(handler.Calls, error != ServerError.None ? Is.EqualTo(8) : Is.EqualTo(6)); } } }
/// <summary>Test helper to test a fail uploading by with the given server error.</summary> /// <param name="error">The error kind.</param> /// <param name="resume">Whether we should resume uploading the stream after the failure.</param> /// <param name="errorOnResume">Whether the first call after resuming should fail.</param> private void SubtestChunkUploadFail(ServerError error, bool resume = false, bool errorOnResume = false) { int chunkSize = 100; var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(true, error, payload.Length, chunkSize, true); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = new MemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.chunkSize = chunkSize; IUploadProgress lastProgressStatus = null; upload.ProgressChanged += (p) => { lastProgressStatus = p; }; upload.Upload(); // Upload should fail. var exepctedCalls = MultipleChunksMessageHandler.ErrorOnCall + service.HttpClient.MessageHandler.NumTries - 1; Assert.That(handler.Calls, Is.EqualTo(exepctedCalls)); Assert.NotNull(lastProgressStatus); Assert.NotNull(lastProgressStatus.Exception); Assert.That(lastProgressStatus.Status, Is.EqualTo(UploadStatus.Failed)); if (resume) { // Hack the handler, so when calling the resume method the upload should succeeded. handler.ResumeFromCall = exepctedCalls + 1; handler.ErrorOnResume = errorOnResume; upload.Resume(); // The first request after resuming is to query the server where the media upload was interrupted. // If errorOnResume is true, the server's first response will be 503. exepctedCalls += MultipleChunksMessageHandler.CallAfterResume + 1 + (errorOnResume ? 1 : 0); Assert.That(handler.Calls, Is.EqualTo(exepctedCalls)); Assert.NotNull(lastProgressStatus); Assert.Null(lastProgressStatus.Exception); Assert.That(lastProgressStatus.Status, Is.EqualTo(UploadStatus.Completed)); Assert.That(payload, Is.EqualTo(handler.ReceivedData.ToArray())); } } }
public void Download_Error_JsonResponse() { var downloadUri = "http://www.sample.com"; var chunkSize = 100; var error = new RequestError { Code = 12345, Message = "Text", Errors = new[] { new SingleError { Message = "Nested error" } } }; var response = new StandardResponse <object> { Error = error }; var responseText = new NewtonsoftJsonSerializer().Serialize(response); var handler = new MultipleChunksMessageHandler { ErrorResponse = responseText }; handler.StatusCode = HttpStatusCode.BadRequest; handler.ChunkSize = chunkSize; // The media downloader adds the parameter... handler.DownloadUri = new Uri(downloadUri + "?alt=media"); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList <IDownloadProgress> progressList = new List <IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); downloader.Download(downloadUri, outputStream); var lastProgress = progressList.LastOrDefault(); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); GoogleApiException exception = (GoogleApiException)lastProgress.Exception; Assert.That(exception.HttpStatusCode, Is.EqualTo(handler.StatusCode)); // Just a smattering of checks - if these two pass, it's surely okay. Assert.That(exception.Error.Code, Is.EqualTo(error.Code)); Assert.That(exception.Error.Errors[0].Message, Is.EqualTo(error.Errors[0].Message)); } }
/// <summary>Tests a single upload request.</summary> /// <param name="knownSize">Defines if the stream size is known</param> /// <param name="expectedCalls">How many HTTP calls should be made to the server</param> /// <param name="error">Defines the type of error this test tests. The default value is none</param> /// <param name="chunkSize">Defines the size of a chunk</param> /// <param name="readBytesOnError">How many bytes the server reads when it returns 5xx</param> private void SubtestTestChunkUpload(bool knownSize, int expectedCalls, ServerError error = ServerError.None, int chunkSize = 100, int readBytesOnError = 0) { // If an error isn't supported by the media upload (4xx) - the upload fails. // Otherwise, we simulate server 503 error or exception, as following: // On the 3th chunk (4th chunk including the initial request), we mimic an error. // In the next request we expect the client to send the content range header with "bytes */[size]", and // server return that the upload was interrupted after x bytes. // From that point the server works as expected, and received the last chunks successfully var payload = Encoding.UTF8.GetBytes(UploadTestData); var handler = new MultipleChunksMessageHandler(knownSize, error, payload.Length, chunkSize); handler.ReadBytesOnError = readBytesOnError; using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var stream = knownSize ? new MemoryStream(payload) : new UnknownSizeMemoryStream(payload); var upload = new MockResumableUpload(service, stream, "text/plain"); upload.chunkSize = chunkSize; IUploadProgress lastProgress = null; upload.ProgressChanged += (p) => lastProgress = p; upload.Upload(); Assert.NotNull(lastProgress); if (error == ServerError.NotFound) { // Upload fails. Assert.That(lastProgress.Status, Is.EqualTo(UploadStatus.Failed)); Assert.True(lastProgress.Exception.Message.Contains( @"Message[Login Required] Location[Authorization - header] Reason[required] Domain[global]"), "Error message is invalid"); } else { Assert.That(lastProgress.Status, Is.EqualTo(UploadStatus.Completed)); Assert.That(payload, Is.EqualTo(handler.ReceivedData.ToArray())); } Assert.That(handler.Calls, Is.EqualTo(expectedCalls)); } }
/// <summary>A helper test to test sync and async downloads.</summary> /// <param name="chunkSize">The chunk size for each part.</param> /// <param name="sync">Indicates if this download should be synchronously or asynchronously.</param> /// <param name="cancelRequest">Defines the request index to cancel the download request.</param> /// <param name="downloadUri">The URI which contains the media to download.</param> private void Subtest_Download_Chunks(int chunkSize, bool sync = true, int cancelRequest = 0, string downloadUri = "http://www.sample.com") { var handler = new MultipleChunksMessageHandler(MediaContent); handler.StatusCode = HttpStatusCode.OK; handler.ChunkSize = chunkSize; handler.DownloadUri = new Uri(downloadUri + (downloadUri.Contains("?") ? "&" : "?") + "alt=media"); // support cancellation if (cancelRequest > 0) { handler.CancelRequestNum = cancelRequest; } handler.CancellationTokenSource = new CancellationTokenSource(); int expectedCalls = (int)Math.Ceiling((double)MediaContent.Length / chunkSize); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList <IDownloadProgress> progressList = new List <IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); if (sync) { downloader.Download(downloadUri, outputStream); } else { try { var result = downloader.DownloadAsync(downloadUri, outputStream, handler.CancellationTokenSource.Token).Result; Assert.AreEqual(0, handler.CancelRequestNum); } catch (AggregateException ex) { Assert.IsInstanceOf <TaskCanceledException>(ex.InnerException); } } var lastProgress = progressList.LastOrDefault(); if (cancelRequest > 0) { // the download was interrupted in the middle Assert.That(handler.Calls, Is.EqualTo(cancelRequest)); // last request should fail Assert.NotNull(lastProgress); Assert.NotNull(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(chunkSize * cancelRequest)); } else { // the download succeeded Assert.That(handler.Calls, Is.EqualTo(expectedCalls)); Assert.NotNull(lastProgress); Assert.Null(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Completed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(MediaContent.Length)); byte[] actual = outputStream.ToArray(); CollectionAssert.AreEqual(MediaContent, actual); } } }
public void Download_Error_PlaintextResponse() { var downloadUri = "http://www.sample.com"; var chunkSize = 100; var responseText = "Not Found"; var handler = new MultipleChunksMessageHandler { ErrorResponse = responseText }; handler.StatusCode = HttpStatusCode.NotFound; handler.ChunkSize = chunkSize; // The media downloader adds the parameter... handler.DownloadUri = new Uri(downloadUri + "?alt=media"); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList<IDownloadProgress> progressList = new List<IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); downloader.Download(downloadUri, outputStream); var lastProgress = progressList.LastOrDefault(); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); GoogleApiException exception = (GoogleApiException) lastProgress.Exception; Assert.That(exception.HttpStatusCode, Is.EqualTo(handler.StatusCode)); Assert.That(exception.Message, Is.EqualTo(responseText)); Assert.IsNull(exception.Error); } }
public void Download_Error_JsonResponse() { var downloadUri = "http://www.sample.com"; var chunkSize = 100; var error = new RequestError { Code = 12345, Message = "Text", Errors = new[] { new SingleError { Message = "Nested error" } } }; var response = new StandardResponse<object> { Error = error }; var responseText = new NewtonsoftJsonSerializer().Serialize(response); var handler = new MultipleChunksMessageHandler { ErrorResponse = responseText }; handler.StatusCode = HttpStatusCode.BadRequest; handler.ChunkSize = chunkSize; // The media downloader adds the parameter... handler.DownloadUri = new Uri(downloadUri + "?alt=media"); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList<IDownloadProgress> progressList = new List<IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); downloader.Download(downloadUri, outputStream); var lastProgress = progressList.LastOrDefault(); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); GoogleApiException exception = (GoogleApiException) lastProgress.Exception; Assert.That(exception.HttpStatusCode, Is.EqualTo(handler.StatusCode)); // Just a smattering of checks - if these two pass, it's surely okay. Assert.That(exception.Error.Code, Is.EqualTo(error.Code)); Assert.That(exception.Error.Errors[0].Message, Is.EqualTo(error.Errors[0].Message)); } }
/// <summary>A helper test to test sync and async downloads.</summary> /// <param name="chunkSize">The chunk size for each part.</param> /// <param name="sync">Indicates if this download should be synchronously or asynchronously.</param> /// <param name="cancelRequest">Defines the request index to cancel the download request.</param> /// <param name="downloadUri">The URI which contains the media to download.</param> private void Subtest_Download_Chunks(int chunkSize, bool sync = true, int cancelRequest = 0, string downloadUri = "http://www.sample.com") { var handler = new MultipleChunksMessageHandler(MediaContent); handler.StatusCode = HttpStatusCode.OK; handler.ChunkSize = chunkSize; handler.DownloadUri = new Uri(downloadUri + (downloadUri.Contains("?") ? "&" : "?") + "alt=media"); // support cancellation if (cancelRequest > 0) { handler.CancelRequestNum = cancelRequest; } handler.CancellationTokenSource = new CancellationTokenSource(); int expectedCalls = (int)Math.Ceiling((double) MediaContent.Length / chunkSize); using (var service = CreateMockClientService(handler)) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList<IDownloadProgress> progressList = new List<IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); if (sync) { downloader.Download(downloadUri, outputStream); } else { try { var result = downloader.DownloadAsync(downloadUri, outputStream, handler.CancellationTokenSource.Token).Result; Assert.AreEqual(0, handler.CancelRequestNum); } catch (AggregateException ex) { Assert.IsInstanceOf<TaskCanceledException>(ex.InnerException); } } var lastProgress = progressList.LastOrDefault(); if (cancelRequest > 0) { // the download was interrupted in the middle Assert.That(handler.Calls, Is.EqualTo(cancelRequest)); // last request should fail Assert.NotNull(lastProgress); Assert.NotNull(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(chunkSize * cancelRequest)); } else { // the download succeeded Assert.That(handler.Calls, Is.EqualTo(expectedCalls)); Assert.NotNull(lastProgress); Assert.Null(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Completed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(MediaContent.Length)); byte[] actual = outputStream.ToArray(); CollectionAssert.AreEqual(MediaContent, actual); } } }
/// <summary>A helper test to test sync and async downloads.</summary> /// <param name="chunkSize">The chunk size for each part.</param> /// <param name="sync">Indicates if this download should be synchronously or asynchronously.</param> /// <param name="cancelRequest">Defines the request index to cancel the download request.</param> private void Subtest_Download_Chunks(int chunkSize, bool sync = true, int cancelRequest = 0) { // reset the steam StreamContent.Position = 0; string downloadUri = "http://www.sample.com"; var handler = new MultipleChunksMessageHandler(); handler.ChunkSize = chunkSize; handler.DownloadUri = new Uri(downloadUri + "?alt=media"); // support cancellation if (cancelRequest > 0) { handler.CancelRequestNum = cancelRequest; } handler.CancellationTokenSource = new CancellationTokenSource(); int expectedCalls = (int)Math.Ceiling((double)StreamContent.Length / chunkSize); using (var service = new MockClientService(new BaseClientService.Initializer() { HttpClientFactory = new MockHttpClientFactory(handler) })) { var downloader = new MediaDownloader(service); downloader.ChunkSize = chunkSize; IList <IDownloadProgress> progressList = new List <IDownloadProgress>(); downloader.ProgressChanged += (p) => { progressList.Add(p); }; var outputStream = new MemoryStream(); if (sync) { downloader.Download(downloadUri, outputStream); Assert.AreEqual(handler.ThreadId, Thread.CurrentThread.ManagedThreadId); } else { var task = downloader.DownloadAsync(downloadUri, outputStream, handler.CancellationTokenSource.Token); try { task.Wait(); Assert.AreEqual(cancelRequest, 0); } catch (AggregateException ex) { Assert.That(ex.InnerException, Is.InstanceOf <TaskCanceledException>()); Assert.AreNotEqual(cancelRequest, 0); } Assert.AreNotEqual(handler.ThreadId, Thread.CurrentThread.ManagedThreadId); } var lastProgress = progressList.LastOrDefault(); if (cancelRequest > 0) { // the download was interrupted in the middle Assert.That(handler.Calls, Is.EqualTo(cancelRequest)); // last request should be failed Assert.NotNull(lastProgress); Assert.NotNull(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Failed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(chunkSize * cancelRequest)); } else { // the download succeeded Assert.That(handler.Calls, Is.EqualTo(expectedCalls)); Assert.NotNull(lastProgress); Assert.Null(lastProgress.Exception); Assert.That(lastProgress.Status, Is.EqualTo(DownloadStatus.Completed)); Assert.That(lastProgress.BytesDownloaded, Is.EqualTo(StreamContent.Length)); byte[] read = new byte[1000]; outputStream.Position = 0; int length = outputStream.Read(read, 0, 1000); Assert.That(Encoding.UTF8.GetString(read, 0, length), Is.EqualTo(MediaContent)); } } }