More EpisodeSearchJob fixes/tests

This commit is contained in:
kay.one 2011-05-26 20:54:28 -07:00
parent 5a812801b7
commit ac2d33443b
4 changed files with 205 additions and 29 deletions

View File

@ -1,16 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Linq; using System.Linq;
using AutoMoq; using AutoMoq;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using Gallio.Framework;
using MbUnit.Framework; using MbUnit.Framework;
using MbUnit.Framework.ContractVerifiers;
using Moq; using Moq;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Providers.Jobs;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality; using NzbDrone.Core.Repository.Quality;
@ -33,17 +31,20 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(MockBehavior.Strict); var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>() mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(true) .Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(true);
.AtMostOnce();
mocker.GetMock<DownloadProvider>() mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(It.IsAny<EpisodeParseResult>())).Returns(true) .Setup(c => c.DownloadReport(It.IsAny<EpisodeParseResult>())).Returns(true);
.AtMostOnce();
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults); mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()), Times.Once());
} }
@ -60,17 +61,18 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(MockBehavior.Strict); var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>() mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(parseResults[0])).Returns(true) .Setup(c => c.IsNeeded(parseResults[0])).Returns(true);
.AtMostOnce();
mocker.GetMock<DownloadProvider>() mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(parseResults[0])).Returns(true) .Setup(c => c.DownloadReport(parseResults[0])).Returns(true);
.AtMostOnce();
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults); mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(parseResults[0]), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(parseResults[0]), Times.Once());
} }
@ -90,17 +92,19 @@ namespace NzbDrone.Core.Test
var mocker = new AutoMoqer(MockBehavior.Strict); var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<InventoryProvider>() mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true) .Setup(c => c.IsNeeded(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true);
.AtMostOnce();
mocker.GetMock<DownloadProvider>() mocker.GetMock<DownloadProvider>()
.Setup(c => c.DownloadReport(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true) .Setup(c => c.DownloadReport(It.Is<EpisodeParseResult>(p => p.Proper))).Returns(true);
.AtMostOnce();
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults); mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.Is<EpisodeParseResult>(p => p.Proper)), Times.Once());
mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.Is<EpisodeParseResult>(p => p.Proper)), Times.Once());
} }
@ -117,18 +121,18 @@ namespace NzbDrone.Core.Test
mocker.GetMock<InventoryProvider>() mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false); .Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults); mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4)); mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4));
ExceptionVerification.ExcpectedWarns(1); ExceptionVerification.ExcpectedWarns(1);
} }
[Test] [Test]
public void failed_is_neede_should_check_the_rest() public void failed_IsNeeded_should_check_the_rest()
{ {
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4) var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build(); .Build();
@ -140,14 +144,152 @@ namespace NzbDrone.Core.Test
mocker.GetMock<InventoryProvider>() mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Throws(new Exception()); .Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Throws(new Exception());
//Act
mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults); mocker.Resolve<EpisodeSearchJob>().ProcessResults(new ProgressNotification("Test"), episode, parseResults);
//Assert
mocker.VerifyAllMocks(); mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4)); mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(4));
ExceptionVerification.ExcpectedErrors(4); ExceptionVerification.ExcpectedErrors(4);
ExceptionVerification.ExcpectedWarns(1); 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<EpisodeSearchJob>().Start(new ProgressNotification("Test"), target);
}
[Test]
public void should_search_all_providers()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew()
.With(c => c.Series = Builder<Series>.CreateNew().Build())
.With(c => c.SeasonNumber = 12)
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisode(episode.EpisodeId))
.Returns(episode);
var indexer1 = new Mock<IndexerBase>();
indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexer2 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexers = new List<IndexerBase> { indexer1.Object, indexer2.Object };
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(indexers);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), episode.EpisodeId);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), Times.Exactly(8));
ExceptionVerification.ExcpectedWarns(1);
indexer1.VerifyAll();
indexer2.VerifyAll();
}
[Test]
public void failed_indexer_should_not_break_job()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(4)
.Build();
var episode = Builder<Episode>.CreateNew()
.With(c => c.Series = Builder<Series>.CreateNew().Build())
.With(c => c.SeasonNumber = 12)
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<EpisodeProvider>()
.Setup(c => c.GetEpisode(episode.EpisodeId))
.Returns(episode);
var indexer1 = new Mock<IndexerBase>();
indexer1.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexer2 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Throws(new Exception()).Verifiable();
var indexer3 = new Mock<IndexerBase>();
indexer2.Setup(c => c.FetchEpisode(episode.Series.Title, episode.SeasonNumber, episode.EpisodeNumber))
.Returns(parseResults).Verifiable();
var indexers = new List<IndexerBase> { indexer1.Object, indexer2.Object, indexer3.Object };
mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(indexers);
mocker.GetMock<InventoryProvider>()
.Setup(c => c.IsNeeded(It.IsAny<EpisodeParseResult>())).Returns(false);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), episode.EpisodeId);
//Assert
mocker.VerifyAllMocks();
mocker.GetMock<InventoryProvider>().Verify(c => c.IsNeeded(It.IsAny<EpisodeParseResult>()), 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<EpisodeProvider>()
.Setup(c => c.GetEpisode(It.IsAny<long>()))
.Returns<Episode>(null);
//Act
mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), 12);
//Assert
mocker.VerifyAllMocks();
ExceptionVerification.ExcpectedErrors(1);
}
} }
} }

