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