Merge remote-tracking branch 'origin/dynamic-jobs'

This commit is contained in:
Mark McDowall 2012-10-19 08:39:07 -07:00
commit db585b3bd7
52 changed files with 292 additions and 208 deletions

View File

@ -79,6 +79,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ConfigFileProviderTest.cs" /> <Compile Include="ConfigFileProviderTest.cs" />
<Compile Include="ReflectionExtensions.cs" />
<Compile Include="ReportingService_ReportParseError_Fixture.cs" /> <Compile Include="ReportingService_ReportParseError_Fixture.cs" />
<Compile Include="PathExtentionFixture.cs" /> <Compile Include="PathExtentionFixture.cs" />
<Compile Include="DiskProviderFixture.cs" /> <Compile Include="DiskProviderFixture.cs" />

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Common.Test
{
public static class ReflectionExtensions
{
public static T GetPropertyValue<T>(this object obj, string propertyName)
{
return (T)obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
}
}

View File

@ -161,7 +161,7 @@ namespace NzbDrone.Core.Test.JobTests
private void StartUpdate() private void StartUpdate()
{ {
Mocker.Resolve<AppUpdateJob>().Start(MockNotification, 0, 0); Mocker.Resolve<AppUpdateJob>().Start(MockNotification, null);
} }
} }
} }

View File

@ -12,6 +12,7 @@ using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq; using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.JobTests namespace NzbDrone.Core.Test.JobTests
@ -39,13 +40,13 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, new { SeriesId = It.IsAny<int>(), SeasonNumber = It.IsAny<int>() }),
Times.Never()); Times.Never());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, new { SeriesId = It.IsAny<int>(), SeasonNumber = 0 }),
Times.Never()); Times.Never());
} }
@ -65,23 +66,19 @@ namespace NzbDrone.Core.Test.JobTests
.With(e => e.Series = series) .With(e => e.Series = series)
.Build(); .Build();
WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<EpisodeSearchJob>() Mocker.GetMock<EpisodeSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), 0)).Verifiable(); .Setup(s => s.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") == 1)));
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)),
Times.Never());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
Times.Once()); Times.Once());
} }
@ -101,23 +98,16 @@ namespace NzbDrone.Core.Test.JobTests
.With(e => e.Series = series) .With(e => e.Series = series)
.Build(); .Build();
WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<EpisodeSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), 0)).Verifiable();
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)),
Times.Never());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
Times.Exactly(episodes.Count)); Times.Exactly(episodes.Count));
} }
@ -138,27 +128,20 @@ namespace NzbDrone.Core.Test.JobTests
.With(e => e.SeasonNumber = 1) .With(e => e.SeasonNumber = 1)
.Build(); .Build();
WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<EpisodeSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), 0)).Verifiable();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); .Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)),
Times.Never()); Times.Exactly(episodes.Count));
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
Times.Exactly(episodes.Count));
} }
[Test] [Test]
@ -179,27 +162,21 @@ namespace NzbDrone.Core.Test.JobTests
.With(e => e.SeasonNumber = 1) .With(e => e.SeasonNumber = 1)
.Build(); .Build();
WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<SeasonSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), It.IsAny<int>())).Verifiable();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(episodes.Select(e => e.EpisodeNumber).ToList()); .Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(episodes.Select(e => e.EpisodeNumber).ToList());
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") >= 0 &&
d.GetPropertyValue<int>("SeasonNumber") >= 0)),
Times.Once()); Times.Once());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0),
Times.Never());
} }
[Test] [Test]
@ -227,30 +204,24 @@ namespace NzbDrone.Core.Test.JobTests
.With(e => e.Series = series2) .With(e => e.Series = series2)
.Build(); .Build();
WithStrictMocker();
WithEnableBacklogSearching(); WithEnableBacklogSearching();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<SeasonSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), It.IsAny<int>())).Verifiable();
Mocker.GetMock<EpisodeSearchJob>()
.Setup(s => s.Start(notification, It.IsAny<int>(), 0)).Verifiable();
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(new List<int> { 1, 2, 3, 4, 5 }); .Setup(s => s.GetEpisodeNumbersBySeason(1, 1)).Returns(new List<int> { 1, 2, 3, 4, 5 });
//Act //Act
Mocker.Resolve<BacklogSearchJob>().Start(notification, 0, 0); Mocker.Resolve<BacklogSearchJob>().Start(notification, null);
//Assert //Assert
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), It.IsAny<int>()), Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") >= 0 &&
d.GetPropertyValue<int>("SeasonNumber") >= 0)),
Times.Once()); Times.Once());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)),
Times.Exactly(5)); Times.Exactly(5));
} }
[Test] [Test]

View File

@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetAllSeries()) Mocker.GetMock<SeriesProvider>().Setup(s => s.GetAllSeries())
.Returns(series); .Returns(series);
Mocker.Resolve<BannerDownloadJob>().Start(_notification, 0, 0); Mocker.Resolve<BannerDownloadJob>().Start(_notification, null);
VerifyDownloadMock(series.Count); VerifyDownloadMock(series.Count);
} }
@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetAllSeries()) Mocker.GetMock<SeriesProvider>().Setup(s => s.GetAllSeries())
.Returns(series); .Returns(series);
Mocker.Resolve<BannerDownloadJob>().Start(_notification, 0, 0); Mocker.Resolve<BannerDownloadJob>().Start(_notification, null);
VerifyDownloadMock(3); VerifyDownloadMock(3);
} }
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(series.SeriesId)) Mocker.GetMock<SeriesProvider>().Setup(s => s.GetSeries(series.SeriesId))
.Returns(series); .Returns(series);
Mocker.Resolve<BannerDownloadJob>().Start(_notification, 1, 0); Mocker.Resolve<BannerDownloadJob>().Start(_notification, new { SeriesId = series.SeriesId });
VerifyDownloadMock(1); VerifyDownloadMock(1);
} }
} }

View File

