DeleteInvalidEpisodes with tests added to delete episodes that TheTvDb no longer has (previously bad data).

This commit is contained in:
Mark McDowall 2011-09-29 21:40:00 -07:00
parent 7ca59b92aa
commit 30ffe79442
5 changed files with 363 additions and 1 deletions

View File

@ -0,0 +1,323 @@
// ReSharper disable RedundantUsingDirective
using System;
using System.Collections.Generic;
using System.Linq;
using AutoMoq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Repository.Quality;
using NzbDrone.Core.Test.Framework;
using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Test
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class EpisodeProviderTest_DeleteInvalidEpisodes : TestBase
{
[Test]
public void Delete_None()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 20)
.With(e => e.EpisodeNumber = 20)
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(1);
}
[Test]
public void Delete_TvDbId()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 20)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 300)
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(0);
}
[Test]
public void Delete_EpisodeNumber()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 1)
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(0);
}
[Test]
public void Delete_Both()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode1 = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 1)
.Build();
var fakeEpisode2 = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 1)
.With(e => e.TvDbEpisodeId = 300)
.Build();
//This should not be deleted
var fakeEpisode3 = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 1)
.With(e => e.TvDbEpisodeId = 1)
.With(e => e.Title = "Not Deleted")
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode1);
db.Insert(fakeEpisode2);
db.Insert(fakeEpisode3);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(1);
result.First().Title.Should().Be("Not Deleted");
}
//Other series, by season/episode + by tvdbid
[Test]
public void Delete_TvDbId_multiple_series()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 20)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 300)
.Build();
//Other Series
var otherFakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = 12345)
.Build();
var otherFakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = 12345)
.With(e => e.SeasonNumber = 20)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 300)
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode);
db.Insert(otherFakeSeries);
db.Insert(otherFakeEpisode);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(1);
}
[Test]
public void Delete_EpisodeNumber_multiple_series()
{
//Setup
const int seriesId = 71663;
const int episodeCount = 10;
var tvDbSeries = Builder<TvdbSeries>.CreateNew().With(
c => c.Episodes =
new List<TvdbEpisode>(Builder<TvdbEpisode>.CreateListOfSize(episodeCount).
WhereAll()
.Have(l => l.Language = new TvdbLanguage(0, "eng", "a"))
.Build())
).With(c => c.Id = seriesId).Build();
var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = seriesId)
.Build();
var fakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = seriesId)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 20)
.With(e => e.TvDbEpisodeId = 1)
.Build();
//Other Series
var otherFakeSeries = Builder<Series>.CreateNew()
.With(c => c.SeriesId = 12345)
.Build();
var otherFakeEpisode = Builder<Episode>.CreateNew()
.With(e => e.SeriesId = 12345)
.With(e => e.SeasonNumber = 1)
.With(e => e.EpisodeNumber = 4)
.With(e => e.TvDbEpisodeId = 2)
.Build();
var mocker = new AutoMoqer();
var db = MockLib.GetEmptyDatabase();
mocker.SetConstant(db);
db.Insert(fakeSeries);
db.Insert(fakeEpisode);
db.Insert(otherFakeSeries);
db.Insert(otherFakeEpisode);
//Act
mocker.Resolve<EpisodeProvider>().DeleteInvalidEpisodes(fakeSeries, tvDbSeries);
//Assert
var result = db.Fetch<Episode>();
result.Should().HaveCount(1);
}
}
}

View File

@ -90,6 +90,7 @@
<ItemGroup> <ItemGroup>
<Compile Include="BacklogSearchJobTest.cs" /> <Compile Include="BacklogSearchJobTest.cs" />
<Compile Include="BannerDownloadJobTest.cs" /> <Compile Include="BannerDownloadJobTest.cs" />
<Compile Include="EpisodeProviderTest_DeleteInvalidEpisodes.cs" />
<Compile Include="InventoryProvider_IsAcceptableSizeTest.cs" /> <Compile Include="InventoryProvider_IsAcceptableSizeTest.cs" />
<Compile Include="QualityTypeProviderTest.cs" /> <Compile Include="QualityTypeProviderTest.cs" />
<Compile Include="MisnamedProviderTest.cs" /> <Compile Include="MisnamedProviderTest.cs" />

View File

