1 package net.sourceforge.cruisecontrol.builders; 2 3 import junit.framework.TestCase; 4 5 import java.util.Properties ; 6 import java.util.Arrays ; 7 import java.util.List ; 8 import java.io.File ; 9 import java.io.PrintWriter ; 10 import java.io.IOException ; 11 import java.io.EOFException ; 12 import java.net.URL ; 13 import java.net.InetAddress ; 14 import java.net.ConnectException ; 15 import java.net.SocketException ; 16 import java.net.MalformedURLException ; 17 18 import org.apache.tools.ant.types.FileSet; 19 import org.apache.tools.ant.Project; 20 import org.apache.log4j.Logger; 21 import org.jdom.Element; 22 import net.sourceforge.cruisecontrol.util.Commandline; 23 import net.sourceforge.cruisecontrol.util.Util; 24 import net.sourceforge.cruisecontrol.util.StreamPumper; 25 import net.sourceforge.cruisecontrol.util.OSEnvironment; 26 import net.sourceforge.cruisecontrol.distributed.BuildAgent; 27 import net.sourceforge.cruisecontrol.distributed.BuildAgentService; 28 import net.sourceforge.cruisecontrol.distributed.BuildAgentServiceImplTest; 29 import net.sourceforge.cruisecontrol.distributed.SearchablePropertyEntries; 30 import net.sourceforge.cruisecontrol.distributed.util.ReggieUtil; 31 import net.sourceforge.cruisecontrol.distributed.util.MulticastDiscovery; 32 import net.sourceforge.cruisecontrol.CruiseControlException; 33 import net.sourceforge.cruisecontrol.Builder; 34 import net.jini.core.lookup.ServiceRegistrar; 35 import net.jini.core.discovery.LookupLocator; 36 import net.jini.core.entry.Entry; 37 import net.jini.discovery.LookupDiscovery; 38 39 43 public class DistributedMasterBuilderTest extends TestCase { 44 45 private static final Logger LOG = Logger.getLogger(DistributedMasterBuilderTest.class); 46 47 public static final String INSECURE_POLICY_FILENAME = "insecure.policy"; 48 private static Properties origSysProps; 49 public static final String JINI_URL_LOCALHOST = "jini://localhost"; 50 51 public static final OSEnvironment OS_ENV = new OSEnvironment(); 52 53 54 public static final String ELM_NAME_CC = "cruisecontrol"; 55 public static final String ELM_NAME_PROJECT = "project"; 56 public static final String ELM_NAME_SCHEDULE = "schedule"; 57 public static final String ELM_NAME_DIST = "distributed"; 58 public static final String ELM_NAME_AND = "ant"; 59 60 public static final String ATR_NAME_NAME = "name"; 61 public static final String ATR_NAME_MODULE = "module"; 62 public static final String ATR_NAME_DAY = "day"; 63 public static final String ATR_NAME_TIME = "time"; 64 public static final String ATR_NAME_MULTIPLE = "multiple"; 65 66 67 public static void addMissingPluginDefaults(final Element elementToFilter) { 68 DistributedMasterBuilder.addMissingPluginDefaults(elementToFilter); 69 } 70 73 private static final class PrefixedPrintWriter extends PrintWriter { 74 private final String writerPrefix; 75 76 PrefixedPrintWriter(final String prefix) { 77 super(System.out); 78 writerPrefix = prefix; 79 } 80 81 public void write(String s) { 82 super.write(writerPrefix + s); 84 } 86 } 87 88 89 90 public static Process startJini() throws Exception { 91 verifyNoLocalLookupService(); 93 94 origSysProps = System.getProperties(); 95 96 120 final String [] args = new String [] { 121 "-Djava.security.policy=conf/insecure.policy", "-Djini.lib=lib", 123 "-Djini.httpPort=8050", "-Djini.codebaseURI=file://lib/cc-agent-dl.jar " 125 + "file://lib/reggie-dl.jar " 126 + "file://lib/fiddler-dl.jar " 127 + "file://lib/mahalo-dl.jar " 128 + "file://lib/mercury-dl.jar " 129 + "file://lib/norm-dl.jar " 130 + "file://lib/outrigger-dl.jar " 131 + "file://lib/phoenix-dl.jar " 132 + "file://lib/holowaa-dl.jar", 133 "-Djini.classpath=.;lib/cc-agent.jar;lib/reggie.jar;lib/fiddler.jar;lib/mahalo.jar;" 134 + "lib/mercury.jar;lib/norm.jar;lib/outrigger.jar;lib/phoenix.jar;lib/holowaa.jar" 135 }; 136 137 final String libDir = "lib/"; 140 FileSet set = new FileSet(); 141 set.setDir(new File (libDir)); 142 set.setIncludes("**/*.jar"); 143 Project project = new Project(); 144 set.setProject(project); 145 String libjars = set.toString(); 146 libjars = libjars.replaceAll("jar" + File.pathSeparator, "jar" + File.pathSeparator + libDir); 147 libjars = libDir + libjars; 148 149 final Commandline cmdLine = new Commandline(); 150 cmdLine.addArguments(args); 151 Commandline.Argument argClasspath = cmdLine.createArgument(); 152 argClasspath.setLine("-classpath " + "conf" + File.pathSeparator + libjars); 153 154 Commandline.Argument argStart = cmdLine.createArgument(); 155 argStart.setLine("-jar lib/start.jar"); 156 157 Commandline.Argument argProg = cmdLine.createArgument(); 158 argProg.setValue("conf/start-jini.config"); 160 cmdLine.setExecutable(getJavaExec()); 161 162 LOG.debug("jini startup command: " + Arrays.asList(cmdLine.getCommandline())); 163 final Process newJiniProcess = Runtime.getRuntime().exec(cmdLine.getCommandline()); 164 165 new Thread (new StreamPumper(newJiniProcess.getErrorStream(), 167 new PrefixedPrintWriter("[JiniErr] "))).start(); 168 new Thread (new StreamPumper(newJiniProcess.getInputStream(), 169 new PrefixedPrintWriter("[JiniOut] "))).start(); 170 171 URL policyFile = ClassLoader.getSystemClassLoader().getResource(INSECURE_POLICY_FILENAME); 173 assertNotNull("Can't load policy file resource: " + INSECURE_POLICY_FILENAME 174 + ". Make sure this file is in the classes (bin) directory.", 175 policyFile); 176 System.setProperty(BuildAgent.JAVA_SECURITY_POLICY, policyFile.toExternalForm()); 177 ReggieUtil.setupRMISecurityManager(); 178 179 ServiceRegistrar serviceRegistrar = findTestLookupService(20); 180 assertNotNull("Failed to start local lookup _service.", serviceRegistrar); 181 assertEquals("Unexpected local lookup _service host", 182 InetAddress.getLocalHost().getCanonicalHostName(), 183 serviceRegistrar.getLocator().getHost()); 184 185 Thread.sleep(1000); return newJiniProcess; 187 } 188 189 public static String getJavaExec() { 190 final String javaExecFilename; 191 if (Util.isWindows()) { 192 javaExecFilename = "java.exe"; 193 } else { 194 javaExecFilename = "java"; 195 } 196 final String javaHome = getJAVA_HOME(); 198 final String javaExec; 199 if (javaHome != null) { 200 javaExec = javaHome + File.separator + "bin" + File.separator + javaExecFilename; 201 } else { 202 String msg = "Unit Test couldn't find JAVA_HOME env var. Maybe java/bin is in the path? Here goes..."; 203 System.out.println(msg); 204 LOG.warn(msg); 205 javaExec = javaExecFilename; 206 } 207 return javaExec; 208 } 209 210 public static String getJAVA_HOME() { 211 return OS_ENV.getVariable("JAVA_HOME"); 212 } 213 214 public static ServiceRegistrar findTestLookupService(int retryTimeoutSecs) 215 throws IOException , ClassNotFoundException , InterruptedException { 216 217 final long startTime = System.currentTimeMillis(); 219 ServiceRegistrar serviceRegistrar = null; 220 final LookupLocator lookup = new LookupLocator(JINI_URL_LOCALHOST); 221 while (serviceRegistrar == null 222 && (System.currentTimeMillis() - startTime < (retryTimeoutSecs * 1000))) { 223 224 try { 225 serviceRegistrar = lookup.getRegistrar(); 226 } catch (ConnectException e) { 227 Thread.sleep(500); 228 } catch (SocketException e) { 229 Thread.sleep(500); 230 } catch (EOFException e) { 231 Thread.sleep(500); 232 } 233 } 236 return serviceRegistrar; 237 } 238 239 public static void killJini(final Process jiniProcess) throws Exception { 240 if (jiniProcess != null) { 241 jiniProcess.destroy(); 242 243 jiniProcess.getInputStream().close(); 244 jiniProcess.getOutputStream().close(); 245 jiniProcess.getErrorStream().close(); 246 247 LOG.debug("Jini process killed."); 248 249 if (findTestLookupService(1) != null) { 252 final int secs = 5; 253 LOG.debug("Waiting " + secs + " seconds for Lookup Service to die...need to fix this."); 254 Thread.sleep(secs * 1000); 255 } 256 verifyNoLocalLookupService(); 257 Thread.sleep(1000); } 259 260 System.setProperties(origSysProps); 262 } 263 264 private static void verifyNoLocalLookupService() throws IOException , ClassNotFoundException , InterruptedException { 265 ServiceRegistrar serviceRegistrar = findTestLookupService(1); 266 assertNull("Found local lookup service, but it should be dead. Is an orphaned java process still running?", 267 serviceRegistrar); 268 } 269 270 271 private Process jiniProcess; 272 273 274 275 private static Element getDistElement(final String projectName, final int projectIndex) 276 throws CruiseControlException { 277 278 final Element rootElement = Util.loadConfigFile(BuildAgentServiceImplTest.TEST_CONFIG_FILE); 279 280 final List projects = rootElement.getChildren(ELM_NAME_PROJECT); 281 final Element project = (Element) projects.get(projectIndex); 282 assertEquals(ELM_NAME_PROJECT, project.getName()); 283 assertEquals(projectName, project.getAttributeValue(ATR_NAME_NAME)); 284 285 final Element schedule = (Element) project.getChildren(ELM_NAME_SCHEDULE).get(0); 286 assertEquals(ELM_NAME_SCHEDULE, schedule.getName()); 287 288 final Element dist = (Element) schedule.getChildren().get(0); 289 assertEquals(ELM_NAME_DIST, dist.getName()); 290 return dist; 291 } 292 293 private static Element getAntElement(final Element dist) { 294 final Element ant = (Element) dist.getChildren().get(0); 295 assertEquals(ELM_NAME_AND, ant.getName()); 296 return ant; 297 } 298 299 300 301 protected void setUp() throws Exception { 302 jiniProcess = DistributedMasterBuilderTest.startJini(); 303 } 304 305 protected void tearDown() throws Exception { 306 DistributedMasterBuilderTest.killJini(jiniProcess); 307 } 308 309 310 311 public void testDistAttribs() throws Exception { 312 313 final Element dist = getDistElement("testproject2", 1); 314 assertEquals("testmodule-attribs", dist.getAttributeValue(ATR_NAME_MODULE)); 315 316 final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 317 masterBuilder.configure(dist); 318 assertEquals("agent/log", masterBuilder.getAgentLogDir()); 319 assertEquals("master/log", masterBuilder.getMasterLogDir()); 320 final String preConfMsg = "Are PreConfgured Plugin settings still broken for distributed builds?" 322 + "\nSee " + BuildAgentServiceImplTest.TEST_CONFIG_FILE + " for more info."; 323 assertEquals(preConfMsg, "build.type=test", dist.getAttributeValue("entries")); 324 325 final Element childBuilder = masterBuilder.getChildBuilderElement(); 327 assertEquals("testtargetSuccess", childBuilder.getAttributeValue("target")); 328 assertEquals(preConfMsg, "${env.ANT_HOME}", childBuilder.getAttributeValue("anthome")); 330 assertEquals(preConfMsg, "test/testdist.build.xml", childBuilder.getAttributeValue("buildfile")); 331 assertEquals(preConfMsg, "true", childBuilder.getAttributeValue("uselogger")); 332 } 333 334 public void testScheduleDay() throws Exception { 335 336 final Element dist = getDistElement("testprojectNoModule", 2); 337 final Element ant = getAntElement(dist); 338 assertEquals("This unit test requires there be a '" + ATR_NAME_DAY + "' attribute", 339 "7", ant.getAttributeValue(ATR_NAME_DAY)); 340 341 final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 342 masterBuilder.configure(dist); 343 344 assertEquals("Distributed builder should wrap child-builder schedule fields", 345 7, masterBuilder.getDay()); 346 assertEquals("Distributed builder should wrap child-builder schedule fields", 347 Builder.NOT_SET, masterBuilder.getTime()); 348 assertEquals("Distributed builder should wrap child-builder schedule fields", 350 1, masterBuilder.getMultiple()); 351 } 352 353 public void testScheduleTime() throws Exception { 354 355 final Element dist = getDistElement("testprojectTime", 3); 356 final Element ant = getAntElement(dist); 357 assertEquals("This unit test requires there be a '" + ATR_NAME_TIME + "' attribute", 358 "0530", ant.getAttributeValue(ATR_NAME_TIME)); 359 360 final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 361 masterBuilder.configure(dist); 362 363 assertEquals("Distributed builder should wrap child-builder schedule fields", 364 530, masterBuilder.getTime()); 365 assertEquals("Distributed builder should wrap child-builder schedule fields", 366 Builder.NOT_SET, masterBuilder.getDay()); 367 assertEquals("Distributed builder should wrap child-builder schedule fields", 368 Builder.NOT_SET, masterBuilder.getMultiple()); 369 } 370 371 public void testScheduleMultiple() throws Exception { 372 373 final Element dist = getDistElement("testprojectMultiple", 4); 374 final Element ant = getAntElement(dist); 375 assertEquals("This unit test requires there be a '" + ATR_NAME_MULTIPLE + "' attribute", 376 "2", ant.getAttributeValue(ATR_NAME_MULTIPLE)); 377 378 final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 379 masterBuilder.configure(dist); 380 381 assertEquals("Distributed builder should wrap child-builder schedule fields", 382 2, masterBuilder.getMultiple()); 383 assertEquals("Distributed builder should wrap child-builder schedule fields", 384 Builder.NOT_SET, masterBuilder.getTime()); 385 assertEquals("Distributed builder should wrap child-builder schedule fields", 386 Builder.NOT_SET, masterBuilder.getDay()); 387 } 388 389 public void testDefaultModuleValue() throws Exception { 390 391 final Element dist = getDistElement("testprojectNoModule", 2); 392 assertNull("This unit test requires there be no '" + ATR_NAME_MODULE + "' attribute", 393 dist.getAttributeValue(ATR_NAME_MODULE)); 394 395 final DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 396 masterBuilder.configure(dist); 398 assertEquals("agent/log", masterBuilder.getAgentLogDir()); 399 assertEquals("master/log", masterBuilder.getMasterLogDir()); 400 final String preConfMsg = "Are PreConfgured Plugin settings still broken for distributed builds?" 402 + "\nSee " + BuildAgentServiceImplTest.TEST_CONFIG_FILE + " for more info."; 403 assertEquals(preConfMsg, "build.type=test", dist.getAttributeValue("entries")); 404 } 405 406 public void testPickAgent2Agents() throws Exception { 407 final BuildAgent agentAvailable = new BuildAgent( 409 BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE, 410 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true); 411 final BuildAgent agentAvailable2 = new BuildAgent( 412 BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE, 413 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true); 414 try { 415 assertFalse(agentAvailable.getService().isBusy()); 416 assertFalse(agentAvailable2.getService().isBusy()); 417 418 DistributedMasterBuilder masterBuilder = createMasterBuilder(); 419 420 final BuildAgentService agentFoundFirst = masterBuilder.pickAgent(); 422 assertNotNull("Couldn't find first agent", agentFoundFirst); 423 assertTrue(agentFoundFirst.isBusy()); 424 final BuildAgentService agentFoundSecond = masterBuilder.pickAgent(); 425 assertNotNull("Couldn't find second agent", agentFoundSecond); 426 427 assertTrue(agentFoundFirst.isBusy()); 428 assertTrue(agentFoundSecond.isBusy()); 429 final BuildAgentService agentFoundThird = masterBuilder.pickAgent(); 430 assertNull("Shouldn't find third agent", agentFoundThird); 431 432 BuildAgentServiceImplTest.callTestDoBuild(false, agentAvailable.getService()); 435 agentAvailable.getService().clearOutputFiles(); 436 final BuildAgentService agentRefound = masterBuilder.pickAgent(); 437 assertNotNull("Couldn't find released agent", agentRefound); 438 assertTrue("Claimed agent should show as busy. (Did we find a better way?)", 439 agentRefound.isBusy()); 440 441 } finally { 442 agentAvailable.terminate(); 444 agentAvailable2.terminate(); 445 } 446 } 447 448 public void testPickAgentAfterReleased() throws Exception { 449 final BuildAgent agentAvailable = new BuildAgent( 451 BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE, 452 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true); 453 try { 454 assertFalse(agentAvailable.getService().isBusy()); 455 agentAvailable.getService().claim(); 457 DistributedMasterBuilder masterBuilder = createMasterBuilder(); 458 459 final BuildAgentService agentBusy = masterBuilder.pickAgent(); 461 assertNull("Shouldn't find any available agents", agentBusy); 462 463 BuildAgentServiceImplTest.callTestDoBuild(false, agentAvailable.getService()); 466 agentAvailable.getService().clearOutputFiles(); 467 final BuildAgentService agentRefound = masterBuilder.pickAgent(); 468 assertNotNull("Couldn't find released agent", agentRefound); 469 assertTrue("Claimed agent should show as busy. (Did we find a better way?)", 470 agentRefound.isBusy()); 471 472 } finally { 473 agentAvailable.terminate(); 475 } 476 } 477 478 public void testPickAgentAgentNotBusy() throws Exception { 479 final BuildAgent agentAvailable = new BuildAgent( 481 BuildAgentServiceImplTest.TEST_AGENT_PROPERTIES_FILE, 482 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE, true); 483 try { 484 assertFalse(agentAvailable.getService().isBusy()); 485 486 DistributedMasterBuilder masterBuilder = createMasterBuilder(); 487 488 final BuildAgentService agent = masterBuilder.pickAgent(); 489 assertNotNull("Couldn't find agent", agent); 490 assertTrue("Claimed agent should show as busy. (Did we find a better way?)", 491 agent.isBusy()); 492 493 final BuildAgentService agentBusy = masterBuilder.pickAgent(); 495 assertNull("Shouldn't find any available agents", agentBusy); 496 497 BuildAgentServiceImplTest.callTestDoBuild(false, agent); agent.clearOutputFiles(); 500 final BuildAgentService agentRefound = masterBuilder.pickAgent(); 501 assertNotNull("Couldn't find released agent", agentRefound); 502 assertTrue("Claimed agent should show as busy. (Did we find a better way?)", 503 agentRefound.isBusy()); 504 } finally { 505 agentAvailable.terminate(); 507 } 508 } 509 510 private static DistributedMasterBuilder createMasterBuilder() throws MalformedURLException , InterruptedException { 511 DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY( 512 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE 513 ); 514 515 int i = 0; 517 int waitSecs = 15; 518 while (!masterBuilder.getDiscovery().isDiscovered() && i < waitSecs) { 519 Thread.sleep(1000); 520 i++; 521 } 522 assertTrue("MasterBuilder was not discovered before timeout.\n" 523 + "1. Make sure MULTICAST is enabled on your network devices (ifconfig -a).\n" 524 + "2. No Firewall is blocking multicasts.\n", 525 masterBuilder.getDiscovery().isDiscovered()); 526 return masterBuilder; 527 } 528 529 public void testPickAgentNoAgents() throws Exception { 530 531 DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY( 532 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE 533 ); 534 535 BuildAgentService agent = masterBuilder.pickAgent(); 536 assertNull(agent); 537 } 538 539 public void testPickAgentNoRegistrars() throws Exception { 540 DistributedMasterBuilderTest.killJini(jiniProcess); 542 543 DistributedMasterBuilder masterBuilder = getMasterBuilder_LocalhostAndTestPropsONLY( 544 BuildAgentServiceImplTest.TEST_USER_DEFINED_PROPERTIES_FILE 545 ); 546 547 BuildAgentService agent = masterBuilder.pickAgent(); 548 assertNull(agent); 549 } 550 551 private static DistributedMasterBuilder getMasterBuilder_LocalhostAndTestPropsONLY( 552 final String testUserPropsFilename) 553 throws MalformedURLException { 554 555 DistributedMasterBuilder masterBuilder = new DistributedMasterBuilder(); 556 557 final LookupLocator[] unicastLocators = new LookupLocator[] { 558 new LookupLocator(DistributedMasterBuilderTest.JINI_URL_LOCALHOST) 559 }; 560 561 final Entry[] entries = SearchablePropertyEntries.getPropertiesAsEntryArray( 562 new SearchablePropertyEntries(testUserPropsFilename).getProperties() 563 ); 564 565 final MulticastDiscovery discovery = new MulticastDiscovery( 566 LookupDiscovery.ALL_GROUPS, unicastLocators, BuildAgentService.class, entries 567 ); 568 masterBuilder.setDiscovery(discovery); 569 masterBuilder.setFailFast(true); return masterBuilder; 571 } 572 573 } 574 | Popular Tags |