@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.JobTests
.Returns(new List<EpisodeFile>()); .Returns(new List<EpisodeFile>());
//Act //Act
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), series.SeriesId, 0); Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), new { SeriesId = series.SeriesId });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.Scan(series[1])) .Setup(s => s.Scan(series[1]))
.Returns(new List<EpisodeFile>()); .Returns(new List<EpisodeFile>());
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0); Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), null);
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
@ -96,7 +96,7 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.Scan(series[1])) .Setup(s => s.Scan(series[1]))
.Throws(new InvalidOperationException("Bad Job")); .Throws(new InvalidOperationException("Bad Job"));
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0); Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), null);
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
@ -126,7 +126,7 @@ namespace NzbDrone.Core.Test.JobTests
.Returns(new List<EpisodeFile>()); .Returns(new List<EpisodeFile>());
Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), 0, 0); Mocker.Resolve<DiskScanJob>().Start(new ProgressNotification("Test"), null);

View File

@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.JobTests
public class ImportNewSeriesJobTest : CoreTest public class ImportNewSeriesJobTest : CoreTest
{ {
[Test] [Test]
public void import_new_series_succesfull() public void import_new_series_succesful()
{ {
var series = Builder<Series>.CreateListOfSize(2) var series = Builder<Series>.CreateListOfSize(2)
.All().With(s => s.LastInfoSync = null) .All().With(s => s.LastInfoSync = null)
@ -39,23 +39,23 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<DiskScanJob>() Mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
.Callback(() => series[0].LastDiskSync = DateTime.Now); .Callback(() => series[0].LastDiskSync = DateTime.Now);
Mocker.GetMock<DiskScanJob>() Mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[1].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)))
.Callback(() => series[1].LastDiskSync = DateTime.Now); .Callback(() => series[1].LastDiskSync = DateTime.Now);
Mocker.GetMock<BannerDownloadJob>() Mocker.GetMock<BannerDownloadJob>()
.Setup(j => j.Start(notification, It.IsAny<int>(), 0)); .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") >= 0)));
Mocker.GetMock<UpdateInfoJob>() Mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
.Callback(() => series[0].LastInfoSync = DateTime.Now); .Callback(() => series[0].LastInfoSync = DateTime.Now);
Mocker.GetMock<UpdateInfoJob>() Mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)))
.Callback(() => series[1].LastInfoSync = DateTime.Now); .Callback(() => series[1].LastInfoSync = DateTime.Now);
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
@ -68,16 +68,14 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>()); .Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
//Act //Act
Mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0, 0); Mocker.Resolve<ImportNewSeriesJob>().Start(notification, null);
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)), Times.Once());
Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)), Times.Once());
Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[0].SeriesId, 0), Times.Once()); Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)), Times.Once());
Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[1].SeriesId, 0), Times.Once()); Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)), Times.Once());
Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[0].SeriesId, 0), Times.Once());
Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[1].SeriesId, 0), Times.Once());
} }
@ -103,19 +101,19 @@ namespace NzbDrone.Core.Test.JobTests
.Returns(series); .Returns(series);
Mocker.GetMock<UpdateInfoJob>() Mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[0].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
.Callback(() => series[0].LastInfoSync = DateTime.Now); .Callback(() => series[0].LastInfoSync = DateTime.Now);
Mocker.GetMock<UpdateInfoJob>() Mocker.GetMock<UpdateInfoJob>()
.Setup(j => j.Start(notification, series[1].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)))
.Throws(new InvalidOperationException()); .Throws(new InvalidOperationException());
Mocker.GetMock<DiskScanJob>() Mocker.GetMock<DiskScanJob>()
.Setup(j => j.Start(notification, series[0].SeriesId, 0)) .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)))
.Callback(() => series[0].LastDiskSync = DateTime.Now); .Callback(() => series[0].LastDiskSync = DateTime.Now);
Mocker.GetMock<BannerDownloadJob>() Mocker.GetMock<BannerDownloadJob>()
.Setup(j => j.Start(notification, series[0].SeriesId, 0)); .Setup(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)));
Mocker.GetMock<SeriesProvider>() Mocker.GetMock<SeriesProvider>()
.Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]); .Setup(s => s.GetSeries(series[0].SeriesId)).Returns(series[0]);
@ -124,15 +122,13 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>()); .Setup(s => s.GetSeriesFiles(It.IsAny<int>())).Returns(new List<EpisodeFile>());
//Act //Act
Mocker.Resolve<ImportNewSeriesJob>().Start(notification, 0, 0); Mocker.Resolve<ImportNewSeriesJob>().Start(notification, null);
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)), Times.Once());
Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[1].SeriesId)), Times.Once());
Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[0].SeriesId, 0), Times.Once()); Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == series[0].SeriesId)), Times.Once());
Mocker.GetMock<UpdateInfoJob>().Verify(j => j.Start(notification, series[1].SeriesId, 0), Times.Once());
Mocker.GetMock<DiskScanJob>().Verify(j => j.Start(notification, series[0].SeriesId, 0), Times.Once());
ExceptionVerification.ExpectedErrors(1); ExceptionVerification.ExpectedErrors(1);

View File

@ -0,0 +1,72 @@
using System.Linq;
using System;
using System.Diagnostics;
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.JobTests
{
[TestFixture]
internal class PostDownloadScanJobFixture : CoreTest
{
[SetUp]
public void Setup()
{
Mocker.GetMock<DiskProvider>().Setup(s => s.FolderExists(It.IsAny<string>())).Returns(true);
}
[Test]
public void should_use_options_Path_when_provided()
{
var path = @"C:\Test\Unsorted TV";
Mocker.GetMock<PostDownloadProvider>().Setup(s => s.ProcessDropFolder(path));
Mocker.Resolve<PostDownloadScanJob>().Start(MockNotification, new { Path = path });
Mocker.GetMock<PostDownloadProvider>().Verify(s => s.ProcessDropFolder(path), Times.Once());
}
[Test]
public void should_not_get_sabDropDir_when_path_is_supplied()
{
var path = @"C:\Test\Unsorted TV";
Mocker.GetMock<PostDownloadProvider>().Setup(s => s.ProcessDropFolder(path));
Mocker.Resolve<PostDownloadScanJob>().Start(MockNotification, new { Path = path });
Mocker.GetMock<ConfigProvider>().Verify(s => s.SabDropDirectory, Times.Never());
}
[Test]
public void should_get_sabDropDir_when_path_is_not_supplied()
{
var path = @"C:\Test\Unsorted TV";
Mocker.GetMock<ConfigProvider>().SetupGet(s => s.SabDropDirectory).Returns(path);
Mocker.Resolve<PostDownloadScanJob>().Start(MockNotification, null);
Mocker.GetMock<ConfigProvider>().Verify(s => s.SabDropDirectory, Times.Once());
}
[Test]
public void should_use_sabDropDir_when_options_Path_is_not_provided()
{
var path = @"C:\Test\Unsorted TV";
Mocker.GetMock<ConfigProvider>().SetupGet(s => s.SabDropDirectory).Returns(path);
Mocker.Resolve<PostDownloadScanJob>().Start(MockNotification, null);
Mocker.GetMock<PostDownloadProvider>().Verify(s => s.ProcessDropFolder(path), Times.Once());
}
}
}