View File

@ -23,6 +23,11 @@ namespace NzbDrone.Core.Providers.Indexer
_logger = LogManager.GetLogger(GetType().ToString()); _logger = LogManager.GetLogger(GetType().ToString());
} }
public IndexerBase()
{
}
/// <summary> /// <summary>
/// Gets the name for the feed /// Gets the name for the feed
/// </summary> /// </summary>
@ -73,7 +78,7 @@ namespace NzbDrone.Core.Providers.Indexer
/// <summary> /// <summary>
/// Fetches RSS feed and process each news item. /// Fetches RSS feed and process each news item.
/// </summary> /// </summary>
public IList<EpisodeParseResult> FetchRss() public virtual IList<EpisodeParseResult> FetchRss()
{ {
_logger.Debug("Fetching feeds from " + Name); _logger.Debug("Fetching feeds from " + Name);
@ -89,7 +94,7 @@ namespace NzbDrone.Core.Providers.Indexer
} }
public IList<EpisodeParseResult> FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber) public virtual IList<EpisodeParseResult> FetchEpisode(string seriesTitle, int seasonNumber, int episodeNumber)
{ {
_logger.Debug("Searching {0} for {1}-S{2}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber); _logger.Debug("Searching {0} for {1}-S{2}E{3:00}", Name, seriesTitle, seasonNumber, episodeNumber);

View File

@ -39,16 +39,37 @@ namespace NzbDrone.Core.Providers.Jobs
public void Start(ProgressNotification notification, int targetId) public void Start(ProgressNotification notification, int targetId)
{ {
var reports = new List<EpisodeParseResult>(); if (targetId <= 0)
throw new ArgumentOutOfRangeException("targetId");
var episode = _episodeProvider.GetEpisode(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 indexers = _indexerProvider.GetEnabledIndexers();
var reports = new List<EpisodeParseResult>();
foreach (var indexer in indexers) foreach (var indexer in indexers)
{ {
try try
{ {
notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name); notification.CurrentMessage = String.Format("Searching for {0} in {1}", episode, indexer.Name);
reports.AddRange(indexer.FetchRss());
IList<EpisodeParseResult> indexerResults = new List<EpisodeParseResult>();
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) 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.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e);
} }
} }
Logger.Warn("Unable to find {0} in any of indexers.", episode); Logger.Warn("Unable to find {0} in any of indexers.", episode);
} }
} }

View File

@ -25,6 +25,14 @@ namespace NzbDrone.Core.Repository
public Boolean Ignored { get; set; } public Boolean Ignored { get; set; }
[SubSonicIgnore]
public Boolean IsDailyEpisode
{
get
{
return EpisodeNumber == 0;
}
}
/// <summary> /// <summary>
/// Gets or sets the grab date. /// Gets or sets the grab date.
@ -74,7 +82,7 @@ namespace NzbDrone.Core.Repository
{ {
var seriesTitle = Series == null ? "[NULL]" : Series.Title; var seriesTitle = Series == null ? "[NULL]" : Series.Title;
if (EpisodeNumber == 0) if (IsDailyEpisode)
return string.Format("{0} - {1}", seriesTitle, AirDate.Date); return string.Format("{0} - {1}", seriesTitle, AirDate.Date);
return string.Format("{0} - S{1:00}E{2}", seriesTitle, SeasonNumber, EpisodeNumber); return string.Format("{0} - S{1:00}E{2}", seriesTitle, SeasonNumber, EpisodeNumber);