001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001, ThoughtWorks, Inc.
004: * 200 E. Randolph, 25th Floor
005: * Chicago, IL 60601 USA
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: *
012: * + Redistributions of source code must retain the above copyright
013: * notice, this list of conditions and the following disclaimer.
014: *
015: * + Redistributions in binary form must reproduce the above
016: * copyright notice, this list of conditions and the following
017: * disclaimer in the documentation and/or other materials provided
018: * with the distribution.
019: *
020: * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
021: * names of its contributors may be used to endorse or promote
022: * products derived from this software without specific prior
023: * written permission.
024: *
025: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
026: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
027: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
028: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
030: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
031: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
032: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
033: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
034: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036: ********************************************************************************/package net.sourceforge.cruisecontrol;
037:
038: import java.util.Calendar;
039: import java.util.Date;
040: import java.util.SimpleTimeZone;
041: import java.util.TimeZone;
042:
043: import junit.framework.TestCase;
044: import net.sourceforge.cruisecontrol.builders.MockBuilder;
045:
046: import org.jdom.Element;
047:
048: public class ScheduleTest extends TestCase {
049: private Schedule schedule;
050: private TimeZone defaultTimeZone;
051:
052: private static final long ONE_MINUTE = Schedule.ONE_MINUTE;
053: private static final long ONE_HOUR = 60 * ONE_MINUTE;
054: private static final long TWELVE_HOURS = 12 * ONE_HOUR;
055: private static final long ONE_DAY = Schedule.ONE_DAY;
056: private static final TimeZone LOS_ANGELES;
057:
058: private static final Calendar FRIDAY;
059: private static final Calendar THURSDAY;
060:
061: private static final Date THURSDAY_1001;
062: private static final Date THURSDAY_1101;
063: private static final Date THURSDAY_1201;
064: private static final Date THURSDAY_2301;
065: private static final Date FRIDAY_0000;
066:
067: private static final MockBuilder NOON_BUILDER;
068: private static final MockBuilder MIDNIGHT_BUILDER;
069: private static final MockBuilder MULTIPLE_5;
070: private static final MockBuilder MULTIPLE_1;
071:
072: private static final PauseBuilder PAUSE_11_13;
073: private static final PauseBuilder PAUSE_11_13_FRIDAY;
074:
075: static {
076: LOS_ANGELES = createLosAngelesTimeZone();
077:
078: NOON_BUILDER = new MockBuilder();
079: NOON_BUILDER.setTime("1200");
080: NOON_BUILDER.setBuildLogXML(new Element("builder1"));
081:
082: MIDNIGHT_BUILDER = new MockBuilder();
083: MIDNIGHT_BUILDER.setTime("0000");
084: MIDNIGHT_BUILDER.setBuildLogXML(new Element("builder1"));
085:
086: MULTIPLE_5 = new MockBuilder();
087: MULTIPLE_5.setMultiple(5);
088: MULTIPLE_5.setBuildLogXML(new Element("builder2"));
089:
090: MULTIPLE_1 = new MockBuilder();
091: MULTIPLE_1.setMultiple(1);
092: MULTIPLE_1.setBuildLogXML(new Element("builder3"));
093:
094: PAUSE_11_13 = new PauseBuilder();
095: PAUSE_11_13.setStartTime(1100);
096: PAUSE_11_13.setEndTime(1300);
097:
098: PAUSE_11_13_FRIDAY = new PauseBuilder();
099: PAUSE_11_13_FRIDAY.setStartTime(1100);
100: PAUSE_11_13_FRIDAY.setEndTime(1300);
101: PAUSE_11_13_FRIDAY.setDay("friday");
102:
103: THURSDAY = Calendar.getInstance();
104: THURSDAY.set(2001, Calendar.NOVEMBER, 22);
105: FRIDAY = Calendar.getInstance();
106: FRIDAY.set(2001, Calendar.NOVEMBER, 23);
107:
108: THURSDAY_1001 = getDate(THURSDAY, 10, 01);
109: THURSDAY_1101 = getDate(THURSDAY, 11, 01);
110: THURSDAY_1201 = getDate(THURSDAY, 12, 01);
111: THURSDAY_2301 = getDate(THURSDAY, 23, 01);
112: FRIDAY_0000 = getDate(FRIDAY, 0, 0);
113: }
114:
115: protected void setUp() {
116: schedule = new Schedule();
117:
118: schedule.add(NOON_BUILDER);
119: schedule.add(MIDNIGHT_BUILDER);
120: schedule.add(MULTIPLE_5);
121: schedule.add(MULTIPLE_1);
122:
123: defaultTimeZone = TimeZone.getDefault();
124: TimeZone.setDefault(LOS_ANGELES);
125: }
126:
127: protected void tearDown() throws Exception {
128: schedule = null;
129: TimeZone.setDefault(defaultTimeZone);
130: }
131:
132: private static TimeZone createLosAngelesTimeZone() {
133: // taken from SimpleTimeZone javadoc:
134:
135: // Base GMT offset: -8:00
136: // DST starts: at 2:00am in standard time
137: // on the first Sunday in April
138: // DST ends: at 2:00am in daylight time
139: // on the last Sunday in October
140: // Save: 1 hour
141: return new SimpleTimeZone(-28800000, "America/Los_Angeles",
142: Calendar.APRIL, 1, -Calendar.SUNDAY, 7200000,
143: Calendar.OCTOBER, -1, Calendar.SUNDAY, 7200000, 3600000);
144: }
145:
146: /**
147: * @param calendar Calendar with date set
148: * @param hour
149: * @param min
150: * @return Date with date and time set
151: */
152: private static Date getDate(Calendar calendar, int hour, int min) {
153: Calendar cal = (Calendar) calendar.clone();
154: cal.setTimeZone(LOS_ANGELES);
155: cal.set(Calendar.HOUR_OF_DAY, hour);
156: cal.set(Calendar.MINUTE, min);
157: return cal.getTime();
158: }
159:
160: public void testSelectBuilder() throws CruiseControlException {
161: Builder buildIsMultipleOfOne = schedule.selectBuilder(13,
162: THURSDAY_1001, THURSDAY_1101);
163: assertEquals(MULTIPLE_1, buildIsMultipleOfOne);
164:
165: Builder buildIsMultipleOfFive = schedule.selectBuilder(10,
166: THURSDAY_1001, THURSDAY_1101);
167: assertEquals(MULTIPLE_5, buildIsMultipleOfFive);
168:
169: Builder middayTimeBuild = schedule.selectBuilder(13,
170: THURSDAY_1001, THURSDAY_1201);
171: assertEquals(NOON_BUILDER, middayTimeBuild);
172:
173: Builder midnightTimeBuild = schedule.selectBuilder(13,
174: THURSDAY_1001, FRIDAY_0000);
175: assertEquals(MIDNIGHT_BUILDER, midnightTimeBuild);
176:
177: Calendar wednesday = Calendar.getInstance();
178: wednesday.set(2001, Calendar.NOVEMBER, 21);
179: Date noonWednesday = getDate(wednesday, 12, 00);
180:
181: Builder timeBuildAcrossDays = schedule.selectBuilder(11,
182: noonWednesday, FRIDAY_0000);
183: assertEquals(MIDNIGHT_BUILDER, timeBuildAcrossDays);
184:
185: Schedule timeBasedSchedule = new Schedule();
186: timeBasedSchedule.add(NOON_BUILDER);
187: timeBasedSchedule.add(MIDNIGHT_BUILDER);
188:
189: Builder nextTimeBuilder = timeBasedSchedule.selectBuilder(3,
190: THURSDAY_1001, THURSDAY_1101);
191: assertEquals(NOON_BUILDER, nextTimeBuilder);
192:
193: try {
194: Schedule badSchedule = new Schedule();
195: badSchedule.selectBuilder(1, THURSDAY_1001, THURSDAY_1101);
196: fail("should fail with no builders");
197: } catch (CruiseControlException expected) {
198: }
199: }
200:
201: public void testSelectBuilder_MultipleBuildersWithDaySet()
202: throws CruiseControlException {
203: Builder thursdayBuilder = new MockBuilder();
204: thursdayBuilder.setDay("thursday");
205: Schedule scheduledByDay = new Schedule();
206: scheduledByDay.add(thursdayBuilder);
207: assertEquals(thursdayBuilder, scheduledByDay.selectBuilder(1,
208: THURSDAY_1001, THURSDAY_1101));
209: assertEquals(thursdayBuilder, scheduledByDay.selectBuilder(1,
210: THURSDAY_1001, FRIDAY_0000));
211:
212: Builder fridayBuilder = new MockBuilder();
213: fridayBuilder.setDay("friday");
214: scheduledByDay.add(fridayBuilder);
215: assertEquals(thursdayBuilder, scheduledByDay.selectBuilder(1,
216: THURSDAY_1001, THURSDAY_1101));
217: assertEquals(fridayBuilder, scheduledByDay.selectBuilder(1,
218: THURSDAY_1001, FRIDAY_0000));
219: }
220:
221: public void testSelectBuilder_ForcedBuildAcrossTimeChangeBoundary()
222: throws CruiseControlException {
223: Builder thursdayBuilder = new MockBuilder();
224:
225: thursdayBuilder.setTime("1120");
226: thursdayBuilder.setDay("thursday");
227: Schedule scheduledByDay = new Schedule();
228: scheduledByDay.add(thursdayBuilder);
229:
230: Calendar oct272005 = Calendar.getInstance();
231: oct272005.set(2005, Calendar.OCTOBER, 27);
232:
233: // mimic a JMX trigger
234: Date last = getDate(oct272005, 11, 20);
235: Date now = getDate(oct272005, 11, 25);
236: assertEquals(thursdayBuilder, scheduledByDay.selectBuilder(123,
237: last, now));
238: }
239:
240: public void testIsPaused() {
241: PauseBuilder pauseBuilder = new PauseBuilder();
242: pauseBuilder.setStartTime(2300);
243: pauseBuilder.setEndTime(2359);
244: schedule.add(pauseBuilder);
245:
246: assertEquals(schedule.isPaused(THURSDAY_2301), true);
247: assertEquals(schedule.isPaused(THURSDAY_1101), false);
248: }
249:
250: public void testGetTimeToNextBuild() {
251: long fiveSeconds = 5 * 1000;
252: long elevenHours = 11 * ONE_HOUR;
253: long oneHourFiftyNineMinutes = (2 * ONE_HOUR) - ONE_MINUTE;
254:
255: PauseBuilder pause = new PauseBuilder();
256: pause.setStartTime(2300);
257: pause.setEndTime(2359);
258: schedule.add(pause);
259:
260: assertEquals("next time build > build interval", fiveSeconds,
261: schedule.getTimeToNextBuild(THURSDAY_1001, fiveSeconds));
262:
263: assertEquals("next time build < build interval",
264: oneHourFiftyNineMinutes, schedule.getTimeToNextBuild(
265: THURSDAY_1001, elevenHours));
266:
267: assertEquals("next time build is tomorrow", TWELVE_HOURS
268: - ONE_MINUTE, schedule.getTimeToNextBuild(
269: THURSDAY_1201, ONE_DAY * 2));
270:
271: assertEquals("wait till after pause",
272: TWELVE_HOURS - ONE_MINUTE, schedule.getTimeToNextBuild(
273: THURSDAY_1201, elevenHours));
274:
275: assertEquals("wait till after pause we're in", ONE_HOUR
276: - ONE_MINUTE, schedule.getTimeToNextBuild(
277: THURSDAY_2301, fiveSeconds));
278:
279: pause = new PauseBuilder();
280: pause.setStartTime(0000);
281: pause.setEndTime(100);
282: schedule.add(pause);
283:
284: assertEquals("wait till after pause on next day", 2 * ONE_HOUR,
285: schedule.getTimeToNextBuild(THURSDAY_2301, ONE_HOUR));
286:
287: assertEquals("two back-to-back pauses", 2 * ONE_HOUR, schedule
288: .getTimeToNextBuild(THURSDAY_2301, fiveSeconds));
289:
290: pause = new PauseBuilder();
291: pause.setStartTime(0000);
292: pause.setEndTime(2359);
293: pause.setDay("friday");
294: schedule.add(pause);
295:
296: assertEquals("chained pauses with day specific pause", ONE_DAY
297: + (2 * ONE_HOUR), schedule.getTimeToNextBuild(
298: THURSDAY_2301, ONE_HOUR));
299: }
300:
301: public void testGetTimeToNextBuild_MultipleBuilderWithDaySet() {
302: Schedule intervalThursdaysSchedule = new Schedule();
303: Builder intervalThursdays = new MockBuilder();
304: intervalThursdays.setDay("thursday");
305: intervalThursdaysSchedule.add(intervalThursdays);
306: assertEquals(ONE_MINUTE, intervalThursdaysSchedule
307: .getTimeToNextBuild(THURSDAY_2301, ONE_MINUTE));
308: assertEquals(6 * ONE_DAY + ONE_HOUR - ONE_MINUTE,
309: intervalThursdaysSchedule.getTimeToNextBuild(
310: THURSDAY_2301, ONE_HOUR));
311: assertEquals(6 * ONE_DAY + ONE_HOUR - ONE_MINUTE,
312: intervalThursdaysSchedule.getTimeToNextBuild(
313: THURSDAY_2301, ONE_DAY));
314: }
315:
316: public void testGetTimeToNextBuild_ShouldUseIntervalWhenThereAreNoBuilders() {
317: Schedule badSchedule = new Schedule();
318:
319: assertEquals(ONE_DAY, badSchedule.getTimeToNextBuild(
320: THURSDAY_1001, ONE_DAY));
321: }
322:
323: public void testGetTimeToNextBuild_ShouldNotExceedMaximumInterval() {
324: Schedule badSchedule = new Schedule();
325: PauseBuilder alwaysPaused = new PauseBuilder();
326: alwaysPaused.setStartTime(0000);
327: alwaysPaused.setEndTime(2359);
328: badSchedule.add(alwaysPaused);
329:
330: assertEquals(Schedule.MAX_INTERVAL_MILLISECONDS, badSchedule
331: .getTimeToNextBuild(THURSDAY_1001, ONE_DAY));
332:
333: badSchedule = new Schedule();
334: badSchedule.add(NOON_BUILDER);
335: badSchedule.add(PAUSE_11_13);
336:
337: assertEquals(Schedule.MAX_INTERVAL_MILLISECONDS, badSchedule
338: .getTimeToNextBuild(THURSDAY_1101, ONE_MINUTE));
339: }
340:
341: public void testGetTimeToNextBuild_DailyBuild() {
342: Schedule dailyBuildSchedule = new Schedule();
343: dailyBuildSchedule.add(NOON_BUILDER);
344:
345: assertEquals("ignore interval when only time builds", ONE_HOUR
346: - ONE_MINUTE, dailyBuildSchedule.getTimeToNextBuild(
347: THURSDAY_1101, ONE_MINUTE));
348:
349: PauseBuilder pause = new PauseBuilder();
350: pause.setStartTime(0000);
351: pause.setEndTime(2359);
352: pause.setDay("friday");
353: dailyBuildSchedule.add(pause);
354:
355: assertEquals("pause w/only time builder", (ONE_DAY * 2)
356: - ONE_MINUTE, dailyBuildSchedule.getTimeToNextBuild(
357: THURSDAY_1201, ONE_MINUTE));
358: }
359:
360: public void testGetTimeToNextBuild_WeeklyBuild() {
361: schedule = new Schedule();
362: Builder weeklyBuilder = new MockBuilder();
363: weeklyBuilder.setTime("0100");
364: weeklyBuilder.setDay("Sunday");
365: schedule.add(weeklyBuilder);
366:
367: assertEquals((ONE_DAY * 2) + ONE_HOUR, schedule
368: .getTimeToNextBuild(FRIDAY_0000, ONE_MINUTE));
369: }
370:
371: public void testGetTimeToNextBuild_WeeklyBuildAcrossDaylightSavingsTimeBoundary() {
372: Builder thursdayBuilder = new MockBuilder();
373:
374: thursdayBuilder.setTime("1120");
375: thursdayBuilder.setDay("thursday");
376: Schedule scheduledByDay = new Schedule();
377: scheduledByDay.add(thursdayBuilder);
378:
379: Calendar oct272005 = Calendar.getInstance();
380: oct272005.set(2005, Calendar.OCTOBER, 27);
381:
382: Date now = getDate(oct272005, 11, 25);
383: long dstEndingAdjustment = ONE_HOUR;
384: assertEquals(((ONE_DAY * 6) + (ONE_HOUR * 23)
385: + (ONE_MINUTE * 55) + dstEndingAdjustment),
386: scheduledByDay.getTimeToNextBuild(now, ONE_MINUTE));
387: }
388:
389: public void testGetTimeToNextBuild_MonthlyBuild() {
390: schedule = new Schedule();
391: Builder monthlyBuilder = new MockBuilder() {
392: private long targetTime = FRIDAY_0000.getTime()
393: + (30 * ONE_DAY);
394:
395: public boolean isValidDay(Date now) {
396: return targetTime <= now.getTime() ? true : false;
397: }
398: };
399: monthlyBuilder.setTime("0000");
400: schedule.add(monthlyBuilder);
401:
402: assertEquals(ONE_DAY * 30, schedule.getTimeToNextBuild(
403: FRIDAY_0000, ONE_MINUTE));
404:
405: }
406:
407: public void testInterval() {
408: assertEquals("default interval", 300 * 1000, schedule
409: .getInterval());
410: schedule.setInterval(500);
411: assertEquals(500 * 1000, schedule.getInterval());
412: }
413:
414: public void testValidate() throws CruiseControlException {
415: schedule = new Schedule();
416:
417: try {
418: schedule.validate();
419: fail("validate should throw exception if it is configured with no builders");
420: } catch (CruiseControlException e) {
421: }
422:
423: schedule.add(MULTIPLE_1);
424: schedule.validate();
425:
426: long oneYearInSeconds = 60 * 60 * 24 * 365;
427: schedule.setInterval(oneYearInSeconds);
428: schedule.validate();
429:
430: schedule.setInterval(oneYearInSeconds + 1);
431: try {
432: schedule.validate();
433: fail("maximum allowed interval should be "
434: + oneYearInSeconds);
435: } catch (CruiseControlException e) {
436: }
437: }
438:
439: public void testCannotSetZeroOrLessInterval() {
440: schedule = new Schedule();
441: assertSetIntervalThrowsException(0);
442: assertSetIntervalThrowsException(-1);
443: assertSetIntervalThrowsException(-100);
444: assertSetIntervalThrowsException(Long.MIN_VALUE);
445: }
446:
447: private void assertSetIntervalThrowsException(long testValue) {
448: try {
449: schedule.setInterval(testValue);
450: fail("Expected an exception");
451: } catch (IllegalArgumentException expected) {
452: //Good
453: }
454: }
455:
456: public void testValidateShouldFailIfAllTimedBuildersInPauses()
457: throws CruiseControlException {
458: schedule = new Schedule();
459:
460: schedule.add(PAUSE_11_13_FRIDAY);
461: schedule.add(NOON_BUILDER);
462: schedule.validate();
463:
464: schedule.add(PAUSE_11_13);
465: try {
466: schedule.validate();
467: fail();
468: } catch (CruiseControlException expected) {
469: }
470:
471: schedule.add(MIDNIGHT_BUILDER);
472: schedule.validate();
473: }
474:
475: public void testGetDayString() {
476: assertEquals("sunday", schedule.getDayString(Calendar.SUNDAY)
477: .toLowerCase());
478: assertEquals("friday", schedule.getDayString(Calendar.FRIDAY)
479: .toLowerCase());
480: try {
481: schedule.getDayString(0);
482: fail();
483: } catch (IllegalArgumentException e) {
484: assertEquals(
485: "valid values of days are between 1 and 7, was 0",
486: e.getMessage());
487: }
488: }
489:
490: }
|