From ac2d33443b58900c51ee4b380f5345d7edfb8cd3 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Thu, 26 May 2011 20:54:28 -0700 Subject: [PATCH] More EpisodeSearchJob fixes/tests --- NzbDrone.Core.Test/EpisodeSearchJobTest.cs | 188 +++++++++++++++--- .../Providers/Indexer/IndexerBase.cs | 9 +- .../Providers/Jobs/EpisodeSearchJob.cs | 27 ++- NzbDrone.Core/Repository/Episode.cs | 10 +- 4 files changed, 205 insertions(+), 29 deletions(-) diff --git a/NzbDrone.Core.Test/EpisodeSearchJobTest.cs b/NzbDrone.Core.Test/EpisodeSearchJobTest.cs index 4bc9bb0f3..49d67b8b5 100644 --- a/NzbDrone.Core.Test/EpisodeSearchJobTest.cs +++ b/NzbDrone.Core.Test/EpisodeSearchJobTest.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; -using System.Text; using System.Linq; using AutoMoq; using FizzWare.NBuilder; -using Gallio.Framework; using MbUnit.Framework; -using MbUnit.Framework.ContractVerifiers; using Moq; using NzbDrone.Core.Model; using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Providers; +using NzbDrone.Core.Providers.Indexer; using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Repository; using NzbDrone.Core.Repository.Quality; @@ -33,17 +31,20 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); mocker.GetMock() - .Setup(c => c.IsNeeded(It.IsAny())).Returns(true) - .AtMostOnce(); + .Setup(c => c.IsNeeded(It.IsAny())).Returns(true); + mocker.GetMock() - .Setup(c => c.DownloadReport(It.IsAny())).Returns(true) - .AtMostOnce(); + .Setup(c => c.DownloadReport(It.IsAny())).Returns(true); + + //Act mocker.Resolve().ProcessResults(new ProgressNotification("Test"), episode, parseResults); - + //Assert mocker.VerifyAllMocks(); + mocker.GetMock().Verify(c => c.IsNeeded(It.IsAny()), Times.Once()); + mocker.GetMock().Verify(c => c.DownloadReport(It.IsAny()), Times.Once()); } @@ -60,17 +61,18 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); mocker.GetMock() - .Setup(c => c.IsNeeded(parseResults[0])).Returns(true) - .AtMostOnce(); + .Setup(c => c.IsNeeded(parseResults[0])).Returns(true); mocker.GetMock() - .Setup(c => c.DownloadReport(parseResults[0])).Returns(true) - .AtMostOnce(); + .Setup(c => c.DownloadReport(parseResults[0])).Returns(true); + //Act mocker.Resolve().ProcessResults(new ProgressNotification("Test"), episode, parseResults); - + //Assert mocker.VerifyAllMocks(); + mocker.GetMock().Verify(c => c.IsNeeded(parseResults[0]), Times.Once()); + mocker.GetMock().Verify(c => c.DownloadReport(parseResults[0]), Times.Once()); } @@ -90,17 +92,19 @@ namespace NzbDrone.Core.Test var mocker = new AutoMoqer(MockBehavior.Strict); mocker.GetMock() - .Setup(c => c.IsNeeded(It.Is(p => p.Proper))).Returns(true) - .AtMostOnce(); + .Setup(c => c.IsNeeded(It.Is(p => p.Proper))).Returns(true); mocker.GetMock() - .Setup(c => c.DownloadReport(It.Is(p => p.Proper))).Returns(true) - .AtMostOnce(); + .Setup(c => c.DownloadReport(It.Is(p => p.Proper))).Returns(true); + + //Act mocker.Resolve().ProcessResults(new ProgressNotification("Test"), episode, parseResults); - + //Assert mocker.VerifyAllMocks(); + mocker.GetMock().Verify(c => c.IsNeeded(It.Is(p => p.Proper)), Times.Once()); + mocker.GetMock().Verify(c => c.DownloadReport(It.Is(p => p.Proper)), Times.Once()); } @@ -117,18 +121,18 @@ namespace NzbDrone.Core.Test mocker.GetMock() .Setup(c => c.IsNeeded(It.IsAny())).Returns(false); + //Act mocker.Resolve().ProcessResults(new ProgressNotification("Test"), episode, parseResults); - + //Assert mocker.VerifyAllMocks(); mocker.GetMock().Verify(c => c.IsNeeded(It.IsAny()), Times.Exactly(4)); - ExceptionVerification.ExcpectedWarns(1); } [Test] - public void failed_is_neede_should_check_the_rest() + public void failed_IsNeeded_should_check_the_rest() { var parseResults = Builder.CreateListOfSize(4) .Build(); @@ -140,14 +144,152 @@ namespace NzbDrone.Core.Test mocker.GetMock() .Setup(c => c.IsNeeded(It.IsAny())).Throws(new Exception()); + //Act mocker.Resolve().ProcessResults(new ProgressNotification("Test"), episode, parseResults); - + //Assert mocker.VerifyAllMocks(); mocker.GetMock().Verify(c => c.IsNeeded(It.IsAny()), Times.Exactly(4)); - ExceptionVerification.ExcpectedErrors(4); ExceptionVerification.ExcpectedWarns(1); } + + + [Test] + [Row(0)] + [Row(-1)] + [Row(-100)] + [ExpectedException(typeof(ArgumentOutOfRangeException))] + public void target_id_less_than_0_throws_exception(int target) + { + var mocker = new AutoMoqer(MockBehavior.Strict); + mocker.Resolve().Start(new ProgressNotification("Test"), target); + } + + + + [Test] + public void should_search_all_providers() + { + var parseResults = Builder.CreateListOfSize(4) + .Build(); + + var episode = Builder.CreateNew() + .With(c => c.Series = Builder.CreateNew().Build()) + .With(c => c.SeasonNumber = 12) + .Build(); + + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(c => c.GetEpisode(episode.EpisodeId)) + .Returns(episode); + + var indexer1 = new Mock(); + indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + .Returns(parseResults).Verifiable(); + + + var indexer2 = new Mock(); + indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + .Returns(parseResults).Verifiable(); + + var indexers = new List { indexer1.Object, indexer2.Object }; + + mocker.GetMock() + .Setup(c => c.GetEnabledIndexers()) + .Returns(indexers); + + mocker.GetMock() + .Setup(c => c.IsNeeded(It.IsAny())).Returns(false); + + //Act + mocker.Resolve().Start(new ProgressNotification("Test"), episode.EpisodeId); + + + //Assert + mocker.VerifyAllMocks(); + mocker.GetMock().Verify(c => c.IsNeeded(It.IsAny()), Times.Exactly(8)); + ExceptionVerification.ExcpectedWarns(1); + indexer1.VerifyAll(); + indexer2.VerifyAll(); + } + + + [Test] + public void failed_indexer_should_not_break_job() + { + var parseResults = Builder.CreateListOfSize(4) + .Build(); + + var episode = Builder.CreateNew() + .With(c => c.Series = Builder.CreateNew().Build()) + .With(c => c.SeasonNumber = 12) + .Build(); + + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(c => c.GetEpisode(episode.EpisodeId)) + .Returns(episode); + + var indexer1 = new Mock(); + indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + .Returns(parseResults).Verifiable(); + + + var indexer2 = new Mock(); + indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + .Throws(new Exception()).Verifiable(); + + var indexer3 = new Mock(); + indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber)) + .Returns(parseResults).Verifiable(); + + + var indexers = new List { indexer1.Object, indexer2.Object, indexer3.Object }; + + mocker.GetMock() + .Setup(c => c.GetEnabledIndexers()) + .Returns(indexers); + + mocker.GetMock() + .Setup(c => c.IsNeeded(It.IsAny())).Returns(false); + + //Act + mocker.Resolve().Start(new ProgressNotification("Test"), episode.EpisodeId); + + + //Assert + mocker.VerifyAllMocks(); + mocker.GetMock().Verify(c => c.IsNeeded(It.IsAny()), Times.Exactly(8)); + + ExceptionVerification.ExcpectedWarns(1); + ExceptionVerification.ExcpectedErrors(1); + indexer1.VerifyAll(); + indexer2.VerifyAll(); + indexer3.VerifyAll(); + } + + + + [Test] + public void no_episode_found_should_return_with_error_logged() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + + mocker.GetMock() + .Setup(c => c.GetEpisode(It.IsAny())) + .Returns(null); + + //Act + mocker.Resolve().Start(new ProgressNotification("Test"), 12); + + + //Assert + mocker.VerifyAllMocks(); + ExceptionVerification.ExcpectedErrors(1); + } + } } diff --git a/NzbDrone.Core/Providers/Indexer/IndexerBase.cs b/NzbDrone.Core/Providers/Indexer/IndexerBase.cs index 8756cf1bf..647cd4f7a 100644 --- a/NzbDrone.Core/Providers/Indexer/IndexerBase.cs +++ b/NzbDrone.Core/Providers/Indexer/IndexerBase.cs @@ -23,6 +23,11 @@ namespace NzbDrone.Core.Providers.Indexer _logger = LogManager.GetLogger(GetType().ToString()); } + public IndexerBase() + { + + } + /// /// Gets the name for the feed /// @@ -73,7 +78,7 @@ namespace NzbDrone.Core.Providers.Indexer /// /// Fetches RSS feed and process each news item. /// - public IList FetchRss() + public virtual IList FetchRss() { _logger.Debug("Fetching feeds from " + Name); @@ -89,7 +94,7 @@ namespace NzbDrone.Core.Providers.Indexer } - public IList FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber) + public virtual IList FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber) { _logger.Debug("Searching {0} for {1}-S{2}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber); diff --git a/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs b/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs index e08219d5a..c26cb4efd 100644 --- a/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs +++ b/NzbDrone.Core/Providers/Jobs/EpisodeSearchJob.cs @@ -39,16 +39,37 @@ namespace NzbDrone.Core.Providers.Jobs public void Start(ProgressNotification notification, int targetId) { - var reports = new List(); + if (targetId <= 0) + throw new ArgumentOutOfRangeException("targetId"); + var episode = _episodeProvider.GetEpisode(targetId); + if (episode == null) + { + Logger.Error("Unbale to find an episode {0} in database", targetId); + return; + } + var indexers = _indexerProvider.GetEnabledIndexers(); + var reports = new List(); foreach (var indexer in indexers) { try { notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name); - reports.AddRange(indexer.FetchRss()); + + IList indexerResults = new List(); + + if (episode.IsDailyEpisode) + { + //TODO:Add support for daily episodes + } + else + { + indexerResults = indexer.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber); + } + + reports.AddRange(indexerResults); } catch (Exception e) { @@ -80,7 +101,7 @@ namespace NzbDrone.Core.Providers.Jobs Logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e); } } - + Logger.Warn("Unable to find {0} in any of indexers.", episode); } } diff --git a/NzbDrone.Core/Repository/Episode.cs b/NzbDrone.Core/Repository/Episode.cs index e7b6f2bdc..8318eb9fa 100644 --- a/NzbDrone.Core/Repository/Episode.cs +++ b/NzbDrone.Core/Repository/Episode.cs @@ -25,6 +25,14 @@ namespace NzbDrone.Core.Repository public Boolean Ignored { get; set; } + [SubSonicIgnore] + public Boolean IsDailyEpisode + { + get + { + return EpisodeNumber == 0; + } + } /// /// Gets or sets the grab date. @@ -74,7 +82,7 @@ namespace NzbDrone.Core.Repository { var seriesTitle = Series == null ? "[NULL]" : Series.Title; - if (EpisodeNumber == 0) + if (IsDailyEpisode) return string.Format("{0} - {1}", seriesTitle, AirDate.Date); return string.Format("{0} - S{1:00}E{2}", seriesTitle, SeasonNumber, EpisodeNumber);