View File

@ -13,6 +13,7 @@ using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq; using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.JobTests namespace NzbDrone.Core.Test.JobTests
@ -41,10 +42,10 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
//Act //Act
Mocker.Resolve<RecentBacklogSearchJob>().Start(MockNotification, 0, 0); Mocker.Resolve<RecentBacklogSearchJob>().Start(MockNotification, null);
//Assert //Assert
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(MockNotification, It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(MockNotification, new { EpisodeId = It.IsAny<int>() }),
Times.Never()); Times.Never());
} }
@ -87,13 +88,13 @@ namespace NzbDrone.Core.Test.JobTests
Mocker.GetMock<EpisodeProvider>() Mocker.GetMock<EpisodeProvider>()
.Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes); .Setup(s => s.EpisodesWithoutFiles(true)).Returns(episodes);
Mocker.GetMock<EpisodeSearchJob>().Setup(c => c.Start(It.IsAny<ProgressNotification>(), It.IsAny<int>(), 0)); Mocker.GetMock<EpisodeSearchJob>().Setup(c => c.Start(It.IsAny<ProgressNotification>(), It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)));
//Act //Act
Mocker.Resolve<RecentBacklogSearchJob>().Start(MockNotification, 0, 0); Mocker.Resolve<RecentBacklogSearchJob>().Start(MockNotification, null);
//Assert //Assert
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(It.IsAny<ProgressNotification>(), It.IsAny<int>(), 0), Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(It.IsAny<ProgressNotification>(), It.Is<object>(d => d.GetPropertyValue<int>("EpisodeId") >= 0)),
Times.Exactly(40)); Times.Exactly(40));
} }

View File

@ -15,21 +15,20 @@ namespace NzbDrone.Core.Test.JobTests
[TestCase(0)] [TestCase(0)]
[TestCase(-1)] [TestCase(-1)]
[TestCase(-100)] [TestCase(-100)]
[ExpectedException(typeof(ArgumentOutOfRangeException))] [ExpectedException(typeof(ArgumentException))]
public void start_target_id_less_than_0_throws_exception(int target) public void start_target_id_less_than_0_throws_exception(int target)
{ {
WithStrictMocker(); WithStrictMocker();
Mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), target, 0); Mocker.Resolve<EpisodeSearchJob>().Start(new ProgressNotification("Test"), new { EpisodeId = target });
} }
[TestCase(0)]
[TestCase(-1)] [TestCase(-1)]
[TestCase(-100)] [TestCase(-100)]
[ExpectedException(typeof(ArgumentOutOfRangeException))] [ExpectedException(typeof(ArgumentException))]
public void start_secondary_target_id_less_than_0_throws_exception(int target) public void start_secondary_target_id_less_than_0_throws_exception(int target)
{ {
WithStrictMocker(); WithStrictMocker();
Mocker.Resolve<SeasonSearchJob>().Start(new ProgressNotification("Test"), 0, target); Mocker.Resolve<SeasonSearchJob>().Start(new ProgressNotification("Test"), new { SeriesId = 1, SeasonNumber = target });
} }
} }
} }

View File

@ -51,12 +51,12 @@ namespace NzbDrone.Core.Test.JobTests
.Returns(episodes.Select(e => e.EpisodeNumber).ToList()); .Returns(episodes.Select(e => e.EpisodeNumber).ToList());
//Act //Act
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1); Mocker.Resolve<SeasonSearchJob>().Start(notification, new { SeriesId = 1, SeasonNumber = 1 });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
Mocker.GetMock<SearchProvider>().Verify(c => c.PartialSeasonSearch(notification, 1, 1), Times.Once()); Mocker.GetMock<SearchProvider>().Verify(c => c.PartialSeasonSearch(notification, 1, 1), Times.Once());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0), Times.Never()); Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, new { EpisodeId = It.IsAny<int>() }), Times.Never());
} }
[Test] [Test]
@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.JobTests
.Returns(new List<int>()); .Returns(new List<int>());
//Act //Act
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1); Mocker.Resolve<SeasonSearchJob>().Start(notification, new { SeriesId = 1, SeasonNumber = 1 });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
@ -104,7 +104,7 @@ namespace NzbDrone.Core.Test.JobTests
//Act //Act
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 1); Mocker.Resolve<SeasonSearchJob>().Start(notification, new { SeriesId = 1, SeasonNumber = 1 });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
@ -118,11 +118,11 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(c => c.PartialSeasonSearch(notification, 1, 0)).Returns(new List<int>()); .Setup(c => c.PartialSeasonSearch(notification, 1, 0)).Returns(new List<int>());
//Act //Act
Mocker.Resolve<SeasonSearchJob>().Start(notification, 1, 0); Mocker.Resolve<SeasonSearchJob>().Start(notification, new { SeriesId = 1, SeasonNumber = 0 });
//Assert //Assert
Mocker.GetMock<SearchProvider>().Verify(c => c.PartialSeasonSearch(notification, 1, 1), Times.Never()); Mocker.GetMock<SearchProvider>().Verify(c => c.PartialSeasonSearch(notification, 1, 1), Times.Never());
Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, It.IsAny<int>(), 0), Times.Never()); Mocker.GetMock<EpisodeSearchJob>().Verify(c => c.Start(notification, new { EpisodeId = It.IsAny<int>() }), Times.Never());
} }
} }
} }

View File

