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);
        }
Esempio n. 8
0
        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());
        }