mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-26 22:46:37 -04:00
New: Rebuilt Completed/Failed download handling from scratch
This commit is contained in:
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
@@ -18,28 +16,21 @@ using NzbDrone.Test.Common;
|
||||
namespace NzbDrone.Core.Test.Download
|
||||
{
|
||||
[TestFixture]
|
||||
public class FailedDownloadServiceFixture : CoreTest<DownloadTrackingService>
|
||||
public class FailedDownloadServiceFixture : CoreTest<FailedDownloadService>
|
||||
{
|
||||
private List<DownloadClientItem> _completed;
|
||||
private List<DownloadClientItem> _failed;
|
||||
private TrackedDownload _trackedDownload;
|
||||
private List<History.History> _grabHistory;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_completed = Builder<DownloadClientItem>.CreateListOfSize(5)
|
||||
.All()
|
||||
var completed = Builder<DownloadClientItem>.CreateNew()
|
||||
.With(h => h.Status = DownloadItemStatus.Completed)
|
||||
.With(h => h.IsEncrypted = false)
|
||||
.With(h => h.OutputPath = new OsPath(@"C:\DropFolder\MyDownload".AsOsAgnostic()))
|
||||
.With(h => h.Title = "Drone.S01E01.HDTV")
|
||||
.Build()
|
||||
.ToList();
|
||||
.Build();
|
||||
|
||||
_failed = Builder<DownloadClientItem>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(h => h.Status = DownloadItemStatus.Failed)
|
||||
.With(h => h.Title = "Drone.S01E01.HDTV")
|
||||
.Build()
|
||||
.ToList();
|
||||
_grabHistory = Builder<History.History>.CreateListOfSize(2).BuildList();
|
||||
|
||||
var remoteEpisode = new RemoteEpisode
|
||||
{
|
||||
@@ -47,410 +38,74 @@ namespace NzbDrone.Core.Test.Download
|
||||
Episodes = new List<Episode> { new Episode { Id = 1 } }
|
||||
};
|
||||
|
||||
Mocker.GetMock<IProvideDownloadClient>()
|
||||
.Setup(c => c.GetDownloadClients())
|
||||
.Returns( new IDownloadClient[] { Mocker.GetMock<IDownloadClient>().Object });
|
||||
_trackedDownload = Builder<TrackedDownload>.CreateNew()
|
||||
.With(c => c.State = TrackedDownloadStage.Downloading)
|
||||
.With(c => c.DownloadItem = completed)
|
||||
.With(c => c.RemoteEpisode = remoteEpisode)
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.SetupGet(c => c.Definition)
|
||||
.Returns(new DownloadClientDefinition { Id = 1, Name = "testClient" });
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableFailedDownloadHandling)
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Imported())
|
||||
.Returns(new List<History.History>());
|
||||
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed))
|
||||
.Returns(_grabHistory);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Int32>(), It.IsAny<IEnumerable<Int32>>()))
|
||||
.Returns(remoteEpisode);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Setup(s => s.Map(It.IsAny<ParsedEpisodeInfo>(), It.IsAny<Int32>(), (SearchCriteriaBase)null))
|
||||
.Returns(remoteEpisode);
|
||||
|
||||
Mocker.SetConstant<IFailedDownloadService>(Mocker.Resolve<FailedDownloadService>());
|
||||
}
|
||||
|
||||
private void GivenNoGrabbedHistory()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Grabbed())
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
private void GivenGrabbedHistory(List<History.History> history)
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Grabbed())
|
||||
.Returns(history);
|
||||
}
|
||||
|
||||
private void GivenNoFailedHistory()
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Failed())
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
private void GivenFailedHistory(List<History.History> failedHistory)
|
||||
{
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Failed())
|
||||
.Returns(failedHistory);
|
||||
}
|
||||
|
||||
private void GivenFailedDownloadClientHistory()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(_failed);
|
||||
}
|
||||
|
||||
private void GivenGracePeriod(int hours)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>().SetupGet(s => s.BlacklistGracePeriod).Returns(hours);
|
||||
}
|
||||
|
||||
private void GivenRetryLimit(int count, int interval = 5)
|
||||
{
|
||||
Mocker.GetMock<IConfigService>().SetupGet(s => s.BlacklistRetryLimit).Returns(count);
|
||||
Mocker.GetMock<IConfigService>().SetupGet(s => s.BlacklistRetryInterval).Returns(interval);
|
||||
}
|
||||
|
||||
private void VerifyNoFailedDownloads()
|
||||
{
|
||||
Mocker.GetMock<IEventAggregator>()
|
||||
.Verify(v => v.PublishEvent(It.IsAny<DownloadFailedEvent>()), Times.Never());
|
||||
}
|
||||
|
||||
private void VerifyFailedDownloads(int count = 1)
|
||||
{
|
||||
Mocker.GetMock<IEventAggregator>()
|
||||
.Verify(v => v.PublishEvent(It.Is<DownloadFailedEvent>(d => d.EpisodeIds.Count == count)), Times.Once());
|
||||
}
|
||||
|
||||
private void VerifyRetryDownload()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Verify(v => v.RetryDownload(It.IsAny<String>()), Times.Once());
|
||||
}
|
||||
|
||||
private void VerifyNoRetryDownload()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Verify(v => v.RetryDownload(It.IsAny<String>()), Times.Never());
|
||||
.Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed))
|
||||
.Returns(new List<History.History>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_no_download_client_history()
|
||||
{
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(new List<DownloadClientItem>());
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Verify(s => s.BetweenDates(It.IsAny<DateTime>(), It.IsAny<DateTime>(), HistoryEventType.Grabbed),
|
||||
Times.Never());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_no_failed_items_in_download_client_history()
|
||||
public void should_not_fail_if_matching_history_is_not_found()
|
||||
{
|
||||
GivenNoGrabbedHistory();
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Mocker.GetMock<IDownloadClient>()
|
||||
.Setup(s => s.GetItems())
|
||||
.Returns(_completed);
|
||||
Subject.Process(_trackedDownload);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Verify(s => s.BetweenDates(It.IsAny<DateTime>(), It.IsAny<DateTime>(), HistoryEventType.Grabbed),
|
||||
Times.Never());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
AssertDownloadNotFailed();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_matching_history_is_not_found()
|
||||
public void should_mark_failed_if_encrypted()
|
||||
{
|
||||
GivenNoGrabbedHistory();
|
||||
GivenFailedDownloadClientHistory();
|
||||
_trackedDownload.DownloadItem.IsEncrypted = true;
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
Subject.Process(_trackedDownload);
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
AssertDownloadFailed();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_grabbed_history_contains_null_downloadclient_id()
|
||||
public void should_mark_failed_if_download_item_is_failed()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
_trackedDownload.DownloadItem.Status = DownloadItemStatus.Failed;
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
Subject.Process(_trackedDownload);
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", null);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
AssertDownloadFailed();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_failed_history_contains_null_downloadclient_id()
|
||||
|
||||
private void AssertDownloadNotFailed()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
Mocker.GetMock<IEventAggregator>()
|
||||
.Verify(v => v.PublishEvent(It.IsAny<DownloadFailedEvent>()), Times.Never());
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
|
||||
var historyFailed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyFailed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyFailed.First().Data.Add("downloadClientId", null);
|
||||
|
||||
GivenFailedHistory(historyFailed);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
_trackedDownload.State.Should().NotBe(TrackedDownloadStage.DownloadFailed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_already_added_to_history_as_failed()
|
||||
|
||||
private void AssertDownloadFailed()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenFailedHistory(history);
|
||||
Mocker.GetMock<IEventAggregator>()
|
||||
.Verify(v => v.PublishEvent(It.IsAny<DownloadFailedEvent>()), Times.Once());
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_not_already_in_failed_history()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
history.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
history.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_have_multiple_episode_ids_when_multi_episode_release_fails()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var history = Builder<History.History>.CreateListOfSize(2)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(history);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
history.ForEach(h =>
|
||||
{
|
||||
h.Data.Add("downloadClient", "SabnzbdClient");
|
||||
h.Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
});
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_skip_if_enable_failed_download_handling_is_off()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.SetupGet(s => s.EnableFailedDownloadHandling)
|
||||
.Returns(false);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_ageHours_is_not_set()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
VerifyNoRetryDownload();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_age_is_greater_than_grace_period()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "48");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
VerifyNoRetryDownload();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_retry_if_already_failed()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "1");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenFailedHistory(historyGrabbed);
|
||||
GivenGracePeriod(6);
|
||||
GivenRetryLimit(1);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
VerifyNoRetryDownload();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_process_if_retry_count_is_greater_than_grace_period()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "48");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
GivenGracePeriod(6);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyFailedDownloads();
|
||||
VerifyNoRetryDownload();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_process_if_age_is_less_than_grace_period()
|
||||
{
|
||||
GivenFailedDownloadClientHistory();
|
||||
|
||||
var historyGrabbed = Builder<History.History>.CreateListOfSize(1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
historyGrabbed.First().Data.Add("downloadClient", "SabnzbdClient");
|
||||
historyGrabbed.First().Data.Add("downloadClientId", _failed.First().DownloadClientId);
|
||||
historyGrabbed.First().Data.Add("ageHours", "1");
|
||||
|
||||
GivenGrabbedHistory(historyGrabbed);
|
||||
GivenNoFailedHistory();
|
||||
GivenGracePeriod(6);
|
||||
GivenRetryLimit(1);
|
||||
|
||||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoFailedDownloads();
|
||||
VerifyNoRetryDownload();
|
||||
|
||||
ExceptionVerification.IgnoreWarns();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_manual_mark_all_episodes_of_release_as_failed()
|
||||
{
|
||||
var historyFailed = Builder<History.History>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.EventType == HistoryEventType.Grabbed)
|
||||
.Do(v => v.Data.Add("downloadClient", "SabnzbdClient"))
|
||||
.Do(v => v.Data.Add("downloadClientId", "test"))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
GivenGrabbedHistory(historyFailed);
|
||||
|
||||
Mocker.GetMock<IHistoryService>()
|
||||
.Setup(s => s.Get(It.IsAny<Int32>()))
|
||||
.Returns<Int32>(i => historyFailed.FirstOrDefault(v => v.Id == i));
|
||||
|
||||
Subject.MarkAsFailed(1);
|
||||
|
||||
VerifyFailedDownloads(2);
|
||||
_trackedDownload.State.Should().Be(TrackedDownloadStage.DownloadFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user