public void WhenScheduleIsNew_UpdateJob_CreatesNewTrigger()
        {
            // Arrange.
            var syncGuid = Guid.Parse("DF1F8724-297C-45AE-8E70-B924FD375620");
            var scheduleGuid = Guid.Parse("{210B8E36-B81D-4E29-AFC0-19C7CA7FCCD1}");
            var jobName = syncGuid.ToString();
            var triggerName = scheduleGuid.ToString();
            const string processName = "TestProcess";

            var newSchedule = Mock.Create<ISchedule>(Behavior.Loose);
            Mock.Arrange(() => newSchedule.Guid).Returns(scheduleGuid);
            Mock.Arrange(() => newSchedule.IsActive).Returns(true);
            Mock.Arrange(() => newSchedule.Equals(Arg.IsAny<ISchedule>())).Returns(false);

            var synchronizer = Mock.Create<IProcessSynchronizer>(Behavior.Loose);

            Mock.Arrange(() => synchronizer.Guid).Returns(syncGuid);
            Mock.Arrange(() => synchronizer.ProcessName).Returns(processName);
            Mock.Arrange(() => synchronizer.Schedules).Returns(new[] { newSchedule });

            var jobDetail = new JobDetail(jobName, QuartzScheduler.QuartzGroupName, typeof(SyncProcessWorker), false, true, false);
            var scheduler = Mock.Create<IScheduler>(Behavior.Loose);

            // Job is already scheduled.
            Mock.Arrange(() => scheduler.GetJobDetail(jobName, QuartzScheduler.QuartzGroupName)).Returns(jobDetail);

            Mock.Arrange(() => scheduler.GetTriggersOfJob(jobName, QuartzScheduler.QuartzGroupName)).Returns(new Trigger[] { });

            var logger = Mock.Create<ILogger>(Behavior.CallOriginal);

            var triggerFactory = Mock.Create<ITriggerFactory>(Behavior.CallOriginal);
            Mock.Arrange(() => triggerFactory.CreateTrigger(Arg.IsAny<ISchedule>())).Returns<ISchedule>(
                s =>
                    {
                        var newTrigger = Mock.Create<ESyncTrigger>(Behavior.Loose);
                        Mock.Arrange(() => newTrigger.ComputeFirstFireTimeUtc(Arg.IsAny<ICalendar>())).Returns(DateTime.UtcNow);
                        newTrigger.Schedule = s;

                        return newTrigger;
                    });

            var target = new DummyQuartzScheduler { Logger = logger, TriggerFactory = triggerFactory };
            target.SetScheduler(scheduler);

            // Act.
            target.UpdateJob(synchronizer);

            // Assert.
            Mock.Assert(() => scheduler.UnscheduleJob(triggerName, QuartzScheduler.QuartzGroupName), Occurs.Never());
            Mock.Assert(() => scheduler.ScheduleJob(Arg.IsAny<Trigger>()), Occurs.Once());
            Mock.Assert(() => logger.Log(LogSeverity.Error, Arg.IsAny<string>(), Arg.IsAny<Exception>()), Occurs.Never());
        }
        public void WhenScheduleIsNotFound_UpdateJob_DeletesTrigger()
        {
            // Arrange.
            var syncGuid = Guid.Parse("DF1F8724-297C-45AE-8E70-B924FD375620");
            var scheduleGuid = Guid.Parse("{210B8E36-B81D-4E29-AFC0-19C7CA7FCCD1}");
            var jobName = syncGuid.ToString();
            var triggerName = scheduleGuid.ToString();
            const string processName = "TestProcess";

            var synchronizerMock = Mock.Create<IProcessSynchronizer>(Behavior.Loose);

            Mock.Arrange(() => synchronizerMock.Guid).Returns(syncGuid);
            Mock.Arrange(() => synchronizerMock.ProcessName).Returns(processName);
            Mock.Arrange(() => synchronizerMock.Schedules).Returns(new ISchedule[] { });

            var jobDetail = new JobDetail(jobName, QuartzScheduler.QuartzGroupName, typeof(SyncProcessWorker), false, true, false);

            var oldSchedule = Mock.Create<ISchedule>(Behavior.Loose);
            Mock.Arrange(() => oldSchedule.Guid).Returns(scheduleGuid);
            var trigger = new ESyncTrigger
            {
                Name = triggerName,
                Schedule = oldSchedule
            };

            var schedulerMock = Mock.Create<IScheduler>(Behavior.Loose);

            // Job is already scheduled.
            Mock.Arrange(() => schedulerMock.GetJobDetail(jobName, QuartzScheduler.QuartzGroupName)).Returns(jobDetail);

            Mock.Arrange(() => schedulerMock.GetTriggersOfJob(jobName, QuartzScheduler.QuartzGroupName)).Returns(new Trigger[] { trigger });

            var loggerMock = Mock.Create<ILogger>(Behavior.CallOriginal);

            var target = new DummyQuartzScheduler { Logger = loggerMock };
            target.SetScheduler(schedulerMock);

            // Act.
            target.UpdateJob(synchronizerMock);

            // Assert.
            Mock.Assert(() => schedulerMock.UnscheduleJob(triggerName, QuartzScheduler.QuartzGroupName), Occurs.Once());
            Mock.Assert(() => schedulerMock.ScheduleJob(Arg.IsAny<Trigger>()), Occurs.Never());
        }
        public void WhenScheduleIsNotActive_UpdateJob_DeletesTrigger()
        {
            // Arrange.
            var syncGuid = Guid.Parse("DF1F8724-297C-45AE-8E70-B924FD375620");
            var scheduleGuid = Guid.Parse("{210B8E36-B81D-4E29-AFC0-19C7CA7FCCD1}");
            var jobName = syncGuid.ToString();
            var triggerName = scheduleGuid.ToString();
            const string processName = "TestProcess";

            var newSchedule = Mock.Create<ISchedule>(Behavior.Loose);
            Mock.Arrange(() => newSchedule.Guid).Returns(scheduleGuid);
            Mock.Arrange(() => newSchedule.IsActive).Returns(false);

            var synchronizer = Mock.Create<IProcessSynchronizer>(Behavior.Loose);

            Mock.Arrange(() => synchronizer.Guid).Returns(syncGuid);
            Mock.Arrange(() => synchronizer.ProcessName).Returns(processName);
            Mock.Arrange(() => synchronizer.Schedules).Returns(new[] { newSchedule });

            var jobDetail = new JobDetail(jobName, QuartzScheduler.QuartzGroupName, typeof(SyncProcessWorker), false, true, false);

            var oldSchedule = Mock.Create<ISchedule>(Behavior.Loose);
            Mock.Arrange(() => oldSchedule.Guid).Returns(scheduleGuid);

            // Make old schedule and new schedule be equal.
            Mock.Arrange(() => oldSchedule.Equals(newSchedule)).Returns(true);
            Mock.Arrange(() => newSchedule.Equals(oldSchedule)).Returns(true);

            var trigger = new ESyncTrigger { Name = triggerName, Schedule = oldSchedule };

            var scheduler = Mock.Create<IScheduler>(Behavior.Loose);

            // Job is already scheduled.
            Mock.Arrange(() => scheduler.GetJobDetail(jobName, QuartzScheduler.QuartzGroupName)).Returns(jobDetail);

            Mock.Arrange(() => scheduler.GetTriggersOfJob(jobName, QuartzScheduler.QuartzGroupName)).Returns(new Trigger[] { trigger });

            var logger = Mock.Create<ILogger>(Behavior.Loose);

            var target = new DummyQuartzScheduler { Logger = logger };
            target.SetScheduler(scheduler);

            // Act.
            target.UpdateJob(synchronizer);

            // Assert.
            Mock.Assert(() => scheduler.UnscheduleJob(triggerName, QuartzScheduler.QuartzGroupName), Occurs.Once());
            Mock.Assert(() => scheduler.ScheduleJob(Arg.IsAny<Trigger>()), Occurs.Never());
            Mock.Assert(() => logger.Log(LogSeverity.Error, Arg.IsAny<string>(), Arg.IsAny<Exception>()), Occurs.Never());
        }
        public void WhenJobIsNew_UpdateJob_AddsNewJob()
        {
            // Arrange.
            var syncGuid = Guid.Parse("DF1F8724-297C-45AE-8E70-B924FD375620");
            var jobName = syncGuid.ToString();
            const string processName = "TestProcess";

            var synchronizerMock = Mock.Create<IProcessSynchronizer>(Behavior.Loose);
            Mock.Arrange(() => synchronizerMock.Guid).Returns(syncGuid);
            Mock.Arrange(() => synchronizerMock.ProcessName).Returns(processName);

            var schedulerMock = Mock.Create<IScheduler>(Behavior.Loose);

            // Job is not scheduled.
            Mock.Arrange(() => schedulerMock.GetJobDetail(jobName, QuartzScheduler.QuartzGroupName)).Returns(null as JobDetail);

            JobDetail jobDetail = null;

            Mock.Arrange(() => schedulerMock.AddJob(Arg.IsAny<JobDetail>(), true)).DoInstead<JobDetail, bool>((jd, replace) => jobDetail = jd);

            var loggerMock = Mock.Create<ILogger>(Behavior.CallOriginal);

            var target = new DummyQuartzScheduler { Logger = loggerMock };
            target.SetScheduler(schedulerMock);

            // Act.
            target.UpdateJob(synchronizerMock);

            // Assert.
            Assert.IsNotNull(jobDetail);
            Assert.AreEqual(jobName, jobDetail.Name);
            Assert.AreEqual(QuartzScheduler.QuartzGroupName, jobDetail.Group);
            Assert.IsFalse(jobDetail.Volatile);
            Assert.IsTrue(jobDetail.Durable);
            Assert.IsFalse(jobDetail.RequestsRecovery);
            Assert.AreEqual(typeof(SyncProcessWorker), jobDetail.JobType);
            Assert.AreEqual(syncGuid, jobDetail.JobDataMap["syncProcessGuid"]);
            Assert.AreEqual(processName, jobDetail.JobDataMap["processName"]);
        }