/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.common.impl.scheduler; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import java.util.Calendar; import java.util.Date; /** * Test case for the {@link CronJobTrigger}. */ public class CronJobTriggerTest { /** Trigger firing several times per minute */ protected CronJobTrigger minuteTrigger = null; /** Cron expression for the minutes trigger */ protected String minutesExpression = "1,27,34 * * * *"; /** Minutes that the trigger will fire */ protected int[] minutes = new int[] { 1, 27, 34 }; /** Trigger firing several times per hour */ protected CronJobTrigger hourTrigger = null; /** Cron expression for the hours trigger */ protected String hoursExpression = "0 4,23 * * *"; /** Hours that the trigger will fire */ protected int[] hours = new int[] { 4, 23 }; /** Trigger firing several times per month */ protected CronJobTrigger dayOfMonthTrigger = null; /** Cron expression for the day of month trigger */ protected String dayOfMonthExpression = "0 0 2,12,26 * *"; /** Days that the trigger will fire */ protected int[] daysOfMonth = new int[] { 2, 12, 26 }; /** Trigger firing several times per year */ protected CronJobTrigger monthTrigger = null; /** Cron expression for the day of month trigger */ protected String monthExpression = "0 0 1 1,jun,11 *"; /** Months that the trigger will fire */ protected int[] months = new int[] { 1, 6, 11 }; /** Trigger firing several times per week */ protected CronJobTrigger dayOfWeekTrigger = null; /** Cron expression for the day of week trigger */ protected String dayOfWeekExpression = "0 0 * 1 mon,5"; /** Days that the trigger will fire */ protected int[] daysOfWeek = new int[] { 1, 5 }; /** Today */ protected Date now = null; /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception { minuteTrigger = new CronJobTrigger(minutesExpression); hourTrigger = new CronJobTrigger(hoursExpression); dayOfMonthTrigger = new CronJobTrigger(dayOfMonthExpression); monthTrigger = new CronJobTrigger(monthExpression); dayOfWeekTrigger = new CronJobTrigger(dayOfWeekExpression); now = new Date(); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#CronJobTrigger()} * . */ @Test public void testCronJobTrigger() { Date now = new Date(); CronJobTrigger emptyTrigger = new CronJobTrigger(); Calendar c = Calendar.getInstance(); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); c.add(Calendar.MINUTE, 1); Date triggerDate = c.getTime(); assertEquals(triggerDate, emptyTrigger.getNextExecutionAfter(now)); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getNextExecutionAfter(java.util.Date)} * . */ @Test public void testGetNextExecutionAfter() { Calendar c = null; Date expectedFireDate = null; // minute expectedFireDate = rollUp(Calendar.getInstance(), Calendar.MINUTE, minutes); assertEquals(expectedFireDate, minuteTrigger.getNextExecutionAfter(now)); // hour c = Calendar.getInstance(); c.set(Calendar.MINUTE, 0); expectedFireDate = rollUp(c, Calendar.HOUR_OF_DAY, hours); assertEquals(expectedFireDate, hourTrigger.getNextExecutionAfter(now)); // day of month c = Calendar.getInstance(); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); expectedFireDate = rollUp(c, Calendar.DAY_OF_MONTH, daysOfMonth); assertEquals(expectedFireDate, dayOfMonthTrigger.getNextExecutionAfter(now)); // month c = Calendar.getInstance(); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.DAY_OF_MONTH, 1); expectedFireDate = rollUp(c, Calendar.MONTH, months); assertEquals(expectedFireDate, monthTrigger.getNextExecutionAfter(now)); // day of week c = Calendar.getInstance(); c.set(Calendar.MINUTE, 0); c.set(Calendar.HOUR_OF_DAY, 0); c.set(Calendar.DAY_OF_MONTH, 1); // Move to the next January (or stay if we are already in January) if (c.get(Calendar.MONTH) != Calendar.JANUARY) { while (c.get(Calendar.MONTH) != Calendar.JANUARY) { while (c.get(Calendar.MONTH) != Calendar.JANUARY) { c.add(Calendar.MONTH, 1); } c.set(Calendar.DATE, 1); expectedFireDate = rollUp(c, Calendar.DAY_OF_WEEK, daysOfWeek); } } else { expectedFireDate = rollUp(c, Calendar.DAY_OF_WEEK, daysOfWeek); } // Are we bleeding over into the next year? while (c.get(Calendar.MONTH) != Calendar.JANUARY) { expectedFireDate = rollUp(c, Calendar.DAY_OF_WEEK, daysOfWeek); if (c.get(Calendar.MONTH) > 1) { c.roll(Calendar.YEAR, 1); c.set(Calendar.MONTH, 1); c.set(Calendar.DAY_OF_MONTH, 1); expectedFireDate = rollUp(c, Calendar.DAY_OF_WEEK, daysOfWeek); } } assertEquals(expectedFireDate, dayOfWeekTrigger.getNextExecutionAfter(now)); } /** * Moves the calendar into the future by increasing the given field until it * reaches the next matching value. * * @param c * the calendar * @param field * the field index * @param fieldValues * possible field values * @return the calendars new date */ private Date rollUp(Calendar c, int field, int[] fieldValues) { boolean matches = false; // Align milliseconds and seconds c.setFirstDayOfWeek(Calendar.SUNDAY); c.set(Calendar.MILLISECOND, 0); c.set(Calendar.SECOND, 0); // Make sure we move past the current time Calendar now = Calendar.getInstance(); int offset = 0; switch (field) { case Calendar.MONTH: offset = 1; break; case Calendar.DAY_OF_WEEK: offset = -1; break; default: offset = 0; } if (field != Calendar.MONTH) { while (!c.after(now)) { c.add(field, 1); } } // see if we are already good for (int v : fieldValues) { int calendarValue = c.get(field) + offset; if (calendarValue == v) { return c.getTime(); } } while (!matches) { int calendarValue = c.get(field) + offset; for (int v : fieldValues) { if (calendarValue == v) { matches = true; break; } } if (!matches) c.add(field, 1); } return c.getTime(); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getMinutes()} * . */ @Test public void testGetMinutes() { assertEquals(minutes.length, minuteTrigger.getMinutes().length); assertEquals(1, hourTrigger.getMinutes().length); assertEquals(1, dayOfMonthTrigger.getMinutes().length); assertEquals(1, monthTrigger.getMinutes().length); assertEquals(1, dayOfWeekTrigger.getMinutes().length); // Additional testing for minutes trigger for (int i = 0; i < minutes.length; i++) assertEquals(minutes[i], minuteTrigger.getMinutes()[i]); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getHours()} * . */ @Test public void testGetHours() { assertEquals(24, minuteTrigger.getHours().length); assertEquals(2, hourTrigger.getHours().length); assertEquals(1, dayOfMonthTrigger.getHours().length); assertEquals(1, monthTrigger.getHours().length); assertEquals(1, dayOfWeekTrigger.getHours().length); // Additional testing for hours trigger for (int i = 0; i < hours.length; i++) assertEquals(hours[i], hourTrigger.getHours()[i]); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getDaysOfMonth()} * . */ @Test public void testGetDaysOfMonth() { assertEquals(31, minuteTrigger.getDaysOfMonth().length); assertEquals(31, hourTrigger.getDaysOfMonth().length); assertEquals(3, dayOfMonthTrigger.getDaysOfMonth().length); assertEquals(1, monthTrigger.getDaysOfMonth().length); assertEquals(31, dayOfWeekTrigger.getDaysOfMonth().length); // Additional testing for the day of month trigger for (int i = 0; i < daysOfMonth.length; i++) assertEquals(daysOfMonth[i], dayOfMonthTrigger.getDaysOfMonth()[i]); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getMonths()} * . */ @Test public void testGetMonths() { assertEquals(12, minuteTrigger.getMonths().length); assertEquals(12, hourTrigger.getMonths().length); assertEquals(12, dayOfMonthTrigger.getMonths().length); assertEquals(3, monthTrigger.getMonths().length); assertEquals(1, dayOfWeekTrigger.getMonths().length); // Additional testing for month trigger for (int i = 0; i < months.length; i++) assertEquals(months[i], monthTrigger.getMonths()[i]); } /** * Test method for * {@link ch.entwine.weblounge.common.impl.scheduler.CronJobTrigger#getDaysOfWeek()} * . */ @Test public void testGetDaysOfWeek() { assertEquals(7, minuteTrigger.getDaysOfWeek().length); assertEquals(7, hourTrigger.getDaysOfWeek().length); assertEquals(7, dayOfMonthTrigger.getDaysOfWeek().length); assertEquals(7, monthTrigger.getDaysOfWeek().length); assertEquals(2, dayOfWeekTrigger.getDaysOfWeek().length); // Additional testing for the day of week trigger for (int i = 0; i < daysOfWeek.length; i++) assertEquals(daysOfWeek[i], dayOfWeekTrigger.getDaysOfWeek()[i]); } /** * Test method for asterisk expressions. */ @Test public void testAsteriskOperator() { CronJobTrigger trigger = new CronJobTrigger("* * * * *"); assertEquals(60, trigger.getMinutes().length); assertEquals(24, trigger.getHours().length); assertEquals(7, trigger.getDaysOfWeek().length); assertEquals(31, trigger.getDaysOfMonth().length); assertEquals(12, trigger.getMonths().length); } /** * Test method for range expressions like asterisk/3 in the hour field, which * results in these hours: <code>0, 3, 6, 9, 12, 15, 18, 21</code>. */ @Test public void testModuloOperator() { CronJobTrigger trigger = new CronJobTrigger("* */3 * * *"); assertEquals(8, trigger.getHours().length); assertEquals(0, trigger.getHours()[0]); assertEquals(3, trigger.getHours()[1]); assertEquals(6, trigger.getHours()[2]); assertEquals(9, trigger.getHours()[3]); assertEquals(12, trigger.getHours()[4]); assertEquals(15, trigger.getHours()[5]); assertEquals(18, trigger.getHours()[6]); assertEquals(21, trigger.getHours()[7]); } /** * Test method for modulo overlap expressions like asterisk/61 in the minutes * field, which results in once every hour. */ @Test public void testModuloOperatorOverlap() { CronJobTrigger trigger = new CronJobTrigger("*/61 * * * *"); assertEquals(1, trigger.getMinutes().length); assertEquals(0, trigger.getMinutes()[0]); assertEquals(24, trigger.getHours().length); } /** * Test method for range expressions like 1,3 (1,3). */ @Test public void testCommaOperator() { CronJobTrigger trigger = new CronJobTrigger("* 1,3 * * *"); assertEquals(2, trigger.getHours().length); assertEquals(1, trigger.getHours()[0]); assertEquals(3, trigger.getHours()[1]); } /** * Test method for range expressions like 1-6 (1,2,3,4,5,6). */ @Test public void testRangeOperator() { CronJobTrigger trigger = new CronJobTrigger("* 1-3 * * *"); assertEquals(3, trigger.getHours().length); assertEquals(1, trigger.getHours()[0]); assertEquals(2, trigger.getHours()[1]); assertEquals(3, trigger.getHours()[2]); } /** * Test method for <code>@restart</code>. */ @Test public void testRestart() { CronJobTrigger rebootTrigger = new CronJobTrigger("@restart"); assertEquals(now, rebootTrigger.getNextExecutionAfter(now)); } /** * Test method for <code>@yearly</code>, which is equivalent to * <code>0 0 1 1 *</code>. */ @Test public void testYearly() { CronJobTrigger yearlyTrigger = new CronJobTrigger("@yearly"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 1 1 *"); assertTrue(compare(yearlyTrigger, equivalentTrigger)); } /** * Test method for <code>@annually</code>, which is equivalent to * <code>0 0 1 1 *</code> and of course <code>@yearly</code>. */ @Test public void testAnnually() { CronJobTrigger annuallyTrigger = new CronJobTrigger("@annually"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 1 1 *"); assertTrue(compare(annuallyTrigger, equivalentTrigger)); } /** * Test method for <code>@monthly</code>, which is equivalent to * <code>0 0 1 * *</code>. */ @Test public void testMonthly() { CronJobTrigger monthlyTrigger = new CronJobTrigger("@monthly"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 1 * *"); assertTrue(compare(monthlyTrigger, equivalentTrigger)); } /** * Test method for <code>@weekly</code>, which is equivalent to * <code>0 0 * * 0</code>. */ @Test public void testWeekly() { CronJobTrigger weeklyTrigger = new CronJobTrigger("@weekly"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 * * 0"); assertTrue(compare(weeklyTrigger, equivalentTrigger)); } /** * Test method for <code>@daily</code>, which is equivalent to * <code>0 0 * * *</code>. */ @Test public void testDaily() { CronJobTrigger dailyTrigger = new CronJobTrigger("@daily"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 * * *"); assertTrue(compare(dailyTrigger, equivalentTrigger)); } /** * Test method for <code>@midnight</code>, which is equivalent to * <code>0 0 * * *</code> and of course to <code>@daily</code>. */ @Test public void testMidnight() { CronJobTrigger midnightTrigger = new CronJobTrigger("@midnight"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 0 * * *"); assertTrue(compare(midnightTrigger, equivalentTrigger)); } /** * Test method for <code>@hourly</code>, which is equivalent to * <code>0 * * * *</code>. */ @Test public void testHourly() { CronJobTrigger hourlyTrigger = new CronJobTrigger("@hourly"); CronJobTrigger equivalentTrigger = new CronJobTrigger("0 * * * *"); assertTrue(compare(hourlyTrigger, equivalentTrigger)); } /** * Compares to cron triggers. * * @param a * trigger a * @param b * trigger b */ private boolean compare(CronJobTrigger a, CronJobTrigger b) { // minutes assertEquals(a.getMinutes().length, b.getMinutes().length); for (short i = 0; i < a.getMinutes().length; i++) { assertEquals(a.getMinutes()[i], b.getMinutes()[i]); } // hours assertEquals(a.getHours().length, b.getHours().length); for (short i = 0; i < a.getHours().length; i++) { assertEquals(a.getHours()[i], b.getHours()[i]); } // daysOfWeek assertEquals(a.getDaysOfWeek().length, b.getDaysOfWeek().length); for (short i = 0; i < a.getDaysOfWeek().length; i++) { assertEquals(a.getDaysOfWeek()[i], b.getDaysOfWeek()[i]); } // month assertEquals(a.getMonths().length, b.getMonths().length); for (short i = 0; i < a.getMonths().length; i++) { assertEquals(a.getMonths()[i], b.getMonths()[i]); } // daysOfMonth assertEquals(a.getDaysOfMonth().length, b.getDaysOfMonth().length); for (short i = 0; i < a.getDaysOfMonth().length; i++) { assertEquals(a.getDaysOfMonth()[i], b.getDaysOfMonth()[i]); } return true; } }