diff --git a/src/NzbDrone.Core.Test/DecisionEngineTests/Search/TorrentSeedingSpecificationFixture.cs b/src/NzbDrone.Core.Test/DecisionEngineTests/Search/TorrentSeedingSpecificationFixture.cs new file mode 100644 index 000000000..56c4ac84f --- /dev/null +++ b/src/NzbDrone.Core.Test/DecisionEngineTests/Search/TorrentSeedingSpecificationFixture.cs @@ -0,0 +1,111 @@ +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Datastore; +using NzbDrone.Core.DecisionEngine.Specifications.Search; +using NzbDrone.Core.Indexers; +using NzbDrone.Core.Indexers.TorrentRss; +using NzbDrone.Core.IndexerSearch.Definitions; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.DecisionEngineTests.Search +{ + [TestFixture] + public class TorrentSeedingSpecificationFixture : TestBase + { + private Series _series; + private RemoteEpisode _remoteEpisode; + private IndexerDefinition _indexerDefinition; + + [SetUp] + public void Setup() + { + _series = Builder.CreateNew().With(s => s.Id = 1).Build(); + + _remoteEpisode = new RemoteEpisode + { + Series = _series, + Release = new TorrentInfo + { + IndexerId = 1, + Title = "Series.Title.S01.720p.BluRay.X264-RlsGrp", + Seeders = 0 + } + }; + + _indexerDefinition = new IndexerDefinition + { + Settings = new TorrentRssIndexerSettings { MinimumSeeders = 5 } + }; + + Mocker.GetMock() + .Setup(v => v.Get(1)) + .Returns(_indexerDefinition); + + } + + private void GivenReleaseSeeders(int? seeders) + { + (_remoteEpisode.Release as TorrentInfo).Seeders = seeders; + } + + [Test] + public void should_return_true_if_not_torrent() + { + _remoteEpisode.Release = new ReleaseInfo + { + IndexerId = 1, + Title = "Series.Title.S01.720p.BluRay.X264-RlsGrp" + }; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_if_indexer_not_specified() + { + _remoteEpisode.Release.IndexerId = 0; + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_if_indexer_no_longer_exists() + { + Mocker.GetMock() + .Setup(v => v.Get(It.IsAny())) + .Callback(i => { throw new ModelNotFoundException(typeof(IndexerDefinition), i); }); + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_return_true_if_seeds_unknown() + { + GivenReleaseSeeders(null); + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } + + [TestCase(5)] + [TestCase(6)] + public void should_return_true_if_seeds_above_or_equal_to_limit(int seeders) + { + GivenReleaseSeeders(seeders); + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); + } + + [TestCase(0)] + [TestCase(4)] + public void should_return_false_if_seeds_belove_limit(int seeders) + { + GivenReleaseSeeders(seeders); + + Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 4bc77554d..1610759ce 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -161,6 +161,7 @@ + diff --git a/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs b/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs index f095170c4..227123f96 100644 --- a/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs +++ b/src/NzbDrone.Core/DecisionEngine/Specifications/TorrentSeedingSpecification.cs @@ -1,6 +1,5 @@ -using System.Linq; -using NLog; -using NzbDrone.Common.Reflection; +using NLog; +using NzbDrone.Core.Datastore; using NzbDrone.Core.Indexers; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Parser.Model; @@ -9,10 +8,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.Search { public class TorrentSeedingSpecification : IDecisionEngineSpecification { - private readonly IndexerFactory _indexerFactory; + private readonly IIndexerFactory _indexerFactory; private readonly Logger _logger; - public TorrentSeedingSpecification(IndexerFactory indexerFactory, Logger logger) + public TorrentSeedingSpecification(IIndexerFactory indexerFactory, Logger logger) { _indexerFactory = indexerFactory; _logger = logger; @@ -26,12 +25,22 @@ public Decision IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchCriteriaBase se { var torrentInfo = remoteEpisode.Release as TorrentInfo; - if (torrentInfo == null) + if (torrentInfo == null || torrentInfo.IndexerId == 0) { return Decision.Accept(); } - var indexer = _indexerFactory.Get(torrentInfo.IndexerId); + IndexerDefinition indexer; + try + { + indexer = _indexerFactory.Get(torrentInfo.IndexerId); + } + catch (ModelNotFoundException) + { + _logger.Debug("Indexer with id {0} does not exist, skipping seeders check", torrentInfo.IndexerId); + return Decision.Accept(); + } + var torrentIndexerSettings = indexer.Settings as ITorrentIndexerSettings; if (torrentIndexerSettings != null)