Skip to content

Commit 35abc67

Browse files
committed
handle exceptions and fix UTs
1 parent 4bd6855 commit 35abc67

File tree

2 files changed

+28
-28
lines changed

2 files changed

+28
-28
lines changed

Tests.Vpn.Service/DownloaderTest.cs

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -375,17 +375,17 @@ public async Task DownloadExistingDifferentContent(CancellationToken ct)
375375

376376
[Test(Description = "Unexpected response code from server")]
377377
[CancelAfter(30_000)]
378-
public void UnexpectedResponseCode(CancellationToken ct)
378+
public async Task UnexpectedResponseCode(CancellationToken ct)
379379
{
380380
using var httpServer = new TestHttpServer(ctx => { ctx.Response.StatusCode = 404; });
381381
var url = new Uri(httpServer.BaseUrl + "/test");
382382
var destPath = Path.Combine(_tempDir, "test");
383383

384384
var manager = new Downloader(NullLogger<Downloader>.Instance);
385-
// The "outer" Task should fail.
386-
var ex = Assert.ThrowsAsync<HttpRequestException>(async () =>
387-
await manager.StartDownloadAsync(new HttpRequestMessage(HttpMethod.Get, url), destPath,
388-
NullDownloadValidator.Instance, ct));
385+
// The "inner" Task should fail.
386+
var dlTask = await manager.StartDownloadAsync(new HttpRequestMessage(HttpMethod.Get, url), destPath,
387+
NullDownloadValidator.Instance, ct);
388+
var ex = Assert.ThrowsAsync<HttpRequestException>(async () => await dlTask.Task);
389389
Assert.That(ex.Message, Does.Contain("404"));
390390
}
391391

@@ -412,22 +412,6 @@ public async Task MismatchedETag(CancellationToken ct)
412412
Assert.That(ex.Message, Does.Contain("ETag does not match SHA1 hash of downloaded file").And.Contains("beef"));
413413
}
414414

415-
[Test(Description = "Timeout on response headers")]
416-
[CancelAfter(30_000)]
417-
public void CancelledOuter(CancellationToken ct)
418-
{
419-
using var httpServer = new TestHttpServer(async _ => { await Task.Delay(TimeSpan.FromSeconds(5), ct); });
420-
var url = new Uri(httpServer.BaseUrl + "/test");
421-
var destPath = Path.Combine(_tempDir, "test");
422-
423-
var manager = new Downloader(NullLogger<Downloader>.Instance);
424-
// The "outer" Task should fail.
425-
var smallerCt = new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token;
426-
Assert.ThrowsAsync<TaskCanceledException>(async () => await manager.StartDownloadAsync(
427-
new HttpRequestMessage(HttpMethod.Get, url), destPath,
428-
NullDownloadValidator.Instance, smallerCt));
429-
}
430-
431415
[Test(Description = "Timeout on response body")]
432416
[CancelAfter(30_000)]
433417
public async Task CancelledInner(CancellationToken ct)
@@ -479,12 +463,10 @@ public async Task ValidationFailureExistingFile(CancellationToken ct)
479463
await File.WriteAllTextAsync(destPath, "test", ct);
480464

481465
var manager = new Downloader(NullLogger<Downloader>.Instance);
466+
var dlTask = await manager.StartDownloadAsync(new HttpRequestMessage(HttpMethod.Get, url), destPath,
467+
new TestDownloadValidator(new Exception("test exception")), ct);
482468
// The "outer" Task should fail because the inner task never starts.
483-
var ex = Assert.ThrowsAsync<Exception>(async () =>
484-
{
485-
await manager.StartDownloadAsync(new HttpRequestMessage(HttpMethod.Get, url), destPath,
486-
new TestDownloadValidator(new Exception("test exception")), ct);
487-
});
469+
var ex = Assert.ThrowsAsync<Exception>(async () => { await dlTask.Task; });
488470
Assert.That(ex.Message, Does.Contain("Existing file failed validation"));
489471
Assert.That(ex.InnerException, Is.Not.Null);
490472
Assert.That(ex.InnerException!.Message, Is.EqualTo("test exception"));

Vpn.Service/Downloader.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Formats.Asn1;
44
using System.Net;
55
using System.Runtime.CompilerServices;
6+
using System.Runtime.ExceptionServices;
67
using System.Security.Cryptography;
78
using System.Security.Cryptography.X509Certificates;
89
using Coder.Desktop.Vpn.Utilities;
@@ -290,7 +291,24 @@ public async Task<DownloadTask> StartDownloadAsync(HttpRequestMessage req, strin
290291
_ => new DownloadTask(_logger, req, destinationPath, validator));
291292
// EnsureStarted is a no-op if we didn't create a new DownloadTask.
292293
// So, we will only remove the destination once for each time we start a new task.
293-
task.EnsureStarted(tsk => _downloads.TryRemove(destinationPath, out _), ct);
294+
task.EnsureStarted(tsk =>
295+
{
296+
// remove the key first, before checking the exception, to ensure
297+
// we still clean up.
298+
_downloads.TryRemove(destinationPath, out _);
299+
if (tsk.Exception == null)
300+
{
301+
return;
302+
}
303+
304+
if (tsk.Exception.InnerException != null)
305+
{
306+
ExceptionDispatchInfo.Capture(tsk.Exception.InnerException).Throw();
307+
}
308+
309+
// not sure if this is hittable, but just in case:
310+
throw tsk.Exception;
311+
}, ct);
294312

295313
// If the existing (or new) task is for the same URL, return it.
296314
if (task.Request.RequestUri == req.RequestUri)
@@ -363,7 +381,7 @@ internal void EnsureStarted(Action<Task> continuation, CancellationToken ct = de
363381
{
364382
using var _ = _semaphore.Lock();
365383
if (Task == null!)
366-
Task = Start(ct).ContinueWith(continuation, CancellationToken.None);
384+
Task = Start(ct).ContinueWith(continuation, ct);
367385
}
368386

369387
/// <summary>

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy