1 package com.atlassian.sal.core.scheduling;
2
3 import com.atlassian.sal.api.scheduling.PluginJob;
4 import com.atlassian.scheduler.JobRunner;
5 import com.atlassian.scheduler.JobRunnerRequest;
6 import com.atlassian.scheduler.JobRunnerResponse;
7 import com.atlassian.scheduler.SchedulerService;
8 import com.atlassian.scheduler.SchedulerServiceException;
9 import com.atlassian.scheduler.config.JobConfig;
10 import com.atlassian.scheduler.config.JobId;
11 import com.atlassian.scheduler.config.RunMode;
12 import com.atlassian.scheduler.config.Schedule;
13 import com.atlassian.scheduler.status.RunOutcome;
14 import org.junit.After;
15 import org.junit.Before;
16 import org.junit.Test;
17 import org.junit.runner.RunWith;
18 import org.mockito.ArgumentCaptor;
19 import org.mockito.Captor;
20 import org.mockito.Mock;
21 import org.mockito.runners.MockitoJUnitRunner;
22
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.Map;
26
27 import static com.atlassian.sal.core.scheduling.DefaultPluginScheduler.JOB_RUNNER_KEY;
28 import static com.atlassian.sal.core.scheduling.DefaultPluginScheduler.toJobId;
29 import static com.atlassian.sal.core.util.Assert.notNull;
30 import static org.hamcrest.Matchers.containsString;
31 import static org.hamcrest.Matchers.is;
32 import static org.junit.Assert.assertThat;
33 import static org.junit.Assert.fail;
34 import static org.mockito.Matchers.eq;
35 import static org.mockito.Matchers.same;
36 import static org.mockito.Mockito.mock;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.verifyZeroInteractions;
39 import static org.mockito.Mockito.when;
40
41 @RunWith(MockitoJUnitRunner.class)
42 public class DefaultPluginSchedulerTest {
43
44
45 private static final ThreadLocal<JobChecker> CALLBACK = new ThreadLocal<JobChecker>() {
46 @Override
47 protected JobChecker initialValue() {
48 return mock(JobChecker.class);
49 }
50 };
51
52 @Mock
53 private SchedulerService schedulerService;
54 @Captor
55 private ArgumentCaptor<JobRunner> runnerCaptor;
56
57 private DefaultPluginScheduler pluginScheduler;
58
59 @Before
60 public void setUp() {
61 pluginScheduler = new DefaultPluginScheduler(schedulerService);
62 pluginScheduler.afterPropertiesSet();
63
64 verify(schedulerService).registerJobRunner(eq(JOB_RUNNER_KEY), runnerCaptor.capture());
65 }
66
67 @After
68 public void tearDown() {
69 CALLBACK.remove();
70 }
71
72
73 @Test
74 public void testUnregisterOnDestroy() {
75 pluginScheduler.destroy();
76
77 verify(schedulerService).unregisterJobRunner(eq(JOB_RUNNER_KEY));
78 }
79
80 @Test
81 public void testSchedule() throws SchedulerServiceException {
82 final String jobName = "testjob";
83 final JobId jobId = toJobId(jobName);
84 final Map<String, Object> jobMap = Collections.<String, Object>singletonMap("a", "b");
85 final Date jobStartTime = new Date();
86 final int repeatInterval = 60000;
87
88
89 pluginScheduler.scheduleJob(jobName, TestPluginJob.class, jobMap, jobStartTime, repeatInterval);
90
91 verify(schedulerService).scheduleJob(jobId, JobConfig.forJobRunnerKey(JOB_RUNNER_KEY)
92 .withRunMode(RunMode.RUN_LOCALLY)
93 .withSchedule(Schedule.forInterval(repeatInterval, jobStartTime)));
94
95
96 final JobRunnerRequest request = mock(JobRunnerRequest.class);
97 when(request.getJobId()).thenReturn(jobId);
98
99 runnerCaptor.getValue().runJob(request);
100 verify(CALLBACK.get()).executedWith(same(jobMap));
101 }
102
103 @Test
104 public void testUnschedule() throws Exception {
105 final String jobName = "testjob";
106 final JobId jobId = toJobId(jobName);
107 final Map<String, Object> jobMap = Collections.<String, Object>singletonMap("a", "b");
108 final Date jobStartTime = new Date();
109 final int repeatInterval = 60000;
110
111 pluginScheduler.scheduleJob(jobName, TestPluginJob.class, jobMap, jobStartTime, repeatInterval);
112
113
114 pluginScheduler.unscheduleJob(jobName);
115
116 final JobRunnerRequest request = mock(JobRunnerRequest.class);
117 when(request.getJobId()).thenReturn(jobId);
118
119
120 final JobRunnerResponse response = notNull(runnerCaptor.getValue().runJob(request), "null response");
121 assertThat(response.getRunOutcome(), is(RunOutcome.ABORTED));
122 assertThat(response.getMessage(), is("Job descriptor not found"));
123 verifyZeroInteractions(CALLBACK.get());
124 }
125
126 @Test
127 public void testUnscheduleInexisting() {
128 final String jobName = "testjob";
129 final JobId jobId = toJobId(jobName);
130
131 try {
132 pluginScheduler.unscheduleJob(jobName);
133 fail("Expected an IllegalArgumentException");
134 } catch (IllegalArgumentException iae) {
135 assertThat(iae.getMessage(), containsString(jobName));
136 }
137
138
139 verify(schedulerService).unscheduleJob(jobId);
140 }
141
142 static class TestPluginJob implements PluginJob {
143 @Override
144 public void execute(Map<String, Object> jobDataMap) {
145 CALLBACK.get().executedWith(jobDataMap);
146 }
147 }
148
149 static interface JobChecker {
150 void executedWith(Map<String, Object> jobDataMap);
151 }
152 }