@ -6,6 +6,7 @@ using NzbDrone.Core.Jobs;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
using NzbDrone.Test.Common.AutoMoq; using NzbDrone.Test.Common.AutoMoq;
namespace NzbDrone.Core.Test.JobTests namespace NzbDrone.Core.Test.JobTests
@ -30,14 +31,14 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(c => c.IsIgnored(It.IsAny<int>(), It.IsAny<int>())).Returns(false); .Setup(c => c.IsIgnored(It.IsAny<int>(), It.IsAny<int>())).Returns(false);
Mocker.GetMock<SeasonSearchJob>() Mocker.GetMock<SeasonSearchJob>()
.Setup(c => c.Start(notification, 1, It.IsAny<int>())).Verifiable(); .Setup(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == 1 && d.GetPropertyValue<int>("SeasonNumber") >= 0))).Verifiable();
//Act //Act
Mocker.Resolve<SeriesSearchJob>().Start(notification, 1, 0); Mocker.Resolve<SeriesSearchJob>().Start(notification, new { SeriesId = 1 });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, 1, It.IsAny<int>()), Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, It.Is<object>(d => d.GetPropertyValue<int>("SeriesId") == 1 && d.GetPropertyValue<int>("SeasonNumber") >= 0)),
Times.Exactly(seasons.Count)); Times.Exactly(seasons.Count));
} }
@ -54,11 +55,11 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(c => c.GetSeasons(1)).Returns(seasons); .Setup(c => c.GetSeasons(1)).Returns(seasons);
//Act //Act
Mocker.Resolve<SeriesSearchJob>().Start(notification, 1, 0); Mocker.Resolve<SeriesSearchJob>().Start(notification, new { SeriesId = 1 });
//Assert //Assert
Mocker.VerifyAllMocks(); Mocker.VerifyAllMocks();
Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, 1, It.IsAny<int>()), Mocker.GetMock<SeasonSearchJob>().Verify(c => c.Start(notification, new { SeriesId = 1, SeasonNumber = It.IsAny<int>() }),
Times.Never()); Times.Never());
} }
@ -69,11 +70,11 @@ namespace NzbDrone.Core.Test.JobTests
.Setup(c => c.GetSeasons(It.IsAny<int>())) .Setup(c => c.GetSeasons(It.IsAny<int>()))
.Returns(new List<int> { 0, 1, 2 }); .Returns(new List<int> { 0, 1, 2 });
Mocker.Resolve<SeriesSearchJob>().Start(MockNotification, 12, 0); Mocker.Resolve<SeriesSearchJob>().Start(MockNotification, new { SeriesId = 12 });
Mocker.GetMock<SeasonSearchJob>() Mocker.GetMock<SeasonSearchJob>()
.Verify(c => c.Start(It.IsAny<ProgressNotification>(), It.IsAny<int>(), 0), Times.Never()); .Verify(c => c.Start(It.IsAny<ProgressNotification>(), new { SeriesId = It.IsAny<int>(), SeasonNumber = 0 }), Times.Never());
} }
} }
} }

View File

@ -74,6 +74,7 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\FluentAssertions.1.7.0\Lib\net40\FluentAssertions.dll</HintPath> <HintPath>..\packages\FluentAssertions.1.7.0\Lib\net40\FluentAssertions.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Practices.ServiceLocation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"> <Reference Include="Microsoft.Practices.ServiceLocation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\CommonServiceLocator.1.0\lib\NET35\Microsoft.Practices.ServiceLocation.dll</HintPath> <HintPath>..\packages\CommonServiceLocator.1.0\lib\NET35\Microsoft.Practices.ServiceLocation.dll</HintPath>
@ -143,6 +144,7 @@
<Compile Include="JobTests\BacklogSearchJobTest.cs" /> <Compile Include="JobTests\BacklogSearchJobTest.cs" />
<Compile Include="JobTests\BannerDownloadJobTest.cs" /> <Compile Include="JobTests\BannerDownloadJobTest.cs" />
<Compile Include="JobTests\RssSyncJobTest.cs" /> <Compile Include="JobTests\RssSyncJobTest.cs" />
<Compile Include="JobTests\PostDownloadScanJobFixture.cs" />
<Compile Include="JobTests\RecentBacklogSearchJobTest.cs" /> <Compile Include="JobTests\RecentBacklogSearchJobTest.cs" />
<Compile Include="ParserFixture\QualityParserTests.cs" /> <Compile Include="ParserFixture\QualityParserTests.cs" />
<Compile Include="ProviderTests\ConfigProviderTests\ConfigCachingFixture.cs" /> <Compile Include="ProviderTests\ConfigProviderTests\ConfigCachingFixture.cs" />

View File

@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following // General Information about an assembly is controlled through the following
@ -37,3 +38,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("NzbDrone.Core")]

View File

@ -436,8 +436,7 @@ namespace NzbDrone.Core.Test.ProviderTests.JobProviderTests
var stuckQueueItem = new JobQueueItem var stuckQueueItem = new JobQueueItem
{ {
JobType = fakeJob.GetType(), JobType = fakeJob.GetType(),
TargetId = 12, Options = new { TargetId = 12 }
SecondaryTargetId = 0
}; };
//Act //Act
@ -446,7 +445,7 @@ namespace NzbDrone.Core.Test.ProviderTests.JobProviderTests
jobProvider.Queue.Add(stuckQueueItem); jobProvider.Queue.Add(stuckQueueItem);
WaitForQueue(); WaitForQueue();
jobProvider.QueueJob(stuckQueueItem.JobType, stuckQueueItem.TargetId, stuckQueueItem.SecondaryTargetId); jobProvider.QueueJob(stuckQueueItem.JobType, stuckQueueItem.Options);
WaitForQueue(); WaitForQueue();
//Assert //Assert

View File

@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.ProviderTests.JobProviderTests
public int ExecutionCount { get; private set; } public int ExecutionCount { get; private set; }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
ExecutionCount++; ExecutionCount++;
Console.WriteLine("Begin " + Name); Console.WriteLine("Begin " + Name);

View File

