package net.joelinn.quartz; import com.fasterxml.jackson.databind.ObjectMapper; import net.joelinn.quartz.jobstore.RedisJobStoreSchema; import net.joelinn.quartz.jobstore.AbstractRedisStorage; import net.joelinn.quartz.jobstore.RedisStorage; import net.joelinn.quartz.jobstore.RedisTriggerState; import org.hamcrest.MatcherAssert; import org.junit.Test; import org.quartz.*; import org.quartz.impl.calendar.WeeklyCalendar; import org.quartz.impl.matchers.GroupMatcher; import org.quartz.impl.triggers.CronTriggerImpl; import org.quartz.spi.OperableTrigger; import org.quartz.spi.SchedulerSignaler; import org.quartz.spi.TriggerFiredResult; import java.util.*; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.collection.IsMapContaining.hasKey; import static org.junit.Assert.*; import static org.mockito.Mockito.mock; /** * Joe Linn * 7/15/2014 */ public class StoreTriggerTest extends BaseTest{ @Test public void storeTrigger() throws Exception { CronTriggerImpl trigger = getCronTrigger(); trigger.getJobDataMap().put("foo", "bar"); jobStore.storeTrigger(trigger, false); final String triggerHashKey = schema.triggerHashKey(trigger.getKey()); Map<String, String> triggerMap = jedis.hgetAll(triggerHashKey); assertThat(triggerMap, hasKey("description")); assertEquals(trigger.getDescription(), triggerMap.get("description")); assertThat(triggerMap, hasKey("trigger_class")); assertEquals(trigger.getClass().getName(), triggerMap.get("trigger_class")); assertTrue("The trigger hash key is not a member of the triggers set.", jedis.sismember(schema.triggersSet(), triggerHashKey)); assertTrue("The trigger group set key is not a member of the trigger group set.", jedis.sismember(schema.triggerGroupsSet(), schema.triggerGroupSetKey(trigger.getKey()))); assertTrue(jedis.sismember(schema.triggerGroupSetKey(trigger.getKey()), triggerHashKey)); assertTrue(jedis.sismember(schema.jobTriggersSetKey(trigger.getJobKey()), triggerHashKey)); String triggerDataMapHashKey = schema.triggerDataMapHashKey(trigger.getKey()); MatcherAssert.assertThat(jedis.exists(triggerDataMapHashKey), equalTo(true)); MatcherAssert.assertThat(jedis.hget(triggerDataMapHashKey, "foo"), equalTo("bar")); } @Test(expected = JobPersistenceException.class) public void storeTriggerNoReplace() throws Exception { jobStore.storeTrigger(getCronTrigger(), false); jobStore.storeTrigger(getCronTrigger(), false); } @Test public void storeTriggerWithReplace() throws Exception { jobStore.storeTrigger(getCronTrigger(), true); jobStore.storeTrigger(getCronTrigger(), true); } @Test public void retrieveTrigger() throws Exception { CronTriggerImpl cronTrigger = getCronTrigger(); jobStore.storeJob(getJobDetail(), false); jobStore.storeTrigger(cronTrigger, false); OperableTrigger operableTrigger = jobStore.retrieveTrigger(cronTrigger.getKey()); assertThat(operableTrigger, instanceOf(CronTriggerImpl.class)); assertThat(operableTrigger.getFireInstanceId(), notNullValue()); CronTriggerImpl retrievedTrigger = (CronTriggerImpl) operableTrigger; assertEquals(cronTrigger.getCronExpression(), retrievedTrigger.getCronExpression()); assertEquals(cronTrigger.getTimeZone(), retrievedTrigger.getTimeZone()); assertEquals(cronTrigger.getStartTime(), retrievedTrigger.getStartTime()); } @Test public void removeTrigger() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "triggerGroup", job.getKey()); trigger1.getJobDataMap().put("foo", "bar"); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "triggerGroup", job.getKey()); jobStore.storeJob(job, false); jobStore.storeTrigger(trigger1, false); jobStore.storeTrigger(trigger2, false); jobStore.removeTrigger(trigger1.getKey()); // ensure that the trigger was removed, but the job was not assertThat(jobStore.retrieveTrigger(trigger1.getKey()), nullValue()); assertThat(jobStore.retrieveJob(job.getKey()), not(nullValue())); // remove the second trigger jobStore.removeTrigger(trigger2.getKey()); // ensure that both the trigger and job were removed assertThat(jobStore.retrieveTrigger(trigger2.getKey()), nullValue()); assertThat(jobStore.retrieveJob(job.getKey()), nullValue()); MatcherAssert.assertThat(jedis.exists(schema.triggerDataMapHashKey(trigger1.getKey())), equalTo(false)); } @Test public void getTriggersForJob() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "triggerGroup", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "triggerGroup", job.getKey()); jobStore.storeJob(job, false); jobStore.storeTrigger(trigger1, false); jobStore.storeTrigger(trigger2, false); List<OperableTrigger> triggers = jobStore.getTriggersForJob(job.getKey()); assertThat(triggers, hasSize(2)); } @Test public void getNumberOfTriggers() throws Exception { JobDetail job = getJobDetail(); jobStore.storeTrigger(getCronTrigger("trigger1", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger2", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger3", "group2", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger4", "group3", job.getKey()), false); int numberOfTriggers = jobStore.getNumberOfTriggers(); assertEquals(4, numberOfTriggers); } @Test public void getTriggerKeys() throws Exception { JobDetail job = getJobDetail(); jobStore.storeTrigger(getCronTrigger("trigger1", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger2", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger3", "group2", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger4", "group3", job.getKey()), false); Set<TriggerKey> triggerKeys = jobStore.getTriggerKeys(GroupMatcher.triggerGroupEquals("group1")); assertThat(triggerKeys, hasSize(2)); assertThat(triggerKeys, containsInAnyOrder(new TriggerKey("trigger2", "group1"), new TriggerKey("trigger1", "group1"))); jobStore.storeTrigger(getCronTrigger("trigger4", "triggergroup1", job.getKey()), false); triggerKeys = jobStore.getTriggerKeys(GroupMatcher.triggerGroupContains("group")); assertThat(triggerKeys, hasSize(5)); triggerKeys = jobStore.getTriggerKeys(GroupMatcher.triggerGroupEndsWith("1")); assertThat(triggerKeys, hasSize(3)); assertThat(triggerKeys, containsInAnyOrder(new TriggerKey("trigger2", "group1"), new TriggerKey("trigger1", "group1"), new TriggerKey("trigger4", "triggergroup1"))); triggerKeys = jobStore.getTriggerKeys(GroupMatcher.triggerGroupStartsWith("trig")); assertThat(triggerKeys, hasSize(1)); assertThat(triggerKeys, containsInAnyOrder(new TriggerKey("trigger4", "triggergroup1"))); } @Test public void getTriggerGroupNames() throws Exception { List<String> triggerGroupNames = jobStore.getTriggerGroupNames(); assertThat(triggerGroupNames, not(nullValue())); assertThat(triggerGroupNames, hasSize(0)); JobDetail job = getJobDetail(); jobStore.storeTrigger(getCronTrigger("trigger1", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger2", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger3", "group2", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger4", "group3", job.getKey()), false); triggerGroupNames = jobStore.getTriggerGroupNames(); assertThat(triggerGroupNames, hasSize(3)); assertThat(triggerGroupNames, containsInAnyOrder("group3", "group2", "group1")); } @Test public void getTriggerState() throws Exception { SchedulerSignaler signaler = mock(SchedulerSignaler.class); AbstractRedisStorage storageDriver = new RedisStorage(new RedisJobStoreSchema(), new ObjectMapper(), signaler, "scheduler1", 2000); // attempt to retrieve the state of a non-existent trigger Trigger.TriggerState state = jobStore.getTriggerState(new TriggerKey("foobar")); assertEquals(Trigger.TriggerState.NONE, state); // store a trigger JobDetail job = getJobDetail(); CronTriggerImpl cronTrigger = getCronTrigger("trigger1", "group1", job.getKey()); jobStore.storeTrigger(cronTrigger, false); // the newly-stored trigger's state should be NONE state = jobStore.getTriggerState(cronTrigger.getKey()); assertEquals(Trigger.TriggerState.NORMAL, state); // set the trigger's state storageDriver.setTriggerState(RedisTriggerState.WAITING, 500, schema.triggerHashKey(cronTrigger.getKey()), jedis); // the trigger's state should now be NORMAL state = jobStore.getTriggerState(cronTrigger.getKey()); assertEquals(Trigger.TriggerState.NORMAL, state); } @Test public void pauseTrigger() throws Exception { SchedulerSignaler signaler = mock(SchedulerSignaler.class); AbstractRedisStorage storageDriver = new RedisStorage(new RedisJobStoreSchema(), new ObjectMapper(), signaler, "scheduler1", 2000); // store a trigger JobDetail job = getJobDetail(); CronTriggerImpl cronTrigger = getCronTrigger("trigger1", "group1", job.getKey()); cronTrigger.setNextFireTime(new Date(System.currentTimeMillis())); jobStore.storeTrigger(cronTrigger, false); // set the trigger's state to COMPLETED storageDriver.setTriggerState(RedisTriggerState.COMPLETED, 500, schema.triggerHashKey(cronTrigger.getKey()), jedis); jobStore.pauseTrigger(cronTrigger.getKey()); // trigger's state should not have changed assertEquals(Trigger.TriggerState.COMPLETE, jobStore.getTriggerState(cronTrigger.getKey())); // set the trigger's state to BLOCKED storageDriver.setTriggerState(RedisTriggerState.BLOCKED, 500, schema.triggerHashKey(cronTrigger.getKey()), jedis); jobStore.pauseTrigger(cronTrigger.getKey()); // trigger's state should be PAUSED assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(cronTrigger.getKey())); // set the trigger's state to ACQUIRED storageDriver.setTriggerState(RedisTriggerState.ACQUIRED, 500, schema.triggerHashKey(cronTrigger.getKey()), jedis); jobStore.pauseTrigger(cronTrigger.getKey()); // trigger's state should be PAUSED assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(cronTrigger.getKey())); } @Test public void pauseTriggersEquals() throws Exception { // store triggers JobDetail job = getJobDetail(); jobStore.storeTrigger(getCronTrigger("trigger1", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger2", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger3", "group2", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger4", "group3", job.getKey()), false); // pause triggers Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupEquals("group1")); assertThat(pausedGroups, hasSize(1)); assertThat(pausedGroups, containsInAnyOrder("group1")); // ensure that the triggers were actually paused assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(new TriggerKey("trigger1", "group1"))); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(new TriggerKey("trigger2", "group1"))); } @Test public void pauseTriggersStartsWith() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger1", "group2", job.getKey()); CronTriggerImpl trigger3 = getCronTrigger("trigger1", "foogroup1", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2, trigger3); Collection<String> pausedTriggerGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupStartsWith("group")); assertThat(pausedTriggerGroups, hasSize(2)); assertThat(pausedTriggerGroups, containsInAnyOrder("group1", "group2")); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger1.getKey())); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger2.getKey())); assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger3.getKey())); } @Test public void pauseTriggersEndsWith() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger1", "group2", job.getKey()); CronTriggerImpl trigger3 = getCronTrigger("trigger1", "foogroup1", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2, trigger3); Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupEndsWith("oup1")); assertThat(pausedGroups, hasSize(2)); assertThat(pausedGroups, containsInAnyOrder("group1", "foogroup1")); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger1.getKey())); assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger2.getKey())); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger3.getKey())); } @Test public void resumeTrigger() throws Exception { // create and store a job and trigger JobDetail job = getJobDetail(); jobStore.storeJob(job, false); CronTriggerImpl trigger = getCronTrigger("trigger1", "group1", job.getKey()); trigger.computeFirstFireTime(new WeeklyCalendar()); jobStore.storeTrigger(trigger, false); // pause the trigger jobStore.pauseTrigger(trigger.getKey()); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger.getKey())); // resume the trigger jobStore.resumeTrigger(trigger.getKey()); // the trigger state should now be NORMAL assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger.getKey())); // attempt to resume the trigger, again jobStore.resumeTrigger(trigger.getKey()); // the trigger state should not have changed assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger.getKey())); } @Test public void resumeTriggersEquals() throws Exception { // store triggers and job JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "group1", job.getKey()); CronTriggerImpl trigger3 = getCronTrigger("trigger3", "group2", job.getKey()); CronTriggerImpl trigger4 = getCronTrigger("trigger4", "group3", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2, trigger3, trigger4); // pause triggers Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupEquals("group1")); assertThat(pausedGroups, hasSize(1)); assertThat(pausedGroups, containsInAnyOrder("group1")); // ensure that the triggers were actually paused assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(new TriggerKey("trigger1", "group1"))); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(new TriggerKey("trigger2", "group1"))); // resume triggers Collection<String> resumedGroups = jobStore.resumeTriggers(GroupMatcher.triggerGroupEquals("group1")); assertThat(resumedGroups, hasSize(1)); assertThat(resumedGroups, containsInAnyOrder("group1")); // ensure that the triggers were resumed assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(new TriggerKey("trigger1", "group1"))); assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(new TriggerKey("trigger2", "group1"))); } @Test public void resumeTriggersEndsWith() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "group1", job.getKey()); CronTriggerImpl trigger3 = getCronTrigger("trigger3", "group2", job.getKey()); CronTriggerImpl trigger4 = getCronTrigger("trigger4", "group3", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2, trigger3, trigger4); Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupEndsWith("1")); assertThat(pausedGroups, hasSize(1)); assertThat(pausedGroups, containsInAnyOrder("group1")); // ensure that the triggers were actually paused assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger1.getKey())); assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger2.getKey())); // resume triggers Collection<String> resumedGroups = jobStore.resumeTriggers(GroupMatcher.triggerGroupEndsWith("1")); assertThat(resumedGroups, hasSize(1)); assertThat(resumedGroups, containsInAnyOrder("group1")); // ensure that the triggers were actually resumed assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger1.getKey())); assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger2.getKey())); } @Test public void resumeTriggersStartsWith() throws Exception { JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "mygroup1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "group1", job.getKey()); CronTriggerImpl trigger3 = getCronTrigger("trigger3", "group2", job.getKey()); CronTriggerImpl trigger4 = getCronTrigger("trigger4", "group3", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2, trigger3, trigger4); Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupStartsWith("my")); assertThat(pausedGroups, hasSize(1)); assertThat(pausedGroups, containsInAnyOrder("mygroup1")); // ensure that the triggers were actually paused assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger1.getKey())); // resume triggers Collection<String> resumedGroups = jobStore.resumeTriggers(GroupMatcher.triggerGroupStartsWith("my")); assertThat(resumedGroups, hasSize(1)); assertThat(resumedGroups, containsInAnyOrder("mygroup1")); // ensure that the triggers were actually resumed assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger1.getKey())); } @Test public void getPausedTriggerGroups() throws Exception { // store triggers JobDetail job = getJobDetail(); jobStore.storeTrigger(getCronTrigger("trigger1", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger2", "group1", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger3", "group2", job.getKey()), false); jobStore.storeTrigger(getCronTrigger("trigger4", "group3", job.getKey()), false); // pause triggers Collection<String> pausedGroups = jobStore.pauseTriggers(GroupMatcher.triggerGroupEquals("group1")); pausedGroups.addAll(jobStore.pauseTriggers(GroupMatcher.triggerGroupEquals("group3"))); assertThat(pausedGroups, hasSize(2)); assertThat(pausedGroups, containsInAnyOrder("group3", "group1")); // retrieve paused trigger groups Set<String> pausedTriggerGroups = jobStore.getPausedTriggerGroups(); assertThat(pausedTriggerGroups, hasSize(2)); assertThat(pausedTriggerGroups, containsInAnyOrder("group1", "group3")); } @Test public void pauseAndResumeAll() throws Exception { // store some jobs with triggers Map<JobDetail, Set<? extends Trigger>> jobsAndTriggers = getJobsAndTriggers(2, 2, 2, 2); jobStore.storeJobsAndTriggers(jobsAndTriggers, false); // ensure that all triggers are in the NORMAL state for (Map.Entry<JobDetail, Set<? extends Trigger>> jobDetailSetEntry : jobsAndTriggers.entrySet()) { for (Trigger trigger : jobDetailSetEntry.getValue()) { assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger.getKey())); } } jobStore.pauseAll(); // ensure that all triggers were paused for (Map.Entry<JobDetail, Set<? extends Trigger>> jobDetailSetEntry : jobsAndTriggers.entrySet()) { for (Trigger trigger : jobDetailSetEntry.getValue()) { assertEquals(Trigger.TriggerState.PAUSED, jobStore.getTriggerState(trigger.getKey())); } } // resume all triggers jobStore.resumeAll(); // ensure that all triggers are again in the NORMAL state for (Map.Entry<JobDetail, Set<? extends Trigger>> jobDetailSetEntry : jobsAndTriggers.entrySet()) { for (Trigger trigger : jobDetailSetEntry.getValue()) { assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger.getKey())); } } } @Test @SuppressWarnings("unchecked") public void triggersFired() throws Exception { // store some jobs with triggers Map<JobDetail, Set<? extends Trigger>> jobsAndTriggers = getJobsAndTriggers(2, 2, 2, 2, "* * * * * ?"); // disallow concurrent execution for one of the jobs Map.Entry<JobDetail, Set<? extends Trigger>> firstEntry = jobsAndTriggers.entrySet().iterator().next(); JobDetail nonConcurrentKey = firstEntry.getKey().getJobBuilder().ofType(TestJobNonConcurrent.class).build(); Set<? extends Trigger> nonConcurrentTriggers = firstEntry.getValue(); jobsAndTriggers.remove(firstEntry.getKey()); jobsAndTriggers.put(nonConcurrentKey, nonConcurrentTriggers); jobStore.storeCalendar("testCalendar", new WeeklyCalendar(), false, true); jobStore.storeJobsAndTriggers(jobsAndTriggers, false); List<OperableTrigger> acquiredTriggers = jobStore.acquireNextTriggers(System.currentTimeMillis() - 1000, 500, 4000); assertThat(acquiredTriggers, hasSize(13)); int lockedTriggers = 0; // ensure that all triggers are in the NORMAL state and have been ACQUIRED for (Map.Entry<JobDetail, Set<? extends Trigger>> jobDetailSetEntry : jobsAndTriggers.entrySet()) { for (Trigger trigger : jobDetailSetEntry.getValue()) { assertEquals(Trigger.TriggerState.NORMAL, jobStore.getTriggerState(trigger.getKey())); String triggerHashKey = schema.triggerHashKey(trigger.getKey()); if (jobDetailSetEntry.getKey().isConcurrentExectionDisallowed()) { if (jedis.zscore(schema.triggerStateKey(RedisTriggerState.ACQUIRED), triggerHashKey) != null) { assertThat("acquired trigger should be locked", jedis.get(schema.triggerLockKey(schema.triggerKey(triggerHashKey))), notNullValue()); lockedTriggers++; } else { assertThat("non-acquired trigger should not be locked", jedis.get(schema.triggerLockKey(schema.triggerKey(triggerHashKey))), nullValue()); } } else { assertThat(jedis.zscore(schema.triggerStateKey(RedisTriggerState.ACQUIRED), triggerHashKey), not(nullValue())); } } } assertThat(lockedTriggers, equalTo(1)); Set<? extends OperableTrigger> triggers = (Set<? extends OperableTrigger>) new ArrayList<>(jobsAndTriggers.entrySet()).get(0).getValue(); List<TriggerFiredResult> triggerFiredResults = jobStore.triggersFired(new ArrayList<>(triggers)); assertThat("exactly one trigger fired for job with concurrent execution disallowed", triggerFiredResults, hasSize(1)); triggers = (Set<? extends OperableTrigger>) new ArrayList<>(jobsAndTriggers.entrySet()).get(1).getValue(); triggerFiredResults = jobStore.triggersFired(new ArrayList<>(triggers)); assertThat("all triggers fired for job with concurrent execution allowed", triggerFiredResults, hasSize(4)); } @Test public void replaceTrigger() throws Exception { assertFalse(jobStore.replaceTrigger(TriggerKey.triggerKey("foo", "bar"), getCronTrigger())); // store triggers and job JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "group1", job.getKey()); storeJobAndTriggers(job, trigger1, trigger2); CronTriggerImpl newTrigger = getCronTrigger("newTrigger", "group1", job.getKey()); assertTrue(jobStore.replaceTrigger(trigger1.getKey(), newTrigger)); // ensure that the proper trigger was replaced assertThat(jobStore.retrieveTrigger(trigger1.getKey()), nullValue()); List<OperableTrigger> jobTriggers = jobStore.getTriggersForJob(job.getKey()); assertThat(jobTriggers, hasSize(2)); List<TriggerKey> jobTriggerKeys = new ArrayList<>(jobTriggers.size()); for (OperableTrigger jobTrigger : jobTriggers) { jobTriggerKeys.add(jobTrigger.getKey()); } assertThat(jobTriggerKeys, containsInAnyOrder(trigger2.getKey(), newTrigger.getKey())); } @Test public void replaceTriggerSingleTriggerNonDurableJob() throws Exception { // store trigger and job JobDetail job = getJobDetail(); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); storeJobAndTriggers(job, trigger1); CronTriggerImpl newTrigger = getCronTrigger("newTrigger", "group1", job.getKey()); assertTrue(jobStore.replaceTrigger(trigger1.getKey(), newTrigger)); // ensure that the proper trigger was replaced assertThat(jobStore.retrieveTrigger(trigger1.getKey()), nullValue()); List<OperableTrigger> jobTriggers = jobStore.getTriggersForJob(job.getKey()); assertThat(jobTriggers, hasSize(1)); // ensure that the job still exists assertThat(jobStore.retrieveJob(job.getKey()), not(nullValue())); } @Test(expected = JobPersistenceException.class) public void replaceTriggerWithDifferentJob() throws Exception { // store triggers and job JobDetail job = getJobDetail(); jobStore.storeJob(job, false); CronTriggerImpl trigger1 = getCronTrigger("trigger1", "group1", job.getKey()); jobStore.storeTrigger(trigger1, false); CronTriggerImpl trigger2 = getCronTrigger("trigger2", "group1", job.getKey()); jobStore.storeTrigger(trigger2, false); CronTriggerImpl newTrigger = getCronTrigger("newTrigger", "group1", JobKey.jobKey("foo", "bar")); jobStore.replaceTrigger(trigger1.getKey(), newTrigger); } }