mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-18 21:34:28 -04:00
splited jobprovider into jobrepo, jobcontroller, moved to object db.
This commit is contained in:
@@ -8,6 +8,7 @@ using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Providers;
|
||||
using NzbDrone.Core.Providers.Core;
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NCrunch.Framework;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.JobTests
|
||||
{
|
||||
[TestFixture]
|
||||
[ExclusivelyUses("JOB_PROVIDER")]
|
||||
public class JobControllerFixture : CoreTest<JobController>
|
||||
{
|
||||
|
||||
FakeJob _fakeJob;
|
||||
SlowJob _slowJob;
|
||||
BrokenJob _brokenJob;
|
||||
DisabledJob _disabledJob;
|
||||
|
||||
|
||||
private JobDefinition _updatedJob = null;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_fakeJob = new FakeJob();
|
||||
_slowJob = new SlowJob();
|
||||
_brokenJob = new BrokenJob();
|
||||
_disabledJob = new DisabledJob();
|
||||
_updatedJob = null;
|
||||
|
||||
IEnumerable<IJob> jobs = new List<IJob> { _fakeJob, _slowJob, _brokenJob, _disabledJob };
|
||||
|
||||
Mocker.SetConstant(jobs);
|
||||
|
||||
Mocker.GetMock<IJobRepository>()
|
||||
.Setup(c => c.Update(It.IsAny<JobDefinition>()))
|
||||
.Callback<JobDefinition>(c => _updatedJob = c);
|
||||
|
||||
|
||||
Mocker.GetMock<IJobRepository>()
|
||||
.Setup(c => c.GetDefinition(It.IsAny<Type>()))
|
||||
.Returns(new JobDefinition());
|
||||
}
|
||||
|
||||
|
||||
private void GivenPendingJob(IList<JobDefinition> jobDefinition)
|
||||
{
|
||||
Mocker.GetMock<IJobRepository>().Setup(c => c.GetPendingJobs()).Returns(jobDefinition);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Subject.Queue.Should().BeEmpty();
|
||||
}
|
||||
|
||||
private void WaitForQueue()
|
||||
{
|
||||
Console.WriteLine("Waiting for queue to clear.");
|
||||
var stopWatch = Mocker.Resolve<JobController>().StopWatch;
|
||||
|
||||
while (stopWatch.IsRunning)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void running_scheduled_jobs_should_updates_last_execution_time()
|
||||
{
|
||||
GivenPendingJob(new List<JobDefinition> { new JobDefinition { TypeName = _fakeJob.GetType().FullName } });
|
||||
|
||||
Subject.QueueScheduled();
|
||||
WaitForQueue();
|
||||
|
||||
_updatedJob.LastExecution.Should().BeWithin(TimeSpan.FromSeconds(10));
|
||||
_updatedJob.LastExecution.Should().BeWithin(TimeSpan.FromSeconds(10));
|
||||
_fakeJob.ExecutionCount.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void failing_scheduled_job_should_mark_job_as_failed()
|
||||
{
|
||||
GivenPendingJob(new List<JobDefinition> { new JobDefinition { TypeName = _brokenJob.GetType().FullName } });
|
||||
|
||||
Subject.QueueScheduled();
|
||||
WaitForQueue();
|
||||
|
||||
_updatedJob.LastExecution.Should().BeWithin(TimeSpan.FromSeconds(10));
|
||||
_updatedJob.Success.Should().BeFalse();
|
||||
_brokenJob.ExecutionCount.Should().Be(1);
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void can_run_async_job_again()
|
||||
{
|
||||
Subject.QueueJob(typeof(FakeJob));
|
||||
WaitForQueue();
|
||||
Subject.QueueJob(typeof(FakeJob));
|
||||
WaitForQueue();
|
||||
|
||||
Subject.Queue.Should().BeEmpty();
|
||||
_fakeJob.ExecutionCount.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void no_concurent_jobs()
|
||||
{
|
||||
Subject.QueueJob(typeof(SlowJob), 1);
|
||||
Subject.QueueJob(typeof(SlowJob), 2);
|
||||
Subject.QueueJob(typeof(SlowJob), 3);
|
||||
|
||||
WaitForQueue();
|
||||
|
||||
Subject.Queue.Should().BeEmpty();
|
||||
_slowJob.ExecutionCount.Should().Be(3);
|
||||
ExceptionVerification.AssertNoUnexcpectedLogs();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void can_run_broken_job_again()
|
||||
{
|
||||
Subject.QueueJob(typeof(BrokenJob));
|
||||
WaitForQueue();
|
||||
|
||||
Subject.QueueJob(typeof(BrokenJob));
|
||||
WaitForQueue();
|
||||
|
||||
|
||||
_brokenJob.ExecutionCount.Should().Be(2);
|
||||
ExceptionVerification.ExpectedErrors(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void schedule_hit_should_be_ignored_if_queue_is_running()
|
||||
{
|
||||
Subject.QueueJob(typeof(SlowJob));
|
||||
Subject.QueueScheduled();
|
||||
WaitForQueue();
|
||||
|
||||
_slowJob.ExecutionCount.Should().Be(1);
|
||||
_fakeJob.ExecutionCount.Should().Be(0);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void can_queue_jobs_at_the_same_time()
|
||||
{
|
||||
|
||||
Subject.QueueJob(typeof(SlowJob));
|
||||
var thread1 = new Thread(() => Subject.QueueJob(typeof(FakeJob)));
|
||||
var thread2 = new Thread(() => Subject.QueueJob(typeof(FakeJob)));
|
||||
|
||||
thread1.Start();
|
||||
thread2.Start();
|
||||
|
||||
thread1.Join();
|
||||
thread2.Join();
|
||||
|
||||
WaitForQueue();
|
||||
|
||||
_fakeJob.ExecutionCount.Should().Be(1);
|
||||
_slowJob.ExecutionCount.Should().Be(1);
|
||||
Subject.Queue.Should().BeEmpty();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void job_with_specific_target_should_not_update_status()
|
||||
{
|
||||
Subject.QueueJob(typeof(FakeJob), 10);
|
||||
|
||||
WaitForQueue();
|
||||
|
||||
Mocker.GetMock<IJobRepository>().Verify(c=>c.Update(It.IsAny<JobDefinition>()),Times.Never());
|
||||
_updatedJob.Should().BeNull();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void Item_added_to_queue_while_scheduler_runs_should_be_executed()
|
||||
{
|
||||
GivenPendingJob(new List<JobDefinition> { new JobDefinition { TypeName = _slowJob.GetType().FullName } });
|
||||
|
||||
var jobThread = new Thread(Subject.QueueScheduled);
|
||||
jobThread.Start();
|
||||
|
||||
Thread.Sleep(200);
|
||||
|
||||
Subject.QueueJob(typeof(DisabledJob), 12);
|
||||
|
||||
WaitForQueue();
|
||||
|
||||
_slowJob.ExecutionCount.Should().Be(1);
|
||||
_disabledJob.ExecutionCount.Should().Be(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void trygin_to_queue_unregistered_job_should_fail()
|
||||
{
|
||||
Subject.QueueJob(typeof(UpdateInfoJob));
|
||||
WaitForQueue();
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void scheduled_job_should_have_scheduler_as_source()
|
||||
{
|
||||
GivenPendingJob(new List<JobDefinition> { new JobDefinition { TypeName = _slowJob.GetType().FullName }, new JobDefinition { TypeName = _slowJob.GetType().FullName } });
|
||||
Subject.QueueScheduled();
|
||||
|
||||
Subject.Queue.Should().OnlyContain(c => c.Source == JobQueueItem.JobSourceType.Scheduler);
|
||||
|
||||
WaitForQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
// ReSharper disable RedundantUsingDirective
|
||||
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NCrunch.Framework;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Model;
|
||||
using NzbDrone.Core.Repository;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.JobTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class JobRepositoryFixture : RepositoryTest<JobRepository, JobDefinition>
|
||||
{
|
||||
FakeJob _fakeJob;
|
||||
DisabledJob _disabledJob;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_fakeJob = new FakeJob();
|
||||
_disabledJob = new DisabledJob();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Init_should_add_defintaions()
|
||||
{
|
||||
IEnumerable<IJob> baseFakeJobs = new List<IJob> { _fakeJob };
|
||||
Mocker.SetConstant(baseFakeJobs);
|
||||
|
||||
|
||||
Subject.Init();
|
||||
|
||||
Storage.All().Should().HaveCount(1);
|
||||
Storage.All()[0].Interval.Should().Be((Int32)_fakeJob.DefaultInterval.TotalMinutes);
|
||||
Storage.All()[0].Name.Should().Be(_fakeJob.Name);
|
||||
Storage.All()[0].TypeName.Should().Be(_fakeJob.GetType().ToString());
|
||||
Storage.All()[0].LastExecution.Should().HaveYear(DateTime.Now.Year);
|
||||
Storage.All()[0].LastExecution.Should().HaveMonth(DateTime.Now.Month);
|
||||
Storage.All()[0].LastExecution.Should().HaveDay(DateTime.Today.Day);
|
||||
Storage.All()[0].Enable.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void inti_should_removed_jobs_that_no_longer_exist()
|
||||
{
|
||||
IEnumerable<IJob> fakeJobs = new List<IJob> { _fakeJob };
|
||||
Mocker.SetConstant(fakeJobs);
|
||||
|
||||
Subject.Init();
|
||||
|
||||
var deletedJob = Builder<JobDefinition>.CreateNew()
|
||||
.With(c => c.OID = 0)
|
||||
.Build();
|
||||
|
||||
Db.Insert(deletedJob);
|
||||
Subject.Init();
|
||||
|
||||
var registeredJobs = Storage.All();
|
||||
registeredJobs.Should().HaveCount(1);
|
||||
registeredJobs.Should().NotContain(c => c.TypeName == deletedJob.TypeName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void inti_should_removed_jobs_that_no_longer_exist_even_with_same_name()
|
||||
{
|
||||
IEnumerable<IJob> fakeJobs = new List<IJob> { _fakeJob };
|
||||
Mocker.SetConstant(fakeJobs);
|
||||
|
||||
Subject.Init();
|
||||
|
||||
var deletedJob = Builder<JobDefinition>.CreateNew()
|
||||
.With(c => c.Name = _fakeJob.Name)
|
||||
.With(c => c.OID = 0)
|
||||
.Build();
|
||||
|
||||
|
||||
Db.Insert(deletedJob);
|
||||
Subject.Init();
|
||||
|
||||
|
||||
|
||||
var registeredJobs = Storage.All();
|
||||
registeredJobs.Should().HaveCount(1);
|
||||
registeredJobs.Should().NotContain(c => c.TypeName == deletedJob.TypeName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void init_should_update_existing_job()
|
||||
{
|
||||
|
||||
var oldJob = Builder<JobDefinition>.CreateNew()
|
||||
.With(c => c.OID = 0)
|
||||
.With(c => c.Name = "OldName")
|
||||
.With(c => c.TypeName = typeof(FakeJob).ToString())
|
||||
.With(c => c.Interval = 0)
|
||||
.With(c => c.Enable = true)
|
||||
.With(c => c.Success = true)
|
||||
.With(c => c.LastExecution = DateTime.Now.AddDays(-7).Date)
|
||||
.Build();
|
||||
|
||||
Storage.Add(oldJob);
|
||||
|
||||
var newJob = new FakeJob();
|
||||
|
||||
IEnumerable<IJob> fakeJobs = new List<IJob> { newJob };
|
||||
Mocker.SetConstant(fakeJobs);
|
||||
|
||||
Subject.Init();
|
||||
|
||||
|
||||
var registeredJobs = Storage.All();
|
||||
registeredJobs.Should().HaveCount(1);
|
||||
registeredJobs.First().TypeName.Should().Be(newJob.GetType().FullName);
|
||||
registeredJobs.First().Name.Should().Be(newJob.Name);
|
||||
registeredJobs.First().Interval.Should().Be((int)newJob.DefaultInterval.TotalMinutes);
|
||||
|
||||
registeredJobs.First().Enable.Should().Be(true);
|
||||
registeredJobs.First().Success.Should().Be(oldJob.Success);
|
||||
registeredJobs.First().LastExecution.Should().Be(oldJob.LastExecution);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void jobs_with_zero_interval_are_registered_as_disabled()
|
||||
{
|
||||
IEnumerable<IJob> fakeJobs = new List<IJob> { _disabledJob };
|
||||
Mocker.SetConstant(fakeJobs);
|
||||
|
||||
Subject.Init();
|
||||
|
||||
|
||||
Storage.All().Should().HaveCount(1);
|
||||
Storage.All().First().Enable.Should().BeFalse();
|
||||
}
|
||||
|
||||
/* [Test]
|
||||
public void disabled_jobs_arent_run_by_scheduler()
|
||||
{
|
||||
IEnumerable<IJob> BaseFakeJobs = new List<IJob> { disabledJob };
|
||||
Mocker.SetConstant(BaseFakeJobs);
|
||||
|
||||
var jobProvider = Mocker.Resolve<JobController>();
|
||||
jobProvider.QueueScheduled();
|
||||
|
||||
WaitForQueue();
|
||||
|
||||
|
||||
disabledJob.ExecutionCount.Should().Be(0);
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NzbDrone.Core.Jobs;
|
||||
using NzbDrone.Core.Model.Notification;
|
||||
|
||||
namespace NzbDrone.Core.Test.JobTests
|
||||
{
|
||||
|
||||
public class FakeJob : IJob
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get { return GetType().Name; }
|
||||
}
|
||||
|
||||
public virtual TimeSpan DefaultInterval
|
||||
{
|
||||
get { return TimeSpan.FromMinutes(15); }
|
||||
}
|
||||
|
||||
public int ExecutionCount { get; private set; }
|
||||
|
||||
public void Start(ProgressNotification notification, dynamic options)
|
||||
{
|
||||
ExecutionCount++;
|
||||
Console.WriteLine("Begin " + Name);
|
||||
Start();
|
||||
Console.WriteLine("End " + Name);
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class DisabledJob : FakeJob
|
||||
{
|
||||
public override TimeSpan DefaultInterval
|
||||
{
|
||||
get { return TimeSpan.FromTicks(0); }
|
||||
}
|
||||
}
|
||||
|
||||
public class BrokenJob : FakeJob
|
||||
{
|
||||
protected override void Start()
|
||||
{
|
||||
throw new ApplicationException("Broken job is broken");
|
||||
}
|
||||
}
|
||||
|
||||
public class SlowJob : FakeJob
|
||||
{
|
||||
protected override void Start()
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user