@ -46,7 +46,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(2); } get { return TimeSpan.FromDays(2); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
notification.CurrentMessage = "Checking for updates"; notification.CurrentMessage = "Checking for updates";

View File

@ -38,7 +38,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(30); } get { return TimeSpan.FromDays(30); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
var missingEpisodes = GetMissingForEnabledSeries().GroupBy(e => new { e.SeriesId, e.SeasonNumber }); var missingEpisodes = GetMissingForEnabledSeries().GroupBy(e => new { e.SeriesId, e.SeasonNumber });
@ -73,7 +73,7 @@ namespace NzbDrone.Core.Jobs
{ {
//Process as a full season //Process as a full season
Logger.Debug("Processing Full Season: {0} Season {1}", seriesId, seasonNumber); Logger.Debug("Processing Full Season: {0} Season {1}", seriesId, seasonNumber);
_seasonSearchJob.Start(notification, seriesId, seasonNumber); _seasonSearchJob.Start(notification, new { SeriesId = seriesId, SeasonNumber = seasonNumber });
} }
} }
} }
@ -82,7 +82,7 @@ namespace NzbDrone.Core.Jobs
//Process the list of remaining episodes, 1 by 1 //Process the list of remaining episodes, 1 by 1
foreach (var episode in individualEpisodes) foreach (var episode in individualEpisodes)
{ {
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); _episodeSearchJob.Start(notification, new { EpisodeId = episode.EpisodeId});
} }
} }

View File

@ -40,13 +40,13 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(30); } get { return TimeSpan.FromDays(30); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
Logger.Debug("Starting banner download job"); Logger.Debug("Starting banner download job");
if (targetId > 0) if (options != null)
{ {
var series = _seriesProvider.GetSeries(targetId); var series = _seriesProvider.GetSeries(options.SeriesId);
if (series != null && !String.IsNullOrEmpty(series.BannerUrl)) if (series != null && !String.IsNullOrEmpty(series.BannerUrl))
{ {

View File

@ -28,7 +28,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(24); } get { return TimeSpan.FromDays(24); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
_recycleBinProvider.Cleanup(); _recycleBinProvider.Cleanup();
} }

View File

@ -35,12 +35,13 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
if (targetId <= 0)
throw new ArgumentOutOfRangeException("targetId");
var episode = _episodeProvider.GetEpisode(targetId); if (options == null || options.EpisodeId <= 0)
throw new ArgumentNullException(options);
var episode = _episodeProvider.GetEpisode(options.EpisodeId);
notification.CurrentMessage = String.Format("Starting Conversion for {0}", episode); notification.CurrentMessage = String.Format("Starting Conversion for {0}", episode);
var outputFile = _handbrakeProvider.ConvertFile(episode, notification); var outputFile = _handbrakeProvider.ConvertFile(episode, notification);

View File

@ -32,9 +32,9 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
DeleteSeries(notification, targetId, Convert.ToBoolean(secondaryTargetId)); DeleteSeries(notification, options.SeriesId, options.DeleteFiless);
} }
private void DeleteSeries(ProgressNotification notification, int seriesId, bool deleteFiles) private void DeleteSeries(ProgressNotification notification, int seriesId, bool deleteFiles)

View File

@ -38,16 +38,16 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromHours(6); } get { return TimeSpan.FromHours(6); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
IList<Series> seriesToScan; IList<Series> seriesToScan;
if (targetId == 0) if (options == null || options.SeriesId == 0)
{ {
seriesToScan = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList(); seriesToScan = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList();
} }
else else
{ {
seriesToScan = new List<Series>() { _seriesProvider.GetSeries(targetId) }; seriesToScan = new List<Series>() { _seriesProvider.GetSeries(options.SeriesId) };
} }
foreach (var series in seriesToScan) foreach (var series in seriesToScan)

View File

@ -28,7 +28,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
_recycleBinProvider.Empty(); _recycleBinProvider.Empty();
} }

View File

@ -31,12 +31,12 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
if (targetId <= 0) if (options == null || options.EpisodeId <= 0)
throw new ArgumentOutOfRangeException("targetId"); throw new ArgumentException("options");
_searchProvider.EpisodeSearch(notification, targetId); _searchProvider.EpisodeSearch(notification, options.EpisodeId);
} }
} }
} }

View File

@ -28,6 +28,6 @@ namespace NzbDrone.Core.Jobs
/// this object should be used to update the progress on the UI</param> /// this object should be used to update the progress on the UI</param>
/// <param name="targetId">The that should be used to limit the target of this job</param> /// <param name="targetId">The that should be used to limit the target of this job</param>
/// /// <param name="secondaryTargetId">The that should be used to limit the target of this job</param> /// /// <param name="secondaryTargetId">The that should be used to limit the target of this job</param>
void Start(ProgressNotification notification, int targetId, int secondaryTargetId); void Start(ProgressNotification notification, dynamic options);
} }
} }

View File

@ -51,7 +51,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromMinutes(1); } get { return TimeSpan.FromMinutes(1); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
_attemptedSeries = new List<int>(); _attemptedSeries = new List<int>();
ScanSeries(notification); ScanSeries(notification);
@ -72,14 +72,14 @@ namespace NzbDrone.Core.Jobs
_attemptedSeries.Add(currentSeries.SeriesId); _attemptedSeries.Add(currentSeries.SeriesId);
notification.CurrentMessage = String.Format("Searching for '{0}'", new DirectoryInfo(currentSeries.Path).Name); notification.CurrentMessage = String.Format("Searching for '{0}'", new DirectoryInfo(currentSeries.Path).Name);
_updateInfoJob.Start(notification, currentSeries.SeriesId, 0); _updateInfoJob.Start(notification, new { SeriesId = currentSeries.SeriesId });
_diskScanJob.Start(notification, currentSeries.SeriesId, 0); _diskScanJob.Start(notification, new { SeriesId = currentSeries.SeriesId });
var updatedSeries = _seriesProvider.GetSeries(currentSeries.SeriesId); var updatedSeries = _seriesProvider.GetSeries(currentSeries.SeriesId);
AutoIgnoreSeasons(updatedSeries.SeriesId); AutoIgnoreSeasons(updatedSeries.SeriesId);
//Download the banner for the new series //Download the banner for the new series
_bannerDownloadJob.Start(notification, updatedSeries.SeriesId, 0); _bannerDownloadJob.Start(notification, new { SeriesId = updatedSeries.SeriesId });
notification.CurrentMessage = String.Format("{0} was successfully imported", updatedSeries.Title); notification.CurrentMessage = String.Format("{0} was successfully imported", updatedSeries.Title);
} }

View File

