/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.aurora.scheduler.cron.quartz; import java.util.List; import java.util.Map; import java.util.TimeZone; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import org.apache.aurora.common.testing.easymock.EasyMockTest; import org.apache.aurora.gen.CronCollisionPolicy; import org.apache.aurora.scheduler.base.TaskTestUtil; import org.apache.aurora.scheduler.cron.CronException; import org.apache.aurora.scheduler.cron.CronJobManager; import org.apache.aurora.scheduler.cron.CrontabEntry; import org.apache.aurora.scheduler.cron.SanitizedCronJob; import org.apache.aurora.scheduler.storage.Storage; import org.apache.aurora.scheduler.storage.Storage.MutateWork.NoResult; import org.apache.aurora.scheduler.storage.db.DbUtil; import org.apache.aurora.scheduler.storage.entities.IJobConfiguration; import org.apache.aurora.scheduler.storage.entities.IJobKey; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.Trigger; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class CronJobManagerImplTest extends EasyMockTest { private Storage storage; private Scheduler scheduler; private CronJobManager cronJobManager; @Before public void setUp() { storage = DbUtil.createStorage(); scheduler = createMock(Scheduler.class); cronJobManager = new CronJobManagerImpl(storage, scheduler, TimeZone.getTimeZone("GMT")); } @Test public void testStartJobNowExistent() throws Exception { populateStorage(); scheduler.triggerJob(QuartzTestUtil.QUARTZ_JOB_KEY); control.replay(); cronJobManager.startJobNow(QuartzTestUtil.AURORA_JOB_KEY); } @Test(expected = CronException.class) public void testStartJobNowFails() throws Exception { populateStorage(); scheduler.triggerJob(QuartzTestUtil.QUARTZ_JOB_KEY); expectLastCall().andThrow(new SchedulerException()); control.replay(); cronJobManager.startJobNow(QuartzTestUtil.AURORA_JOB_KEY); } @Test(expected = CronException.class) public void testStartJobNowNonexistent() throws Exception { control.replay(); cronJobManager.startJobNow(QuartzTestUtil.AURORA_JOB_KEY); } @Test public void testUpdateExistingJob() throws Exception { SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob(); expect(scheduler.deleteJob(QuartzTestUtil.QUARTZ_JOB_KEY)).andReturn(true); expect(scheduler.scheduleJob(anyObject(JobDetail.class), anyObject(Trigger.class))) .andReturn(null); populateStorage(); control.replay(); cronJobManager.updateJob(sanitizedCronJob); assertEquals(sanitizedCronJob.getSanitizedConfig().getJobConfig(), fetchFromStorage().orNull()); } @Test public void testUpdateNonexistentJob() throws Exception { control.replay(); try { cronJobManager.updateJob(QuartzTestUtil.makeUpdatedJob()); fail(); } catch (CronException e) { // Expected. } assertEquals(Optional.absent(), fetchFromStorage()); } @Test public void testCreateNonexistentJob() throws Exception { SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob(); expect(scheduler.scheduleJob(anyObject(JobDetail.class), anyObject(Trigger.class))) .andReturn(null); control.replay(); cronJobManager.createJob(sanitizedCronJob); assertEquals( sanitizedCronJob.getSanitizedConfig().getJobConfig(), fetchFromStorage().orNull()); } @Test(expected = CronException.class) public void testCreateNonexistentJobFails() throws Exception { SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob(); expect(scheduler.scheduleJob(anyObject(JobDetail.class), anyObject(Trigger.class))) .andThrow(new SchedulerException()); control.replay(); cronJobManager.createJob(sanitizedCronJob); } @Test(expected = CronException.class) public void testCreateExistingJobFails() throws Exception { SanitizedCronJob sanitizedCronJob = QuartzTestUtil.makeSanitizedCronJob(); populateStorage(); control.replay(); cronJobManager.createJob(sanitizedCronJob); } @Test public void testNoRunOverlap() throws Exception { SanitizedCronJob runOverlapJob = SanitizedCronJob.fromUnsanitized( TaskTestUtil.CONFIGURATION_MANAGER, IJobConfiguration.build(QuartzTestUtil.JOB.newBuilder() .setCronCollisionPolicy(CronCollisionPolicy.RUN_OVERLAP))); control.replay(); try { cronJobManager.createJob(runOverlapJob); fail(); } catch (CronException e) { // Expected. } try { cronJobManager.updateJob(runOverlapJob); } catch (CronException e) { // Expected. } assertEquals(Optional.absent(), fetchFromStorage()); } @Test public void testDeleteJob() throws Exception { expect(scheduler.deleteJob(QuartzTestUtil.QUARTZ_JOB_KEY)).andReturn(true); control.replay(); assertFalse(cronJobManager.deleteJob(QuartzTestUtil.AURORA_JOB_KEY)); populateStorage(); assertTrue(cronJobManager.deleteJob(QuartzTestUtil.AURORA_JOB_KEY)); assertEquals(Optional.absent(), fetchFromStorage()); } @Test public void testFailedDeleteJobDoesNotThrow() throws Exception { expect(scheduler.deleteJob(QuartzTestUtil.QUARTZ_JOB_KEY)).andThrow(new SchedulerException()); control.replay(); populateStorage(); cronJobManager.deleteJob(QuartzTestUtil.AURORA_JOB_KEY); } @Test public void testGetScheduledJobs() throws Exception { CronTrigger cronTrigger = createMock(CronTrigger.class); expect(scheduler.getJobKeys(anyObject())) .andReturn(ImmutableSet.of(QuartzTestUtil.QUARTZ_JOB_KEY)); EasyMock. <List<? extends Trigger>>expect(scheduler.getTriggersOfJob(QuartzTestUtil.QUARTZ_JOB_KEY)) .andReturn(ImmutableList.of(cronTrigger)); expect(cronTrigger.getDescription()).andReturn("* * * * *"); control.replay(); Map<IJobKey, CrontabEntry> scheduledJobs = cronJobManager.getScheduledJobs(); assertEquals(CrontabEntry.parse("* * * * *"), scheduledJobs.get(QuartzTestUtil.AURORA_JOB_KEY)); } @Test public void testGetScheduledJobsEmpty() throws Exception { expect(scheduler.getJobKeys(anyObject())) .andReturn(ImmutableSet.of(QuartzTestUtil.QUARTZ_JOB_KEY)); EasyMock. <List<? extends Trigger>>expect(scheduler.getTriggersOfJob(QuartzTestUtil.QUARTZ_JOB_KEY)) .andReturn(ImmutableList.of()); control.replay(); assertEquals(ImmutableMap.of(), cronJobManager.getScheduledJobs()); } @Test(expected = RuntimeException.class) public void testGetScheduledJobsFails() throws Exception { expect(scheduler.getJobKeys(anyObject())) .andReturn(ImmutableSet.of(QuartzTestUtil.QUARTZ_JOB_KEY)); EasyMock. <List<? extends Trigger>>expect(scheduler.getTriggersOfJob(QuartzTestUtil.QUARTZ_JOB_KEY)) .andThrow(new SchedulerException()); control.replay(); cronJobManager.getScheduledJobs(); } private void populateStorage() throws Exception { storage.write((NoResult.Quiet) storeProvider -> storeProvider.getCronJobStore().saveAcceptedJob( QuartzTestUtil.makeSanitizedCronJob().getSanitizedConfig().getJobConfig())); } private Optional<IJobConfiguration> fetchFromStorage() { return storage.read( storeProvider -> storeProvider.getCronJobStore().fetchJob(QuartzTestUtil.AURORA_JOB_KEY)); } }