001: /********************************************************************************
002: * CruiseControl, a Continuous Integration Toolkit
003: * Copyright (c) 2001-2003, 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.io.ByteArrayOutputStream;
039: import java.io.File;
040: import java.io.FileInputStream;
041: import java.io.FileOutputStream;
042: import java.io.IOException;
043: import java.io.ObjectInputStream;
044: import java.io.ObjectOutputStream;
045: import java.text.SimpleDateFormat;
046: import java.util.ArrayList;
047: import java.util.Calendar;
048: import java.util.Date;
049: import java.util.GregorianCalendar;
050: import java.util.Map;
051: import java.util.TimeZone;
052:
053: import junit.framework.TestCase;
054: import net.sourceforge.cruisecontrol.builders.MockBuilder;
055: import net.sourceforge.cruisecontrol.buildloggers.MergeLogger;
056: import net.sourceforge.cruisecontrol.events.BuildProgressEvent;
057: import net.sourceforge.cruisecontrol.events.BuildProgressListener;
058: import net.sourceforge.cruisecontrol.events.BuildResultEvent;
059: import net.sourceforge.cruisecontrol.events.BuildResultListener;
060: import net.sourceforge.cruisecontrol.labelincrementers.DefaultLabelIncrementer;
061: import net.sourceforge.cruisecontrol.testutil.TestUtil.FilesToDelete;
062: import net.sourceforge.cruisecontrol.testutil.TestUtil;
063: import net.sourceforge.cruisecontrol.util.DateUtil;
064: import net.sourceforge.cruisecontrol.util.IO;
065: import net.sourceforge.cruisecontrol.util.Util;
066:
067: import org.apache.log4j.Level;
068: import org.apache.log4j.Logger;
069: import org.jdom.Element;
070:
071: public class ProjectTest extends TestCase {
072:
073: private static final Logger LOG = Logger
074: .getLogger(ProjectTest.class);
075:
076: private static final String TEST_DIR = "tmp";
077:
078: private Project project;
079: private ProjectConfig projectConfig;
080: private final FilesToDelete filesToDelete = new FilesToDelete();
081:
082: protected void setUp() throws CruiseControlException {
083: project = new Project();
084: project.setName("TestProject");
085:
086: projectConfig = new ProjectConfig();
087: projectConfig.add(new DefaultLabelIncrementer());
088: project.setProjectConfig(projectConfig);
089:
090: // required for runners where log4j isn't initialized
091: Logger.getLogger(Project.class).setLevel(Level.INFO);
092: }
093:
094: public void tearDown() {
095: project.stop();
096: project = null;
097: projectConfig = null;
098:
099: // minimize logging to the console during test runs
100: Logger.getLogger(Project.class).setLevel(Level.ALL);
101: LOG.getLoggerRepository().setThreshold(Level.ALL);
102:
103: filesToDelete.delete();
104: }
105:
106: public void testNotifyListeners() {
107: MockListener listener = new MockListener();
108: ProjectConfig.Listeners listeners = new ProjectConfig.Listeners();
109: listeners.add(listener);
110: projectConfig.add(listeners);
111: // this for init to work only.
112: project.init();
113: ProjectEvent event = new ProjectEvent("foo") {
114: };
115: project.notifyListeners(event);
116: assertTrue(listener.wasNotified());
117: }
118:
119: public void testBuild() throws CruiseControlException, IOException {
120: Date now = new Date();
121: MockModificationSet modSet = new MockModificationSet();
122: modSet.setTimeOfCheck(now);
123: MockSchedule sched = new MockSchedule();
124: projectConfig.add(sched);
125:
126: Log log = new Log();
127: File logDir = new File(TEST_DIR + File.separator
128: + "test-results");
129: logDir.mkdir();
130: filesToDelete.add(logDir);
131: final String myProjectName = "myproject";
132: log.setProjectName(myProjectName);
133: filesToDelete.add(new File(TestUtil.getTargetDir(),
134: myProjectName + ".ser"));
135: log.setDir(logDir.getAbsolutePath());
136: log.setEncoding("ISO-8859-1");
137: log.validate();
138:
139: projectConfig.add(log);
140:
141: MergeLogger logger = new MergeLogger();
142: logger.setFile(TEST_DIR + File.separator + "_auxLog1.xml");
143: logger.validate();
144: log.add(logger);
145:
146: logger = new MergeLogger();
147: logger.setDir(TEST_DIR + File.separator + "_auxLogs");
148: logger.validate();
149: log.add(logger);
150:
151: projectConfig.add(modSet);
152: project.setProjectConfig(projectConfig);
153:
154: project.setLabel("1.2.2");
155: project.setName("myproject");
156: project.setWasLastBuildSuccessful(false);
157:
158: project.setLastBuild(formatTime(now));
159: project.setLastSuccessfulBuild(formatTime(now));
160: writeFile(TEST_DIR + File.separator + "_auxLog1.xml", "<one/>");
161: File auxLogsDirectory = new File(TEST_DIR + File.separator
162: + "_auxLogs");
163: auxLogsDirectory.mkdir();
164: filesToDelete.add(auxLogsDirectory);
165: writeFile(TEST_DIR + File.separator + "_auxLogs/_auxLog2.xml",
166: "<testsuite><properties><property/></properties><testcase/></testsuite>");
167: writeFile(TEST_DIR + File.separator + "_auxLogs/_auxLog3.xml",
168: "<testsuite/>");
169:
170: final ArrayList resultEvents = new ArrayList();
171: project.addBuildResultListener(new BuildResultListener() {
172: public void handleBuildResult(BuildResultEvent event) {
173: resultEvents.add(event);
174: }
175: });
176:
177: final ArrayList progressEvents = new ArrayList();
178: project.addBuildProgressListener(new BuildProgressListener() {
179: public void handleBuildProgress(BuildProgressEvent event) {
180: progressEvents.add(event);
181: }
182: });
183:
184: projectConfig.add(new DefaultLabelIncrementer());
185: project.init();
186:
187: project.start();
188: project.build();
189: project.stop();
190: File expectedLogFile = new File(logDir, "log"
191: + DateUtil.getFormattedTime(now) + "L1.2.2.xml");
192: assertTrue(expectedLogFile.isFile());
193: filesToDelete.add(expectedLogFile);
194:
195: assertTrue(project.isLastBuildSuccessful());
196:
197: String expected = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><cruisecontrol><modifications />"
198: + "<info>"
199: + "<property name=\"projectname\" value=\"myproject\" />"
200: + "<property name=\"lastbuild\" value=\""
201: + DateUtil.getFormattedTime(now)
202: + "\" />"
203: + "<property name=\"lastsuccessfulbuild\" value=\""
204: + project.getLastSuccessfulBuild()
205: + "\" />"
206: + "<property name=\"builddate\" value=\""
207: + DateFormatFactory.getDateFormat().format(now)
208: + "\" />"
209: + "<property name=\"cctimestamp\" value=\""
210: + DateUtil.getFormattedTime(now)
211: + "\" />"
212: + "<property name=\"label\" value=\"1.2.2\" />"
213: + "<property name=\"interval\" value=\"300\" />"
214: + "<property name=\"lastbuildsuccessful\" value=\"false\" />"
215: + "<property name=\"logdir\" value=\""
216: + logDir.getAbsolutePath()
217: + "\" />"
218: + "<property name=\"logfile\" value=\""
219: + "log"
220: + DateUtil.getFormattedTime(now)
221: + "L1.2.2.xml\" />"
222: + "</info><build /><one /><testsuite><testcase /></testsuite><testsuite /></cruisecontrol>";
223: assertEquals(expected, Util.readFileToString(expectedLogFile));
224: assertEquals("Didn't increment the label", "1.2.3", project
225: .getLabel().intern());
226:
227: //look for sourcecontrol properties
228: java.util.Map props = sched.getBuildProperties();
229: assertNotNull("Build properties were null.", props);
230: assertEquals("Build property count.", 10, props.size());
231: assertTrue("projectname not found.", props
232: .containsKey("projectname"));
233: assertEquals("wrong projectname.", "myproject", props
234: .get("projectname"));
235: assertTrue("filemodified not found.", props
236: .containsKey("filemodified"));
237: assertTrue("fileremoved not found.", props
238: .containsKey("fileremoved"));
239: assertEquals(project.getLastSuccessfulBuild(), props
240: .get("cclastgoodbuildtimestamp"));
241: assertEquals(project.getLastBuild(), props
242: .get("cclastbuildtimestamp"));
243: assertTrue("cvstimestamp not passed.", props
244: .containsKey("cvstimestamp"));
245:
246: // check that the proper events were fired
247: assertEquals("Should be exactly one build result event", 1,
248: resultEvents.size());
249: BuildResultEvent resultEvent = (BuildResultEvent) resultEvents
250: .get(0);
251: assertTrue("Should be successful build result event",
252: resultEvent.isBuildSuccessful());
253: assertTrue(
254: "Should have at least one of each project state except queued",
255: progressEvents.size() >= 8);
256: }
257:
258: public void testBuildShouldThrowExceptionWhenNoConfig()
259: throws CruiseControlException {
260: project = new Project();
261: try {
262: project.build();
263: fail();
264: } catch (IllegalStateException expected) {
265: assertEquals(
266: "projectConfig must be set on project before calling build()",
267: expected.getMessage());
268: }
269:
270: project.setProjectConfig(projectConfig);
271: project.build();
272: }
273:
274: public void testBuildRequiresSchedule()
275: throws CruiseControlException {
276: MockProject mockProject = new MockProject() {
277: public void run() {
278: loop();
279: }
280:
281: void checkWait() throws InterruptedException {
282: waitIfPaused();
283: }
284: };
285: mockProject.setName("MockProject");
286: mockProject.setProjectConfig(projectConfig);
287: mockProject.start();
288: mockProject.init();
289: try {
290: mockProject.build();
291: fail();
292: } catch (IllegalStateException expected) {
293: assertEquals("project must have a schedule", expected
294: .getMessage());
295: } finally {
296: mockProject.stopLooping();
297: }
298: }
299:
300: /*
301: * With forceonly true, the build should not be called even with a modification
302: */
303: public void testBuild_forceOnly() throws CruiseControlException {
304: MockProject mockProject = new MockProject() {
305: public void run() {
306: loop();
307: }
308:
309: void setBuildStartTime(Date date) {
310: throw new RuntimeException("Should not run");
311: }
312: };
313: MockModificationSet modSet = new MockModificationSet();
314:
315: mockProject.setName("MockProject");
316: mockProject.setProjectConfig(projectConfig);
317: // Element modifications = modSet.getModifications(null);
318: projectConfig.add(modSet);
319: projectConfig.setForceOnly(true);
320: modSet.setModified(true);
321: mockProject.start();
322: mockProject.init();
323: try {
324: mockProject.build();
325: } finally {
326: mockProject.stopLooping();
327: }
328: }
329:
330: public void testBuildWithMinimumConfig()
331: throws CruiseControlException {
332: Schedule schedule = new Schedule();
333: schedule.add(new MockBuilder());
334: projectConfig.add(schedule);
335: MockLog mockLog = new MockLog();
336: mockLog.setProjectName(project.getName());
337: projectConfig.add(mockLog);
338: project.start();
339: project.setBuildForced(true);
340: project.init();
341: project.build();
342: }
343:
344: /*
345: * This test simulates what happens when there are multiple build threads
346: * and the config.xml gets reloaded while a project is building. This was
347: * causing NPEs but has now been fixed.
348: */
349: public void testBuildWithNewProjectConfigDuringBuild()
350: throws CruiseControlException {
351: projectConfig = new ProjectConfig() {
352: Project readProject(String projectName) {
353: return project;
354: }
355: };
356: final String testProjectForNewConfigDuringBuild = "TestProjectForGettingNewProjectConfigDuringBuild";
357: projectConfig.setName(testProjectForNewConfigDuringBuild);
358: filesToDelete.add(new File(TestUtil.getTargetDir(),
359: testProjectForNewConfigDuringBuild + ".ser"));
360: projectConfig.add(new DefaultLabelIncrementer());
361: projectConfig.configureProject();
362:
363: Schedule schedule = new Schedule();
364: schedule
365: .add(new MockBuilderChangesProjectConfig(projectConfig));
366: projectConfig.add(schedule);
367: MockLog mockLog = new MockLog();
368: mockLog.setProjectName(project.getName());
369: projectConfig.add(mockLog);
370: project.start();
371: project.setBuildForced(true);
372: project.init();
373: project.build();
374: }
375:
376: public void testBadLabel() {
377: try {
378: project.validateLabel("build_0", projectConfig
379: .getLabelIncrementer());
380: fail("Expected exception due to bad label");
381: } catch (CruiseControlException expected) {
382: }
383: }
384:
385: public void testPublish() throws CruiseControlException {
386: MockSchedule sched = new MockSchedule();
387: projectConfig.add(sched);
388:
389: MockPublisher publisher = new MockPublisher();
390: Publisher exceptionThrower = new MockPublisher() {
391: public void publish(Element log)
392: throws CruiseControlException {
393: throw new CruiseControlException("exception");
394: }
395: };
396:
397: ProjectConfig.Publishers publishers = new ProjectConfig.Publishers();
398: publishers.add(publisher);
399: publishers.add(exceptionThrower);
400: publishers.add(publisher);
401:
402: projectConfig.add(publishers);
403: project.setName("projectName");
404: project.setLabel("label.1");
405:
406: projectConfig.add(new DefaultLabelIncrementer());
407: projectConfig.add(new Log());
408: project.init();
409:
410: project.publish(projectConfig.getLog());
411:
412: assertEquals(2, publisher.getPublishCount());
413: }
414:
415: public void testSetLastBuild() throws CruiseControlException {
416: String lastBuild = "20000101120000";
417:
418: project.setLastBuild(lastBuild);
419:
420: assertEquals(lastBuild, project.getLastBuild());
421: }
422:
423: public void testNullLastBuild() throws CruiseControlException {
424: try {
425: project.setLastBuild(null);
426: fail("Expected an IllegalArgumentException for a null last build");
427: } catch (IllegalArgumentException e) {
428: }
429: }
430:
431: public void testBadLastBuild() {
432: try {
433: project.setLastBuild("af32455432");
434: fail("Expected a CruiseControlException for a bad last build");
435: } catch (CruiseControlException e) {
436: }
437: }
438:
439: public void testGetFormattedTime() {
440: assertNull(DateUtil.getFormattedTime(null));
441: }
442:
443: public void testGetModifications() {
444: MockModificationSet modSet = new MockModificationSet();
445: Element modifications = modSet.retrieveModificationsAsElement(
446: null, null);
447: projectConfig.add(modSet);
448: project.init();
449:
450: modSet.setModified(true);
451: assertEquals(modifications, project.getModifications(false));
452: assertEquals(modifications, project.getModifications(true));
453:
454: modSet.setModified(false);
455: assertEquals(null, project.getModifications(false));
456: assertEquals(modifications, project.getModifications(true));
457:
458: // TODO: need tests for when lastBuildSuccessful = false
459: }
460:
461: public void testGetModifications_NoModificationElementRequired() {
462: assertNull(project.getModifications(false));
463: project.setBuildForced(true);
464: assertNotNull(project.getModifications(true));
465: }
466:
467: public void testGetModifications_NoModificationElementAndRequireModificationsFalse() {
468: assertNull(project.getModifications(false));
469: projectConfig.setRequiremodification(false);
470: project.init();
471: assertNotNull(project.getModifications(false));
472: }
473:
474: public void testGetModifications_requireModificationsTrue() {
475: MockModificationSet modSet = new MockModificationSet();
476: // Element modifications = modSet.getModifications(null);
477: projectConfig.add(modSet);
478: projectConfig.setRequiremodification(true);
479: project.init();
480:
481: modSet.setModified(false);
482: assertNull(project.getModifications(false));
483: }
484:
485: public void testGetModifications_requireModificationsFalse() {
486: MockModificationSet modSet = new MockModificationSet();
487: // Element modifications = modSet.getModifications(null);
488: projectConfig.add(modSet);
489: projectConfig.setRequiremodification(false);
490: project.init();
491:
492: modSet.setModified(false);
493: assertNotNull(project.getModifications(false));
494: }
495:
496: public void testCheckOnlySinceLastBuild()
497: throws CruiseControlException {
498:
499: project.setLastBuild("20030218010101");
500: project.setLastSuccessfulBuild("20030218010101");
501: assertEquals(false, project.checkOnlySinceLastBuild());
502:
503: project.setLastBuild("20030218020202");
504: assertEquals(false, project.checkOnlySinceLastBuild());
505:
506: project.setBuildAfterFailed(false);
507: assertEquals(true, project.checkOnlySinceLastBuild());
508:
509: project.setLastBuild("20030218010102");
510: assertEquals(false, project.checkOnlySinceLastBuild());
511:
512: project.setLastBuild("20020101010101");
513: assertEquals(false, project.checkOnlySinceLastBuild());
514: }
515:
516: public void testWaitIfPaused() throws InterruptedException,
517: CruiseControlException {
518: MockProject mockProject = new MockProject() {
519: public void run() {
520: loop();
521: }
522:
523: void checkWait() throws InterruptedException {
524: waitIfPaused();
525: }
526: };
527:
528: projectConfig.add(new MockSchedule());
529: mockProject.setProjectConfig(projectConfig);
530: mockProject.init();
531:
532: new Thread(mockProject).start();
533:
534: int firstLoopCount = mockProject.getLoopCount();
535: Thread.sleep(100);
536: int secondLoopCount = mockProject.getLoopCount();
537: assertTrue(
538: "loop counts should have been different when not paused",
539: firstLoopCount != secondLoopCount);
540:
541: mockProject.setPaused(true);
542: Thread.sleep(100);
543: firstLoopCount = mockProject.getLoopCount();
544: Thread.sleep(100);
545: secondLoopCount = mockProject.getLoopCount();
546: assertEquals("loop counts should be same when paused",
547: firstLoopCount, secondLoopCount);
548:
549: mockProject.setPaused(false);
550: Thread.sleep(100);
551: int lastLoopCount = mockProject.getLoopCount();
552: assertTrue("loop count increased after pause ended",
553: lastLoopCount > secondLoopCount);
554:
555: mockProject.stopLooping();
556: }
557:
558: public void testWaitForNextBuild() throws InterruptedException,
559: CruiseControlException {
560: projectConfig.add(new MockSchedule());
561:
562: MockProject mockProject = new MockProject() {
563: public void run() {
564: loop();
565: }
566:
567: void checkWait() throws InterruptedException {
568: waitForNextBuild();
569: }
570: };
571: mockProject.overrideBuildInterval(1000);
572: mockProject.setProjectConfig(projectConfig);
573: mockProject.init();
574:
575: new Thread(mockProject).start();
576:
577: Thread.sleep(100);
578: assertEquals(1, mockProject.getLoopCount());
579:
580: Thread.sleep(100);
581: assertEquals(1, mockProject.getLoopCount());
582:
583: mockProject.forceBuild();
584: Thread.sleep(100);
585: assertEquals(2, mockProject.getLoopCount());
586:
587: mockProject.stopLooping();
588: }
589:
590: public void testWaitForBuildToFinish() throws InterruptedException {
591: MockProject mockProject = new MockProject() {
592: public void run() {
593: loop();
594: }
595:
596: void checkWait() throws InterruptedException {
597: waitForBuildToFinish();
598: }
599: };
600:
601: new Thread(mockProject).start();
602:
603: Thread.sleep(100);
604: assertEquals(1, mockProject.getLoopCount());
605:
606: Thread.sleep(100);
607: assertEquals(1, mockProject.getLoopCount());
608:
609: mockProject.buildFinished();
610: Thread.sleep(100);
611: assertEquals(2, mockProject.getLoopCount());
612:
613: mockProject.stopLooping();
614: }
615:
616: public void testNeedToWait() {
617: assertTrue(Project.needToWaitForNextBuild(1));
618: assertFalse(Project.needToWaitForNextBuild(0));
619: assertFalse(Project.needToWaitForNextBuild(-1));
620: }
621:
622: public void testToString() {
623: project.setName("foo");
624: assertEquals("Project foo: stopped", project.toString());
625: project.setPaused(true);
626: assertEquals("Project foo: stopped (paused)", project
627: .toString());
628: }
629:
630: public void testInitShouldThrowExceptionWhenConfigNotSet()
631: throws CruiseControlException {
632: project = new Project();
633: try {
634: project.init();
635: fail();
636: } catch (IllegalStateException expected) {
637: assertEquals(
638: "projectConfig must be set on project before calling init()",
639: expected.getMessage());
640: }
641:
642: project.setProjectConfig(projectConfig);
643: project.init();
644: }
645:
646: public void testSerialization() throws IOException {
647: ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
648: ObjectOutputStream objects = new ObjectOutputStream(outBytes);
649: try {
650: objects.writeObject(new Project());
651: objects.flush();
652: } finally {
653: objects.close();
654: }
655:
656: project.serializeProject();
657: }
658:
659: public void testDeserialization() throws Exception {
660: File f = new File("test.ser");
661: filesToDelete.add(f);
662: FileOutputStream outFile = new FileOutputStream(f);
663: ObjectOutputStream objects = new ObjectOutputStream(outFile);
664: try {
665: objects.writeObject(new Project());
666: objects.flush();
667: } finally {
668: objects.close();
669: }
670:
671: FileInputStream inFile = new FileInputStream(f);
672: ObjectInputStream inObjects = new ObjectInputStream(inFile);
673: Object p;
674: try {
675: p = inObjects.readObject();
676: } finally {
677: inObjects.close();
678: }
679: assertNotNull("Read object must not be null", p);
680: assertTrue("Object must be instanceof Project class",
681: p instanceof Project);
682: Project deserializedProject = (Project) p;
683: deserializedProject
684: .addBuildProgressListener(new BuildProgressListener() {
685: public void handleBuildProgress(
686: BuildProgressEvent event) {
687: }
688: });
689: }
690:
691: public void testStartAfterDeserialization() throws Exception {
692: TestProject beforeSerialization = new TestProject();
693: projectConfig.add(new MockSchedule());
694: beforeSerialization.setProjectConfig(projectConfig);
695: beforeSerialization.init();
696:
697: beforeSerialization.start();
698:
699: File f = new File("test.ser");
700: filesToDelete.add(f);
701: FileOutputStream outFile = new FileOutputStream(f);
702: ObjectOutputStream objects = new ObjectOutputStream(outFile);
703: try {
704: objects.writeObject(beforeSerialization);
705: objects.flush();
706: } finally {
707: objects.close();
708: }
709:
710: FileInputStream inFile = new FileInputStream(f);
711: ObjectInputStream inObjects = new ObjectInputStream(inFile);
712: Object p;
713: try {
714: p = inObjects.readObject();
715: } finally {
716: inObjects.close();
717: }
718: TestProject deserializedProject = (TestProject) p;
719: deserializedProject.resetCreateNewSchedulingThreadCalled();
720: deserializedProject.setProjectConfig(projectConfig);
721: deserializedProject.start();
722: assertTrue("failed to create schedule thread",
723: deserializedProject
724: .wasCreateNewSchedulingThreadCalled());
725: }
726:
727: public void testProgressDefault() throws Exception {
728: TestProject testProject = new TestProject();
729: assertNotNull(testProject.getProgress());
730: assertNotNull(testProject.getProgress().getValue());
731: }
732:
733: public void testBuildForcedAfterSuccessfulBuild() throws Exception {
734: projectConfig.add(new MockSchedule());
735:
736: final Log log = new Log();
737: final File logDir = new File(TEST_DIR + File.separator
738: + "test-results");
739: logDir.mkdir();
740: filesToDelete.add(logDir);
741:
742: log.setProjectName("myproject");
743: log.setDir(logDir.getAbsolutePath());
744: log.setEncoding("ISO-8859-1");
745: log.validate();
746: projectConfig.add(log);
747:
748: project.setBuildQueue(new BuildQueue());
749:
750: final File serializedProjectFile = new File(project.getName()
751: + ".ser");
752: filesToDelete.add(serializedProjectFile);
753: if (serializedProjectFile.exists()) {
754: assertTrue(serializedProjectFile.delete());
755: }
756: assertFalse(serializedProjectFile.exists());
757:
758: assertFalse(project.isBuildForced());
759: project.setBuildForced(true);
760: project.start();
761: project.execute(); // performs a build, which performs project serialization
762:
763: final ObjectInputStream inObjects = new ObjectInputStream(
764: new FileInputStream(serializedProjectFile));
765: final Object p;
766: try {
767: p = inObjects.readObject();
768: } finally {
769: inObjects.close();
770: }
771: assertNotNull("Read object must not be null", p);
772: assertTrue("Object must be instanceof Project class",
773: p instanceof Project);
774: final Project deserializedProject = (Project) p;
775: assertFalse(
776: "buildForced should be false after deserialization",
777: deserializedProject.isBuildForced());
778: }
779:
780: public void testGetProjectPropertiesMap()
781: throws CruiseControlException {
782: String label = "labeL.1";
783: project.setLabel(label);
784: String lastBuild = "20000101120000";
785: project.setLastBuild(lastBuild);
786: String lastGoodBuild = "19990101120000";
787: project.setLastSuccessfulBuild(lastGoodBuild);
788: project.setWasLastBuildSuccessful(true);
789: TimeZone cest = TimeZone.getTimeZone("Europe/Copenhagen");
790: Calendar now = new GregorianCalendar(cest);
791: now.set(2005, Calendar.AUGUST, 10, 13, 7, 43);
792: String cvstimestamp = "2005-08-10 11:07:43 GMT";
793:
794: projectConfig.add(new MockSchedule());
795: project.init();
796:
797: // The returned time is dependent on the default timezone hence
798: // the use of DateUtil.getFormattedTime()
799: String cctimestamp = DateUtil.getFormattedTime(now.getTime());
800: Map map = project.getProjectPropertiesMap(now.getTime());
801:
802: assertEquals(label, map.get("label"));
803: assertEquals(cctimestamp, map.get("cctimestamp"));
804: assertEquals(lastGoodBuild, map.get("cclastgoodbuildtimestamp"));
805: assertEquals(lastBuild, map.get("cclastbuildtimestamp"));
806: assertEquals("true", map.get("lastbuildsuccessful"));
807: assertEquals(cvstimestamp, map.get("cvstimestamp"));
808: }
809:
810: public void testGetTimeToNextBuild_AfterShortBuild() {
811: Schedule schedule = new Schedule();
812: MockBuilder noonBuilder = new MockBuilder();
813: noonBuilder.setTime("1200");
814: noonBuilder.setBuildLogXML(new Element("builder1"));
815: schedule.add(noonBuilder);
816:
817: projectConfig.add(schedule);
818:
819: Calendar cal = Calendar.getInstance();
820: cal.set(2001, Calendar.NOVEMBER, 22);
821: cal.set(Calendar.HOUR_OF_DAY, 12);
822: cal.set(Calendar.MINUTE, 0);
823: Date noonBuild = cal.getTime();
824: project.setBuildStartTime(noonBuild);
825:
826: project.init();
827:
828: cal.set(Calendar.SECOND, 30);
829: Date postNoonBuild = cal.getTime();
830:
831: long time = project.getTimeToNextBuild(postNoonBuild);
832: assertEquals(Schedule.ONE_DAY, time);
833: }
834:
835: private void writeFile(String fileName, String contents)
836: throws CruiseControlException {
837:
838: File f = new File(fileName);
839: filesToDelete.add(f);
840: IO.write(f, contents);
841: }
842:
843: private static String formatTime(Date time) {
844: return new SimpleDateFormat("yyyyMMddHHmmss").format(time);
845: }
846:
847: private class MockPublisher implements Publisher {
848: private int publishCount = 0;
849:
850: public void validate() {
851: }
852:
853: public void publish(Element log) throws CruiseControlException {
854: publishCount++;
855: }
856:
857: int getPublishCount() {
858: return publishCount;
859: }
860: }
861:
862: private class MockListener implements Listener {
863: private boolean notified = false;
864:
865: public boolean wasNotified() {
866: return notified;
867: }
868:
869: public void handleEvent(ProjectEvent event)
870: throws CruiseControlException {
871: notified = true;
872: }
873:
874: public void validate() throws CruiseControlException {
875: }
876: }
877:
878: private static class TestProject extends Project {
879: private boolean createNewSchedulingThreadCalled = false;
880:
881: protected void createNewSchedulingThread() {
882: createNewSchedulingThreadCalled = true;
883: }
884:
885: boolean wasCreateNewSchedulingThreadCalled() {
886: return createNewSchedulingThreadCalled;
887: }
888:
889: void resetCreateNewSchedulingThreadCalled() {
890: createNewSchedulingThreadCalled = false;
891: }
892: }
893:
894: private class MockLog extends Log {
895:
896: protected void callManipulators() {
897: }
898:
899: protected void writeLogFile(File file, Element element)
900: throws CruiseControlException {
901: }
902:
903: }
904:
905: public class MockBuilderChangesProjectConfig extends MockBuilder {
906:
907: private final ProjectConfig oldProjectConfig;
908:
909: public MockBuilderChangesProjectConfig(
910: ProjectConfig projectConfig) {
911: oldProjectConfig = projectConfig;
912: }
913:
914: /*
915: * This is to simulate what happens when the config file changes during a build.
916: */
917: public Element build(Map properties, Progress progress) {
918: ProjectConfig newProjectConfig = new ProjectConfig();
919: newProjectConfig.add(new DefaultLabelIncrementer());
920: Schedule schedule = new Schedule();
921: schedule.add(new MockBuilder());
922: newProjectConfig.add(schedule);
923: newProjectConfig.add(new MockLog());
924:
925: try {
926: newProjectConfig
927: .getStateFromOldProject(oldProjectConfig);
928: } catch (CruiseControlException e) {
929: throw new RuntimeException(e);
930: }
931:
932: return super.build(properties, progress);
933: }
934:
935: }
936: }
|