Diskscan/Info update job refactoring and test

pull/2/head
kay.one 13 years ago
parent fb63d0536a
commit e4ff0d6471

@ -0,0 +1,125 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using AutoMoq;
using FizzWare.NBuilder;
using MbUnit.Framework;
using Moq;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Jobs;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class DiskScanJobTest : TestBase
{
[Test]
public void series_specific_scan_should_scan_series()
{
var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12)
.With(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(series.SeriesId))
.Returns(series);
mocker.GetMock<MediaFileProvider>()
.Setup(p => p.Scan(series))
.Returns(new List<EpisodeFile>());
//Act
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId);
//Assert
mocker.VerifyAllMocks();
}
[Test]
public void series_with_no_episodes_should_skip_scan()
{
var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12)
.With(s => s.Episodes = new List<Episode>())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(series.SeriesId))
.Returns(series);
//Act
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId);
//Assert
mocker.VerifyAllMocks();
}
[Test]
public void job_with_no_target_should_scan_all_series()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.AndTheNext(1).Has(s => s.SeriesId = 15)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
[Test]
public void job_with_no_target_should_scan_series_with_episodes()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.And(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.AndTheNext(1).Has(s => s.SeriesId = 15)
.And(s => s.Episodes = new List<Episode>())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
}
}

@ -0,0 +1,140 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using AutoMoq;
using FizzWare.NBuilder;
using MbUnit.Framework;
using Moq;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Jobs;
using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class ImportNewSeriesJobTest : TestBase
{
[Test]
public void series_specific_scan_should_scan_series()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.WhereAll().Have(s => s.LastInfoSync = null)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.AndTheNext(1).Has(s => s.SeriesId = 15)
.Build();
var notification = new ProgressNotification("Test");
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable())
.Callback(() => series.ToList().ForEach(c => c.LastInfoSync = DateTime.Now));//Set the last scan time on the collection
mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId));
mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[1].SeriesId));
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId));
mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId));
//Act
mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0);
//Assert
mocker.VerifyAllMocks();
}
[Test]
public void series_with_no_episodes_should_skip_scan()
{
var series = Builder<Series>.CreateNew()
.With(s => s.SeriesId = 12)
.With(s => s.Episodes = new List<Episode>())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetSeries(series.SeriesId))
.Returns(series);
//Act
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId);
//Assert
mocker.VerifyAllMocks();
}
[Test]
public void job_with_no_target_should_scan_all_series()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.AndTheNext(1).Has(s => s.SeriesId = 15)
.WhereAll().Have(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
[Test]
public void job_with_no_target_should_scan_series_with_episodes()
{
var series = Builder<Series>.CreateListOfSize(2)
.WhereTheFirst(1).Has(s => s.SeriesId = 12)
.And(s => s.Episodes = Builder<Episode>.CreateListOfSize(10).Build())
.AndTheNext(1).Has(s => s.SeriesId = 15)
.And(s => s.Episodes = new List<Episode>())
.Build();
var mocker = new AutoMoqer(MockBehavior.Strict);
mocker.GetMock<SeriesProvider>()
.Setup(p => p.GetAllSeries())
.Returns(series.AsQueryable());
mocker.GetMock<MediaFileProvider>()
.Setup(s => s.Scan(series[0]))
.Returns(new List<EpisodeFile>());
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0);
mocker.VerifyAllMocks();
}
}
}

@ -334,7 +334,7 @@ namespace NzbDrone.Core.Test
mocker.GetMock<MediaFileProvider>(MockBehavior.Strict)
.Setup(c => c.Scan(It.Is<Series>(s => s.LastInfoSync != null))).Returns(new List<EpisodeFile>()).Verifiable();
mocker.Resolve<MediaFileScanJob>().Start(new ProgressNotification("test"), 0);
mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("test"), 0);
mocker.VerifyAllMocks();
}

@ -85,6 +85,8 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ImportNewSeriesJobTest.cs" />
<Compile Include="DiskScanJobTest.cs" />
<Compile Include="InventoryProviderTest.cs" />
<Compile Include="Framework\AutoMoq\AutoMoqer.cs" />
<Compile Include="Framework\AutoMoq\AutoMoqerTest.cs" />