@ -6,6 +6,7 @@ using NLog;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using PetaPoco; using PetaPoco;
using TvdbLib.Data;
namespace NzbDrone.Core.Providers namespace NzbDrone.Core.Providers
{ {
@ -262,6 +263,9 @@ namespace NzbDrone.Core.Providers
Logger.Info("Finished episode refresh for series: {0}. Successful: {1} - Failed: {2} ", Logger.Info("Finished episode refresh for series: {0}. Successful: {1} - Failed: {2} ",
tvDbSeriesInfo.SeriesName, successCount, failCount); tvDbSeriesInfo.SeriesName, successCount, failCount);
//DeleteInvalidEpisodes
DeleteInvalidEpisodes(series, tvDbSeriesInfo);
} }
public virtual void UpdateEpisode(Episode episode) public virtual void UpdateEpisode(Episode episode)
@ -364,5 +368,38 @@ namespace NzbDrone.Core.Providers
episode.Series = _seriesProvider.GetSeries(episode.SeriesId); episode.Series = _seriesProvider.GetSeries(episode.SeriesId);
return episode; return episode;
} }
public virtual void DeleteInvalidEpisodes(Series series, TvdbSeries tvDbSeriesInfo)
{
Logger.Info("Starting deletion of invalid episode for series: {0}", series.Title.WithDefault(series.SeriesId));
var seasons = tvDbSeriesInfo.Episodes.Select(e => e.SeasonNumber).Distinct();
foreach (var s in seasons)
{
//Avoiding accessing modified closure
var season = s;
Logger.Trace("Processing invalid episodes for {0}, Season: {1}", series.SeriesId, season);
var episodesInSeason = tvDbSeriesInfo.Episodes.Where(e => e.SeasonNumber == season).Select(e => e.EpisodeNumber);
var episodesString = String.Join(", ", episodesInSeason);
var seasonQuery = String.Format("DELETE FROM Episodes WHERE SeriesId = {0} AND SeasonNumber = {1} AND EpisodeNumber NOT IN ({2})",
series.SeriesId, season, episodesString);
_database.Execute(seasonQuery);
}
//Delete Episodes not matching TvDbIds for this series
var tvDbIds = tvDbSeriesInfo.Episodes.Select(e => e.Id);
var tvDbIdString = String.Join(", ", tvDbIds);
var tvDbIdQuery = String.Format("DELETE FROM Episodes WHERE SeriesId = {0} AND TvDbEpisodeId > 0 AND TvDbEpisodeId NOT IN ({1})",
series.SeriesId, tvDbIdString);
Logger.Trace("Deleting nivalid episodes by TvDbId for {0}", series.SeriesId);
_database.Execute(tvDbIdQuery);
Logger.Trace("Finished deleting invalid episodes for {0}", series.SeriesId);
}
} }
} }

View File

@ -82,7 +82,7 @@ namespace NzbDrone.Core.Providers
public virtual Series UpdateSeriesInfo(int seriesId) public virtual Series UpdateSeriesInfo(int seriesId)
{ {
var tvDbSeries = _tvDbProvider.GetSeries(seriesId, true); var tvDbSeries = _tvDbProvider.GetSeries(seriesId, false);
var series = GetSeries(seriesId); var series = GetSeries(seriesId);
series.SeriesId = tvDbSeries.Id; series.SeriesId = tvDbSeries.Id;

View File

@ -31,6 +31,7 @@ NZBDrone makes use of the following projects:
* [MVC Mini Profiler](http://code.google.com/p/mvc-mini-profiler/) * [MVC Mini Profiler](http://code.google.com/p/mvc-mini-profiler/)
* [Migrator.NET](https://github.com/kayone/Migrator.NET) * [Migrator.NET](https://github.com/kayone/Migrator.NET)
* [Telerik Extensions for ASP.NET MVC](http://www.telerik.com/products/aspnet-mvc.aspx) * [Telerik Extensions for ASP.NET MVC](http://www.telerik.com/products/aspnet-mvc.aspx)
## Development Tools ## Development Tools
* [Visual Studio 2010](http://www.microsoft.com/visualstudio/en-us/products/2010-editions) * [Visual Studio 2010](http://www.microsoft.com/visualstudio/en-us/products/2010-editions)
* [ReSharper 6](http://www.jetbrains.com/resharper/index.html) * [ReSharper 6](http://www.jetbrains.com/resharper/index.html)