Allow to override download client

Towards #2331
This commit is contained in:
Bogdan 2024-01-13 00:27:53 +02:00
parent e968fcaff6
commit d23ce9ecc2
7 changed files with 35 additions and 30 deletions

View file

@ -68,7 +68,7 @@ public async Task should_download_report_if_book_was_not_already_downloaded()
decisions.Add(new DownloadDecision(remoteBook));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>(), null), Times.Once());
}
[Test]
@ -82,7 +82,7 @@ public async Task should_only_download_book_once()
decisions.Add(new DownloadDecision(remoteBook));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>(), null), Times.Once());
}
[Test]
@ -101,7 +101,7 @@ public async Task should_not_download_if_any_book_was_already_downloaded()
decisions.Add(new DownloadDecision(remoteBook2));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>(), null), Times.Once());
}
[Test]
@ -172,7 +172,7 @@ public async Task should_not_add_to_downloaded_list_when_download_fails()
var decisions = new List<DownloadDecision>();
decisions.Add(new DownloadDecision(remoteBook));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteBook>())).Throws(new Exception());
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteBook>(), null)).Throws(new Exception());
var result = await Subject.ProcessDecisions(decisions);
@ -201,7 +201,7 @@ public async Task should_not_grab_if_pending()
decisions.Add(new DownloadDecision(remoteBook, new Rejection("Failure!", RejectionType.Temporary)));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>()), Times.Never());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>(), null), Times.Never());
}
[Test]
@ -242,11 +242,11 @@ public async Task should_add_to_failed_if_already_failed_for_that_protocol()
decisions.Add(new DownloadDecision(remoteBook));
decisions.Add(new DownloadDecision(remoteBook));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteBook>()))
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.IsAny<RemoteBook>(), null))
.Throws(new DownloadClientUnavailableException("Download client failed"));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>()), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.IsAny<RemoteBook>(), null), Times.Once());
}
[Test]
@ -260,12 +260,12 @@ public async Task should_not_add_to_failed_if_failed_for_a_different_protocol()
decisions.Add(new DownloadDecision(remoteBook));
decisions.Add(new DownloadDecision(remoteBook2));
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)))
Mocker.GetMock<IDownloadService>().Setup(s => s.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet), null))
.Throws(new DownloadClientUnavailableException("Download client failed"));
await Subject.ProcessDecisions(decisions);
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet)), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Torrent)), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Usenet), null), Times.Once());
Mocker.GetMock<IDownloadService>().Verify(v => v.DownloadReport(It.Is<RemoteBook>(r => r.Release.DownloadProtocol == DownloadProtocol.Torrent), null), Times.Once());
}
[Test]
@ -278,7 +278,7 @@ public async Task should_add_to_rejected_if_release_unavailable_on_indexer()
decisions.Add(new DownloadDecision(remoteBook));
Mocker.GetMock<IDownloadService>()
.Setup(s => s.DownloadReport(It.IsAny<RemoteBook>()))
.Setup(s => s.DownloadReport(It.IsAny<RemoteBook>(), null))
.Throws(new ReleaseUnavailableException(remoteBook.Release, "That 404 Error is not just a Quirk"));
var result = await Subject.ProcessDecisions(decisions);

View file

