mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
ACE-403: As an administrator I want to be able to defer the start of cron based jobs
- Added System Integration Test to enforce that all CronTriggerBeans have a specified delay. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@63443 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -436,5 +436,6 @@ public class Repository01TestSuite extends TestSuite
|
|||||||
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.ApplicationContextInitTest.class));
|
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.ApplicationContextInitTest.class));
|
||||||
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.TemporaryNodesTest.class));
|
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.TemporaryNodesTest.class));
|
||||||
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.TemporarySitesTest.class));
|
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.test.junitrules.TemporarySitesTest.class));
|
||||||
|
suite.addTest(new JUnit4TestAdapter(org.alfresco.util.CronTriggerBeanTest.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.alfresco.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class tests that the CronTriggerBean correctly delays jobs when
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @author Ahmed Owian
|
||||||
|
*/
|
||||||
|
public class CronTriggerBeanSystemTest
|
||||||
|
{
|
||||||
|
private ClassPathXmlApplicationContext context;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
this.context = (ClassPathXmlApplicationContext) ApplicationContextHelper
|
||||||
|
.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All CronTriggerBean classes should be configured with a delay
|
||||||
|
* to allow the server to start before the jobs run.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAllCronTriggerBeansHaveDelay()
|
||||||
|
{
|
||||||
|
Map<String, CronTriggerBean> beans = this.context
|
||||||
|
.getBeansOfType(org.alfresco.util.CronTriggerBean.class);
|
||||||
|
assertFalse(beans.isEmpty());
|
||||||
|
List<String> undelayedJobs = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, CronTriggerBean> entry : beans.entrySet())
|
||||||
|
{
|
||||||
|
CronTriggerBean bean = entry.getValue();
|
||||||
|
if (bean.getStartDelay() == 0)
|
||||||
|
{
|
||||||
|
undelayedJobs.add(entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("Undelayed CronTriggerBeans: " + undelayedJobs, undelayedJobs.isEmpty());
|
||||||
|
}
|
||||||
|
}
|
@@ -1,3 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Alfresco Software Limited.
|
||||||
|
*
|
||||||
|
* This file is part of Alfresco
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
package org.alfresco.util;
|
package org.alfresco.util;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
@@ -16,40 +34,64 @@ import org.quartz.impl.StdSchedulerFactory;
|
|||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
|
|
||||||
public class CronTriggerBeanTest {
|
|
||||||
// One second - an arbitrarily small amount of time to allow for the scheduler to start the jobs
|
/**
|
||||||
|
* This class tests that the CronTriggerBean correctly delays jobs when specified.
|
||||||
|
* @author Ahmed Owian
|
||||||
|
*/
|
||||||
|
public class CronTriggerBeanTest
|
||||||
|
{
|
||||||
|
// One second - an arbitrarily small amount of time to allow for the
|
||||||
|
// scheduler to start the jobs
|
||||||
final long PRECISION_LEEWAY = 1000L;
|
final long PRECISION_LEEWAY = 1000L;
|
||||||
|
|
||||||
final long INTERVAL = 1000L;// One run every second
|
final long INTERVAL = 1000L;// One run every second
|
||||||
|
|
||||||
private ClassPathXmlApplicationContext context;
|
private ClassPathXmlApplicationContext context;
|
||||||
|
|
||||||
private Scheduler scheduler;
|
private Scheduler scheduler;
|
||||||
|
|
||||||
private static Map<String, ArrayList<Long>> dummyJobRuns;
|
private static Map<String, ArrayList<Long>> dummyJobRuns;
|
||||||
|
|
||||||
private static Object lockToken = new Object();
|
private static Object lockToken = new Object();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
dummyJobRuns = new HashMap<String, ArrayList<Long>>();
|
dummyJobRuns = new HashMap<String, ArrayList<Long>>();
|
||||||
this.context = null;
|
this.context = null;
|
||||||
this.scheduler = null;
|
this.scheduler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception
|
||||||
try {
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
this.scheduler.shutdown();
|
this.scheduler.shutdown();
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
context.close();
|
context.close();
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that jobs that are coded without a delay run without delay.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCodedCronTriggerBean() throws Exception {
|
public void testCodedCronTriggerBean() throws Exception
|
||||||
|
{
|
||||||
final String JOB_NAME = "codedCronJob";
|
final String JOB_NAME = "codedCronJob";
|
||||||
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
||||||
assertEquals(0, jobRuns.size());
|
assertEquals(0, jobRuns.size());
|
||||||
@@ -69,25 +111,36 @@ public class CronTriggerBeanTest {
|
|||||||
this.assertJobStopsAfterShutdown(jobRuns);
|
this.assertJobStopsAfterShutdown(jobRuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that jobs that are configured without a delay run without delay.
|
||||||
|
* @throws BeansException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testConfiguredCronTriggerBean() throws BeansException, Exception {
|
public void testConfiguredCronTriggerBean() throws BeansException, Exception
|
||||||
|
{
|
||||||
final String JOB_NAME = "configuredCronJob";
|
final String JOB_NAME = "configuredCronJob";
|
||||||
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
||||||
assertEquals(0, jobRuns.size());
|
assertEquals(0, jobRuns.size());
|
||||||
context = new ClassPathXmlApplicationContext(
|
context = new ClassPathXmlApplicationContext("alfresco/scheduler-core-context.xml",
|
||||||
"alfresco/scheduler-core-context.xml",
|
|
||||||
"org/alfresco/util/test-scheduled-jobs-context.xml");
|
"org/alfresco/util/test-scheduled-jobs-context.xml");
|
||||||
CronTriggerBean ctBean = context.getBean("cronTriggerBean", CronTriggerBean.class);
|
CronTriggerBean ctBean = context.getBean("cronTriggerBean", CronTriggerBean.class);
|
||||||
scheduler = ctBean.getScheduler();
|
scheduler = ctBean.getScheduler();
|
||||||
scheduler.start();
|
scheduler.start();
|
||||||
|
|
||||||
assertJobRunsAfterInterval(jobRuns);
|
assertJobRunsAfterInterval(jobRuns);
|
||||||
context.close(); // When the context closes, the scheduler should close, thereby stopping the job
|
context.close(); // When the context closes, the scheduler should close,
|
||||||
|
// thereby stopping the job
|
||||||
assertJobStopsAfterShutdown(jobRuns);
|
assertJobStopsAfterShutdown(jobRuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that jobs that are coded with a delay run after the delay.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCodedDelayedCronTriggerBean() throws Exception {
|
public void testCodedDelayedCronTriggerBean() throws Exception
|
||||||
|
{
|
||||||
final String JOB_NAME = "codedDelayedCronJob";
|
final String JOB_NAME = "codedDelayedCronJob";
|
||||||
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
||||||
assertEquals(0, jobRuns.size());
|
assertEquals(0, jobRuns.size());
|
||||||
@@ -103,7 +156,8 @@ public class CronTriggerBeanTest {
|
|||||||
ctBean.setStartDelay(START_DELAY);
|
ctBean.setStartDelay(START_DELAY);
|
||||||
|
|
||||||
final long PRE_SCHEDULING = System.currentTimeMillis();
|
final long PRE_SCHEDULING = System.currentTimeMillis();
|
||||||
ctBean.afterPropertiesSet(); // This is when the trigger is actually scheduled
|
ctBean.afterPropertiesSet(); // This is when the trigger is actually
|
||||||
|
// scheduled
|
||||||
long startTime = ctBean.getTrigger().getStartTime().getTime();
|
long startTime = ctBean.getTrigger().getStartTime().getTime();
|
||||||
assertTrue("The startTime should be the time when the trigger is scheduled plus the START_DELAY.",
|
assertTrue("The startTime should be the time when the trigger is scheduled plus the START_DELAY.",
|
||||||
startTime - PRE_SCHEDULING - START_DELAY <= PRECISION_LEEWAY);
|
startTime - PRE_SCHEDULING - START_DELAY <= PRECISION_LEEWAY);
|
||||||
@@ -116,16 +170,22 @@ public class CronTriggerBeanTest {
|
|||||||
assertJobStopsAfterShutdown(jobRuns);
|
assertJobStopsAfterShutdown(jobRuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that jobs that are configured with a delay run after the delay.
|
||||||
|
* @throws BeansException
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testConfiguredDelayedCronTriggerBean() throws BeansException, Exception {
|
public void testConfiguredDelayedCronTriggerBean() throws BeansException, Exception
|
||||||
|
{
|
||||||
final String JOB_NAME = "configuredDelayedCronJob";
|
final String JOB_NAME = "configuredDelayedCronJob";
|
||||||
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
List<Long> jobRuns = this.getRunList(JOB_NAME);
|
||||||
assertEquals(0, jobRuns.size());
|
assertEquals(0, jobRuns.size());
|
||||||
|
|
||||||
// Captures the system time before the Spring context is initialized and the triggers are scheduled
|
// Captures the system time before the Spring context is initialized and
|
||||||
|
// the triggers are scheduled
|
||||||
final long PRE_INITIALIZATION = System.currentTimeMillis();
|
final long PRE_INITIALIZATION = System.currentTimeMillis();
|
||||||
context = new ClassPathXmlApplicationContext(
|
context = new ClassPathXmlApplicationContext("alfresco/scheduler-core-context.xml",
|
||||||
"alfresco/scheduler-core-context.xml",
|
|
||||||
"org/alfresco/util/test-scheduled-jobs-context.xml");
|
"org/alfresco/util/test-scheduled-jobs-context.xml");
|
||||||
CronTriggerBean ctBean = context.getBean("cronTriggerBeanDelayed", CronTriggerBean.class);
|
CronTriggerBean ctBean = context.getBean("cronTriggerBeanDelayed", CronTriggerBean.class);
|
||||||
final long START_DELAY = ctBean.getStartDelay();
|
final long START_DELAY = ctBean.getStartDelay();
|
||||||
@@ -138,13 +198,15 @@ public class CronTriggerBeanTest {
|
|||||||
scheduler.start();
|
scheduler.start();
|
||||||
assertJobDoesNotRunBeforeStartTime(jobRuns, startTime);
|
assertJobDoesNotRunBeforeStartTime(jobRuns, startTime);
|
||||||
assertJobRunsAfterInterval(jobRuns);
|
assertJobRunsAfterInterval(jobRuns);
|
||||||
context.close(); // When the context closes, the scheduler should close, thereby stopping the job
|
context.close(); // When the context closes, the scheduler should close,
|
||||||
|
// thereby stopping the job
|
||||||
assertJobStopsAfterShutdown(jobRuns);
|
assertJobStopsAfterShutdown(jobRuns);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertJobStopsAfterShutdown(List<Long> jobRuns) throws InterruptedException
|
private void assertJobStopsAfterShutdown(List<Long> jobRuns) throws InterruptedException
|
||||||
{
|
{
|
||||||
// Gives the job one final interval to stop, but after that, there should be no more runs
|
// Gives the job one final interval to stop, but after that, there
|
||||||
|
// should be no more runs
|
||||||
Thread.sleep(INTERVAL);
|
Thread.sleep(INTERVAL);
|
||||||
int runs = jobRuns.size();
|
int runs = jobRuns.size();
|
||||||
Thread.sleep(INTERVAL);
|
Thread.sleep(INTERVAL);
|
||||||
@@ -167,20 +229,24 @@ public class CronTriggerBeanTest {
|
|||||||
synchronized (lockToken)
|
synchronized (lockToken)
|
||||||
{
|
{
|
||||||
// It should not run before the start time
|
// It should not run before the start time
|
||||||
while (System.currentTimeMillis() < startTime) {
|
while (System.currentTimeMillis() < startTime)
|
||||||
|
{
|
||||||
assertEquals(0, jobRuns.size());
|
assertEquals(0, jobRuns.size());
|
||||||
Thread.sleep(20); // Sleeps so as to not take up all the CPU
|
Thread.sleep(20); // Sleeps so as to not take up all the CPU
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DummyJob implements Job {
|
public static class DummyJob implements Job
|
||||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
{
|
||||||
|
public void execute(JobExecutionContext context) throws JobExecutionException
|
||||||
|
{
|
||||||
synchronized (lockToken)
|
synchronized (lockToken)
|
||||||
{
|
{
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
ArrayList<Long> runs = dummyJobRuns.get(context.getJobDetail().getName());
|
ArrayList<Long> runs = dummyJobRuns.get(context.getJobDetail().getName());
|
||||||
if (runs == null) {
|
if (runs == null)
|
||||||
|
{
|
||||||
runs = new ArrayList<Long>();
|
runs = new ArrayList<Long>();
|
||||||
dummyJobRuns.put(context.getJobDetail().getName(), runs);
|
dummyJobRuns.put(context.getJobDetail().getName(), runs);
|
||||||
}
|
}
|
||||||
@@ -189,9 +255,11 @@ public class CronTriggerBeanTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Long> getRunList(String jobName) {
|
private List<Long> getRunList(String jobName)
|
||||||
|
{
|
||||||
ArrayList<Long> runs = dummyJobRuns.get(jobName);
|
ArrayList<Long> runs = dummyJobRuns.get(jobName);
|
||||||
if (runs == null) {
|
if (runs == null)
|
||||||
|
{
|
||||||
runs = new ArrayList<Long>();
|
runs = new ArrayList<Long>();
|
||||||
dummyJobRuns.put(jobName, runs);
|
dummyJobRuns.put(jobName, runs);
|
||||||
}
|
}
|
||||||
|
@@ -77,6 +77,9 @@
|
|||||||
<property name="cronExpression">
|
<property name="cronExpression">
|
||||||
<value>0 * * * * ?</value>
|
<value>0 * * * * ?</value>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="startDelayMinutes">
|
||||||
|
<value>${system.cronJob.startDelayMinutes}</value>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- Job to scan for expired content in website staging areas -->
|
<!-- Job to scan for expired content in website staging areas -->
|
||||||
@@ -102,6 +105,9 @@
|
|||||||
<property name="cronExpression">
|
<property name="cronExpression">
|
||||||
<value>0 30 3 * * ?</value>
|
<value>0 30 3 * * ?</value>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="startDelayMinutes">
|
||||||
|
<value>${system.cronJob.startDelayMinutes}</value>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- There is a job available to purge old deploymentattempt nodes -->
|
<!-- There is a job available to purge old deploymentattempt nodes -->
|
||||||
|
Reference in New Issue
Block a user