@ -131,9 +131,9 @@ namespace NzbDrone.Core
private static void BindJobs()
{
_kernel.Bind<IJob>().To<RssSyncJob>().InTransientScope();
_kernel.Bind<IJob>().To<NewSeriesUpdate>().InTransientScope();
_kernel.Bind<IJob>().To<ImportNewSeriesJob>().InTransientScope();
_kernel.Bind<IJob>().To<UpdateInfoJob>().InTransientScope();
_kernel.Bind<IJob>().To<MediaFileScanJob>().InTransientScope();
_kernel.Bind<IJob>().To<DiskScanJob>().InTransientScope();
_kernel.Bind<IJob>().To<DeleteSeriesJob>().InTransientScope();
_kernel.Get<JobProvider>().Initialize();

@ -128,17 +128,11 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>Libraries\Exceptioneer.WindowsFormsClient.dll</HintPath>
</Reference>
<Reference Include="Gallio, Version=3.2.0.0, Culture=neutral, PublicKeyToken=eb9cfa67ee6ab36e, processorArchitecture=MSIL" />
<Reference Include="MbUnit, Version=3.2.0.0, Culture=neutral, PublicKeyToken=eb9cfa67ee6ab36e, processorArchitecture=MSIL" />
<Reference Include="Ninject, Version=2.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Ninject.2.2.1.0\lib\.NetFramework 4.0\Ninject.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL" />
<Reference Include="NLog.Extended, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Libraries\NLog.Extended.dll</HintPath>
</Reference>
<Reference Include="SubSonic.Core, Version=3.0.0.3, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Libraries\SubSonic.Core.dll</HintPath>
@ -178,8 +172,8 @@
<Compile Include="Providers\AutoConfigureProvider.cs" />
<Compile Include="Providers\Indexer\NzbMatrix.cs" />
<Compile Include="Providers\Jobs\DeleteSeriesJob.cs" />
<Compile Include="Providers\Jobs\MediaFileScanJob.cs" />
<Compile Include="Providers\Jobs\NewSeriesUpdate.cs" />
<Compile Include="Providers\Jobs\DiskScanJob.cs" />
<Compile Include="Providers\Jobs\ImportNewSeriesJob.cs" />
<Compile Include="Providers\Jobs\JobProvider.cs" />
<Compile Include="Providers\Indexer\Newzbin.cs" />
<Compile Include="Providers\Indexer\NzbsRUs.cs" />

@ -7,17 +7,21 @@ using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.Jobs
{
public class MediaFileScanJob : IJob
public class DiskScanJob : IJob
{
private readonly SeriesProvider _seriesProvider;
private readonly MediaFileProvider _mediaFileProvider;
public MediaFileScanJob(SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider)
public DiskScanJob(SeriesProvider seriesProvider, MediaFileProvider mediaFileProvider)
{
_seriesProvider = seriesProvider;
_mediaFileProvider = mediaFileProvider;
}
public DiskScanJob()
{
}
public string Name
{
get { return "Media File Scan"; }
@ -28,7 +32,7 @@ namespace NzbDrone.Core.Providers.Jobs
get { return 60; }
}
public void Start(ProgressNotification notification, int targetId)
public virtual void Start(ProgressNotification notification, int targetId)
{
IList<Series> seriesToScan;
if (targetId == 0)
@ -40,7 +44,7 @@ namespace NzbDrone.Core.Providers.Jobs
seriesToScan = new List<Series>() { _seriesProvider.GetSeries(targetId) };
}
foreach (var series in seriesToScan.Where(c => c.LastInfoSync != null))
foreach (var series in seriesToScan.Where(c => c.Episodes.Count != 0))
{
notification.CurrentMessage = string.Format("Scanning disk for '{0}'", series.Title);
_mediaFileProvider.Scan(series);

@ -0,0 +1,97 @@
using System;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.Jobs
{
/// <summary>
/// This job processes newly added jobs by downloading their info
/// from TheTVDB.org and doing a disk scan. this job should only
/// </summary>
public class ImportNewSeriesJob : IJob
{
private readonly SeriesProvider _seriesProvider;
private readonly MediaFileProvider _mediaFileProvider;
private readonly SeasonProvider _seasonProvider;
private readonly UpdateInfoJob _updateInfoJob;
private readonly DiskScanJob _diskScanJob;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public ImportNewSeriesJob(SeriesProvider seriesProvider, SeasonProvider seasonProvider,
MediaFileProvider mediaFileProvider, UpdateInfoJob updateInfoJob, DiskScanJob diskScanJob)
{
_seriesProvider = seriesProvider;
_mediaFileProvider = mediaFileProvider;
_seasonProvider = seasonProvider;
_updateInfoJob = updateInfoJob;
_diskScanJob = diskScanJob;
}
public string Name
{
get { return "New Series Update"; }
}
public int DefaultInterval
{
get { return 1; }
}
public void Start(ProgressNotification notification, int targetId)
{
ScanSeries(notification);
}
private void ScanSeries(ProgressNotification notification)
{
var syncList = _seriesProvider.GetAllSeries().Where(s => s.LastInfoSync == null).ToList();
if (syncList.Count == 0)
{
return;
}
foreach (var currentSeries in syncList)
{
try
{
notification.CurrentMessage = String.Format("Searching for '{0}'", new DirectoryInfo(currentSeries.Path).Name);
_updateInfoJob.Start(notification, currentSeries.SeriesId);
_diskScanJob.Start(notification, currentSeries.SeriesId);
var updatedSeries = _seriesProvider.GetSeries(currentSeries.SeriesId);
AutoIgnoreSeasons(updatedSeries);
}
catch (Exception e)
{
Logger.ErrorException(e.Message, e);
}
}
//Keep scanning until there no more shows left.
ScanSeries(notification);
}
private void AutoIgnoreSeasons(Series updatedSeries)
{
if (_mediaFileProvider.GetSeriesFiles(updatedSeries.SeriesId).Count() != 0)
{
Logger.Debug("Looking for seasons to ignore");
foreach (var season in updatedSeries.Seasons)
{
if (season.SeasonNumber != updatedSeries.Seasons.Max(s => s.SeasonNumber) && _mediaFileProvider.GetSeasonFiles(season.SeasonId).Count() == 0)
{
Logger.Info("Season {0} of {1} doesn't have any files on disk. season will not be monitored.", season.SeasonNumber, updatedSeries.Title);
season.Monitored = false;
_seasonProvider.SaveSeason(season);
}
}
}
}
}
}

@ -1,90 +0,0 @@
using System;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Core.Model.Notification;
namespace NzbDrone.Core.Providers.Jobs
{
public class NewSeriesUpdate : IJob
{
private readonly SeriesProvider _seriesProvider;
private readonly EpisodeProvider _episodeProvider;
private readonly MediaFileProvider _mediaFileProvider;
private readonly SeasonProvider _seasonProvider;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public NewSeriesUpdate(SeriesProvider seriesProvider, EpisodeProvider episodeProvider, MediaFileProvider mediaFileProvider, SeasonProvider seasonProvider)
{
_seriesProvider = seriesProvider;
_episodeProvider = episodeProvider;
_mediaFileProvider = mediaFileProvider;
_seasonProvider = seasonProvider;
}
public string Name
{
get { return "New Series Update"; }
}
public int DefaultInterval
{
get { return 1; }
}
public void Start(ProgressNotification notification, int targetId)
{
ScanSeries(notification);
}
private void ScanSeries(ProgressNotification notification)
{
var syncList = _seriesProvider.GetAllSeries().Where(s => s.LastInfoSync == null).ToList();
if (syncList.Count == 0)
{
return;
}
foreach (var currentSeries in syncList)
{
try
{
notification.CurrentMessage = String.Format("Searching for '{0}'",
new DirectoryInfo(currentSeries.Path).Name);
var updatedSeries = _seriesProvider.UpdateSeriesInfo(currentSeries.SeriesId);
notification.CurrentMessage = String.Format("Downloading episode info for '{0}'",
updatedSeries.Title);
_episodeProvider.RefreshEpisodeInfo(updatedSeries.SeriesId);
notification.CurrentMessage = String.Format("Scanning disk for '{0}' files", updatedSeries.Title);
_mediaFileProvider.Scan(_seriesProvider.GetSeries(updatedSeries.SeriesId));
if (_mediaFileProvider.GetSeriesFiles(currentSeries.SeriesId).Count() != 0)
{
Logger.Debug("Looking for seasons to ignore");
foreach (var season in updatedSeries.Seasons)
{
if (season.SeasonNumber != updatedSeries.Seasons.Max(s => s.SeasonNumber) && _mediaFileProvider.GetSeasonFiles(season.SeasonId).Count() == 0)
{
Logger.Info("Season {0} of {1} doesn't have any files on disk. season will not be monitored.", season.SeasonNumber, updatedSeries.Title);
season.Monitored = false;
_seasonProvider.SaveSeason(season);
}
}
}
}
catch (Exception e)
{
Logger.ErrorException(e.Message, e);
}
}
//Keep scanning until there no more shows left.
ScanSeries(notification);
}
}
}

@ -16,6 +16,11 @@ namespace NzbDrone.Core.Providers.Jobs
_episodeProvider = episodeProvider;
}
public UpdateInfoJob()
{
}
public string Name
{
get { return "Update Info"; }
@ -26,7 +31,7 @@ namespace NzbDrone.Core.Providers.Jobs
get { return 1440; } //Daily
}
public void Start(ProgressNotification notification, int targetId)
public virtual void Start(ProgressNotification notification, int targetId)
{
IList<Series> seriesToUpdate;
if (targetId == 0)

@ -40,7 +40,7 @@ namespace NzbDrone.Core.Repository
public virtual EpisodeFile EpisodeFile { get; set; }
[SubSonicToManyRelation]
public virtual List<History> Histories { get; protected set; }
public virtual IList<History> Histories { get; protected set; }
}
}

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Repository
public DateTime DateAdded { get; set; }
[SubSonicToManyRelation]
public virtual List<Episode> Episodes { get; private set; }
public virtual IList<Episode> Episodes { get; private set; }
[SubSonicToOneRelation(ThisClassContainsJoinKey = true)]
public virtual Series Series { get; private set; }

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Repository
public DayOfWeek? LastDiskSync { get; set; }
[SubSonicToManyRelation]
public virtual List<Episode> Episodes { get; set; }
public virtual IList<Episode> Episodes { get; set; }
[SubSonicToOneRelation(ThisClassContainsJoinKey = true)]
public virtual Series Series { get; set; }

@ -36,6 +36,15 @@ namespace NzbDrone.Core.Repository
public bool Monitored { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Series"/> is hidden.
/// </summary>
/// <value><c>true</c> if hidden; otherwise, <c>false</c>.</value>
/// <remarks>This field will be used for shows that are pending delete or
/// new series that haven't been successfully imported</remarks>
public bool Hidden { get; set; }
public virtual int QualityProfileId { get; set; }
public bool SeasonFolder { get; set; }
@ -48,12 +57,12 @@ namespace NzbDrone.Core.Repository
public virtual QualityProfile QualityProfile { get; set; }
[SubSonicToManyRelation]
public virtual List<Season> Seasons { get; protected set; }
public virtual IList<Season> Seasons { get; protected set; }
[SubSonicToManyRelation]
public virtual List<Episode> Episodes { get; protected set; }
public virtual IList<Episode> Episodes { get; set; }
[SubSonicToManyRelation]
public virtual List<EpisodeFile> EpisodeFiles { get; protected set; }
public virtual IList<EpisodeFile> EpisodeFiles { get; protected set; }
}
}

@ -36,7 +36,7 @@ namespace NzbDrone.Web.Controllers
[HttpPost]
public JsonResult ScanNewSeries()
{
_jobProvider.QueueJob(typeof(NewSeriesUpdate));
_jobProvider.QueueJob(typeof(ImportNewSeriesJob));
return new JsonResult();
}

@ -265,7 +265,7 @@ namespace NzbDrone.Web.Controllers
public ActionResult SyncEpisodesOnDisk(int seriesId)
{
//Syncs the episodes on disk for the specified series
_jobProvider.QueueJob(typeof(MediaFileScanJob), seriesId);
_jobProvider.QueueJob(typeof(DiskScanJob), seriesId);
return RedirectToAction("Details", new { seriesId });
}

Loading…
Cancel
Save