@ -83,7 +83,7 @@ public async Task Download_report_should_publish_on_grab_event()
var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()));
await Subject.DownloadReport(_parseResult);
await Subject.DownloadReport(_parseResult, null);
VerifyEventPublished<BookGrabbedEvent>();
}
@ -94,7 +94,7 @@ public async Task Download_report_should_grab_using_client()
var mock = WithUsenetClient();
mock.Setup(s => s.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()));
await Subject.DownloadReport(_parseResult);
await Subject.DownloadReport(_parseResult, null);
mock.Verify(s => s.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Once());
}
@ -106,7 +106,7 @@ public void Download_report_should_not_publish_on_failed_grab_event()
mock.Setup(s => s.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()))
.Throws(new WebException());
Assert.ThrowsAsync<WebException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<WebException>(async () => await Subject.DownloadReport(_parseResult, null));
VerifyEventNotPublished<BookGrabbedEvent>();
}
@ -121,7 +121,7 @@ public void Download_report_should_trigger_indexer_backoff_on_indexer_error()
throw new ReleaseDownloadException(v.Release, "Error", new WebException());
});
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Once());
@ -141,7 +141,7 @@ public void Download_report_should_trigger_indexer_backoff_on_http429_with_long_
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
});
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), TimeSpan.FromMinutes(5.0)), Times.Once());
@ -161,7 +161,7 @@ public void Download_report_should_trigger_indexer_backoff_on_http429_based_on_d
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
});
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<ReleaseDownloadException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(),
@ -175,7 +175,7 @@ public void Download_report_should_not_trigger_indexer_backoff_on_downloadclient
mock.Setup(s => s.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()))
.Throws(new DownloadClientException("Some Error"));
Assert.ThrowsAsync<DownloadClientException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<DownloadClientException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Never());
@ -191,7 +191,7 @@ public void Download_report_should_not_trigger_indexer_backoff_on_indexer_404_er
throw new ReleaseUnavailableException(v.Release, "Error", new WebException());
});
Assert.ThrowsAsync<ReleaseUnavailableException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<ReleaseUnavailableException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IIndexerStatusService>()
.Verify(v => v.RecordFailure(It.IsAny<int>(), It.IsAny<TimeSpan>()), Times.Never());
@ -200,7 +200,7 @@ public void Download_report_should_not_trigger_indexer_backoff_on_indexer_404_er
[Test]
public void should_not_attempt_download_if_client_isnt_configured()
{
Assert.ThrowsAsync<DownloadClientUnavailableException>(async () => await Subject.DownloadReport(_parseResult));
Assert.ThrowsAsync<DownloadClientUnavailableException>(async () => await Subject.DownloadReport(_parseResult, null));
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Never());
VerifyEventNotPublished<BookGrabbedEvent>();
@ -222,7 +222,7 @@ public async Task should_attempt_download_even_if_client_is_disabled()
}
});
await Subject.DownloadReport(_parseResult);
await Subject.DownloadReport(_parseResult, null);
Mocker.GetMock<IDownloadClientStatusService>().Verify(c => c.GetBlockedProviders(), Times.Never());
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Once());
@ -235,7 +235,7 @@ public async Task should_send_download_to_correct_usenet_client()
var mockTorrent = WithTorrentClient();
var mockUsenet = WithUsenetClient();
await Subject.DownloadReport(_parseResult);
await Subject.DownloadReport(_parseResult, null);
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Never());
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Once());
@ -249,7 +249,7 @@ public async Task should_send_download_to_correct_torrent_client()
_parseResult.Release.DownloadProtocol = DownloadProtocol.Torrent;
await Subject.DownloadReport(_parseResult);
await Subject.DownloadReport(_parseResult, null);
mockTorrent.Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Once());
mockUsenet.Verify(c => c.Download(It.IsAny<RemoteBook>(), It.IsAny<IIndexer>()), Times.Never());

View file

@ -17,7 +17,7 @@ namespace NzbDrone.Core.Download
{
public interface IDownloadService
{
Task DownloadReport(RemoteBook remoteBook);
Task DownloadReport(RemoteBook remoteBook, int? downloadClientId);
}
public class DownloadService : IDownloadService
@ -50,13 +50,15 @@ public DownloadService(IProvideDownloadClient downloadClientProvider,
_logger = logger;
}
public async Task DownloadReport(RemoteBook remoteBook)
public async Task DownloadReport(RemoteBook remoteBook, int? downloadClientId)
{
var filterBlockedClients = remoteBook.Release.PendingReleaseReason == PendingReleaseReason.DownloadClientUnavailable;
var tags = remoteBook.Author?.Tags;
var downloadClient = _downloadClientProvider.GetDownloadClient(remoteBook.Release.DownloadProtocol, remoteBook.Release.IndexerId, filterBlockedClients, tags);
var downloadClient = downloadClientId.HasValue
? _downloadClientProvider.Get(downloadClientId.Value)
: _downloadClientProvider.GetDownloadClient(remoteBook.Release.DownloadProtocol, remoteBook.Release.IndexerId, filterBlockedClients, tags);
await DownloadReport(remoteBook, downloadClient);
}

View file

@ -76,7 +76,7 @@ public async Task<ProcessedDecisions> ProcessDecisions(List<DownloadDecision> de
try
{
_logger.Trace("Grabbing from Indexer {0} at priority {1}.", remoteBook.Release.Indexer, remoteBook.Release.IndexerPriority);
await _downloadService.DownloadReport(remoteBook);
await _downloadService.DownloadReport(remoteBook, null);
grabbed.Add(report);
}
catch (ReleaseUnavailableException)

View file

@ -124,7 +124,7 @@ public async Task<ActionResult<ReleaseResource>> DownloadRelease(ReleaseResource
throw new NzbDroneClientException(HttpStatusCode.NotFound, "Unable to parse books in the release");
}
await _downloadService.DownloadReport(remoteBook);
await _downloadService.DownloadReport(remoteBook, release.DownloadClientId);
}
catch (ReleaseDownloadException ex)
{

View file

@ -56,6 +56,9 @@ public class ReleaseResource : RestResource
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int? BookId { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
public int? DownloadClientId { get; set; }
}
public static class ReleaseResourceMapper

View file

@ -30,7 +30,7 @@ public async Task<object> Grab(int id)
throw new NotFoundException();
}
await _downloadService.DownloadReport(pendingRelease.RemoteBook);
await _downloadService.DownloadReport(pendingRelease.RemoteBook, null);
return new { };
}
@ -48,7 +48,7 @@ public async Task<object> Grab([FromBody] QueueBulkResource resource)
throw new NotFoundException();
}
await _downloadService.DownloadReport(pendingRelease.RemoteBook);
await _downloadService.DownloadReport(pendingRelease.RemoteBook, null);
}
return new { };