Searching refactored

#ND-135 fixed
This commit is contained in:
Mark McDowall
2013-01-13 00:24:48 -08:00
parent 829ba1cf92
commit 5e7c0951b7
24 changed files with 1848 additions and 1536 deletions
@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{
public class GetSeriesTitleFixture : TestBase
{
private Series _series;
private const string SCENE_NAME = "Scandal";
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.With(s => s.Title = "Scandal (2012)")
.Build();
}
private void WithSceneName()
{
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetSceneName(_series.SeriesId))
.Returns("Scandal");
}
[Test]
public void should_return_scene_name_when_sceneName_is_available()
{
WithSceneName();
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(SCENE_NAME);
}
[Test]
public void should_return_seriesTitle_when_sceneName_is_not_available()
{
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(_series.Title);
}
[TestCase("Mike & Molly", "Mike and Molly")]
[TestCase("Franklin & Bash", "Franklin and Bash")]
[TestCase("Law & Order", "Law and Order")]
public void should_replace_ampersand_with_and_when_returning_title(string seriesTitle, string expectedTitle)
{
_series.Title = seriesTitle;
Mocker.Resolve<SearchProvider>().GetSeriesTitle(_series).Should().Be(expectedTitle);
}
}
}
@@ -1,282 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{
public class PerformSearchFixture : CoreTest
{
private const string SCENE_NAME = "Scene Name";
private const int SEASON_NUMBER = 5;
private const int EPISODE_NUMBER = 1;
private const int PARSE_RESULT_COUNT = 10;
private Mock<IndexerBase> _episodeIndexer1;
private Mock<IndexerBase> _episodeIndexer2;
private Mock<IndexerBase> _brokenIndexer;
private Mock<IndexerBase> _nullIndexer;
private List<IndexerBase> _indexers;
private Series _series;
private IList<Episode> _episodes;
[SetUp]
public void Setup()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(PARSE_RESULT_COUNT)
.Build();
_series = Builder<Series>.CreateNew()
.Build();
_episodes = Builder<Episode>.CreateListOfSize(1)
.Build();
BuildIndexers(parseResults);
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _episodeIndexer2.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void BuildIndexers(IList<EpisodeParseResult> parseResults)
{
_episodeIndexer1 = new Mock<IndexerBase>();
_episodeIndexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer1.Setup(s => s.Name).Returns("Episode Indexer 1");
_episodeIndexer2 = new Mock<IndexerBase>();
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2.Setup(s => s.Name).Returns("Episode Indexer 2");
_brokenIndexer = new Mock<IndexerBase>();
_brokenIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_brokenIndexer.Setup(s => s.Name).Returns("Broken Indexer");
_nullIndexer = new Mock<IndexerBase>();
_nullIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns<List<EpisodeParseResult>>(null);
_nullIndexer.Setup(s => s.Name).Returns("Null Indexer");
}
private void WithTwoGoodOneBrokenIndexer()
{
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _brokenIndexer.Object, _episodeIndexer2.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void WithNullIndexers()
{
_indexers = new List<IndexerBase> { _nullIndexer.Object, _nullIndexer.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void WithSceneName()
{
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetSceneName(_series.SeriesId)).Returns(SCENE_NAME);
}
private void With30Episodes()
{
_episodes = Builder<Episode>.CreateListOfSize(30)
.Build();
}
private void WithNullEpisodes()
{
_episodes = null;
}
private void VerifyFetchEpisode(Times times)
{
_episodeIndexer1.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchDailyEpisode(Times times)
{
_episodeIndexer1.Verify(v => v.FetchDailyEpisode(_series.Title, It.IsAny<DateTime>())
, times);
_episodeIndexer2.Verify(v => v.FetchDailyEpisode(_series.Title, It.IsAny<DateTime>())
, times);
}
private void VerifyFetchEpisodeWithSceneName(Times times)
{
_episodeIndexer1.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchEpisodeBrokenIndexer(Times times)
{
_brokenIndexer.Verify(v => v.FetchEpisode(It.IsAny<string>(), SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchPartialSeason(Times times)
{
_episodeIndexer1.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchSeason(Times times)
{
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
}
[Test]
public void PerformSearch_should_search_all_enabled_providers()
{
//Act
var result = Mocker.Resolve<SearchProvider>().PerformEpisodeSearch(_series, SEASON_NUMBER, _episodes.First().EpisodeNumber);
//Assert
VerifyFetchEpisode(Times.Once());
result.Should().HaveCount(PARSE_RESULT_COUNT * 2);
}
[Test]
public void broken_indexer_should_not_block_other_indexers()
{
//Setup
WithTwoGoodOneBrokenIndexer();
//Act
var result = Mocker.Resolve<SearchProvider>().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER);
//Assert
result.Should().HaveCount(PARSE_RESULT_COUNT * 2);
VerifyFetchEpisode(Times.Once());
VerifyFetchEpisodeBrokenIndexer(Times.Once());
Mocker.GetMock<SceneMappingProvider>().Verify(c => c.GetSceneName(_series.SeriesId),
Times.Once());
ExceptionVerification.ExpectedErrors(1);
}
[Test]
public void PerformSearch_for_episode_should_call_FetchEpisode()
{
//Act
var result = Mocker.Resolve<SearchProvider>().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER);
//Assert
result.Should().HaveCount(PARSE_RESULT_COUNT * 2);
VerifyFetchEpisode(Times.Once());
}
[Test]
public void PerformSearch_for_daily_episode_should_call_FetchEpisode()
{
//Setup
_series.IsDaily = true;
//Act
var result = Mocker.Resolve<SearchProvider>().PerformDailyEpisodeSearch(_series, _episodes.First());
//Assert
result.Should().HaveCount(PARSE_RESULT_COUNT * 2);
VerifyFetchDailyEpisode(Times.Once());
}
[Test]
public void PerformSearch_for_partial_season_should_call_FetchPartialSeason()
{
With30Episodes();
//Act
var result = Mocker.Resolve<SearchProvider>().PerformPartialSeasonSearch(_series, SEASON_NUMBER, new List<int>{0, 1, 2, 3});
//Assert
result.Should().HaveCount(80);
VerifyFetchPartialSeason(Times.Exactly(4));
}
[Test]
public void PerformSearch_for_season_should_call_FetchSeason()
{
WithNullEpisodes();
//Act
var result = Mocker.Resolve<SearchProvider>().PerformSeasonSearch(_series, SEASON_NUMBER);
//Assert
result.Should().HaveCount(20);
VerifyFetchSeason(Times.Once());
}
[Test]
public void PerformSearch_should_return_empty_list_when_results_from_indexers_are_null()
{
//Setup
WithNullIndexers();
//Act
var result = Mocker.Resolve<SearchProvider>().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER);
//Assert
result.Should().HaveCount(0);
ExceptionVerification.ExpectedErrors(2);
}
[Test]
public void should_use_scene_name_to_search_for_episode_when_avilable()
{
WithSceneName();
Mocker.Resolve<SearchProvider>().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER);
VerifyFetchEpisodeWithSceneName(Times.Once());
}
}
}
@@ -1,283 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.DecisionEngine;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class ProcessDailySearchResultsFixture : CoreTest
{
private Series _matchingSeries = null;
private Series _mismatchedSeries = null;
private Series _nullSeries = null;
[SetUp]
public void setup()
{
_matchingSeries = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 79488)
.With(s => s.Title = "30 Rock")
.Build();
_mismatchedSeries = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12345)
.With(s => s.Title = "Not 30 Rock")
.Build();
}
private void WithMatchingSeries()
{
Mocker.GetMock<SeriesProvider>()
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_matchingSeries);
}
private void WithMisMatchedSeries()
{
Mocker.GetMock<SeriesProvider>()
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_mismatchedSeries);
}
private void WithNullSeries()
{
Mocker.GetMock<SeriesProvider>()
.Setup(s => s.FindSeries(It.IsAny<string>())).Returns(_nullSeries);
}
private void WithSuccessfulDownload()
{
Mocker.GetMock<DownloadProvider>()
.Setup(s => s.DownloadReport(It.IsAny<EpisodeParseResult>()))
.Returns(true);
}
private void WithFailingDownload()
{
Mocker.GetMock<DownloadProvider>()
.Setup(s => s.DownloadReport(It.IsAny<EpisodeParseResult>()))
.Returns(false);
}
private void WithQualityNeeded()
{
Mocker.GetMock<AllowedDownloadSpecification>()
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
.Returns(ReportRejectionType.None);
}
private void WithQualityNotNeeded()
{
Mocker.GetMock<AllowedDownloadSpecification>()
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()))
.Returns(ReportRejectionType.ExistingQualityIsEqualOrBetter);
}
[Test]
public void processSearchResults_higher_quality_should_be_called_first()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(c => c.AirDate = DateTime.Today)
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.Random(1)
.With(c => c.Quality = new QualityModel(QualityTypes.Bluray1080p, true))
.Build();
WithMatchingSeries();
WithSuccessfulDownload();
Mocker.GetMock<AllowedDownloadSpecification>()
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.Quality == QualityTypes.Bluray1080p)))
.Returns(ReportRejectionType.None);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().Contain(n => n.Success);
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
Times.Once());
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Once());
}
[Test]
public void processSearchResults_when_quality_is_not_needed_should_check_the_rest()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(c => c.AirDate = DateTime.Today)
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.Build();
WithMatchingSeries();
WithQualityNotNeeded();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().NotContain(n => n.Success);
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
Times.Exactly(5));
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_series_is_null()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.AirDate = DateTime.Today)
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithNullSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().NotContain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_series_is_mismatched()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.AirDate = DateTime.Today)
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithMisMatchedSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().NotContain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_return_after_successful_download()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
.All()
.With(e => e.AirDate = DateTime.Today)
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.Build();
WithMatchingSeries();
WithQualityNeeded();
WithSuccessfulDownload();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().Contain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Once());
}
[Test]
public void processSearchResults_should_try_next_if_download_fails()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
.All()
.With(e => e.AirDate = DateTime.Today)
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.TheLast(1)
.With(c => c.Quality = new QualityModel(QualityTypes.SDTV, true))
.Build();
WithMatchingSeries();
WithQualityNeeded();
Mocker.GetMock<DownloadProvider>()
.Setup(s => s.DownloadReport(It.Is<EpisodeParseResult>(d => d.Quality.Quality == QualityTypes.DVD)))
.Returns(false);
Mocker.GetMock<DownloadProvider>()
.Setup(s => s.DownloadReport(It.Is<EpisodeParseResult>(d => d.Quality.Quality == QualityTypes.SDTV)))
.Returns(true);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().Contain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Exactly(2));
}
[Test]
public void processSearchResults_should_skip_if_parseResult_does_not_have_airdate()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.AirDate = null)
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithMatchingSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().NotContain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_parseResult_airdate_does_not_match()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.AirDate = DateTime.Today.AddDays(10))
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithMatchingSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, _matchingSeries, DateTime.Today);
//Assert
result.Should().NotContain(n => n.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
}
}
@@ -1,210 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.DecisionEngine;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
{
public class SearchFixture : CoreTest
{
private const string SCENE_NAME = "Scene Name";
private const int SEASON_NUMBER = 5;
private const int PARSE_RESULT_COUNT = 10;
private Mock<IndexerBase> _episodeIndexer1;
private Mock<IndexerBase> _episodeIndexer2;
private Mock<IndexerBase> _brokenIndexer;
private Mock<IndexerBase> _nullIndexer;
private List<IndexerBase> _indexers;
private Series _series;
private IList<Episode> _episodes;
[SetUp]
public void Setup()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(PARSE_RESULT_COUNT)
.Build();
_series = Builder<Series>.CreateNew()
.Build();
_episodes = Builder<Episode>.CreateListOfSize(1)
.Build();
BuildIndexers(parseResults);
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _episodeIndexer2.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void BuildIndexers(IList<EpisodeParseResult> parseResults)
{
_episodeIndexer1 = new Mock<IndexerBase>();
_episodeIndexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2 = new Mock<IndexerBase>();
_episodeIndexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchSeason(It.IsAny<string>(), It.IsAny<int>()))
.Returns(parseResults);
_episodeIndexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(parseResults);
_brokenIndexer = new Mock<IndexerBase>();
_brokenIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_nullIndexer = new Mock<IndexerBase>();
_nullIndexer.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns<List<EpisodeParseResult>>(null);
}
private void WithTwoGoodOneBrokenIndexer()
{
_indexers = new List<IndexerBase> { _episodeIndexer1.Object, _brokenIndexer.Object, _episodeIndexer2.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void WithNullIndexers()
{
_indexers = new List<IndexerBase> { _nullIndexer.Object, _nullIndexer.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
private void WithSceneName()
{
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetSceneName(_series.SeriesId)).Returns(SCENE_NAME);
}
private void With30Episodes()
{
_episodes = Builder<Episode>.CreateListOfSize(30)
.Build();
}
private void WithNullEpisodes()
{
_episodes = null;
}
private void VerifyFetchEpisode(Times times)
{
_episodeIndexer1.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchEpisode(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchEpisodeWithSceneName(Times times)
{
_episodeIndexer1.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchEpisode(SCENE_NAME, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchEpisodeBrokenIndexer(Times times)
{
_brokenIndexer.Verify(v => v.FetchEpisode(It.IsAny<string>(), SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchPartialSeason(Times times)
{
_episodeIndexer1.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
_episodeIndexer2.Verify(v => v.FetchPartialSeason(_series.Title, SEASON_NUMBER, It.IsAny<int>())
, times);
}
private void VerifyFetchSeason(Times times)
{
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
_episodeIndexer1.Verify(v => v.FetchSeason(_series.Title, SEASON_NUMBER), times);
}
[Test]
public void SeasonSearch_should_skip_daily_series()
{
//Setup
_series.IsDaily = true;
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(1)).Returns(_series);
//Act
var result = Mocker.Resolve<SearchProvider>().SeasonSearch(MockNotification, _series.SeriesId, 1);
//Assert
result.Should().BeEmpty();
}
[Test]
public void PartialSeasonSearch_should_skip_daily_series()
{
//Setup
_series.IsDaily = true;
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(1)).Returns(_series);
//Act
var result = Mocker.Resolve<SearchProvider>().PartialSeasonSearch(MockNotification, _series.SeriesId, 1);
//Assert
result.Should().BeEmpty();
}
[Test]
public void EpisodeSearch_should_skip_if_air_date_is_null_and_is_a_daily_series()
{
//Setup
_series.IsDaily = true;
var episode = _episodes.First();
episode.AirDate = null;
episode.Series = _series;
Mocker.GetMock<UpgradePossibleSpecification>().Setup(s => s.IsSatisfiedBy(It.IsAny<Episode>()))
.Returns(true);
Mocker.GetMock<EpisodeProvider>().Setup(s => s.GetEpisode(episode.EpisodeId))
.Returns(episode);
//Act
var result = Mocker.Resolve<SearchProvider>().EpisodeSearch(MockNotification, episode.EpisodeId);
//Assert
result.Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Search;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.DailyEpisodeSearchTests
{
[TestFixture]
public class CheckReportFixture : TestBase
{
private Series _series;
private Episode _episode;
private EpisodeParseResult _episodeParseResult;
private SearchHistoryItem _searchHistoryItem;
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.Build();
_episode = Builder<Episode>
.CreateNew()
.With(e => e.SeriesId = _series.SeriesId)
.With(e => e.Series = _series)
.Build();
_episodeParseResult = Builder<EpisodeParseResult>
.CreateNew()
.With(p => p.AirDate = _episode.AirDate)
.With(p => p.Episodes = new List<Episode> { _episode })
.With(p => p.Series = _series)
.Build();
_searchHistoryItem = new SearchHistoryItem();
}
[Test]
public void should_return_WrongEpisode_is_parseResult_doesnt_have_airdate()
{
_episodeParseResult.AirDate = null;
Mocker.Resolve<DailyEpisodeSearch>()
.CheckReport(_series, new {Episode = _episode}, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongEpisode);
}
[Test]
public void should_return_WrongEpisode_is_parseResult_airdate_doesnt_match_episode()
{
_episodeParseResult.AirDate = _episode.AirDate.Value.AddDays(-10);
Mocker.Resolve<DailyEpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongEpisode);
}
[Test]
public void should_not_return_error_when_airDates_match()
{
Mocker.Resolve<DailyEpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.None);
}
}
}
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.DailyEpisodeSearchTests
{
[TestFixture]
public class PerformSearchFixture : PerformSearchTestBase
{
[Test]
public void should_throw_if_episode_is_null()
{
Episode nullEpisode = null;
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<DailyEpisodeSearch>()
.PerformSearch(_series, new { Episode = nullEpisode }, notification));
}
[Test]
public void should_fetch_results_from_indexers()
{
WithValidIndexers();
Mocker.Resolve<DailyEpisodeSearch>()
.PerformSearch(_series, new {Episode = _episode}, notification)
.Should()
.HaveCount(20);
}
[Test]
public void should_log_error_when_fetching_from_indexer_fails()
{
WithInvalidIndexers();
Mocker.Resolve<DailyEpisodeSearch>()
.PerformSearch(_series, new { Episode = _episode }, notification)
.Should()
.HaveCount(0);
ExceptionVerification.ExpectedErrors(2);
}
}
}
@@ -0,0 +1,131 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Search;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.EpisodeSearchTests
{
[TestFixture]
public class CheckReportFixture : TestBase
{
private Series _series;
private Episode _episode;
private EpisodeParseResult _episodeParseResult;
private SearchHistoryItem _searchHistoryItem;
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.Build();
_episode = Builder<Episode>
.CreateNew()
.With(e => e.SeriesId = _series.SeriesId)
.With(e => e.Series = _series)
.Build();
_episodeParseResult = Builder<EpisodeParseResult>
.CreateNew()
.With(p => p.SeasonNumber = 1)
.With(p => p.EpisodeNumbers = new List<int>{ _episode.EpisodeNumber })
.With(p => p.Episodes = new List<Episode> { _episode })
.With(p => p.Series = _series)
.Build();
_searchHistoryItem = new SearchHistoryItem();
}
[Test]
public void should_return_WrongSeason_when_season_doesnt_match()
{
_episode.SeasonNumber = 10;
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new {Episode = _episode}, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongSeason);
}
[Test]
public void should_return_WrongEpisode_when_episode_doesnt_match()
{
_episode.EpisodeNumber = 10;
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongEpisode);
}
[Test]
public void should_not_return_error_when_season_and_episode_match()
{
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.None);
}
[Test]
public void should_return_WrongSeason_when_season_doesnt_match_for_scene_series()
{
_series.UseSceneNumbering = true;
_episode.SceneSeasonNumber = 10;
_episode.SeasonNumber = 10;
_episode.EpisodeNumber = 10;
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongSeason);
}
[Test]
public void should_return_WrongEpisode_when_episode_doesnt_match_for_scene_series()
{
_series.UseSceneNumbering = true;
_episode.SceneEpisodeNumber = 10;
_episode.SeasonNumber = 10;
_episode.EpisodeNumber = 10;
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.WrongEpisode);
}
[Test]
public void should_not_return_error_when_season_and_episode_match_for_scene_series()
{
_series.UseSceneNumbering = true;
_episode.SceneSeasonNumber = _episode.SeasonNumber;
_episode.SceneEpisodeNumber = _episode.EpisodeNumber;
_episode.SeasonNumber = 10;
_episode.EpisodeNumber = 10;
Mocker.Resolve<EpisodeSearch>()
.CheckReport(_series, new { Episode = _episode }, _episodeParseResult, _searchHistoryItem)
.SearchError
.Should()
.Be(ReportRejectionType.None);
}
}
}
@@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.EpisodeSearchTests
{
[TestFixture]
public class PerformSearchFixture : PerformSearchTestBase
{
[Test]
public void should_throw_if_episode_is_null()
{
Episode nullEpisode = null;
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new { Episode = nullEpisode }, notification));
}
[Test]
public void should_fetch_results_from_indexers()
{
WithValidIndexers();
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new {Episode = _episode}, notification)
.Should()
.HaveCount(20);
}
[Test]
public void should_log_error_when_fetching_from_indexer_fails()
{
WithInvalidIndexers();
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new { Episode = _episode }, notification)
.Should()
.HaveCount(0);
ExceptionVerification.ExpectedErrors(2);
}
[Test]
public void should_use_scene_numbering_when_available()
{
_series.UseSceneNumbering = true;
_episode.SceneEpisodeNumber = 5;
_episode.SceneSeasonNumber = 10;
WithValidIndexers();
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new { Episode = _episode }, notification)
.Should()
.HaveCount(20);
_indexer1.Verify(v => v.FetchEpisode(_series.Title, 10, 5), Times.Once());
_indexer2.Verify(v => v.FetchEpisode(_series.Title, 10, 5), Times.Once());
}
[Test]
public void should_use_standard_numbering_when_scene_series_set_but_info_is_not_available()
{
_series.UseSceneNumbering = true;
_episode.SceneEpisodeNumber = 0;
_episode.SceneSeasonNumber = 0;
WithValidIndexers();
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new { Episode = _episode }, notification)
.Should()
.HaveCount(20);
_indexer1.Verify(v => v.FetchEpisode(_series.Title, _episode.SeasonNumber, _episode.EpisodeNumber), Times.Once());
_indexer2.Verify(v => v.FetchEpisode(_series.Title, _episode.SeasonNumber, _episode.EpisodeNumber), Times.Once());
}
[Test]
public void should_use_standard_numbering_when_not_scene_series()
{
_series.UseSceneNumbering = false;
WithValidIndexers();
Mocker.Resolve<EpisodeSearch>()
.PerformSearch(_series, new { Episode = _episode }, notification)
.Should()
.HaveCount(20);
_indexer1.Verify(v => v.FetchEpisode(_series.Title, _episode.SeasonNumber, _episode.EpisodeNumber), Times.Once());
_indexer2.Verify(v => v.FetchEpisode(_series.Title, _episode.SeasonNumber, _episode.EpisodeNumber), Times.Once());
}
}
}
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests
{
public class GetSearchTitleFixture : TestBase
{
private Series _series;
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.With(s => s.Title = "Hawaii Five-0")
.Build();
}
private void WithSceneMapping()
{
Mocker.GetMock<SceneMappingProvider>()
.Setup(s => s.GetSceneName(_series.SeriesId))
.Returns("Hawaii Five 0 2010");
}
[Test]
public void should_return_series_title_when_there_is_no_scene_mapping()
{
Mocker.Resolve<TestSearch>().GetSearchTitle(_series, 5)
.Should().Be(_series.Title);
}
[Test]
public void should_return_scene_mapping_when_one_exists()
{
WithSceneMapping();
Mocker.Resolve<TestSearch>().GetSearchTitle(_series, 5)
.Should().Be("Hawaii Five 0 2010");
}
[Test]
public void should_replace_ampersand_with_and()
{
_series.Title = "Franklin & Bash";
Mocker.Resolve<TestSearch>().GetSearchTitle(_series, 5)
.Should().Be("Franklin and Bash");
}
}
}
@@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Search;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.PartialSeasonSearchTests
{
[TestFixture]
public class CheckReportFixture : TestBase
{
private Series _series;
private List<Episode> _episodes;
private EpisodeParseResult _episodeParseResult;
private SearchHistoryItem _searchHistoryItem;
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.Build();
_episodes = Builder<Episode>
.CreateListOfSize(10)
.All()
.With(e => e.SeriesId = _series.SeriesId)
.With(e => e.Series = _series)
.Build()
.ToList();
_episodeParseResult = Builder<EpisodeParseResult>
.CreateNew()
.With(p => p.SeasonNumber = 1)
.Build();
_searchHistoryItem = new SearchHistoryItem();
}
[Test]
public void should_return_wrongSeason_when_season_does_not_match()
{
Mocker.Resolve<PartialSeasonSearch>()
.CheckReport(_series, new { SeasonNumber = 2, Episodes = _episodes }, _episodeParseResult, _searchHistoryItem)
.SearchError.Should().Be(ReportRejectionType.WrongSeason);
}
[Test]
public void should_not_return_error_when_season_matches()
{
Mocker.Resolve<PartialSeasonSearch>()
.CheckReport(_series, new { SeasonNumber = 1, Episodes = _episodes }, _episodeParseResult, _searchHistoryItem)
.SearchError.Should().Be(ReportRejectionType.None);
}
}
}
@@ -0,0 +1,81 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests.PartialSeasonSearchTests
{
[TestFixture]
public class PerformSearchFixture : PerformSearchTestBase
{
[Test]
public void should_throw_if_season_number_is_less_than_zero()
{
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<PartialSeasonSearch>()
.PerformSearch(_series, new
{
SeasonNumber = -1,
Episodes = new List<Episode>{ new Episode() }
}, notification));
}
[Test]
public void should_throw_if_episodes_is_empty()
{
Assert.Throws<ArgumentException>(() =>
Mocker.Resolve<PartialSeasonSearch>()
.PerformSearch(_series, new { SeasonNumber = 10, Episodes = new List<Episode>() }, notification));
}
[Test]
public void should_fetch_results_from_indexers()
{
WithValidIndexers();
Mocker.Resolve<PartialSeasonSearch>()
.PerformSearch(_series, new { SeasonNumber = 1, Episodes = _episodes }, notification)
.Should()
.HaveCount(40);
}
[Test]
public void should_log_error_when_fetching_from_indexer_fails()
{
WithInvalidIndexers();
Mocker.Resolve<PartialSeasonSearch>()
.PerformSearch(_series, new { SeasonNumber = 1, Episodes = _episodes }, notification)
.Should()
.HaveCount(0);
ExceptionVerification.ExpectedErrors(4);
}
[Test]
public void should_hit_each_indexer_once_for_each_prefix()
{
WithValidIndexers();
Mocker.Resolve<PartialSeasonSearch>()
.PerformSearch(_series, new { SeasonNumber = 1, Episodes = _episodes }, notification)
.Should()
.HaveCount(40);
_indexer1.Verify(v => v.FetchPartialSeason(_series.Title, 1, 0), Times.Once());
_indexer1.Verify(v => v.FetchPartialSeason(_series.Title, 1, 1), Times.Once());
_indexer2.Verify(v => v.FetchPartialSeason(_series.Title, 1, 0), Times.Once());
_indexer2.Verify(v => v.FetchPartialSeason(_series.Title, 1, 1), Times.Once());
}
}
}
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Indexer;
using NzbDrone.Core.Repository;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests
{
public class PerformSearchTestBase : TestBase
{
protected Series _series;
protected Episode _episode;
protected List<Episode> _episodes;
protected ProgressNotification notification = new ProgressNotification("Testing");
protected Mock<IndexerBase> _indexer1;
protected Mock<IndexerBase> _indexer2;
protected List<IndexerBase> _indexers;
protected IList<EpisodeParseResult> _parseResults;
[SetUp]
public void Setup()
{
_series = Builder<Series>
.CreateNew()
.Build();
_episode = Builder<Episode>
.CreateNew()
.With(e => e.SeriesId = _series.SeriesId)
.With(e => e.Series = _series)
.Build();
_episodes = Builder<Episode>
.CreateListOfSize(10)
.All()
.With(e => e.SeriesId = _series.SeriesId)
.With(e => e.Series = _series)
.Build()
.ToList();
_parseResults = Builder<EpisodeParseResult>
.CreateListOfSize(10)
.Build();
_indexer1 = new Mock<IndexerBase>();
_indexer2 = new Mock<IndexerBase>();
_indexers = new List<IndexerBase> { _indexer1.Object, _indexer2.Object };
Mocker.GetMock<IndexerProvider>()
.Setup(c => c.GetEnabledIndexers())
.Returns(_indexers);
}
protected void WithValidIndexers()
{
_indexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(_parseResults);
_indexer1.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Returns(_parseResults);
_indexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(_parseResults);
_indexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(_parseResults);
_indexer2.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Returns(_parseResults);
_indexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Returns(_parseResults);
}
protected void WithInvalidIndexers()
{
_indexer1.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_indexer1.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Throws(new Exception());
_indexer1.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_indexer2.Setup(c => c.FetchEpisode(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_indexer2.Setup(c => c.FetchDailyEpisode(It.IsAny<string>(), It.IsAny<DateTime>()))
.Throws(new Exception());
_indexer2.Setup(c => c.FetchPartialSeason(It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
.Throws(new Exception());
_indexer1.SetupGet(c => c.Name).Returns("Indexer1");
_indexer1.SetupGet(c => c.Name).Returns("Indexer2");
}
}
}
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
@@ -9,23 +10,28 @@ using NzbDrone.Core.Model;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.DecisionEngine;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Repository.Search;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
namespace NzbDrone.Core.Test.ProviderTests.SearchTests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class ProcessSearchResultsFixture : CoreTest
public class ProcessResultsFixture : TestBase
{
private Series _matchingSeries = null;
private Series _mismatchedSeries = null;
private Series _matchingSeries;
private Series _mismatchedSeries;
private Series _nullSeries = null;
private SearchHistory _searchHistory;
private ProgressNotification _notification;
private IList<Episode> _episodes;
[SetUp]
public void setup()
public void Setup()
{
_matchingSeries = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 79488)
@@ -36,6 +42,17 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.With(s => s.SeriesId = 12345)
.With(s => s.Title = "Not 30 Rock")
.Build();
_searchHistory = new SearchHistory();
_notification = new ProgressNotification("Test");
_episodes = Builder<Episode>
.CreateListOfSize(1)
.Build();
Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodesByParseResult(It.IsAny<EpisodeParseResult>()))
.Returns(_episodes);
}
private void WithMatchingSeries()
@@ -85,8 +102,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void processSearchResults_higher_quality_should_be_called_first()
public void should_process_higher_quality_results_first()
{
WithMatchingSeries();
WithSuccessfulDownload();
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
@@ -96,21 +116,18 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.Random(1)
.With(c => c.Quality = new QualityModel(QualityTypes.Bluray1080p, true))
.With(c => c.Age = 100)
.Build();
.Build()
.ToList();
WithMatchingSeries();
WithSuccessfulDownload();
Mocker.GetMock<AllowedDownloadSpecification>()
.Setup(s => s.IsSatisfiedBy(It.Is<EpisodeParseResult>(d => d.Quality.Quality == QualityTypes.Bluray1080p)))
.Returns(ReportRejectionType.None);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().Contain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().Contain(s => s.Success);
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
Times.Once());
@@ -119,31 +136,29 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void processSearchResults_newer_report_should_be_called_first()
public void should_process_newer_reports_first()
{
WithMatchingSeries();
WithSuccessfulDownload();
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumbers = new List<int> { 1 })
.With(c => c.Quality = new QualityModel(QualityTypes.Bluray1080p, true))
.With(c => c.Age = 300)
.Build();
.Build()
.ToList();
parseResults[2].Age = 100;
WithMatchingSeries();
WithSuccessfulDownload();
Mocker.GetMock<AllowedDownloadSpecification>()
.Setup(s => s.IsSatisfiedBy(It.IsAny<EpisodeParseResult>())).Returns(ReportRejectionType.None);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(MockNotification, parseResults, new SearchHistory(), _matchingSeries, 1, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().Contain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().Contain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.Is<EpisodeParseResult>(d => d.Age != 100)), Times.Never());
@@ -151,24 +166,23 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void processSearchResults_when_quality_is_not_needed_should_check_the_rest()
public void should_check_other_reports_when_quality_is_not_wanted()
{
WithMatchingSeries();
WithQualityNotNeeded();
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumbers = new List<int> { 1 })
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.Build();
.Build()
.ToList();
WithMatchingSeries();
WithQualityNotNeeded();
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().NotContain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().NotContain(s => s.Success);
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
Times.Exactly(5));
@@ -177,99 +191,55 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
}
[Test]
public void processSearchResults_should_skip_if_series_is_null()
public void should_should_skip_if_series_is_not_watched()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumbers = new List<int> { 1 })
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
.Build()
.ToList();
WithNullSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().NotContain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().NotContain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_series_is_mismatched()
public void should_skip_if_series_does_not_match_searched_series()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumbers = new List<int> { 1 })
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
.Build()
.ToList();
WithMisMatchedSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().NotContain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().NotContain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_season_doesnt_match()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 2)
.With(e => e.EpisodeNumbers = new List<int> { 1 })
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithMatchingSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().NotContain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_episodeNumber_doesnt_match()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumbers = new List<int> { 2 })
.With(e => e.Quality = new QualityModel(QualityTypes.HDTV720p, false))
.Build();
WithMatchingSeries();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1, 1);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().NotContain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Never());
}
[Test]
public void processSearchResults_should_skip_if_any_episodeNumber_was_already_added_to_download_queue()
public void should_skip_if_episode_was_already_downloaded()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
.All()
@@ -278,25 +248,26 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.TheLast(1)
.With(e => e.EpisodeNumbers = new List<int> { 1, 2, 3, 4, 5 })
.Build();
.Build()
.ToList();
WithMatchingSeries();
WithQualityNeeded();
WithSuccessfulDownload();
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().Contain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().Contain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Once());
}
[Test]
public void processSearchResults_should_try_next_if_download_fails()
public void should_try_next_report_if_download_fails()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(2)
.All()
@@ -305,7 +276,8 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.With(c => c.Quality = new QualityModel(QualityTypes.DVD, true))
.TheLast(1)
.With(c => c.Quality = new QualityModel(QualityTypes.SDTV, true))
.Build();
.Build()
.ToList();
WithMatchingSeries();
WithQualityNeeded();
@@ -319,18 +291,18 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.Returns(true);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, new SearchHistory(), _matchingSeries, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
result.Should().HaveCount(parseResults.Count);
result.Should().Contain(s => s.Success);
result.SearchHistoryItems.Should().HaveCount(parseResults.Count);
result.SearchHistoryItems.Should().Contain(s => s.Success);
Mocker.GetMock<DownloadProvider>().Verify(c => c.DownloadReport(It.IsAny<EpisodeParseResult>()),
Times.Exactly(2));
}
[Test]
public void processSearchResults_Successes_should_not_be_null_or_empty()
public void should_return_valid_successes_when_one_or_more_downloaded()
{
var parseResults = Builder<EpisodeParseResult>.CreateListOfSize(5)
.All()
@@ -341,9 +313,8 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.Random(1)
.With(c => c.Quality = new QualityModel(QualityTypes.Bluray1080p, true))
.With(c => c.Age = 100)
.Build();
var searchHistory = new SearchHistory();
.Build()
.ToList();
WithMatchingSeries();
WithSuccessfulDownload();
@@ -353,11 +324,11 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
.Returns(ReportRejectionType.None);
//Act
var result = Mocker.Resolve<SearchProvider>().ProcessSearchResults(new ProgressNotification("Test"), parseResults, searchHistory, _matchingSeries, 1, 1);
var result = Mocker.Resolve<TestSearch>().ProcessReports(_matchingSeries, new { }, parseResults, _searchHistory, _notification);
//Assert
searchHistory.Successes.Should().NotBeNull();
searchHistory.Successes.Should().NotBeEmpty();
result.Successes.Should().NotBeNull();
result.Successes.Should().NotBeEmpty();
Mocker.GetMock<AllowedDownloadSpecification>().Verify(c => c.IsSatisfiedBy(It.IsAny<EpisodeParseResult>()),
Times.Once());
@@ -365,4 +336,4 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests
Times.Once());
}
}
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NLog;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.DecisionEngine;
using NzbDrone.Core.Providers.Search;
using NzbDrone.Core.Repository.Search;
namespace NzbDrone.Core.Test.ProviderTests.SearchTests
{
public class TestSearch : SearchBase
{
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public TestSearch(SeriesProvider seriesProvider, EpisodeProvider episodeProvider, DownloadProvider downloadProvider,
IndexerProvider indexerProvider, SceneMappingProvider sceneMappingProvider,
AllowedDownloadSpecification allowedDownloadSpecification, SearchHistoryProvider searchHistoryProvider)
: base(seriesProvider, episodeProvider, downloadProvider, indexerProvider, sceneMappingProvider,
allowedDownloadSpecification, searchHistoryProvider)
{
}
public override List<EpisodeParseResult> PerformSearch(Repository.Series series, dynamic options, Model.Notification.ProgressNotification notification)
{
if (options.Episode == null)
throw new ArgumentException("Episode is invalid");
notification.CurrentMessage = "Looking for " + options.Episode;
var reports = new List<EpisodeParseResult>();
var title = GetSearchTitle(series);
var seasonNumber = options.Episode.SeasonNumber;
var episodeNumber = options.Episode.EpisodeNumber;
Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer =>
{
try
{
reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodeNumber));
}
catch (Exception e)
{
logger.ErrorException(String.Format("An error has occurred while searching for {0}-S{1:00}E{2:00} from: {3}",
series.Title, options.SeasonNumber, options.EpisodeNumber, indexer.Name), e);
}
});
return reports;
}
public override SearchHistoryItem CheckReport(Repository.Series series, dynamic options, EpisodeParseResult episodeParseResult, Repository.Search.SearchHistoryItem item)
{
return item;
}
protected override void FinalizeSearch(Repository.Series series, dynamic options, bool reportsFound, Model.Notification.ProgressNotification notification)
{
logger.Warn("Unable to find {0} in any of indexers.", series.Title);
}
}
}