/* * Copyright 2002-2013 the original author or authors. * * 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.springframework.scheduling.concurrent; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import org.junit.Ignore; import org.junit.Test; import org.springframework.core.task.NoOpRunnable; import org.springframework.tests.Assume; import org.springframework.tests.TestGroup; import static org.junit.Assert.*; import static org.mockito.BDDMockito.*; /** * @author Rick Evans * @author Juergen Hoeller */ public class ScheduledExecutorFactoryBeanTests { @Test public void testThrowsExceptionIfPoolSizeIsLessThanZero() throws Exception { try { ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setPoolSize(-1); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new NoOpScheduledExecutorTask() }); factory.afterPropertiesSet(); fail("Pool size less than zero"); } catch (IllegalArgumentException expected) { } } @Test @SuppressWarnings("serial") public void testShutdownNowIsPropagatedToTheExecutorOnDestroy() throws Exception { final ScheduledExecutorService executor = mock(ScheduledExecutorService.class); ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { @Override protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { return executor; } }; factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new NoOpScheduledExecutorTask() }); factory.afterPropertiesSet(); factory.destroy(); verify(executor).shutdownNow(); } @Test @SuppressWarnings("serial") public void testShutdownIsPropagatedToTheExecutorOnDestroy() throws Exception { final ScheduledExecutorService executor = mock(ScheduledExecutorService.class); ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { @Override protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { return executor; } }; factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new NoOpScheduledExecutorTask() }); factory.setWaitForTasksToCompleteOnShutdown(true); factory.afterPropertiesSet(); factory.destroy(); verify(executor).shutdown(); } @Test public void testOneTimeExecutionIsSetUpAndFiresCorrectly() throws Exception { Assume.group(TestGroup.PERFORMANCE); Runnable runnable = mock(Runnable.class); ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new ScheduledExecutorTask(runnable) }); factory.afterPropertiesSet(); pauseToLetTaskStart(1); factory.destroy(); verify(runnable).run(); } @Test public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { Assume.group(TestGroup.PERFORMANCE); Runnable runnable = mock(Runnable.class); ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); task.setPeriod(500); task.setFixedRate(true); ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); factory.afterPropertiesSet(); pauseToLetTaskStart(2); factory.destroy(); verify(runnable, atLeast(2)).run(); } @Test public void testFixedRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { Assume.group(TestGroup.PERFORMANCE); Runnable runnable = mock(Runnable.class); willThrow(new IllegalStateException()).given(runnable).run(); ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); task.setPeriod(500); task.setFixedRate(true); ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{task}); factory.setContinueScheduledExecutionAfterException(true); factory.afterPropertiesSet(); pauseToLetTaskStart(2); factory.destroy(); verify(runnable, atLeast(2)).run(); } @Ignore @Test public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectly() throws Exception { Runnable runnable = mock(Runnable.class); ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); task.setPeriod(500); task.setDelay(3000); // nice long wait... ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); factory.afterPropertiesSet(); pauseToLetTaskStart(1); // invoke destroy before tasks have even been scheduled... factory.destroy(); // Mock must never have been called verify(runnable, never()).run(); } @Ignore @Test public void testWithInitialDelayRepeatedExecutionIsSetUpAndFiresCorrectlyAfterException() throws Exception { Runnable runnable = mock(Runnable.class); willThrow(new IllegalStateException()).given(runnable).run(); ScheduledExecutorTask task = new ScheduledExecutorTask(runnable); task.setPeriod(500); task.setDelay(3000); // nice long wait... ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); factory.setScheduledExecutorTasks(new ScheduledExecutorTask[] {task}); factory.setContinueScheduledExecutionAfterException(true); factory.afterPropertiesSet(); pauseToLetTaskStart(1); // invoke destroy before tasks have even been scheduled... factory.destroy(); // Mock must never have been called verify(runnable, never()).run(); } @Test @SuppressWarnings("serial") public void testSettingThreadFactoryToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { @Override protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { assertNotNull("Bah; the setThreadFactory(..) method must use a default ThreadFactory if a null arg is passed in."); return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); } }; factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new NoOpScheduledExecutorTask() }); factory.setThreadFactory(null); // the null must not propagate factory.afterPropertiesSet(); factory.destroy(); } @Test @SuppressWarnings("serial") public void testSettingRejectedExecutionHandlerToNullForcesUseOfDefaultButIsOtherwiseCool() throws Exception { ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean() { @Override protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { assertNotNull("Bah; the setRejectedExecutionHandler(..) method must use a default RejectedExecutionHandler if a null arg is passed in."); return super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler); } }; factory.setScheduledExecutorTasks(new ScheduledExecutorTask[]{ new NoOpScheduledExecutorTask() }); factory.setRejectedExecutionHandler(null); // the null must not propagate factory.afterPropertiesSet(); factory.destroy(); } @Test public void testObjectTypeReportsCorrectType() throws Exception { ScheduledExecutorFactoryBean factory = new ScheduledExecutorFactoryBean(); assertEquals(ScheduledExecutorService.class, factory.getObjectType()); } private static void pauseToLetTaskStart(int seconds) { try { Thread.sleep(seconds * 1000); } catch (InterruptedException ignored) { } } private static class NoOpScheduledExecutorTask extends ScheduledExecutorTask { public NoOpScheduledExecutorTask() { super(new NoOpRunnable()); } } }