public void SaveJobDetails_RoundTripWithGetJobDetails() { // Create job and set details. Assert.IsTrue(jobStore.CreateJob(dummyJobSpec, DateTime.UtcNow, CreateJobConflictAction.Throw)); JobDetails savedJobDetails = jobStore.GetJobDetails(dummyJobSpec.Name); savedJobDetails.JobState = JobState.Running; savedJobDetails.LastJobExecutionDetails = new JobExecutionDetails(SchedulerGuid, DateTime.UtcNow); savedJobDetails.LastJobExecutionDetails.StatusMessage = "Status"; savedJobDetails.LastJobExecutionDetails.Succeeded = true; savedJobDetails.LastJobExecutionDetails.EndTimeUtc = new DateTime(1969, 12, 31); savedJobDetails.NextTriggerFireTimeUtc = new DateTime(1970, 1, 1); savedJobDetails.NextTriggerMisfireThreshold = new TimeSpan(0, 1, 0); savedJobDetails.JobSpec.JobData = new JobData(); savedJobDetails.JobSpec.JobData.State["key"] = "new value"; savedJobDetails.JobSpec.Trigger.Schedule(TriggerScheduleCondition.Latch, DateTime.MaxValue, null); dummyJobSpec.Trigger.Schedule(TriggerScheduleCondition.Latch, DateTime.MaxValue, null); jobStore.SaveJobDetails(savedJobDetails); // Check job details. JobDetails loadedJobDetails = jobStore.GetJobDetails(dummyJobSpec.Name); JobAssert.AreEqual(savedJobDetails, loadedJobDetails); }
public void ClonePerformsADeepCopy(bool useGenericClonable) { Dictionary <string, object> dict = new Dictionary <string, object>(); JobData jobData = new JobData(dict); JobData clone = useGenericClonable ? jobData.Clone() : (JobData)((ICloneable)jobData).Clone(); Assert.AreNotSame(jobData, clone); Assert.AreNotSame(dict, clone.State); JobAssert.AreEqual(jobData, clone); }
public void ClonePerformsADeepCopy(bool useGenericClonable) { DateTime now = DateTime.UtcNow; JobExecutionDetails details = new JobExecutionDetails(SchedulerGuid, now); details.EndTimeUtc = new DateTime(2000, 3, 4); details.Succeeded = true; details.StatusMessage = "Blah"; JobExecutionDetails clone = useGenericClonable ? details.Clone() : (JobExecutionDetails)((ICloneable)details).Clone(); Assert.AreNotSame(details, clone); JobAssert.AreEqual(details, clone); }
public void GetJobDetails_ReturnsCorrectDetailsAfterCreateJob() { DateTime creationTime = DateTime.UtcNow; Assert.IsTrue(jobStore.CreateJob(dummyJobSpec, creationTime, CreateJobConflictAction.Throw)); JobDetails jobDetails = jobStore.GetJobDetails(dummyJobSpec.Name); Assert.IsNotNull(jobDetails); JobAssert.AreEqual(dummyJobSpec, jobDetails.JobSpec); JobAssert.AreEqualUpToErrorLimit(creationTime, jobDetails.CreationTimeUtc); Assert.AreEqual(JobState.Pending, jobDetails.JobState); Assert.IsNull(jobDetails.LastJobExecutionDetails); Assert.IsNull(jobDetails.NextTriggerFireTimeUtc); Assert.IsNull(jobDetails.NextTriggerMisfireThreshold); }
public void ClonePerformsADeepCopy(bool useGenericClonable) { JobDetails jobDetails = new JobDetails(jobSpec, DateTime.UtcNow); jobDetails.LastJobExecutionDetails = new JobExecutionDetails(SchedulerGuid, DateTime.UtcNow); jobDetails.JobState = JobState.Scheduled; jobDetails.NextTriggerFireTimeUtc = DateTime.UtcNow; jobDetails.NextTriggerMisfireThreshold = TimeSpan.MaxValue; JobDetails clone = useGenericClonable ? jobDetails.Clone() : (JobDetails)((ICloneable)jobDetails).Clone(); Assert.AreNotSame(jobDetails, clone); Assert.AreNotSame(jobDetails.JobSpec, clone.JobSpec); Assert.AreNotSame(jobDetails.LastJobExecutionDetails, clone.LastJobExecutionDetails); JobAssert.AreEqual(jobDetails, clone); }
public void ClonePerformsADeepCopy(bool useGenericClonable, bool jobDataIsNull) { JobSpec spec = new JobSpec("abc", "some job", "with this key", trigger); spec.JobData = jobDataIsNull ? null : new JobData(); JobSpec clone = useGenericClonable ? spec.Clone() : (JobSpec)((ICloneable)spec).Clone(); Assert.AreNotSame(spec, clone); Assert.AreNotSame(trigger, clone.Trigger); if (!jobDataIsNull) { Assert.AreNotSame(spec.JobData, clone.JobData); } JobAssert.AreEqual(spec, clone); }
public void UpdateJob_CanRenameJobsAndAlterOtherProperties() { Mocks.ReplayAll(); JobDetails originalJob = CreateRunningJob("originalJob"); JobSpec updatedJobSpec = new JobSpec("updatedJob", "This is updated.", "The new key", PeriodicTrigger.CreateOneShotTrigger(new DateTime(2000, 3, 4))); jobStore.UpdateJob("originalJob", updatedJobSpec); Assert.IsNull(jobStore.GetJobDetails("originalJob"), "The job should not be accessible under its original name."); // The job gets a new job spec, but all other properties should be preserved including // the job's execution history. JobDetails updatedJob = jobStore.GetJobDetails("updatedJob"); JobDetails expectedUpdatedJob = originalJob.Clone(); expectedUpdatedJob.JobSpec = updatedJobSpec; JobAssert.AreEqual(expectedUpdatedJob, updatedJob); }
public void SchedulerExecutesJobsAndHandlesSuccessFailureOrException( bool jobSucceeds, bool jobThrows, bool savingCompletedJobThrows) { JobData newJobData = new JobData(); ExecuteDelegate execute = delegate(JobExecutionContext context) { Assert.IsNotNull(context); Assert.AreSame(scheduler, context.Scheduler); Assert.IsNotNull(context.Logger); Assert.IsNotNull(context.JobSpec); context.JobData = newJobData; if (jobThrows) { throw new Exception("Oh no!"); } return(jobSucceeds); }; PrepareJobForExecution(execute.BeginInvoke, execute.EndInvoke); /* Note: We used to drop back into ScheduleJob again immediately after a job completed. * That's a cheap optimization but it makes it more difficult to ensure that * the scheduler will shut down cleanly since it could just keep re-executing the job. * TriggerScheduleCondition expectedCondition = jobSucceeds ? TriggerScheduleCondition.JobSucceeded : TriggerScheduleCondition.JobFailed; * Expect.Call(mockTrigger.Schedule(expectedCondition, DateTime.UtcNow)) * .Constraints(Is.Equal(expectedCondition), Is.Anything()) * .Return(TriggerScheduleAction.Stop); * Expect.Call(mockTrigger.NextFireTime).Return(null); * Expect.Call(mockTrigger.NextMisfireThreshold).Return(null); */ mockJobStore.SaveJobDetails(null); LastCall.IgnoreArguments().Do((SaveJobDetailsDelegate) delegate(JobDetails completedJobDetails) { Assert.IsNotNull(completedJobDetails); Assert.AreEqual(dummyJobSpec.Name, completedJobDetails.JobSpec.Name); Assert.IsNotNull(completedJobDetails.LastJobExecutionDetails); Assert.AreEqual(scheduler.Guid, completedJobDetails.LastJobExecutionDetails.SchedulerGuid); Assert.GreaterOrEqual(completedJobDetails.LastJobExecutionDetails.StartTimeUtc, completedJobDetails.CreationTimeUtc); Assert.IsNotNull(completedJobDetails.LastJobExecutionDetails.EndTimeUtc); Assert.GreaterOrEqual(completedJobDetails.LastJobExecutionDetails.EndTimeUtc.Value.Ticks, completedJobDetails.LastJobExecutionDetails.StartTimeUtc.Ticks); Assert.AreEqual(jobSucceeds, completedJobDetails.LastJobExecutionDetails.Succeeded); if (!jobThrows) { JobAssert.AreEqual(newJobData, completedJobDetails.JobSpec.JobData); } else { Assert.IsNull(completedJobDetails.JobSpec.JobData); } Wake(); }); Mocks.ReplayAll(); RunSchedulerUntilWake(); }
public void JobWatcher_YieldsJobsInExpectedSequence() { IJobWatcher watcher = jobStore.CreateJobWatcher(SchedulerGuid); JobDetails orphaned = CreateOrphanedJob("orphaned", new DateTime(1970, 1, 3)); JobDetails pending = CreatePendingJob("pending", new DateTime(1970, 1, 2)); JobDetails triggered = CreateTriggeredJob("triggered", new DateTime(1970, 1, 6)); JobDetails completed = CreateCompletedJob("completed", new DateTime(1970, 1, 1)); JobDetails scheduled = CreateScheduledJob("scheduled", new DateTime(1970, 1, 4)); // Ensure we tolerate a few odd cases where data may not be available like it should. JobDetails scheduled2 = CreateScheduledJob("scheduled2", new DateTime(1970, 1, 2)); scheduled2.NextTriggerFireTimeUtc = null; jobStore.SaveJobDetails(scheduled2); JobDetails completed2 = CreateCompletedJob("completed2", new DateTime(1970, 1, 1)); completed2.LastJobExecutionDetails = null; jobStore.SaveJobDetails(completed2); JobDetails orphaned2 = CreateOrphanedJob("orphaned2", new DateTime(1970, 1, 3)); orphaned2.LastJobExecutionDetails.EndTimeUtc = null; jobStore.SaveJobDetails(orphaned2); // Populate a table of expected jobs. List <JobDetails> expectedJobs = new List <JobDetails>(new JobDetails[] { orphaned, pending, triggered, completed, scheduled, scheduled2 , completed2, orphaned2 }); // Add in some extra jobs in other states that will not be returned. CreateRunningJob("running1"); CreateStoppedJob("stopped1"); CreateScheduledJob("scheduled-in-the-future", DateTime.MaxValue); // Ensure expected jobs are retrieved. while (expectedJobs.Count != 0) { JobDetails actualJob = watcher.GetNextJobToProcess(); JobDetails expectedJob = expectedJobs.Find(delegate(JobDetails candidate) { return(candidate.JobSpec.Name == actualJob.JobSpec.Name); }); Assert.IsNotNull(expectedJob, "Did expect job {0}", actualJob.JobSpec.Name); // All expected scheduled jobs will have been triggered. if (expectedJob.JobState == JobState.Scheduled) { expectedJob.JobState = JobState.Triggered; } JobAssert.AreEqual(expectedJob, actualJob); if (expectedJobs.Count == 1) { // Ensure same job is returned a second time until its status is changed. // We wait for Count == 1 because that's the easiest case for which to verify // this behavior. JobDetails actualJob2 = watcher.GetNextJobToProcess(); JobAssert.AreEqual(expectedJob, actualJob2); } // Change the status to progress. actualJob.JobState = JobState.Stopped; jobStore.SaveJobDetails(actualJob); expectedJobs.Remove(expectedJob); } // Ensure next request blocks but is released by the call to dispose. ThreadPool.QueueUserWorkItem(delegate { Thread.Sleep(2); watcher.Dispose(); }); // This call blocks until the dispose runs. Assert.IsNull(watcher.GetNextJobToProcess()); }