diff --git a/NzbDrone.Core.Test/JobTests/SeriesSearchJobTest.cs b/NzbDrone.Core.Test/JobTests/SeriesSearchJobTest.cs index 6c74b4faf..8b527ee20 100644 --- a/NzbDrone.Core.Test/JobTests/SeriesSearchJobTest.cs +++ b/NzbDrone.Core.Test/JobTests/SeriesSearchJobTest.cs @@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.JobTests Mocker.GetMock() .Setup(c => c.GetSeasons(1)).Returns(seasons); - Mocker.GetMock() + Mocker.GetMock() .Setup(c => c.IsIgnored(It.IsAny(), It.IsAny())).Returns(false); Mocker.GetMock() diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 2126da70d..c69605810 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -115,6 +115,7 @@ + diff --git a/NzbDrone.Core.Test/ProviderTests/EpisodeProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/EpisodeProviderTest.cs index 47ff0f5f7..3ee535711 100644 --- a/NzbDrone.Core.Test/ProviderTests/EpisodeProviderTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/EpisodeProviderTest.cs @@ -439,7 +439,6 @@ namespace NzbDrone.Core.Test.ProviderTests result.Should().HaveSameCount(fakeEpisodes.Episodes); } - [Test] public void RefreshEpisodeInfo_ignore_season_zero() { @@ -466,6 +465,10 @@ namespace NzbDrone.Core.Test.ProviderTests .Setup(c => c.GetSeries(seriesId, true)) .Returns(fakeEpisodes); + Mocker.GetMock() + .Setup(s => s.IsIgnored(seriesId, 0)) + .Returns(true); + //Act Mocker.Resolve().RefreshEpisodeInfo(fakeSeries); @@ -694,6 +697,10 @@ namespace NzbDrone.Core.Test.ProviderTests .Setup(c => c.GetSeries(seriesId, true)) .Returns(tvdbSeries); + Mocker.GetMock() + .Setup(s => s.IsIgnored(seriesId, It.IsAny())) + .Returns(true); + //Act Mocker.Resolve().RefreshEpisodeInfo(fakeSeries); @@ -704,180 +711,6 @@ namespace NzbDrone.Core.Test.ProviderTests result.Where(e => e.Ignored).Should().HaveCount(episodeCount); } - [Test] - public void IsSeasonIgnored_should_return_true_if_all_episodes_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.Ignored = true) - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 2) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 2); - - //Assert - result.Should().BeTrue(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_none_of_episodes_are_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.Ignored = false) - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 2) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 2); - - //Assert - result.Should().BeFalse(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_some_of_episodes_are_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 2) - .With(c => c.Ignored = true) - .Build(); - - episodes[2].Ignored = false; - - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 2); - - //Assert - result.Should().BeFalse(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_zero_episodes_in_db_for_season() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 3) - .With(c => c.Ignored = true) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 2); - - //Assert - result.Should().BeFalse(); - } - - [Test] - public void IsSeasonIgnored_should_return_true_if_zero_episodes_in_db_for_season_and_previous_is_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 3) - .With(c => c.Ignored = true) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 4); - - //Assert - result.Should().BeTrue(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_zero_episodes_in_db_for_season_and_previous_is_not_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 3) - .With(c => c.Ignored = false) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 4); - - //Assert - result.Should().BeFalse(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_zero_episodes_in_db_for_season_one() - { - WithRealDb(); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 1); - - //Assert - result.Should().BeFalse(); - } - - [Test] - public void IsSeasonIgnored_should_return_true_if_zero_episodes_in_db_for_season_zero() - { - WithRealDb(); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 0); - - //Assert - result.Should().BeTrue(); - } - - [Test] - public void IsSeasonIgnored_should_return_false_if_season_zero_is_not_ignored() - { - WithRealDb(); - - var episodes = Builder.CreateListOfSize(4) - .All() - .With(c => c.SeriesId = 10) - .With(c => c.SeasonNumber = 0) - .With(c => c.Ignored = false) - .Build(); - - episodes.ToList().ForEach(c => Db.Insert(c)); - - //Act - var result = Mocker.Resolve().IsIgnored(10, 0); - - //Assert - result.Should().BeFalse(); - } - [Test] [Explicit] public void Add_daily_show_episodes() @@ -1049,6 +882,10 @@ namespace NzbDrone.Core.Test.ProviderTests .With(e => e.Ignored = false) .Build(); + Mocker.GetMock() + .Setup(s => s.IsIgnored(newEpisode.SeriesId, newEpisode.SeasonNumber)) + .Returns(true); + //Act Mocker.Resolve().AddEpisode(newEpisode); diff --git a/NzbDrone.Core.Test/ProviderTests/SeasonProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/SeasonProviderTest.cs new file mode 100644 index 000000000..2a4401c22 --- /dev/null +++ b/NzbDrone.Core.Test/ProviderTests/SeasonProviderTest.cs @@ -0,0 +1,193 @@ +// ReSharper disable RedundantUsingDirective + +using System; +using System.Collections.Generic; +using System.Linq; + +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.Model; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Repository; +using NzbDrone.Core.Repository.Quality; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Test.Common.AutoMoq; +using PetaPoco; +using TvdbLib.Data; + +namespace NzbDrone.Core.Test.ProviderTests +{ + [TestFixture] + // ReSharper disable InconsistentNaming + public class SeasonProviderTest : CoreTest + { + [Test] + public void AddSeason_should_insert_season_to_database_with_ignored_false() + { + WithRealDb(); + + var seriesId = 10; + var seasonNumber = 50; + + //Act + Mocker.Resolve().Add(seriesId, seasonNumber); + + //Assert + var result = Db.Fetch(); + result.Should().HaveCount(1); + result.First().SeriesId.Should().Be(seriesId); + result.First().SeasonNumber.Should().Be(seasonNumber); + result.First().Ignored.Should().BeFalse(); + } + + [TestCase(true)] + [TestCase(false)] + public void AddSeason_should_insert_season_to_database_with_preset_ignored_status(bool isIgnored) + { + WithRealDb(); + + var seriesId = 10; + var seasonNumber = 50; + + //Act + Mocker.Resolve().Add(seriesId, seasonNumber, isIgnored); + + //Assert + var result = Db.Fetch(); + result.Should().HaveCount(1); + result.First().SeriesId.Should().Be(seriesId); + result.First().SeasonNumber.Should().Be(seasonNumber); + result.First().Ignored.Should().Be(isIgnored); + } + + [Test] + public void DeleteSeason_should_remove_season_from_database() + { + WithRealDb(); + + var fakeSeason = Builder.CreateNew().Build(); + + Db.Insert(fakeSeason); + + //Act + Mocker.Resolve().Delete(fakeSeason.SeriesId, fakeSeason.SeasonNumber); + + //Assert + var result = Db.Fetch(); + result.Should().BeEmpty(); + } + + [Test] + public void SetIgnore_should_update_ignored_status() + { + WithRealDb(); + + var fakeSeason = Builder.CreateNew() + .With(s => s.Ignored = false) + .Build(); + + var id = Db.Insert(fakeSeason); + + //Act + Mocker.Resolve().SetIgnore(fakeSeason.SeriesId, fakeSeason.SeasonNumber, true); + + //Assert + var result = Db.SingleOrDefault(id); + result.Ignored.Should().BeTrue(); + } + + [Test] + public void IsIgnored_should_return_ignored_status_of_season() + { + //Setup + var fakeSeason = Builder.CreateNew() + .With(s => s.Ignored = false) + .Build(); + + Db.Insert(fakeSeason); + + //Act + var result = Mocker.Resolve().IsIgnored(fakeSeason.SeriesId, fakeSeason.SeasonNumber); + + //Assert + result.Should().Be(fakeSeason.Ignored); + Db.Fetch().Count.Should().Be(1); + } + + [Test] + public void IsIgnored_should_return_true_if_not_in_db_and_is_season_zero() + { + //Setup + WithRealDb(); + + //Act + var result = Mocker.Resolve().IsIgnored(10, 0); + + //Assert + result.Should().BeTrue(); + Db.Fetch().Should().HaveCount(1); + } + + [Test] + public void IsIgnored_should_return_false_if_not_in_db_and_is_season_one() + { + //Setup + WithRealDb(); + + //Act + var result = Mocker.Resolve().IsIgnored(10, 1); + + //Assert + result.Should().BeFalse(); + Db.Fetch().Should().HaveCount(1); + } + + [Test] + public void IsIgnored_should_return_false_if_not_in_db_and_previous_season_is_not_ignored() + { + //Setup + WithRealDb(); + + var lastSeason = Builder.CreateNew() + .With(s => s.SeriesId = 10) + .With(s => s.SeasonNumber = 4) + .With(s => s.Ignored = true) + .Build(); + + Db.Insert(lastSeason); + + //Act + var result = Mocker.Resolve().IsIgnored(10, 5); + + //Assert + result.Should().BeFalse(); + Db.Fetch().Should().HaveCount(2); + } + + [Test] + public void IsIgnored_should_return_true_if_not_in_db_and_previous_season_is_ignored() + { + //Setup + WithRealDb(); + + var lastSeason = Builder.CreateNew() + .With(s => s.SeriesId = 10) + .With(s => s.SeasonNumber = 4) + .With(s => s.Ignored = true) + .Build(); + + Db.Insert(lastSeason); + + //Act + var result = Mocker.Resolve().IsIgnored(10, 5); + + //Assert + result.Should().BeTrue(); + Db.Fetch().Should().HaveCount(2); + } + } +} diff --git a/NzbDrone.Core/Datastore/Migrations/Migration20120220.cs b/NzbDrone.Core/Datastore/Migrations/Migration20120220.cs new file mode 100644 index 000000000..0d4d40de7 --- /dev/null +++ b/NzbDrone.Core/Datastore/Migrations/Migration20120220.cs @@ -0,0 +1,22 @@ +using System; +using System.Data; +using Migrator.Framework; + +namespace NzbDrone.Core.Datastore.Migrations +{ + + [Migration(20120220)] + public class Migration20120220 : NzbDroneMigration + { + protected override void MainDbUpgrade() + { + Database.AddTable("Seasons", new[] + { + new Column("SeasonId", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("SeriesId", DbType.Int32, ColumnProperty.NotNull), + new Column("SeasonNumber", DbType.Int32, ColumnProperty.NotNull), + new Column("Ignored", DbType.Boolean, ColumnProperty.NotNull) + }); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Jobs/SeriesSearchJob.cs b/NzbDrone.Core/Jobs/SeriesSearchJob.cs index 5e225f1dd..6886b4cb4 100644 --- a/NzbDrone.Core/Jobs/SeriesSearchJob.cs +++ b/NzbDrone.Core/Jobs/SeriesSearchJob.cs @@ -8,15 +8,16 @@ namespace NzbDrone.Core.Jobs { public class SeriesSearchJob : IJob { - private readonly EpisodeProvider _episodeProvider; private readonly SeasonSearchJob _seasonSearchJob; + private readonly SeasonProvider _seasonProvider; private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public SeriesSearchJob(EpisodeProvider episodeProvider, SeasonSearchJob seasonSearchJob) + public SeriesSearchJob(SeasonSearchJob seasonSearchJob, + SeasonProvider seasonProvider) { - _episodeProvider = episodeProvider; _seasonSearchJob = seasonSearchJob; + _seasonProvider = seasonProvider; } public string Name @@ -35,12 +36,12 @@ namespace NzbDrone.Core.Jobs throw new ArgumentOutOfRangeException("targetId"); Logger.Debug("Getting seasons from database for series: {0}", targetId); - var seasons = _episodeProvider.GetSeasons(targetId).Where(s => s > 0); + var seasons = _seasonProvider.GetSeasons(targetId).Where(s => s > 0); foreach (var season in seasons) { //Skip ignored seasons - if (_episodeProvider.IsIgnored(targetId, season)) + if (_seasonProvider.IsIgnored(targetId, season)) continue; _seasonSearchJob.Start(notification, targetId, season); diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 3b73de5e5..e9d984107 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -222,6 +222,7 @@ + @@ -269,6 +270,7 @@ + @@ -337,6 +339,7 @@ + diff --git a/NzbDrone.Core/Providers/EpisodeProvider.cs b/NzbDrone.Core/Providers/EpisodeProvider.cs index 0aceb7799..dbc157735 100644 --- a/NzbDrone.Core/Providers/EpisodeProvider.cs +++ b/NzbDrone.Core/Providers/EpisodeProvider.cs @@ -20,13 +20,16 @@ namespace NzbDrone.Core.Providers private static readonly Regex multiPartCleanupRegex = new Regex(@"\(\d+\)$", RegexOptions.Compiled); private readonly TvDbProvider _tvDbProvider; + private readonly SeasonProvider _seasonProvider; private readonly IDatabase _database; private readonly SeriesProvider _seriesProvider; [Inject] - public EpisodeProvider(IDatabase database, SeriesProvider seriesProvider, TvDbProvider tvDbProviderProvider) + public EpisodeProvider(IDatabase database, SeriesProvider seriesProvider, + TvDbProvider tvDbProviderProvider, SeasonProvider seasonProvider) { _tvDbProvider = tvDbProviderProvider; + _seasonProvider = seasonProvider; _database = database; _seriesProvider = seriesProvider; } @@ -38,8 +41,7 @@ namespace NzbDrone.Core.Providers public virtual void AddEpisode(Episode episode) { //If Season is ignored ignore this episode - if (IsIgnored(episode.SeriesId, episode.SeasonNumber)) - episode.Ignored = true; + episode.Ignored = _seasonProvider.IsIgnored(episode.SeriesId, episode.SeasonNumber); _database.Insert(episode); } @@ -312,7 +314,7 @@ namespace NzbDrone.Core.Providers //Else we need to check if this episode should be ignored based on IsIgnored rules else { - episodeToUpdate.Ignored = IsIgnored(series.SeriesId, episode.SeasonNumber); + episodeToUpdate.Ignored = _seasonProvider.IsIgnored(series.SeriesId, episode.SeasonNumber); } } else @@ -396,10 +398,14 @@ namespace NzbDrone.Core.Providers return _database.Fetch("SELECT EpisodeNumber FROM Episodes WHERE SeriesId=@0 AND SeasonNumber=@1", seriesId, seasonNumber).OrderBy(c => c).ToList(); } - public virtual void SetSeasonIgnore(long seriesId, int seasonNumber, bool isIgnored) + public virtual void SetSeasonIgnore(int seriesId, int seasonNumber, bool isIgnored) { logger.Info("Setting ignore flag on Series:{0} Season:{1} to {2}", seriesId, seasonNumber, isIgnored); + //Set the SeasonIgnore + _seasonProvider.SetIgnore(seriesId, seasonNumber, isIgnored); + + //Ignore all the episodes in the season _database.Execute(@"UPDATE Episodes SET Ignored = @0 WHERE SeriesId = @1 AND SeasonNumber = @2 AND Ignored = @3", isIgnored, seriesId, seasonNumber, !isIgnored); diff --git a/NzbDrone.Core/Providers/SeasonProvider.cs b/NzbDrone.Core/Providers/SeasonProvider.cs new file mode 100644 index 000000000..f80ba99f5 Binary files /dev/null and b/NzbDrone.Core/Providers/SeasonProvider.cs differ diff --git a/NzbDrone.Core/Repository/Season.cs b/NzbDrone.Core/Repository/Season.cs new file mode 100644 index 000000000..8f9ce8f74 --- /dev/null +++ b/NzbDrone.Core/Repository/Season.cs @@ -0,0 +1,16 @@ +using System; +using NzbDrone.Core.Model; +using PetaPoco; + +namespace NzbDrone.Core.Repository +{ + [TableName("Seasons")] + [PrimaryKey("SeasonId", autoIncrement = true)] + public class Season + { + public int SeasonId { get; set; } + public int SeriesId { get; set; } + public int SeasonNumber { get; set; } + public Boolean Ignored { get; set; } + } +} \ No newline at end of file