@ -145,13 +145,12 @@ namespace NzbDrone.Core.Jobs
logger.Trace("{0} Scheduled tasks have been added to the queue", pendingJobTypes.Count); logger.Trace("{0} Scheduled tasks have been added to the queue", pendingJobTypes.Count);
} }
public virtual void QueueJob(Type jobType, int targetId = 0, int secondaryTargetId = 0, JobQueueItem.JobSourceType source = JobQueueItem.JobSourceType.User) public virtual void QueueJob(Type jobType, dynamic options = null, JobQueueItem.JobSourceType source = JobQueueItem.JobSourceType.User)
{ {
var queueItem = new JobQueueItem var queueItem = new JobQueueItem
{ {
JobType = jobType, JobType = jobType,
TargetId = targetId, Options = options,
SecondaryTargetId = secondaryTargetId,
Source = source Source = source
}; };
@ -277,7 +276,7 @@ namespace NzbDrone.Core.Jobs
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();
_notificationProvider.Register(_notification); _notificationProvider.Register(_notification);
jobImplementation.Start(_notification, queueItem.TargetId, queueItem.SecondaryTargetId); jobImplementation.Start(_notification, queueItem.Options);
_notification.Status = ProgressNotificationStatus.Completed; _notification.Status = ProgressNotificationStatus.Completed;
settings.LastExecution = DateTime.Now; settings.LastExecution = DateTime.Now;
@ -303,7 +302,7 @@ namespace NzbDrone.Core.Jobs
} }
//Only update last execution status if was triggered by the scheduler //Only update last execution status if was triggered by the scheduler
if (queueItem.TargetId == 0) if (queueItem.Options == null)
{ {
SaveDefinition(settings); SaveDefinition(settings);
} }

View File

@ -36,14 +36,14 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
var missingEpisodes = GetMissingForEnabledSeries(); var missingEpisodes = GetMissingForEnabledSeries();
Logger.Debug("Processing missing episodes from the past week, count: {0}", missingEpisodes.Count); Logger.Debug("Processing missing episodes from the past week, count: {0}", missingEpisodes.Count);
foreach (var episode in missingEpisodes) foreach (var episode in missingEpisodes)
{ {
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); _episodeSearchJob.Start(notification, new { EpisodeId = episode.EpisodeId });
} }
} }

View File

@ -39,9 +39,15 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromMinutes(1); } get { return TimeSpan.FromMinutes(1); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
var dropFolder = _configProvider.SabDropDirectory; string dropFolder;
if (options != null && !String.IsNullOrWhiteSpace(options.Path))
dropFolder = options.Path;
else
dropFolder = _configProvider.SabDropDirectory;
if (String.IsNullOrWhiteSpace(dropFolder)) if (String.IsNullOrWhiteSpace(dropFolder))
{ {

View File

@ -36,14 +36,14 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(1); } get { return TimeSpan.FromDays(1); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
var missingEpisodes = GetMissingForEnabledSeries(); var missingEpisodes = GetMissingForEnabledSeries();
Logger.Debug("Processing missing episodes from the last 30 days, count: {0}", missingEpisodes.Count); Logger.Debug("Processing missing episodes from the last 30 days, count: {0}", missingEpisodes.Count);
foreach (var episode in missingEpisodes) foreach (var episode in missingEpisodes)
{ {
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); _episodeSearchJob.Start(notification, new { EpisodeId = episode.EpisodeId });
} }
} }

View File

@ -36,15 +36,15 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
List<Series> seriesToRefresh; List<Series> seriesToRefresh;
if (targetId <= 0) if (options == null || options.SeriesId <= 0)
seriesToRefresh = _seriesProvider.GetAllSeries().ToList(); seriesToRefresh = _seriesProvider.GetAllSeries().ToList();
else else
seriesToRefresh = new List<Series> { _seriesProvider.GetSeries(targetId) }; seriesToRefresh = new List<Series> { _seriesProvider.GetSeries(options.SeriesId) };
foreach(var series in seriesToRefresh) foreach(var series in seriesToRefresh)
{ {

View File

@ -41,24 +41,24 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
if (targetId <= 0) if (options == null || options.SeriesId <= 0)
throw new ArgumentOutOfRangeException("targetId"); throw new ArgumentException("options");
if (secondaryTargetId <= 0) if (options.SeasonNumber < 0)
throw new ArgumentOutOfRangeException("secondaryTargetId"); throw new ArgumentException("options.SeasonNumber");
var series = _seriesProvider.GetSeries(targetId); var series = _seriesProvider.GetSeries(options.SeriesId);
notification.CurrentMessage = String.Format("Renaming episodes for {0} Season {1}", series.Title, secondaryTargetId); notification.CurrentMessage = String.Format("Renaming episodes for {0} Season {1}", series.Title, options.SeasonNumber);
logger.Debug("Getting episodes from database for series: {0} and season: {1}", targetId, secondaryTargetId); logger.Debug("Getting episodes from database for series: {0} and season: {1}", options.SeriesId, options.SeasonNumber);
var episodeFiles = _mediaFileProvider.GetSeasonFiles(targetId, secondaryTargetId); var episodeFiles = _mediaFileProvider.GetSeasonFiles(options.SeriesId, options.SeasonNumber);
if (episodeFiles == null || !episodeFiles.Any()) if (episodeFiles == null || !episodeFiles.Any())
{ {
logger.Warn("No episodes in database found for series: {0} and season: {1}.", targetId, secondaryTargetId); logger.Warn("No episodes in database found for series: {0} and season: {1}.", options.SeriesId, options.SeasonNumber);
return; return;
} }
@ -91,10 +91,10 @@ namespace NzbDrone.Core.Jobs
//Start AfterRename //Start AfterRename
var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, secondaryTargetId); var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, options.SeasonNumber);
_externalNotificationProvider.AfterRename(message, series); _externalNotificationProvider.AfterRename(message, series);
notification.CurrentMessage = String.Format("Rename completed for {0} Season {1}", series.Title, secondaryTargetId); notification.CurrentMessage = String.Format("Rename completed for {0} Season {1}", series.Title, options.SeasonNumber);
} }
} }
} }

View File

