// ReSharper disable RedundantUsingDirective using System; using System.Collections.Generic; using System.Threading; using AutoMoq; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Model; using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Providers.Jobs; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.ProviderTests { [TestFixture] // ReSharper disable InconsistentNaming public class JobProviderTest : TestBase { [TestFixtureSetUp] public void Setup() { JobProvider.Queue.Clear(); } [Test] public void Run_Jobs_Updates_Last_Execution() { IList fakeJobs = new List { new FakeJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); //Act var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueScheduled(); //Assert var settings = timerProvider.All(); Assert.AreNotEqual(DateTime.MinValue, settings[0].LastExecution); } [Test] public void Run_Jobs_Updates_Last_Execution_Mark_as_unsuccesful() { IList fakeJobs = new List { new BrokenJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); //Act var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueScheduled(); Thread.Sleep(1000); //Assert var settings = timerProvider.All(); Assert.AreNotEqual(DateTime.MinValue, settings[0].LastExecution); settings[0].Success.Should().BeFalse(); ExceptionVerification.ExcpectedErrors(1); } [Test] public void scheduler_skips_jobs_that_arent_mature_yet() { var fakeJob = new FakeJob(); var mocker = new AutoMoqer(); IList fakeJobs = new List { fakeJob }; mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueScheduled(); Thread.Sleep(500); timerProvider.QueueScheduled(); Thread.Sleep(500); fakeJob.ExecutionCount.Should().Be(1); } [Test] //This test will confirm that the concurrency checks are rest //after execution so the job can successfully run. public void can_run_async_job_again() { var fakeJob = new FakeJob(); var mocker = new AutoMoqer(); IList fakeJobs = new List { fakeJob }; mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueJob(typeof(FakeJob)); Thread.Sleep(1000); timerProvider.QueueJob(typeof(FakeJob)); Thread.Sleep(1000); JobProvider.Queue.Should().BeEmpty(); fakeJob.ExecutionCount.Should().Be(2); } [Test] //This test will confirm that the concurrency checks are rest //after execution so the job can successfully run. public void no_concurent_jobs() { IList fakeJobs = new List { new SlowJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueJob(typeof(SlowJob), 1); timerProvider.QueueJob(typeof(SlowJob), 2); timerProvider.QueueJob(typeof(SlowJob), 3); Thread.Sleep(10000); JobProvider.Queue.Should().BeEmpty(); //Asserts are done in ExceptionVerification } [Test] //This test will confirm that the concurrency checks are rest //after execution so the job can successfully run. public void can_run_broken_async_job_again() { var brokenJob = new BrokenJob(); IList fakeJobs = new List { brokenJob }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueJob(typeof(BrokenJob)); Thread.Sleep(2000); timerProvider.QueueJob(typeof(BrokenJob)); Thread.Sleep(2000); JobProvider.Queue.Should().BeEmpty(); brokenJob.ExecutionCount.Should().Be(2); ExceptionVerification.ExcpectedErrors(2); } [Test] //This test will confirm that the concurrency checks are rest //after execution so the job can successfully run. public void can_run_two_jobs_at_the_same_time() { var slowJob = new SlowJob(); IList fakeJobs = new List { slowJob }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); var thread1 = new Thread(() => timerProvider.QueueScheduled()); thread1.Start(); Thread.Sleep(1000); var thread2 = new Thread(() => timerProvider.QueueScheduled()); thread2.Start(); thread1.Join(); thread2.Join(); slowJob.ExecutionCount = 2; } [Test] //This test will confirm that the concurrency checks are rest //after execution so the job can successfully run. public void can_queue_jobs_at_the_same_time() { var slowJob = new SlowJob(); IList fakeJobs = new List { slowJob }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); var thread1 = new Thread(() => timerProvider.QueueJob(typeof(SlowJob))); var thread2 = new Thread(() => timerProvider.QueueJob(typeof(SlowJob))); thread1.Start(); thread2.Start(); thread1.Join(); thread2.Join(); Thread.Sleep(5000); Assert.AreEqual(1, slowJob.ExecutionCount); JobProvider.Queue.Should().BeEmpty(); } [Test] public void Init_Jobs() { var fakeTimer = new FakeJob(); IList fakeJobs = new List { fakeTimer }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); var timers = timerProvider.All(); //Assert timers.Should().HaveCount(1); timers[0].Interval.Should().Be(fakeTimer.DefaultInterval); timers[0].Name.Should().Be(fakeTimer.Name); timers[0].TypeName.Should().Be(fakeTimer.GetType().ToString()); timers[0].LastExecution.Should().HaveYear(2000); timers[0].Enable.Should().BeTrue(); } [Test] public void Init_Timers_only_registers_once() { var repo = MockLib.GetEmptyDatabase(); for (int i = 0; i < 2; i++) { var fakeTimer = new FakeJob(); IList fakeJobs = new List { fakeTimer }; var mocker = new AutoMoqer(); mocker.SetConstant(repo); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); } var mocker2 = new AutoMoqer(); mocker2.SetConstant(repo); var assertTimerProvider = mocker2.Resolve(); var timers = assertTimerProvider.All(); //Assert timers.Should().HaveCount(1); timers[0].Enable.Should().BeTrue(); } [Test] public void Init_Timers_sets_interval_0_to_disabled() { var repo = MockLib.GetEmptyDatabase(); for (int i = 0; i < 2; i++) { var disabledJob = new DisabledJob(); IList fakeJobs = new List { disabledJob }; var mocker = new AutoMoqer(); mocker.SetConstant(repo); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); } var mocker2 = new AutoMoqer(); mocker2.SetConstant(repo); var assertTimerProvider = mocker2.Resolve(); var timers = assertTimerProvider.All(); //Assert timers.Should().HaveCount(1); Assert.IsFalse(timers[0].Enable); } [Test] public void Get_Next_Execution_Time() { IList fakeJobs = new List { new FakeJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); //Act var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueScheduled(); var next = timerProvider.NextScheduledRun(typeof(FakeJob)); //Assert var settings = timerProvider.All(); Assert.IsNotEmpty(settings); Assert.AreEqual(next, settings[0].LastExecution.AddMinutes(15)); } [Test] public void Disabled_isnt_run_by_scheduler() { var repo = MockLib.GetEmptyDatabase(); var disabledJob = new DisabledJob(); IList fakeJobs = new List { disabledJob }; var mocker = new AutoMoqer(); mocker.SetConstant(repo); mocker.SetConstant(fakeJobs); var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueScheduled(); Thread.Sleep(1000); //Assert Assert.AreEqual(0, disabledJob.ExecutionCount); } [Test] public void SingleId_do_not_update_last_execution() { IList fakeJobs = new List { new FakeJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); //Act var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueJob(typeof(FakeJob), 10); Thread.Sleep(1000); //Assert var settings = timerProvider.All(); settings.Should().NotBeEmpty(); settings[0].LastExecution.Should().HaveYear(2000); JobProvider.Queue.Should().BeEmpty(); } [Test] public void SingleId_do_not_set_success() { IList fakeJobs = new List { new FakeJob() }; var mocker = new AutoMoqer(); mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); //Act var timerProvider = mocker.Resolve(); timerProvider.Initialize(); timerProvider.QueueJob(typeof(FakeJob), 10); Thread.Sleep(1000); //Assert var settings = timerProvider.All(); Assert.IsNotEmpty(settings); Assert.IsFalse(settings[0].Success); } [Test] public void existing_queue_should_start_queue_if_not_running() { var mocker = new AutoMoqer(); var fakeJob = new FakeJob(); IList fakeJobs = new List { fakeJob }; mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); var fakeQueueItem = new JobQueueItem { JobType = fakeJob.GetType(), TargetId = 12, SecondaryTargetId = 0 }; //Act var jobProvider = mocker.Resolve(); jobProvider.Initialize(); JobProvider.Queue.Add(fakeQueueItem); jobProvider.QueueJob(fakeJob.GetType(), 12); Thread.Sleep(1000); //Assert fakeJob.ExecutionCount.Should().Be(1); } [Test] public void Item_added_to_queue_while_scheduler_runs_is_executed() { var mocker = new AutoMoqer(); var slowJob = new SlowJob(); var disabledJob = new DisabledJob(); IList fakeJobs = new List { slowJob, disabledJob }; mocker.SetConstant(MockLib.GetEmptyDatabase()); mocker.SetConstant(fakeJobs); mocker.Resolve().Initialize(); var _jobThread = new Thread(() => mocker.Resolve().QueueScheduled()); _jobThread.Start(); Thread.Sleep(200); mocker.Resolve().QueueJob(typeof(DisabledJob), 12); Thread.Sleep(3000); //Assert JobProvider.Queue.Should().BeEmpty(); slowJob.ExecutionCount.Should().Be(1); disabledJob.ExecutionCount.Should().Be(1); } } public class FakeJob : IJob { public string Name { get { return "FakeJob"; } } public int DefaultInterval { get { return 15; } } public int ExecutionCount { get; set; } public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) { ExecutionCount++; } } public class DisabledJob : IJob { public string Name { get { return "DisabledJob"; } } public int DefaultInterval { get { return 0; } } public int ExecutionCount { get; set; } public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) { ExecutionCount++; } } public class BrokenJob : IJob { public string Name { get { return "FakeJob"; } } public int DefaultInterval { get { return 15; } } public int ExecutionCount { get; set; } public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) { ExecutionCount++; throw new ApplicationException("Broken job is broken"); } } public class SlowJob : IJob { public string Name { get { return "FakeJob"; } } public int DefaultInterval { get { return 15; } } public int ExecutionCount { get; set; } public void Start(ProgressNotification notification, int targetId, int secondaryTargetId) { Console.WriteLine("Starting Job"); Thread.Sleep(2000); ExecutionCount++; Console.WriteLine("Finishing Job"); } } }