From e67de6aae85f9285c638f55a0d3b31aae9a4d962 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Tue, 6 Oct 2015 22:22:37 -0700 Subject: [PATCH] New: Blackhole won't grab another release if release in last hour meets the cutoff Fixed: Invalid season packs preventing future releases from being grabbed when using SAB as download client Closes #837 Fixes #625 --- .../HistorySpecificationFixture.cs | 118 +++++++----------- .../RssSync/HistorySpecification.cs | 40 ++---- 2 files changed, 55 insertions(+), 103 deletions(-) diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs index 35c440766..d223dd135 100644 --- a/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/HistorySpecificationFixture.cs @@ -1,11 +1,11 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications.RssSync; using NzbDrone.Core.Download; -using NzbDrone.Core.Download.Clients.Sabnzbd; using NzbDrone.Core.History; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser.Model; @@ -28,6 +28,8 @@ public class HistorySpecificationFixture : CoreTest private QualityModel _upgradableQuality; private QualityModel _notupgradableQuality; private Series _fakeSeries; + private const int FIRST_EPISODE_ID = 1; + private const int SECOND_EPISODE_ID = 2; [SetUp] public void Setup() @@ -35,10 +37,10 @@ public void Setup() Mocker.Resolve(); _upgradeHistory = Mocker.Resolve(); - var singleEpisodeList = new List { new Episode { Id = 1, SeasonNumber = 12, EpisodeNumber = 3 } }; + var singleEpisodeList = new List { new Episode { Id = FIRST_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 3 } }; var doubleEpisodeList = new List { - new Episode {Id = 1, SeasonNumber = 12, EpisodeNumber = 3 }, - new Episode {Id = 2, SeasonNumber = 12, EpisodeNumber = 4 }, + new Episode {Id = FIRST_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 3 }, + new Episode {Id = SECOND_EPISODE_ID, SeasonNumber = 12, EpisodeNumber = 4 }, new Episode {Id = 3, SeasonNumber = 12, EpisodeNumber = 5 } }; @@ -62,71 +64,84 @@ public void Setup() _upgradableQuality = new QualityModel(Quality.SDTV, new Revision(version: 1)); _notupgradableQuality = new QualityModel(Quality.HDTV1080p, new Revision(version: 2)); - - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 1)).Returns(_notupgradableQuality); - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 2)).Returns(_notupgradableQuality); - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 3)).Returns(null); - - Mocker.GetMock() - .Setup(c => c.GetDownloadClients()) - .Returns(new IDownloadClient[] { Mocker.GetMock().Object }); } - private void WithFirstReportUpgradable() + private void GivenMostRecentForEpisode(int episodeId, string downloadId, QualityModel quality, DateTime date, HistoryEventType eventType) { - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 1)).Returns(_upgradableQuality); + Mocker.GetMock().Setup(s => s.MostRecentForEpisode(episodeId)) + .Returns(new History.History { DownloadId = downloadId, Quality = quality, Date = date, EventType = eventType }); } - private void WithSecondReportUpgradable() + [Test] + public void should_return_true_if_it_is_a_search() { - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 2)).Returns(_upgradableQuality); + _upgradeHistory.IsSatisfiedBy(_parseResultMulti, new SeasonSearchCriteria()).Accepted.Should().BeTrue(); } - private void GivenSabnzbdDownloadClient() + [Test] + public void should_return_true_if_latest_history_item_is_null() { - Mocker.GetMock() - .Setup(c => c.GetDownloadClients()) - .Returns(new IDownloadClient[] { Mocker.Resolve() }); + Mocker.GetMock().Setup(s => s.MostRecentForEpisode(It.IsAny())).Returns((History.History)null); + _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } - private void GivenMostRecentForEpisode(HistoryEventType eventType) + [Test] + public void should_return_true_if_latest_history_item_is_not_grabbed() { - Mocker.GetMock().Setup(s => s.MostRecentForEpisode(It.IsAny())) - .Returns(new History.History { EventType = eventType }); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.DownloadFailed); + _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_if_latest_history_has_a_download_id() + { + GivenMostRecentForEpisode(FIRST_EPISODE_ID, "test", _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_if_latest_history_item_is_old_than_one_hour() + { + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow.AddHours(-6), HistoryEventType.DownloadFailed); + _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } [Test] public void should_be_upgradable_if_only_episode_is_upgradable() { - WithFirstReportUpgradable(); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeTrue(); } [Test] public void should_be_upgradable_if_both_episodes_are_upgradable() { - WithFirstReportUpgradable(); - WithSecondReportUpgradable(); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); } [Test] public void should_not_be_upgradable_if_both_episodes_are_not_upgradable() { + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } [Test] public void should_be_not_upgradable_if_only_first_episodes_is_upgradable() { - WithFirstReportUpgradable(); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } [Test] public void should_be_not_upgradable_if_only_second_episodes_is_upgradable() { - WithSecondReportUpgradable(); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _notupgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); + GivenMostRecentForEpisode(SECOND_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); } @@ -137,50 +152,9 @@ public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing() _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _upgradableQuality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); - Mocker.GetMock().Setup(c => c.GetBestQualityInHistory(It.IsAny(), 1)).Returns(_upgradableQuality); + GivenMostRecentForEpisode(FIRST_EPISODE_ID, string.Empty, _upgradableQuality, DateTime.UtcNow, HistoryEventType.Grabbed); _upgradeHistory.IsSatisfiedBy(_parseResultSingle, null).Accepted.Should().BeFalse(); } - - [Test] - public void should_return_true_if_it_is_a_search() - { - _upgradeHistory.IsSatisfiedBy(_parseResultMulti, new SeasonSearchCriteria()).Accepted.Should().BeTrue(); - } - - [Test] - public void should_return_true_if_using_sabnzbd_and_nothing_in_history() - { - GivenSabnzbdDownloadClient(); - - _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); - } - - [Test] - public void should_return_false_if_most_recent_in_history_is_grabbed() - { - GivenSabnzbdDownloadClient(); - GivenMostRecentForEpisode(HistoryEventType.Grabbed); - - _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeFalse(); - } - - [Test] - public void should_return_true_if_most_recent_in_history_is_failed() - { - GivenSabnzbdDownloadClient(); - GivenMostRecentForEpisode(HistoryEventType.DownloadFailed); - - _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); - } - - [Test] - public void should_return_true_if_most_recent_in_history_is_imported() - { - GivenSabnzbdDownloadClient(); - GivenMostRecentForEpisode(HistoryEventType.DownloadFolderImported); - - _upgradeHistory.IsSatisfiedBy(_parseResultMulti, null).Accepted.Should().BeTrue(); - } } -} \ No newline at end of file +} diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs index 8c035a865..65d5af73d 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/RssSync/HistorySpecification.cs @@ -1,7 +1,6 @@ -using System.Linq; +using System; using NLog; -using NzbDrone.Core.Download; -using NzbDrone.Core.Download.Clients.Sabnzbd; +using NzbDrone.Common.Extensions; using NzbDrone.Core.History; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser.Model; @@ -12,17 +11,14 @@ public class HistorySpecification : IDecisionEngineSpecification { private readonly IHistoryService _historyService; private readonly QualityUpgradableSpecification _qualityUpgradableSpecification; - private readonly IProvideDownloadClient _downloadClientProvider; private readonly Logger _logger; public HistorySpecification(IHistoryService historyService, QualityUpgradableSpecification qualityUpgradableSpecification, - IProvideDownloadClient downloadClientProvider, Logger logger) { _historyService = historyService; _qualityUpgradableSpecification = qualityUpgradableSpecification; - _downloadClientProvider = downloadClientProvider; _logger = logger; } @@ -36,35 +32,17 @@ public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase return Decision.Accept(); } - var downloadClients = _downloadClientProvider.GetDownloadClients(); - - foreach (var downloadClient in downloadClients.OfType()) - { - _logger.Debug("Performing history status check on report"); - foreach (var episode in subject.Episodes) - { - _logger.Debug("Checking current status of episode [{0}] in history", episode.Id); - var mostRecent = _historyService.MostRecentForEpisode(episode.Id); - - if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed) - { - _logger.Debug("Latest history item is downloading, rejecting."); - return Decision.Reject("Download has not been imported yet"); - } - } - return Decision.Accept(); - } - + _logger.Debug("Performing history status check on report"); foreach (var episode in subject.Episodes) { - var bestQualityInHistory = _historyService.GetBestQualityInHistory(subject.Series.Profile, episode.Id); - if (bestQualityInHistory != null) - { - _logger.Debug("Comparing history quality with report. History is {0}", bestQualityInHistory); + _logger.Debug("Checking current status of episode [{0}] in history", episode.Id); + var mostRecent = _historyService.MostRecentForEpisode(episode.Id); - if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.Profile, bestQualityInHistory, subject.ParsedEpisodeInfo.Quality)) + if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed && mostRecent.DownloadId.IsNullOrWhiteSpace() && mostRecent.Date.After(DateTime.UtcNow.AddHours(-1))) + { + if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.Profile, mostRecent.Quality, subject.ParsedEpisodeInfo.Quality)) { - return Decision.Reject("Existing file in history is of equal or higher quality: {0}", bestQualityInHistory); + return Decision.Reject("Existing grab event in history is of equal or higher quality: {0}", mostRecent.Quality); } } }