@ -41,18 +41,18 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
List<Series> seriesToRename; List<Series> seriesToRename;
if (targetId <= 0) if (options == null || options.SeriesId <= 0)
{ {
seriesToRename = _seriesProvider.GetAllSeries().ToList(); seriesToRename = _seriesProvider.GetAllSeries().ToList();
} }
else else
{ {
seriesToRename = new List<Series>{ _seriesProvider.GetSeries(targetId) }; seriesToRename = new List<Series>{ _seriesProvider.GetSeries(options.SeriesId) };
} }
foreach(var series in seriesToRename) foreach(var series in seriesToRename)

View File

@ -49,7 +49,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromMinutes(_configProvider.RssSyncInterval); } get { return TimeSpan.FromMinutes(_configProvider.RssSyncInterval); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
var reports = new List<EpisodeParseResult>(); var reports = new List<EpisodeParseResult>();

View File

@ -36,7 +36,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromHours(24); } get { return TimeSpan.FromHours(24); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
Logger.Info("Running search history cleanup."); Logger.Info("Running search history cleanup.");
_searchHistoryProvider.Cleanup(); _searchHistoryProvider.Cleanup();

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs namespace NzbDrone.Core.Jobs
{ {
@ -37,27 +39,27 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
if (targetId <= 0) if (options == null || options.SeriesId <= 0)
throw new ArgumentOutOfRangeException("targetId"); throw new ArgumentException("options");
if (secondaryTargetId < 0) if (options.SeasonNumber < 0)
throw new ArgumentOutOfRangeException("secondaryTargetId"); throw new ArgumentException("options.SeasonNumber");
//Perform a Partial Season Search - Because a full season search is a waste //Perform a Partial Season Search - Because a full season search is a waste
//3 searches should guarentee results, (24 eps) versus, a potential 4 to get the same eps. //3 searches should guarentee results, (24 eps) versus, a potential 4 to get the same eps.
var successes = _searchProvider.PartialSeasonSearch(notification, targetId, secondaryTargetId); List<int> successes = _searchProvider.PartialSeasonSearch(notification, options.SeriesId, options.SeasonNumber);
if (successes.Count == 0) if (successes.Count == 0)
return; return;
Logger.Debug("Getting episodes from database for series: {0} and season: {1}", targetId, secondaryTargetId); Logger.Debug("Getting episodes from database for series: {0} and season: {1}", options.SeriesId, options.SeasonNumber);
var episodes = _episodeProvider.GetEpisodesBySeason(targetId, secondaryTargetId); List<Episode> episodes = _episodeProvider.GetEpisodesBySeason(options.SeriesId, options.SeasonNumber);
if (episodes == null || episodes.Count == 0) if (episodes == null || episodes.Count == 0)
{ {
Logger.Warn("No episodes in database found for series: {0} and season: {1}.", targetId, secondaryTargetId); Logger.Warn("No episodes in database found for series: {0} and season: {1}.", options.SeriesId, options.SeasonNumber);
return; return;
} }
@ -68,7 +70,7 @@ namespace NzbDrone.Core.Jobs
foreach (var episode in episodes.Where(e => !e.Ignored && missingEpisodes.Contains(e.EpisodeNumber)).OrderBy(o => o.EpisodeNumber)) foreach (var episode in episodes.Where(e => !e.Ignored && missingEpisodes.Contains(e.EpisodeNumber)).OrderBy(o => o.EpisodeNumber))
{ {
_episodeSearchJob.Start(notification, episode.EpisodeId, 0); _episodeSearchJob.Start(notification, new { EpisodeId = episode.EpisodeId });
} }
} }
} }

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs namespace NzbDrone.Core.Jobs
{ {
@ -30,19 +32,19 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromTicks(0); } get { return TimeSpan.FromTicks(0); }
} }
public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public void Start(ProgressNotification notification, dynamic options)
{ {
if (targetId <= 0) if (options == null || options.SeriesId <= 0)
throw new ArgumentOutOfRangeException("targetId"); throw new ArgumentException("options.SeriesId");
logger.Debug("Getting seasons from database for series: {0}", targetId); logger.Debug("Getting seasons from database for series: {0}", options.SeriesId);
var seasons = _seasonProvider.GetSeasons(targetId).Where(s => s > 0); IList<int> seasons = _seasonProvider.GetSeasons(options.SeriesId);
foreach (var season in seasons) foreach (var season in seasons.Where(s => s > 0))
{ {
if (!_seasonProvider.IsIgnored(targetId, season)) if (!_seasonProvider.IsIgnored(options.SeriesId, season))
{ {
_seasonSearchJob.Start(notification, targetId, season); _seasonSearchJob.Start(notification, new { SeriesId = options.SeriesId, SeasonNumber = season });
} }
} }
} }

View File

@ -24,7 +24,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromDays(1); } get { return TimeSpan.FromDays(1); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
_logProvider.Trim(); _logProvider.Trim();
} }

View File

@ -41,16 +41,16 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromHours(12); } get { return TimeSpan.FromHours(12); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
IList<Series> seriesToUpdate; IList<Series> seriesToUpdate;
if (targetId == 0) if (options == null || options.SeriesId == 0)
{ {
seriesToUpdate = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList(); seriesToUpdate = _seriesProvider.GetAllSeries().OrderBy(o => SortHelper.SkipArticles(o.Title)).ToList();
} }
else else
{ {
seriesToUpdate = new List<Series> { _seriesProvider.GetSeries(targetId) }; seriesToUpdate = new List<Series> { _seriesProvider.GetSeries(options.SeriesId) };
} }
//Update any Daily Series in the DB with the IsDaily flag //Update any Daily Series in the DB with the IsDaily flag

View File

@ -29,7 +29,7 @@ namespace NzbDrone.Core.Jobs
get { return TimeSpan.FromHours(12); } get { return TimeSpan.FromHours(12); }
} }
public virtual void Start(ProgressNotification notification, int targetId, int secondaryTargetId) public virtual void Start(ProgressNotification notification, dynamic options)
{ {
_sceneNameMappingProvider.UpdateMappings(); _sceneNameMappingProvider.UpdateMappings();
} }

View File

