0001: package net.sourceforge.cruisecontrol.distributed;
0002:
0003: import junit.framework.TestCase;
0004:
0005: import java.util.Properties;
0006: import java.util.Map;
0007: import java.util.HashMap;
0008: import java.util.Arrays;
0009: import java.util.Date;
0010:
0011: import java.io.File;
0012: import java.io.IOException;
0013:
0014: import java.rmi.RemoteException;
0015:
0016: import org.jdom.Element;
0017: import org.apache.log4j.Logger;
0018:
0019: import net.sourceforge.cruisecontrol.distributed.core.PropertiesHelper;
0020: import net.sourceforge.cruisecontrol.distributed.core.CCDistVersion;
0021: import net.sourceforge.cruisecontrol.distributed.core.RemoteResult;
0022: import net.sourceforge.cruisecontrol.distributed.core.RemoteResultTest;
0023: import net.sourceforge.cruisecontrol.distributed.core.jnlputil.JNLPServiceUtil;
0024: import net.sourceforge.cruisecontrol.builders.MockBuilder;
0025: import net.sourceforge.cruisecontrol.builders.DistributedMasterBuilderTest;
0026: import net.sourceforge.cruisecontrol.builders.AntBuilder;
0027: import net.sourceforge.cruisecontrol.builders.CompositeBuilder;
0028: import net.sourceforge.cruisecontrol.builders.AntScript;
0029: import net.sourceforge.cruisecontrol.CruiseControlException;
0030: import net.sourceforge.cruisecontrol.Progress;
0031: import net.sourceforge.cruisecontrol.util.Util;
0032:
0033: import javax.jnlp.UnavailableServiceException;
0034:
0035: /**
0036: * @author Dan Rollo
0037: * Date: May 25, 2005
0038: * Time: 1:54:38 PM
0039: */
0040: public class BuildAgentServiceImplTest extends TestCase {
0041:
0042: private static final Logger LOG = Logger
0043: .getLogger(BuildAgentServiceImplTest.class);
0044:
0045: public static final String TEST_AGENT_PROPERTIES_FILE = "testdist.agent.properties";
0046: public static final String TEST_USER_DEFINED_PROPERTIES_FILE = "testdist.user-defined.properties";
0047: public static final String ENTRY_NAME_BUILD_TYPE = "build.type";
0048:
0049: private static final File DIR_LOGS = new File(
0050: PropertiesHelper.RESULT_TYPE_LOGS);
0051: private static final File DIR_OUTPUT = new File(
0052: PropertiesHelper.RESULT_TYPE_OUTPUT);
0053: private static final File DIR_FILE = new File(
0054: PropertiesHelper.RESULT_TYPE_DIR);
0055:
0056: private static final RemoteResult[] REMOTE_RESULTS_EMPTY = new RemoteResult[] {};
0057:
0058: public static final RemoteResult[] REMOTE_RESULTS_ONE = new RemoteResult[] { new RemoteResult(
0059: 0) };
0060: static {
0061: REMOTE_RESULTS_ONE[0]
0062: .setAgentDir(PropertiesHelper.RESULT_TYPE_DIR);
0063: REMOTE_RESULTS_ONE[0].setMasterDir("masterResultFile");
0064: }
0065:
0066: private static final RemoteResult[] REMOTE_RESULTS_TWO_WITHEMPTYDIR = new RemoteResult[] {
0067: REMOTE_RESULTS_ONE[0], new RemoteResult(1) };
0068: static {
0069: REMOTE_RESULTS_TWO_WITHEMPTYDIR[1]
0070: .setAgentDir(PropertiesHelper.RESULT_TYPE_DIR + "2");
0071: REMOTE_RESULTS_TWO_WITHEMPTYDIR[1]
0072: .setMasterDir("masterResultFile2");
0073: }
0074:
0075: private Properties origSysProps;
0076: private static final String TEST_PROJECT_FAIL = "testproject-fail";
0077: private static final String TEST_PROJECT_SUCCESS = "testproject-success";
0078: private static final int KILL_DELAY = 1000;
0079:
0080: private static final String EXPECTED_SUFFIX_AS_STRING_VER = "\n\tVersion: "
0081: + CCDistVersion.getVersion()
0082: + " (Compiled: "
0083: + CCDistVersion.getVersionBuildDate() + ")";
0084:
0085: protected void setUp() throws Exception {
0086: DIR_LOGS.delete();
0087: DIR_OUTPUT.delete();
0088: DIR_FILE.delete();
0089: origSysProps = System.getProperties();
0090:
0091: RemoteResultTest.resetTempZippedFile(REMOTE_RESULTS_ONE[0]);
0092: }
0093:
0094: protected void tearDown() throws Exception {
0095: System.setProperties(origSysProps);
0096: deleteDirConfirm(DIR_LOGS);
0097: deleteDirConfirm(DIR_OUTPUT);
0098: deleteDirConfirm(DIR_FILE);
0099: }
0100:
0101: private static void deleteDirConfirm(final File dirToDelete) {
0102: if (dirToDelete.exists()) {
0103: assertTrue("Error cleaning up test directory: "
0104: + dirToDelete.getAbsolutePath()
0105: + "\nDir Contents:\n"
0106: + Arrays.asList(dirToDelete.listFiles()),
0107: dirToDelete.delete());
0108: }
0109: }
0110:
0111: private static class MyAgentStatusListener implements
0112: BuildAgent.AgentStatusListener {
0113: private int agentStatusChangeCount;
0114:
0115: public void statusChanged(
0116: BuildAgentService buildAgentServiceImpl) {
0117: agentStatusChangeCount++;
0118: }
0119:
0120: int getAgentStatusChangeCount() {
0121: return agentStatusChangeCount;
0122: }
0123:
0124: void resetAgentStatusChangeCount() {
0125: this .agentStatusChangeCount = 0;
0126: }
0127: }
0128:
0129: private static final File LOGGER_JAR_REAL_MAIN_DIST
0130: // @todo Change path to main/dist if we move CCDist into main
0131: = new File(DistributedMasterBuilderTest.MAIN_CCDIST_DIR
0132: + "../../main/dist", AntScript.LIBNAME_PROGRESS_LOGGER);
0133:
0134: private static final File LOGGER_JAR_MOVED = new File(
0135: LOGGER_JAR_REAL_MAIN_DIST.getParentFile(), "hidden"
0136: + AntScript.LIBNAME_PROGRESS_LOGGER);
0137:
0138: private static void hideAntProgressLoggerLib() {
0139: LOGGER_JAR_REAL_MAIN_DIST.renameTo(LOGGER_JAR_MOVED);
0140: }
0141:
0142: private static void unhideAntProgressLoggerLib() {
0143: LOGGER_JAR_MOVED.renameTo(LOGGER_JAR_REAL_MAIN_DIST);
0144: }
0145:
0146: public void testInjectProgressLibBeforeValidation()
0147: throws Exception {
0148:
0149: final class MyAntBuilder extends AntBuilder {
0150: static final String MSG_FORCED_FAILURE = "Forced Failure for unit testing";
0151: private boolean isValidateCalled;
0152:
0153: boolean isValidateCalled() {
0154: return isValidateCalled;
0155: }
0156:
0157: private boolean isBuildCalled;
0158:
0159: boolean isBuildCalled() {
0160: return isBuildCalled;
0161: }
0162:
0163: void resetFlags() {
0164: isValidateCalled = false;
0165: isBuildCalled = false;
0166: }
0167:
0168: public void validate() throws CruiseControlException {
0169: isValidateCalled = true;
0170: super .validate();
0171: }
0172:
0173: public Element build(Map buildProperties,
0174: Progress progressIn) throws CruiseControlException {
0175:
0176: isBuildCalled = true;
0177: // for failure
0178: throw new CruiseControlException(MSG_FORCED_FAILURE);
0179: }
0180: }
0181: final MyAntBuilder antBuilder = new MyAntBuilder();
0182: antBuilder.setUseLogger(true);
0183: antBuilder.setShowAntOutput(true);
0184: antBuilder.setProgressLoggerLib(LOGGER_JAR_REAL_MAIN_DIST
0185: .getAbsolutePath());
0186:
0187: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0188: null);
0189:
0190: final Map distributedAgentProps = new HashMap();
0191:
0192: final Map projectProperties = new HashMap();
0193: projectProperties.put(PropertiesHelper.PROJECT_NAME,
0194: TEST_PROJECT_SUCCESS);
0195:
0196: hideAntProgressLoggerLib();
0197: try {
0198: agentImpl
0199: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0200:
0201: try {
0202: try {
0203: agentImpl.doBuild(antBuilder, projectProperties,
0204: distributedAgentProps, null,
0205: REMOTE_RESULTS_EMPTY);
0206: fail("Missing progressLoggerLib should have failed validation");
0207: } catch (RemoteException e) {
0208: assertTrue(e
0209: .getMessage()
0210: .startsWith(
0211: "Failed to validate nested Builder on agent"));
0212: assertTrue(e.getCause() instanceof CruiseControlException);
0213: final CruiseControlException cce = (CruiseControlException) e
0214: .getCause();
0215: assertTrue(cce.getMessage().startsWith(
0216: "File specified ["));
0217: }
0218:
0219: assertTrue(antBuilder.isValidateCalled());
0220: assertFalse(antBuilder.isBuildCalled());
0221: } finally {
0222: agentImpl.clearOutputFiles();
0223: }
0224: } finally {
0225: unhideAntProgressLoggerLib();
0226: }
0227:
0228: antBuilder.resetFlags();
0229: try {
0230: try {
0231: agentImpl.doBuild(antBuilder, projectProperties,
0232: distributedAgentProps, null,
0233: REMOTE_RESULTS_EMPTY);
0234: fail("build failure should have been forced");
0235: } catch (RemoteException e) {
0236: assertTrue(e.getMessage().startsWith(
0237: "Failed to complete build on agent"));
0238: assertTrue(e.getCause() instanceof CruiseControlException);
0239: final CruiseControlException cce = (CruiseControlException) e
0240: .getCause();
0241: assertEquals(MyAntBuilder.MSG_FORCED_FAILURE, cce
0242: .getMessage());
0243: }
0244: assertTrue(antBuilder.isValidateCalled());
0245: assertTrue(antBuilder.isBuildCalled());
0246: } finally {
0247: agentImpl.clearOutputFiles();
0248: }
0249: }
0250:
0251: public void testInjectAntProgressLoggerLibIfNeeded()
0252: throws Exception {
0253: hideAntProgressLoggerLib();
0254: try {
0255:
0256: final AntBuilder antBuilder = new AntBuilder();
0257:
0258: // should attempt injection
0259: try {
0260: BuildAgentServiceImpl
0261: .injectAntProgressLoggerLibIfNeeded(antBuilder);
0262: fail("Expected JNLP Basic Service to be unavailable");
0263: } catch (JNLPServiceUtil.JNLPServiceException e) {
0264: assertTrue(
0265: "Unexpected exception cause.",
0266: e.getCause() instanceof UnavailableServiceException);
0267: }
0268:
0269: // test found via default lib location
0270: unhideAntProgressLoggerLib();
0271: BuildAgentServiceImpl
0272: .injectAntProgressLoggerLibIfNeeded(antBuilder);
0273: hideAntProgressLoggerLib();
0274:
0275: // test path already set
0276: antBuilder
0277: .setProgressLoggerLib("someProgressLoggerLibPath");
0278: BuildAgentServiceImpl
0279: .injectAntProgressLoggerLibIfNeeded(antBuilder);
0280: } finally {
0281: unhideAntProgressLoggerLib();
0282: }
0283: }
0284:
0285: public void testInjectAntProgressLoggerLibIfNeededWithComposite()
0286: throws Exception {
0287: hideAntProgressLoggerLib();
0288: try {
0289: final CompositeBuilder compositeBuilder = new CompositeBuilder();
0290: BuildAgentServiceImpl
0291: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0292:
0293: compositeBuilder.add(new MockBuilder());
0294: BuildAgentServiceImpl
0295: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0296:
0297: final AntBuilder antBuilder = new AntBuilder();
0298: compositeBuilder.add(antBuilder);
0299:
0300: // should attempt injection
0301: try {
0302: BuildAgentServiceImpl
0303: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0304: fail("Expected JNLP Basic Service to be unavailable");
0305: } catch (JNLPServiceUtil.JNLPServiceException e) {
0306: assertTrue(
0307: "Unexpected exception cause.",
0308: e.getCause() instanceof UnavailableServiceException);
0309: }
0310: // test path already set
0311: antBuilder
0312: .setProgressLoggerLib("someProgressLoggerLibPath");
0313: BuildAgentServiceImpl
0314: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0315:
0316: // test with composite inside composite
0317: final CompositeBuilder compositeBuilder2 = new CompositeBuilder();
0318: compositeBuilder.add(compositeBuilder2);
0319: BuildAgentServiceImpl
0320: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0321:
0322: final AntBuilder antBuilder2 = new AntBuilder();
0323: compositeBuilder2.add(antBuilder2);
0324: // should attempt injection
0325: try {
0326: BuildAgentServiceImpl
0327: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0328: fail("Expected JNLP Basic Service to be unavailable");
0329: } catch (JNLPServiceUtil.JNLPServiceException e) {
0330: assertTrue(
0331: "Unexpected exception cause.",
0332: e.getCause() instanceof UnavailableServiceException);
0333: }
0334: // test path already set
0335: antBuilder2
0336: .setProgressLoggerLib("someProgressLoggerLibPath");
0337: BuildAgentServiceImpl
0338: .injectAntProgressLoggerLibIfNeeded(compositeBuilder);
0339: } finally {
0340: unhideAntProgressLoggerLib();
0341: }
0342: }
0343:
0344: public void testBuildOverrideTarget() throws Exception {
0345: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0346: null);
0347: agentImpl
0348: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0349:
0350: final Map distributedAgentProps = new HashMap();
0351: // build w/out override to verify null target value after build
0352: distributedAgentProps.put(
0353: PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET, null);
0354:
0355: final MockBuilder mockBuilder = createMockBuilder(false,
0356: REMOTE_RESULTS_EMPTY);
0357: assertNull(mockBuilder.getTarget());
0358:
0359: final Map projectProperties = new HashMap();
0360: projectProperties.put(PropertiesHelper.PROJECT_NAME,
0361: TEST_PROJECT_SUCCESS);
0362:
0363: try {
0364: assertNotNull(agentImpl.doBuild(mockBuilder,
0365: projectProperties, distributedAgentProps, null,
0366: REMOTE_RESULTS_EMPTY));
0367: clearDefaultSuccessResultDirs();
0368: assertNull(mockBuilder.getTarget());
0369: } finally {
0370: agentImpl.clearOutputFiles();
0371: }
0372:
0373: // build with override
0374: distributedAgentProps.put(
0375: PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET,
0376: TEST_PROJECT_SUCCESS);
0377: assertNull(mockBuilder.getTarget());
0378: try {
0379: assertNotNull(agentImpl.doBuild(mockBuilder,
0380: projectProperties, distributedAgentProps, null,
0381: REMOTE_RESULTS_EMPTY));
0382: clearDefaultSuccessResultDirs();
0383: assertEquals(TEST_PROJECT_SUCCESS, mockBuilder.getTarget());
0384: } finally {
0385: agentImpl.clearOutputFiles();
0386: }
0387: }
0388:
0389: /**
0390: * Re-use of builder caused problems with null value in overrideTarget.
0391: * This test verifies null values in the Map are allowed.
0392: * @throws Exception if anything unexpected goes wrong in the test
0393: */
0394: public void testGetPropertiesMap() throws Exception {
0395: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0396: null);
0397: agentImpl
0398: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0399:
0400: MyAgentStatusListener agentListener = new MyAgentStatusListener();
0401: agentImpl.addAgentStatusListener(agentListener);
0402:
0403: String agentAsString = agentImpl.asString();
0404: assertTrue("Wrong value: " + agentAsString, agentAsString
0405: .startsWith("Machine Name: "));
0406:
0407: String expectedSuffix = "Busy: false;\tSince: null;\tProject: null\n\t"
0408: + "Pending Restart: false;\tPending Restart Since: null\n\t"
0409: + "Pending Kill: false;\tPending Kill Since: null"
0410: + EXPECTED_SUFFIX_AS_STRING_VER;
0411: assertTrue("Wrong value: \n" + agentAsString
0412: + "\n expected suffix: \n" + expectedSuffix,
0413: agentAsString.endsWith(expectedSuffix));
0414:
0415: final Map distributedAgentProps = new HashMap();
0416: final String testProjectName = "testProjectName";
0417: final Map projectProperties = new HashMap();
0418: projectProperties.put(PropertiesHelper.PROJECT_NAME,
0419: testProjectName);
0420:
0421: distributedAgentProps.put(
0422: PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET, null);
0423: try {
0424: // fails at nestedBuilder.validate() due to null nestedBuilder
0425: agentImpl.doBuild(null, projectProperties,
0426: distributedAgentProps, null, null);
0427: fail("should fail w/ NPE");
0428: } catch (NullPointerException e) {
0429: assertEquals(null, e.getMessage());
0430: }
0431: assertEquals("Wrong agent status change count", 2,
0432: agentListener.getAgentStatusChangeCount());
0433:
0434: distributedAgentProps
0435: .remove(PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET);
0436: agentImpl.setBusy(false);
0437: agentListener.resetAgentStatusChangeCount();
0438: try {
0439: // gets far enough to fire 2nd agent status change
0440: agentImpl.doBuild(null, projectProperties,
0441: distributedAgentProps, null, null);
0442: fail("should fail w/ NPE");
0443: } catch (NullPointerException e) {
0444: assertEquals(null, e.getMessage());
0445: }
0446: assertEquals("Wrong agent status", 2, agentListener
0447: .getAgentStatusChangeCount());
0448:
0449: agentAsString = agentImpl.asString();
0450: assertTrue("Wrong value: " + agentAsString, agentAsString
0451: .startsWith("Machine Name: "));
0452: assertTrue("Wrong value: " + agentAsString, agentAsString
0453: .indexOf("Busy: true;\tSince: ") > -1);
0454:
0455: expectedSuffix = ";\tProject: "
0456: + testProjectName
0457: + "\n\tPending Restart: false;\tPending Restart Since: null\n\t"
0458: + "Pending Kill: false;\tPending Kill Since: null"
0459: + EXPECTED_SUFFIX_AS_STRING_VER;
0460:
0461: assertTrue("Wrong value: \n" + agentAsString
0462: + "\n expected suffix: \n" + expectedSuffix,
0463: agentAsString.endsWith(expectedSuffix));
0464: }
0465:
0466: public void testAsString() throws Exception {
0467: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0468: null);
0469: agentImpl
0470: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0471:
0472: String agentAsString = agentImpl.asString();
0473: assertTrue("Wrong value: " + agentAsString, agentAsString
0474: .startsWith("Machine Name: "));
0475: assertTrue(
0476: "Wrong value: " + agentAsString,
0477: agentAsString
0478: .endsWith("Busy: false;\tSince: null;\tProject: null\n\t"
0479: + "Pending Restart: false;\tPending Restart Since: null\n\t"
0480: + "Pending Kill: false;\tPending Kill Since: null"
0481: + EXPECTED_SUFFIX_AS_STRING_VER));
0482:
0483: final Map distributedAgentProps = new HashMap();
0484:
0485: final String testProjectName = "testProjectName";
0486: final Map projectProperties = new HashMap();
0487: projectProperties.put(PropertiesHelper.PROJECT_NAME,
0488: testProjectName);
0489:
0490: try {
0491: // gets far enough to set Project name...
0492: agentImpl.doBuild(null, projectProperties,
0493: distributedAgentProps, null, null);
0494: fail("should fail w/ NPE");
0495: } catch (NullPointerException e) {
0496: assertEquals(null, e.getMessage());
0497: }
0498:
0499: agentAsString = agentImpl.asString();
0500: assertTrue("Wrong value: " + agentAsString, agentAsString
0501: .startsWith("Machine Name: "));
0502: assertTrue("Wrong value: " + agentAsString, agentAsString
0503: .indexOf("Busy: true;\tSince: ") > -1);
0504: assertTrue(
0505: "Wrong value: " + agentAsString,
0506: agentAsString
0507: .endsWith(";\tProject: "
0508: + testProjectName
0509: + "\n\tPending Restart: false;\tPending Restart Since: null\n\t"
0510: + "Pending Kill: false;\tPending Kill Since: null"
0511: + EXPECTED_SUFFIX_AS_STRING_VER));
0512:
0513: agentImpl.kill(true);
0514: agentAsString = agentImpl.asString();
0515: assertTrue("Wrong value: " + agentAsString, agentAsString
0516: .indexOf("Busy: true;\tSince: ") > -1);
0517: assertTrue(
0518: "Wrong value: " + agentAsString,
0519: agentAsString
0520: .indexOf(";\tProject: "
0521: + testProjectName
0522: + "\n\tPending Restart: false;\tPending Restart Since: null\n\t"
0523: + "Pending Kill: true;\tPending Kill Since: ") > -1);
0524: assertNotNull(agentImpl.getPendingKillSince());
0525:
0526: agentImpl.setBusy(false); // fake build finish
0527: assertTrue("Pending kill should keep agent marked busy",
0528: agentImpl.isBusy());
0529: agentAsString = agentImpl.asString();
0530: assertTrue(
0531: "Wrong value: " + agentAsString,
0532: agentAsString
0533: .indexOf("Pending Restart: false;\tPending Restart Since: null\n\t"
0534: + "Pending Kill: true;\tPending Kill Since: ") > -1);
0535: assertNotNull(agentImpl.getPendingKillSince());
0536: }
0537:
0538: public void testGetBuildingProject() throws Exception {
0539: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0540: null);
0541: agentImpl
0542: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0543:
0544: assertNull(agentImpl.getProjectName());
0545:
0546: final Map distributedAgentProps = new HashMap();
0547:
0548: final String testProjectName = "testProjectName";
0549: final Map projectProperties = new HashMap();
0550: projectProperties.put(PropertiesHelper.PROJECT_NAME,
0551: testProjectName);
0552:
0553: try {
0554: // gets far enough to set Project name...
0555: agentImpl.doBuild(null, projectProperties,
0556: distributedAgentProps, null, null);
0557: fail("should fail w/ NPE");
0558: } catch (NullPointerException e) {
0559: assertEquals(null, e.getMessage());
0560: }
0561:
0562: assertEquals(testProjectName, agentImpl.getProjectName());
0563:
0564: agentImpl.setBusy(false); // fake build finish
0565: assertNull(agentImpl.getProjectName());
0566: }
0567:
0568: public void testKillNoWait() throws Exception {
0569: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0570: null);
0571: agentImpl
0572: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0573:
0574: assertFalse(agentImpl.isBusy());
0575: assertFalse(agentImpl.isPendingKill());
0576: assertNull(agentImpl.getPendingKillSince());
0577: assertFalse(agentImpl.isPendingRestart());
0578: assertNull(agentImpl.getPendingRestartSince());
0579: // make agent think it's building now
0580: agentImpl.claim();
0581: assertTrue(agentImpl.isBusy());
0582: assertFalse(agentImpl.isPendingKill());
0583: assertFalse(agentImpl.isPendingRestart());
0584: agentImpl.kill(false);
0585: assertTrue(agentImpl.isBusy());
0586: assertTrue(agentImpl.isPendingKill());
0587: assertNotNull(agentImpl.getPendingKillSince());
0588: assertFalse(agentImpl.isPendingRestart());
0589: assertNull(agentImpl.getPendingRestartSince());
0590:
0591: // fake finish agent build - not really needed here
0592: agentImpl.setBusy(false);
0593: }
0594:
0595: public void testRestartNoWait() throws Exception {
0596: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0597: null);
0598: agentImpl
0599: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0600:
0601: assertFalse(agentImpl.isBusy());
0602: assertFalse(agentImpl.isPendingKill());
0603: assertNull(agentImpl.getPendingKillSince());
0604: assertFalse(agentImpl.isPendingRestart());
0605: assertNull(agentImpl.getPendingRestartSince());
0606: // make agent think it's building now
0607: agentImpl.claim();
0608: assertTrue(agentImpl.isBusy());
0609: assertFalse(agentImpl.isPendingKill());
0610: assertFalse(agentImpl.isPendingRestart());
0611: // fake finish agent build
0612: try {
0613: agentImpl.restart(false);
0614: fail("Restart should fail outside of webstart");
0615: } catch (RuntimeException e) {
0616: assertEquals(
0617: "Couldn't find webstart Basic Service. Is Agent running outside of webstart?",
0618: e.getMessage());
0619: }
0620: assertTrue(agentImpl.isBusy());
0621: assertFalse(agentImpl.isPendingKill());
0622: assertNull(agentImpl.getPendingKillSince());
0623: assertTrue(agentImpl.isPendingRestart());
0624: assertNotNull(agentImpl.getPendingRestartSince());
0625: }
0626:
0627: public void testKillWithWait() throws Exception {
0628: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0629: null);
0630: agentImpl
0631: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0632:
0633: assertFalse(agentImpl.isBusy());
0634: assertFalse(agentImpl.isPendingKill());
0635: assertNull(agentImpl.getPendingKillSince());
0636: assertFalse(agentImpl.isPendingRestart());
0637: assertNull(agentImpl.getPendingRestartSince());
0638: // make agent think it's building now
0639: agentImpl.claim();
0640: assertTrue(agentImpl.isBusy());
0641: assertFalse(agentImpl.isPendingKill());
0642: assertFalse(agentImpl.isPendingRestart());
0643: agentImpl.kill(true);
0644: assertTrue(agentImpl.isBusy());
0645: assertTrue(agentImpl.isPendingKill());
0646: assertNotNull(agentImpl.getPendingKillSince());
0647: assertFalse(agentImpl.isPendingRestart());
0648:
0649: // fake finish agent build
0650: agentImpl.setBusy(false);
0651: }
0652:
0653: public void testRestartWithWait() throws Exception {
0654: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
0655: null);
0656: agentImpl
0657: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
0658:
0659: assertFalse(agentImpl.isBusy());
0660: assertFalse(agentImpl.isPendingKill());
0661: assertNull(agentImpl.getPendingKillSince());
0662: assertFalse(agentImpl.isPendingRestart());
0663: assertNull(agentImpl.getPendingRestartSince());
0664: // make agent think it's building now
0665: agentImpl.claim();
0666: assertTrue(agentImpl.isBusy());
0667: assertFalse(agentImpl.isPendingKill());
0668: assertNull(agentImpl.getPendingRestartSince());
0669: assertFalse(agentImpl.isPendingRestart());
0670: assertNull(agentImpl.getPendingRestartSince());
0671: assertNull(agentImpl.getLastDelayedAction());
0672: agentImpl.restart(true);
0673: assertTrue(agentImpl.isBusy());
0674: assertFalse(agentImpl.isPendingKill());
0675: assertTrue(agentImpl.isPendingRestart());
0676: assertNotNull(agentImpl.getPendingRestartSince());
0677:
0678: // use a fairly short delay in unit test
0679: System
0680: .setProperty(
0681: BuildAgentServiceImpl.SYSPROP_CCDIST_DELAY_MS_KILLRESTART,
0682: KILL_DELAY + "");
0683:
0684: // fake finish agent build
0685: assertTrue(agentImpl.isBusy());
0686: agentImpl.setBusy(false);
0687: assertTrue("Agent should still be busy due to pending restart",
0688: agentImpl.isBusy());
0689: assertNotNull(agentImpl.getLastDelayedAction());
0690: assertEquals(BuildAgentServiceImpl.DelayedAction.Type.RESTART,
0691: agentImpl.getLastDelayedAction().getType());
0692: waitForDelayedAction(agentImpl);
0693:
0694: assertEquals(
0695: "Couldn't find webstart Basic Service. Is Agent running outside of webstart?",
0696: agentImpl.getLastDelayedAction().getThrown()
0697: .getMessage());
0698: }
0699:
0700: public void testRecursiveFilesExist() throws Exception {
0701: final File testDir = new File(DIR_LOGS, "testDir");
0702: testDir.deleteOnExit();
0703: assertFalse("Non-existant base dir should show empty",
0704: BuildAgentServiceImpl.recursiveFilesExist(testDir));
0705:
0706: final File testDirSub = new File(testDir, "testSubDir");
0707: testDirSub.deleteOnExit();
0708:
0709: final File testDirSubSub = new File(testDirSub, "testSubSubDir");
0710: testDirSubSub.deleteOnExit();
0711:
0712: final File testFileSub = new File(testDirSub, "testFileSub");
0713: testFileSub.deleteOnExit();
0714:
0715: try {
0716: Util.doMkDirs(testDir);
0717: assertFalse("Existant, empty base dir should show empty",
0718: BuildAgentServiceImpl.recursiveFilesExist(testDir));
0719:
0720: Util.doMkDirs(testDirSub);
0721: assertFalse(
0722: "Existant, empty base dir, empty sub dir should show empty",
0723: BuildAgentServiceImpl.recursiveFilesExist(testDir));
0724:
0725: Util.doMkDirs(testDirSubSub);
0726: assertFalse(
0727: "Existant, empty base dir, empty sub, empty sub 2 should show empty",
0728: BuildAgentServiceImpl.recursiveFilesExist(testDir));
0729:
0730: testFileSub.createNewFile();
0731: assertTrue(
0732: "Existant, empty base dir, non-empty sub dir should show files exist",
0733: BuildAgentServiceImpl.recursiveFilesExist(testDir));
0734:
0735: } finally {
0736: testDirSubSub.delete();
0737: testFileSub.delete();
0738: testDirSub.delete();
0739: testDir.delete();
0740: }
0741: }
0742:
0743: public void testRemoteResultOneExistsOneEmpty() throws Exception {
0744: // test the case where one RemoteResult exists, but a second does not
0745: final String resultType = PropertiesHelper.RESULT_TYPE_DIR;
0746: final RemoteResult[] remoteResults = REMOTE_RESULTS_TWO_WITHEMPTYDIR;
0747:
0748: final File resultTypeBaseDir = new File(resultType);
0749:
0750: final File testDirResult = new File(
0751: resultTypeBaseDir,
0752: (PropertiesHelper.RESULT_TYPE_LOGS.equals(resultType) ? "myTest"
0753: + resultType + "Dir"
0754: : TEST_PROJECT_SUCCESS)); // use default dir since no property is set
0755:
0756: testDirResult.deleteOnExit();
0757: Util.doMkDirs(testDirResult);
0758:
0759: REMOTE_RESULTS_TWO_WITHEMPTYDIR[1].getAgentDir().deleteOnExit();
0760: Util.doMkDirs(REMOTE_RESULTS_TWO_WITHEMPTYDIR[1].getAgentDir());
0761:
0762: final Map distributedAgentProps = new HashMap();
0763: distributedAgentProps.put(
0764: PropertiesHelper.DISTRIBUTED_AGENT_LOGDIR,
0765: testDirResult.getAbsolutePath());
0766: final BuildAgentServiceImpl agentImpl = createTestAgentDoBuild(
0767: false, distributedAgentProps, remoteResults);
0768: // clear out default result dirs
0769: clearDefaultSuccessResultDirs();
0770: // second RemoteResult dir is left empty by MockBuilder
0771:
0772: try {
0773: assertFalse(agentImpl.remoteResultExists(0));
0774: assertFalse(agentImpl.remoteResultExists(1));
0775: // make file in first RemoteResultDir
0776: new File(resultTypeBaseDir, "testRemoteResult1")
0777: .createNewFile();
0778: assertTrue(agentImpl.remoteResultExists(0));
0779: assertFalse(agentImpl.remoteResultExists(1));
0780:
0781: assertTrue(agentImpl.retrieveRemoteResult(0).length > 0);
0782: // second RemoteResult dir is left empty by MockBuilder
0783: try {
0784: agentImpl.retrieveRemoteResult(1);
0785: fail("retrieveRemoteResult on missing result should fail");
0786: } catch (RuntimeException e) {
0787: assertEquals("Unable to get remote result file: "
0788: + REMOTE_RESULTS_TWO_WITHEMPTYDIR[1]
0789: .getAgentDir().getAbsolutePath(), e
0790: .getMessage());
0791: }
0792: } finally {
0793: // cleanup left over files
0794: agentImpl.clearOutputFiles();
0795: testDirResult.delete();
0796: deleteDirConfirm(REMOTE_RESULTS_TWO_WITHEMPTYDIR[1]
0797: .getAgentDir());
0798: }
0799: }
0800:
0801: public void testResultsExistAfterBuild() throws Exception {
0802: checkResultsExistByType(PropertiesHelper.RESULT_TYPE_LOGS,
0803: REMOTE_RESULTS_EMPTY);
0804: checkResultsExistByType(PropertiesHelper.RESULT_TYPE_OUTPUT,
0805: REMOTE_RESULTS_EMPTY);
0806: checkResultsExistByType(PropertiesHelper.RESULT_TYPE_DIR,
0807: REMOTE_RESULTS_ONE);
0808: }
0809:
0810: private static void checkResultsExistByType(
0811: final String resultType, final RemoteResult[] remoteResults)
0812: throws IOException {
0813:
0814: final File resultTypeBaseDir = new File(resultType);
0815:
0816: final File testDirResult = new File(
0817: resultTypeBaseDir,
0818: (PropertiesHelper.RESULT_TYPE_LOGS.equals(resultType) ? "myTest"
0819: + resultType + "Dir"
0820: : TEST_PROJECT_SUCCESS)); // use default dir since no property is set
0821:
0822: testDirResult.deleteOnExit();
0823: Util.doMkDirs(testDirResult);
0824:
0825: final Map distributedAgentProps = new HashMap();
0826: distributedAgentProps.put(
0827: PropertiesHelper.DISTRIBUTED_AGENT_LOGDIR,
0828: testDirResult.getAbsolutePath());
0829: final BuildAgentServiceImpl agentImpl = createTestAgentDoBuild(
0830: false, distributedAgentProps, remoteResults);
0831: // clear out default result dirs
0832: clearDefaultSuccessResultDirs();
0833:
0834: final File testFileResult = new File(testDirResult,
0835: "myTestFile");
0836: final File testDirResultSub = new File(testDirResult,
0837: "myTestResultSubDir");
0838: testDirResultSub.deleteOnExit();
0839: final File testDirResultSubSub = new File(testDirResultSub,
0840: "myTestSubSubDir");
0841: testDirResultSubSub.deleteOnExit();
0842: final File testFileSub = new File(testDirResultSub,
0843: "myTestFileSub");
0844:
0845: // test behavior if log dir exists, and is empty except for sub dirs.
0846: // use case: subdirs hold test report files, and a compile error occurs
0847: // before unit tests are run, and hence no test log files have been created yet
0848: // in sub dirs.
0849: try {
0850: assertResultsExistByType(null, false, resultType, agentImpl);
0851: Util.doMkDirs(testDirResultSubSub);
0852: assertResultsExistByType(
0853: "Result dir with no files, only subdirs, should be considered empty",
0854: false, resultType, agentImpl);
0855:
0856: testFileSub.createNewFile();
0857: assertResultsExistByType(
0858: "Any file in tree should produce results", true,
0859: resultType, agentImpl);
0860:
0861: testFileResult.createNewFile();
0862: testFileResult.deleteOnExit();
0863: assertResultsExistByType(
0864: "Multiple files in tree should produce results",
0865: true, resultType, agentImpl);
0866:
0867: } finally {
0868: // cleanup left over files
0869: agentImpl.clearOutputFiles();
0870: testFileSub.delete();
0871: testFileResult.delete();
0872: testDirResultSubSub.delete();
0873: testDirResultSub.delete();
0874: testDirResult.delete();
0875: }
0876: }
0877:
0878: private static void assertResultsExistByType(final String msg,
0879: final boolean expectedExists, final String resultType,
0880: BuildAgentServiceImpl agentImpl) throws RemoteException {
0881:
0882: if (PropertiesHelper.RESULT_TYPE_DIR.equals(resultType)) {
0883: assertEquals(msg, expectedExists, agentImpl
0884: .remoteResultExists(0));
0885: } else {
0886: assertEquals(msg, expectedExists, agentImpl
0887: .resultsExist(resultType));
0888: }
0889: }
0890:
0891: private static void clearDefaultSuccessResultDirs() {
0892:
0893: final File tmpLogSuccessDir = new File(DIR_LOGS,
0894: TEST_PROJECT_SUCCESS);
0895: new File(tmpLogSuccessDir, "TEST-bogustestclassSuccess.xml")
0896: .delete();
0897: deleteDirConfirm(tmpLogSuccessDir);
0898:
0899: final File tmpOutputSuccessDir = new File(DIR_OUTPUT,
0900: TEST_PROJECT_SUCCESS);
0901: new File(tmpOutputSuccessDir, "testoutputSuccess").delete();
0902: deleteDirConfirm(tmpOutputSuccessDir);
0903:
0904: final File tmpResultSuccessDir = new File(DIR_FILE,
0905: TEST_PROJECT_SUCCESS);
0906: new File(tmpResultSuccessDir, "remoteResult").delete();
0907: deleteDirConfirm(tmpResultSuccessDir);
0908: }
0909:
0910: public void testRetrieveResultsWithAgentLogDir() throws Exception {
0911: final File testLogDir = new File(DIR_LOGS, "myTestLogDir");
0912: testLogDir.deleteOnExit();
0913: Util.doMkDirs(testLogDir);
0914:
0915: final Map distributedAgentProps = new HashMap();
0916: distributedAgentProps.put(
0917: PropertiesHelper.DISTRIBUTED_AGENT_LOGDIR, testLogDir
0918: .getAbsolutePath());
0919:
0920: final BuildAgentServiceImpl agentImpl = createTestAgentDoBuild(
0921: false, distributedAgentProps, REMOTE_RESULTS_EMPTY);
0922: // delete result zips here to avoid left overs when prepareLogsAndArtifacts() is called below.
0923: //assertTrue(agentImpl.getResultsZip(PropertiesHelper.RESULT_TYPE_LOGS).delete());
0924: assertTrue(agentImpl.getResultsZip(
0925: PropertiesHelper.RESULT_TYPE_OUTPUT).delete());
0926:
0927: // clear out default log dir
0928: clearDefaultSuccessResultDirs();
0929:
0930: final File testLog = new File(testLogDir, "myTestLog");
0931: final File testLogSubDir = new File(testLogDir,
0932: "myTestLogSubDir");
0933: testLogSubDir.deleteOnExit();
0934: final File testLogSubSubDir = new File(testLogSubDir,
0935: "myTestLogSubSubDir");
0936: testLogSubSubDir.deleteOnExit();
0937: final File testLogSub = new File(testLogSubDir,
0938: "myTestLogSubSubFile");
0939: try {
0940: // test behavior if log dir exists, and is empty except for sub dirs.
0941: // use case: subdirs hold test report files, and a compile error occurs
0942: // before unit tests are run, and hence no test log files have been created yet
0943: // in sub dirs.
0944: assertFalse(agentImpl
0945: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
0946: Util.doMkDirs(testLogSubSubDir);
0947: assertFalse(
0948: "Result dir with no files, only subdirs, should be considered empty",
0949: agentImpl
0950: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
0951: agentImpl.prepareLogsAndArtifacts();
0952: try {
0953: agentImpl
0954: .retrieveResultsAsZip(PropertiesHelper.RESULT_TYPE_LOGS);
0955: fail("Attempt to retrieve empty zip file should fail");
0956: } catch (RuntimeException e) {
0957: assertTrue(e.getMessage().startsWith(
0958: "Unable to get file "
0959: + new File(testLogDir.getParentFile()
0960: .getCanonicalPath())
0961: .getParentFile()
0962: .getCanonicalPath()));
0963: }
0964: testLogSub.createNewFile();
0965: assertTrue(
0966: "Any file in tree should produce results",
0967: agentImpl
0968: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
0969:
0970: // make sure agent looks in myTestLog dir for files
0971: testLog.createNewFile();
0972: testLog.deleteOnExit();
0973: assertTrue(agentImpl
0974: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
0975:
0976: assertFalse(
0977: "Default output files should have been deleted during unit test",
0978: agentImpl
0979: .resultsExist(PropertiesHelper.RESULT_TYPE_OUTPUT));
0980:
0981: assertTrue(
0982: "Agent should be busy until build results are retrived and cleared.",
0983: agentImpl.isBusy());
0984: } finally {
0985: // cleanup left over files
0986: agentImpl.clearOutputFiles();
0987: testLog.delete();
0988: testLogDir.delete();
0989: }
0990: assertFalse(agentImpl.isBusy());
0991: }
0992:
0993: public void testRetrieveResultsAsZipBuildSuccess() throws Exception {
0994: final BuildAgentServiceImpl agentImpl = createTestAgentDoBuild(
0995: false, new HashMap(), REMOTE_RESULTS_ONE);
0996: try {
0997: assertTrue(agentImpl
0998: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
0999: assertTrue(agentImpl
1000: .resultsExist(PropertiesHelper.RESULT_TYPE_OUTPUT));
1001: assertTrue(agentImpl.remoteResultExists(0));
1002: assertTrue(
1003: "Agent should be busy until build results are retrived and cleared.",
1004: agentImpl.isBusy());
1005:
1006: // make sure we can actually get the results
1007: assertNonEmptyResultsZip(agentImpl,
1008: PropertiesHelper.RESULT_TYPE_LOGS);
1009: assertNonEmptyResultsZip(agentImpl,
1010: PropertiesHelper.RESULT_TYPE_OUTPUT);
1011: assertNonEmptyResultsZip(agentImpl,
1012: PropertiesHelper.RESULT_TYPE_DIR);
1013: } finally {
1014: // cleanup left over files
1015: agentImpl.clearOutputFiles();
1016: }
1017: assertFalse(agentImpl.isBusy());
1018: }
1019:
1020: private static void assertNonEmptyResultsZip(
1021: final BuildAgentServiceImpl agentImpl,
1022: final String resultType) throws RemoteException {
1023:
1024: final byte[] resultZip;
1025: if (PropertiesHelper.RESULT_TYPE_DIR.equals(resultType)) {
1026: resultZip = agentImpl.retrieveRemoteResult(0);
1027: } else {
1028: resultZip = agentImpl.retrieveResultsAsZip(resultType);
1029: }
1030:
1031: assertNotNull("Null " + resultType + " zip bytes.", resultZip);
1032: assertTrue("Empty " + resultType + " zip bytes.",
1033: resultZip.length > 0);
1034: }
1035:
1036: public void testRetrieveResultsAsZipBuildFail() throws Exception {
1037: final BuildAgentServiceImpl agentImpl = createTestAgentDoBuild(
1038: true, new HashMap(), REMOTE_RESULTS_ONE);
1039: try {
1040: assertTrue(agentImpl
1041: .resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
1042: assertNonEmptyResultsZip(agentImpl,
1043: PropertiesHelper.RESULT_TYPE_LOGS);
1044:
1045: assertFalse(agentImpl
1046: .resultsExist(PropertiesHelper.RESULT_TYPE_OUTPUT));
1047: try {
1048: agentImpl
1049: .retrieveResultsAsZip(PropertiesHelper.RESULT_TYPE_OUTPUT);
1050: fail("should've failed retrieval of non-existant results.");
1051: } catch (RuntimeException e) {
1052: assertTrue(e.getMessage().startsWith(
1053: "Unable to get file "));
1054: }
1055:
1056: assertFalse(agentImpl.remoteResultExists(0));
1057: try {
1058: agentImpl.retrieveRemoteResult(0);
1059: fail("should've failed retrieval of non-existant results.");
1060: } catch (RuntimeException e) {
1061: assertTrue("Wrong message: " + e.getMessage(), e
1062: .getMessage().startsWith(
1063: "Unable to get remote result file: "));
1064: }
1065:
1066: assertTrue(
1067: "Agent should be busy until build results are retrived and cleared.",
1068: agentImpl.isBusy());
1069: } finally {
1070: // cleanup left over files
1071: agentImpl.clearOutputFiles();
1072: }
1073: assertFalse(agentImpl.isBusy());
1074: }
1075:
1076: public void testClearOutputFilesBuildValidateError()
1077: throws Exception {
1078:
1079: final Map projectProperties = new HashMap();
1080: projectProperties.put(PropertiesHelper.PROJECT_NAME,
1081: TEST_PROJECT_FAIL);
1082:
1083: final HashMap distributedAgentProps = new HashMap();
1084: final BuildAgentServiceImpl agentImpl = createTestAgent(distributedAgentProps);
1085: try {
1086: callTestDoBuild(projectProperties, agentImpl,
1087: distributedAgentProps, REMOTE_RESULTS_ONE, true);
1088: } catch (RemoteException e) {
1089: assertTrue("Wrong root cause of exception",
1090: e.getCause() instanceof CruiseControlException);
1091: CruiseControlException ce = (CruiseControlException) e
1092: .getCause();
1093: assertEquals("Wrong excecption msg",
1094: MSG_BUILDER_VALIDATE_FAIL, ce.getMessage());
1095: }
1096: try {
1097: // NOTE: prepareLogsAndArtifacts() sets log/output member vars, but is not called if
1098: // builder.validate() fails. May want to change this?
1099: //agentImpl.prepareLogsAndArtifacts();
1100: //assertFalse(agentImpl.resultsExist(PropertiesHelper.RESULT_TYPE_LOGS));
1101: //assertFalse(agentImpl.resultsExist(PropertiesHelper.RESULT_TYPE_OUTPUT));
1102:
1103: assertFalse(
1104: "Agent should NOT be busy after builder.validate() error.",
1105: agentImpl.isBusy());
1106: } finally {
1107: // cleanup left over files
1108: agentImpl.clearOutputFiles();
1109: }
1110: assertFalse(agentImpl.isBusy());
1111: }
1112:
1113: private static BuildAgentServiceImpl createTestAgentDoBuild(
1114: final boolean isBuildFailure,
1115: final Map distributedAgentProps,
1116: final RemoteResult[] remoteResults) throws RemoteException {
1117:
1118: final BuildAgentServiceImpl agentImpl = createTestAgent(distributedAgentProps);
1119:
1120: final Map projectProperties = new HashMap();
1121: if (isBuildFailure) {
1122: projectProperties.put(PropertiesHelper.PROJECT_NAME,
1123: TEST_PROJECT_FAIL);
1124: } else {
1125: projectProperties.put(PropertiesHelper.PROJECT_NAME,
1126: TEST_PROJECT_SUCCESS);
1127: }
1128:
1129: callTestDoBuild(projectProperties, agentImpl,
1130: distributedAgentProps, remoteResults, false);
1131:
1132: return agentImpl;
1133: }
1134:
1135: private static BuildAgentServiceImpl createTestAgent(
1136: final Map distributedAgentProps) {
1137: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
1138: null);
1139: agentImpl
1140: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
1141:
1142: if (!distributedAgentProps
1143: .containsKey(PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET)) {
1144: distributedAgentProps.put(
1145: PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET, null);
1146: }
1147:
1148: return agentImpl;
1149: }
1150:
1151: /**
1152: * Call doBuild() on a build that should succeed on the given agent using test settings
1153: * @param agent the build agent on which to run the build
1154: * @return the build result jdom element
1155: * @throws RemoteException if something else dies
1156: */
1157: public static Element callTestDoBuildSuccess(
1158: final BuildAgentService agent) throws RemoteException {
1159:
1160: final Map projectProperties = new HashMap();
1161: projectProperties.put(PropertiesHelper.PROJECT_NAME,
1162: TEST_PROJECT_SUCCESS);
1163:
1164: final Map distributedAgentProps = new HashMap();
1165: // handle re-use case of DMB when overrideTarget is null
1166: distributedAgentProps.put(
1167: PropertiesHelper.DISTRIBUTED_OVERRIDE_TARGET, null);
1168:
1169: return callTestDoBuild(projectProperties, agent,
1170: distributedAgentProps, REMOTE_RESULTS_ONE, false);
1171: }
1172:
1173: /**
1174: * Call doBuild() on the given agent using test settings
1175: * @param projectProperties map passed to build() method, contains "projectname" property
1176: * @param agent the build agent on which to run the build
1177: * @param distributedAgentProps the map of distributed props used by the build agent
1178: * @param remoteResults the array of (possible) build results to be returned from agent
1179: * @param isValidateFailure if true, force the builder.validate() call to fail.
1180: * @return the build result jdom element
1181: * @throws RemoteException if something else dies
1182: */
1183: private static Element callTestDoBuild(final Map projectProperties,
1184: final BuildAgentService agent,
1185: final Map distributedAgentProps,
1186: final RemoteResult[] remoteResults,
1187: final boolean isValidateFailure) throws RemoteException {
1188:
1189: final MockBuilder mockBuilder = createMockBuilder(
1190: isValidateFailure, remoteResults);
1191:
1192: return agent.doBuild(mockBuilder, projectProperties,
1193: distributedAgentProps, null, remoteResults);
1194: }
1195:
1196: private static final String MSG_BUILDER_VALIDATE_FAIL = "Unit Test forced builder.validate() failure.";
1197:
1198: private static class CCDistMockChildBuilder extends MockBuilder {
1199: final boolean isValidateFailure;
1200: final RemoteResult[] remoteResults;
1201:
1202: public CCDistMockChildBuilder(final boolean isValidateFailure,
1203: final RemoteResult[] remoteResults) {
1204: super ("testCCDistMockChildBuilder");
1205: this .isValidateFailure = isValidateFailure;
1206: this .remoteResults = remoteResults;
1207: }
1208:
1209: public void validate() throws CruiseControlException {
1210: super .validate();
1211: if (isValidateFailure) {
1212: throw new CruiseControlException(
1213: MSG_BUILDER_VALIDATE_FAIL);
1214: }
1215: }
1216:
1217: public Element build(Map properties, Progress progress) {
1218: final String projectName = (String) properties
1219: .get(PropertiesHelper.PROJECT_NAME);
1220:
1221: final boolean isBuildFailure = TEST_PROJECT_FAIL
1222: .equals(projectName);
1223:
1224: final Element retVal = super .build(properties, progress);
1225:
1226: // create a file in the expected dirs
1227: createExpectedBuildArtifact(new File("logs/" + projectName
1228: + "/TEST-bogustestclassSuccess.xml"));
1229: if (!isBuildFailure) {
1230: createExpectedBuildArtifact(new File("output/"
1231: + projectName + "/testoutputSuccess"));
1232:
1233: for (int i = 0; i < remoteResults.length; i++) {
1234: // skip artifact creation for empty RemoteResult test
1235: if (!REMOTE_RESULTS_TWO_WITHEMPTYDIR[1]
1236: .equals(remoteResults[i])) {
1237: createExpectedBuildArtifact(new File(
1238: remoteResults[i].getAgentDir(),
1239: projectName + "/remoteResult"));
1240: }
1241: }
1242: }
1243:
1244: return retVal;
1245: }
1246: }
1247:
1248: private static MockBuilder createMockBuilder(
1249: final boolean isValidateFailure,
1250: final RemoteResult[] remoteResults) {
1251: return new CCDistMockChildBuilder(isValidateFailure,
1252: remoteResults);
1253: }
1254:
1255: private static void createExpectedBuildArtifact(
1256: File buildProducedFile) {
1257: if (!buildProducedFile.getParentFile().exists()) {
1258: Util.doMkDirs(buildProducedFile.getParentFile());
1259: }
1260: try {
1261: if (!buildProducedFile.exists()) {
1262: assertTrue(buildProducedFile.createNewFile());
1263: }
1264: } catch (IOException e) {
1265: fail("couldn't create expected output build produced file: "
1266: + buildProducedFile.getAbsolutePath());
1267: }
1268: buildProducedFile.deleteOnExit();
1269: buildProducedFile.getParentFile().deleteOnExit();
1270: buildProducedFile.getParentFile().getParentFile()
1271: .deleteOnExit();
1272: }
1273:
1274: public void testClaim() {
1275: final BuildAgentServiceImpl agentImpl = createAndClaimNewBuildAgent();
1276: final Date firstClaimDate = agentImpl.getDateClaimed();
1277:
1278: try {
1279: agentImpl.claim();
1280: fail("Should throw exception if attempt is made to claim a busy agent");
1281: } catch (IllegalStateException e) {
1282: assertTrue(
1283: "Unexpected error message w/ invalid call to claim(): "
1284: + e.getMessage(), e.getMessage()
1285: .startsWith("Cannot claim agent on "));
1286: assertTrue(
1287: "Unexpected error message w/ invalid call to claim(): "
1288: + e.getMessage(), e.getMessage().indexOf(
1289: "that is busy building project: null") > 0);
1290: }
1291: assertEquals(firstClaimDate, agentImpl.getDateClaimed());
1292:
1293: releaseClaimedAgent(agentImpl, firstClaimDate);
1294: }
1295:
1296: // NOTE: Can't do test w/ RestartPending, since Restart requires Agent running in Webstart.
1297: public void testClaimWhileKillPending() throws Exception {
1298: final BuildAgentServiceImpl agentImpl = createAndClaimNewBuildAgent();
1299: final Date firstClaimDate = agentImpl.getDateClaimed();
1300:
1301: // use a fairly short delay in unit test
1302: System
1303: .setProperty(
1304: BuildAgentServiceImpl.SYSPROP_CCDIST_DELAY_MS_KILLRESTART,
1305: KILL_DELAY + "");
1306:
1307: // set a pending Restart
1308: agentImpl.kill(true);
1309:
1310: assertFalse("Kill should not have executed.", agentImpl
1311: .isDoKillExecuted());
1312:
1313: // call doBuild() on agent
1314: callDoBuildWithNulls(agentImpl, firstClaimDate);
1315:
1316: assertEquals(
1317: "Agent kill should be delayed "
1318: + KILL_DELAY
1319: + " milliseconds, and agent should be busy during delay.",
1320: true, agentImpl.isBusy());
1321: assertFalse("Kill should not have executed.", agentImpl
1322: .isDoKillExecuted());
1323:
1324: // wait for doKill to execute
1325: waitForDelayedAction(agentImpl);
1326:
1327: assertTrue("Kill should have executed.", agentImpl
1328: .isDoKillExecuted());
1329:
1330: // Agent will still show as "claimed" in unit tests (since it can't system.exit).
1331: // That is the correct behavior since is prevents agent from being acquired while
1332: // an action is pending.
1333: assertEquals(
1334: "Agent should be busy after doKill executes in unit test.",
1335: true, agentImpl.isBusy());
1336: assertEquals(firstClaimDate, agentImpl.getDateClaimed());
1337: }
1338:
1339: private static void waitForDelayedAction(
1340: BuildAgentServiceImpl agentImpl)
1341: throws InterruptedException {
1342: // wait for Restart() outside of webstart exception
1343: final long begin = System.currentTimeMillis();
1344:
1345: final BuildAgentServiceImpl.DelayedAction delayedAction = agentImpl
1346: .getLastDelayedAction();
1347: assertNotNull("Last DelayedAction should not be null",
1348: delayedAction);
1349:
1350: final BuildAgentServiceImpl.DelayedAction.FinishedListener finishedListener = new BuildAgentServiceImpl.DelayedAction.FinishedListener() {
1351:
1352: public void finished(
1353: final BuildAgentServiceImpl.DelayedAction delayedAction) {
1354: synchronized (delayedAction) {
1355: delayedAction.notifyAll();
1356: }
1357: }
1358: };
1359:
1360: delayedAction.setFinishedListener(finishedListener);
1361: try {
1362: synchronized (delayedAction) {
1363: int count = 0;
1364: while (!delayedAction.isFinished() && count < 6) {
1365: delayedAction.wait(10 * 1000);
1366: count++;
1367: }
1368: }
1369: } finally {
1370: delayedAction.setFinishedListener(null);
1371: }
1372:
1373: final float elapsedSecs = (System.currentTimeMillis() - begin) / 1000f;
1374:
1375: assertTrue(
1376: "Delayed action didn't finish before timeout. elapsed: \n"
1377: + elapsedSecs + " sec", delayedAction
1378: .isFinished());
1379:
1380: LOG.info(DistributedMasterBuilderTest.MSG_PREFIX_STATS
1381: + "Unit test Agent Delayed Action took: " + elapsedSecs
1382: + " sec");
1383: }
1384:
1385: // @todo should agent expose a release() method to clear busy flag? Very dangerous if agent is building...
1386: private static void releaseClaimedAgent(
1387: BuildAgentServiceImpl agentImpl, Date firstClaimDate) {
1388: callDoBuildWithNulls(agentImpl, firstClaimDate);
1389:
1390: assertFalse(
1391: "Expected agent busy flag to be false after cleanup call.",
1392: agentImpl.isBusy());
1393: assertNull(agentImpl.getDateClaimed());
1394: }
1395:
1396: private static void callDoBuildWithNulls(
1397: BuildAgentServiceImpl agentImpl, Date firstClaimDate) {
1398: try {
1399: agentImpl.doBuild(null, null, null, null, null);
1400: fail("Should have failed to build");
1401: } catch (NullPointerException e) {
1402: assertEquals("Unexpected build error: " + e.getMessage(),
1403: null, e.getMessage());
1404: } catch (RemoteException e) {
1405: assertTrue(
1406: "Unexpected build error: " + e.getMessage(),
1407: e
1408: .getMessage()
1409: .startsWith(
1410: "Failed to complete build on agent; nested exception is: \n"
1411: + "\tnet.sourceforge.cruisecontrol.CruiseControlException: ant logfile "));
1412: }
1413: assertEquals(firstClaimDate, agentImpl.getDateClaimed());
1414:
1415: // we now avoid NPE error during cleanup since logDir and outputDir can be null
1416: agentImpl.clearOutputFiles();
1417: }
1418:
1419: private static BuildAgentServiceImpl createAndClaimNewBuildAgent() {
1420:
1421: final BuildAgentServiceImpl agentImpl = new BuildAgentServiceImpl(
1422: null);
1423: agentImpl
1424: .setAgentPropertiesFilename(TEST_AGENT_PROPERTIES_FILE);
1425:
1426: assertFalse(agentImpl.isBusy());
1427: assertNull(agentImpl.getDateClaimed());
1428: agentImpl.claim();
1429: assertTrue(agentImpl.isBusy());
1430: assertNotNull(agentImpl.getDateClaimed());
1431: return agentImpl;
1432: }
1433: }
|