@ -5,20 +5,18 @@ namespace NzbDrone.Core.Model
public class JobQueueItem : IEquatable<JobQueueItem> public class JobQueueItem : IEquatable<JobQueueItem>
{ {
public Type JobType { get; set; } public Type JobType { get; set; }
public int TargetId { get; set; } public dynamic Options { get; set; }
public int SecondaryTargetId { get; set; }
public JobSourceType Source { get; set; } public JobSourceType Source { get; set; }
public bool Equals(JobQueueItem other) public bool Equals(JobQueueItem other)
{ {
return (JobType == other.JobType && TargetId == other.TargetId return (JobType == other.JobType && Options == other.Options);
&& SecondaryTargetId == other.SecondaryTargetId);
} }
public override string ToString() public override string ToString()
{ {
return string.Format("[{0}({1}, {2})]", JobType.Name, TargetId, SecondaryTargetId); return string.Format("[{0}({1})]", JobType.Name, Options);
} }
public enum JobSourceType public enum JobSourceType

View File

@ -12,6 +12,7 @@ using System.Runtime.InteropServices;
[assembly: Guid("3C29FEF7-4B07-49ED-822E-1C29DC49BFAB")] [assembly: Guid("3C29FEF7-4B07-49ED-822E-1C29DC49BFAB")]
[assembly: InternalsVisibleTo("NzbDrone.Core.Test")] [assembly: InternalsVisibleTo("NzbDrone.Core.Test")]
[assembly: InternalsVisibleTo("NzbDrone.Web")]
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:

View File

@ -89,6 +89,7 @@
<Compile Include="ExceptionVerification.cs" /> <Compile Include="ExceptionVerification.cs" />
<Compile Include="LoggingTest.cs" /> <Compile Include="LoggingTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectionExtensions.cs" />
<Compile Include="TestBase.cs" /> <Compile Include="TestBase.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Test.Common
{
public static class ReflectionExtensions
{
public static T GetPropertyValue<T>(this object obj, string propertyName)
{
return (T)obj.GetType().GetProperty(propertyName).GetValue(obj, null);
}
}
}

View File

@ -26,7 +26,7 @@ namespace NzbDrone.Web.Controllers
public JsonResult SearchSeason(int seriesId, int seasonNumber) public JsonResult SearchSeason(int seriesId, int seasonNumber)
{ {
_jobProvider.QueueJob(typeof(SeasonSearchJob), seriesId, seasonNumber); _jobProvider.QueueJob(typeof(SeasonSearchJob), new { SeriesId = seriesId, SeasonNumber = seasonNumber });
return JsonNotificationResult.Queued("Season search"); return JsonNotificationResult.Queued("Season search");
} }
@ -40,7 +40,7 @@ namespace NzbDrone.Web.Controllers
public JsonResult RenameSeason(int seriesId, int seasonNumber) public JsonResult RenameSeason(int seriesId, int seasonNumber)
{ {
_jobProvider.QueueJob(typeof(RenameSeasonJob), seriesId, seasonNumber); _jobProvider.QueueJob(typeof(RenameSeasonJob), new { SeriesId = seriesId, SeasonNumber = seasonNumber });
return JsonNotificationResult.Queued("Season rename"); return JsonNotificationResult.Queued("Season rename");
} }

View File

@ -91,9 +91,9 @@ namespace NzbDrone.Web.Controllers
} }
[HttpPost] [HttpPost]
public EmptyResult DeleteSeries(int seriesId, bool deleteFiles) public EmptyResult Delete(int seriesId, bool deleteFiles)
{ {
_jobProvider.QueueJob(typeof(DeleteSeriesJob), seriesId, Convert.ToInt32(deleteFiles)); _jobProvider.QueueJob(typeof(DeleteSeriesJob), new { SeriesId = seriesId, DeleteFiles = deleteFiles });
return new EmptyResult(); return new EmptyResult();
} }

View File

@ -41,8 +41,7 @@ namespace NzbDrone.Web.Controllers
var queue = _jobProvider.Queue.Select(c => new JobQueueItemModel var queue = _jobProvider.Queue.Select(c => new JobQueueItemModel
{ {
Name = c.JobType.Name, Name = c.JobType.Name,
TargetId = c.TargetId, Options = c.Options
SecondaryTargetId = c.SecondaryTargetId
}); });
var serializedQueue = new JavaScriptSerializer().Serialize(queue); var serializedQueue = new JavaScriptSerializer().Serialize(queue);

View File

@ -7,7 +7,6 @@ namespace NzbDrone.Web.Models
public class JobQueueItemModel public class JobQueueItemModel
{ {
public string Name { get; set; } public string Name { get; set; }
public int TargetId { get; set; } public dynamic Options { get; set; }
public int SecondaryTargetId { get; set; }
} }
} }

View File

@ -1,4 +1,5 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
[assembly: AssemblyTitle("NzbDrone.Web")] [assembly: AssemblyTitle("NzbDrone.Web")]
@ -11,3 +12,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyVersion("1.0.0.*")] [assembly: AssemblyVersion("1.0.0.*")]
[assembly: AssemblyFileVersion("1.0.0.*")] [assembly: AssemblyFileVersion("1.0.0.*")]
[assembly: InternalsVisibleTo("NzbDrone.Core")]

View File

@ -1,6 +1,6 @@
var seriesEditorUrl = '../Series/Edit'; var seriesEditorUrl = '../Series/Edit';
var saveSeriesEditorUrl = '../Series/Edit'; var saveSeriesEditorUrl = '../Series/Edit';
var seriesDeleteUrl = '../Series/DeleteSeries'; var seriesDeleteUrl = '../Series/Delete';
$("#seriesEditor").dialog({ $("#seriesEditor").dialog({
autoOpen: false, autoOpen: false,

View File

@ -30,8 +30,7 @@
<thead> <thead>
<tr> <tr>
<th>Type</th> <th>Type</th>
<th>Target</th> <th>Options</th>
<th>Secondary</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -91,8 +90,7 @@
"sPaginationType": "four_button", "sPaginationType": "four_button",
"aoColumns": [ "aoColumns": [
{ sWidth: 'auto', "mDataProp": "Type"}, //Type { sWidth: 'auto', "mDataProp": "Type"}, //Type
{ sWidth: '100px', "mDataProp": "Target" }, //Target { sWidth: '100px', "mDataProp": "Options" } //Options
{ sWidth: '100px', "mDataProp": "SecondaryTarget" }, //SecondaryTarget
] ]
}); });
}); });