/** * Tests {@link * TriggerContextConverter#unmarshal(com.thoughtworks.xstream.io.HierarchicalStreamReader, * com.thoughtworks.xstream.converters.UnmarshallingContext)}. With "matrix_build.xml" as input. * * @throws Exception if so. */ @Test public void testUnmarshalOldMatrixBuild() throws Exception { XStream xStream = new XStream2(); xStream.registerConverter(new TriggerContextConverter()); xStream.alias("matrix-run", MatrixRun.class); Object obj = xStream.fromXML(getClass().getResourceAsStream("matrix_build.xml")); assertTrue(obj instanceof MatrixRun); MatrixRun run = (MatrixRun) obj; Cause.UpstreamCause upCause = run.getCause(Cause.UpstreamCause.class); List upstreamCauses = Whitebox.getInternalState(upCause, "upstreamCauses"); GerritCause cause = (GerritCause) upstreamCauses.get(0); assertNotNull(cause.getEvent()); assertEquals("platform/project", cause.getEvent().getChange().getProject()); assertNotNull(cause.getContext()); assertNotNull(cause.getContext().getThisBuild()); assertEquals("Gerrit_master-theme_matrix", cause.getContext().getThisBuild().getProjectId()); assertEquals(102, cause.getContext().getThisBuild().getBuildNumber().intValue()); assertNotNull(cause.getContext().getOthers()); assertEquals(1, cause.getContext().getOthers().size()); TriggeredItemEntity entity = cause.getContext().getOthers().get(0); assertEquals("master-theme", entity.getProjectId()); assertNull(entity.getBuildNumber()); }
/** * Determines if the given configuration is currently running. If any of the configurations are * currently stuck in the queue, it is logged. * * @param execution Contains information about the general build, including the listener used to * log queue blockage. * @param configuration The configuration being checked to see if it's running. * @param mutableWhyMap Mutable map used to track the reasons a configuration is stuck in the * queue. This prevents duplicate reasons from flooding the logs. * @return True if the build represented by the given configuration is currently running or stuck * in the queue. False if the build has finished running. */ private boolean isBuilding( MatrixBuild.MatrixBuildExecution execution, MatrixConfiguration configuration, Map<String, String> mutableWhyMap) { MatrixRun build = configuration.getBuildByNumber(execution.getBuild().getNumber()); if (build != null) { return build.isBuilding(); } Queue.Item queueItem = configuration.getQueueItem(); if (queueItem != null) { String why = queueItem.getWhy(); String key = queueItem.task.getFullDisplayName() + " " + queueItem.id; String oldWhy = mutableWhyMap.get(key); if (why == null) { mutableWhyMap.remove(key); } if (why != null && !why.equals(oldWhy)) { mutableWhyMap.put(key, why); BuildListener listener = execution.getListener(); PrintStream logger = listener.getLogger(); logger.print( "Configuration " + ModelHyperlinkNote.encodeTo(configuration) + " is still in the queue: "); queueItem.getCauseOfBlockage().print(listener); // this is still shown on the same line } } return true; }
public void testNoInterpreter() throws Exception { ToxBuilder builder = new ToxBuilder("tox.ini", false, null); MatrixProject project = createMatrixProject(); AxisList axes = new AxisList(new ToxAxis(new String[] {"py27"})); project.setAxes(axes); project.getBuildersList().add(builder); MatrixBuild build = project.scheduleBuild2(0).get(); List<MatrixRun> runs = build.getRuns(); assertEquals(1, runs.size()); MatrixRun run = runs.get(0); String log = FileUtils.readFileToString(run.getLogFile()); assertTrue( "should not have found an interpreter:\n" + log, log.contains(Messages.BuilderUtil_NoInterpreterFound())); }
public void testNoAxis() throws Exception { ToxBuilder builder = new ToxBuilder("tox.ini", false, null); MatrixProject project = createMatrixProject(); AxisList axes = new AxisList(new TextAxis("TOTO", "TUTU")); project.setAxes(axes); project.getBuildersList().add(builder); MatrixBuild build = project.scheduleBuild2(0).get(); List<MatrixRun> runs = build.getRuns(); assertEquals(1, runs.size()); MatrixRun run = runs.get(0); String log = FileUtils.readFileToString(run.getLogFile()); assertTrue( "should not have found a tox axis:\n" + log, log.contains(Messages.ToxBuilder_ToxAxis_Required())); }
public void testToxAxisSuccessful() throws Exception { configureCPython2(); ToxBuilder builder = new ToxBuilder("tox.ini", false, null); MatrixProject project = createMatrixProject(); AxisList axes = new AxisList(new ToxAxis(new String[] {"py27"})); project.setScm(new ToxSCM("tox.ini", "[testenv]\ncommand = echo")); project.setAxes(axes); project.getBuildersList().add(builder); MatrixBuild build = project.scheduleBuild2(0).get(); List<MatrixRun> runs = build.getRuns(); assertEquals(1, runs.size()); MatrixRun run = runs.get(0); String log = FileUtils.readFileToString(run.getLogFile()); assertTrue("tox should have been successful:\n" + log, log.contains("congratulations :)")); assertTrue("build should have been successful:\n" + log, log.contains("SUCCESS")); }
@Test public void shortenMatrix() throws Exception { Node slave = j.createOnlineSlave(); setMaxPathLength(slave, 1); // Not enough for anything MatrixProject mp = j.createMatrixProject(); mp.setAssignedNode(slave); mp.setAxes(new AxisList(new LabelExpAxis("axis", slave.getNodeName()))); MatrixBuild build = j.buildAndAssertSuccess(mp); assertThat(build.getBuiltOn(), equalTo(slave)); MatrixRun run = build.getExactRuns().get(0); assertThat(run.getBuiltOn(), equalTo(slave)); System.out.println(build.getWorkspace()); System.out.println(run.getWorkspace()); }
public void testToxenvPatternBlank() throws Exception { configureCPython2(); ToxBuilder builder = new ToxBuilder("tox.ini", false, "$FOOBAR"); MatrixProject project = createMatrixProject(); AxisList axes = new AxisList(new TextAxis("FOOBAR2", "badluck")); project.setScm(new ToxSCM("tox.ini", "[testenv]\ncommand = echo")); project.setAxes(axes); project.getBuildersList().add(builder); MatrixBuild build = project.scheduleBuild2(0).get(); List<MatrixRun> runs = build.getRuns(); assertEquals(1, runs.size()); MatrixRun run = runs.get(0); String log = FileUtils.readFileToString(run.getLogFile()); System.out.println(log); assertTrue( "should not be able to run with a blank TOXENV pattern:\n" + log, log.contains(Messages.ToxBuilder_ToxenvPattern_Invalid("$FOOBAR"))); }
public void testToxAxisAndToxenvPattern() throws Exception { configureCPython2(); ToxBuilder builder = new ToxBuilder("tox.ini", false, "$INTERPRETER$VERSION"); MatrixProject project = createMatrixProject(); AxisList axes = new AxisList( new ToxAxis(new String[] {"py27"}), new TextAxis("INTERPRETER", "py"), new TextAxis("VERSION", "27")); project.setScm(new ToxSCM("tox.ini", "[testenv]\ncommand = echo")); project.setAxes(axes); project.getBuildersList().add(builder); MatrixBuild build = project.scheduleBuild2(0).get(); List<MatrixRun> runs = build.getRuns(); assertEquals(1, runs.size()); MatrixRun run = runs.get(0); String log = FileUtils.readFileToString(run.getLogFile()); System.out.println(log); assertTrue( "should not be able to run with both Tox axis and TOXENV pattern:\n" + log, log.contains(Messages.ToxBuilder_ToxAxis_And_ToxenvPattern())); }
/** * Checks if the logs of the given run match any of the given patterns, line-by-line. * * @param matrixRun The run to be considered. * @param patterns The patterns to match with. * @return True if at least one line of the logs match at least one of the given patterns. * @throws IOException If there's a problem reading the log file. */ private boolean matchesPattern(MatrixRun matrixRun, List<Pattern> patterns) throws IOException { if (patterns == null || patterns.isEmpty()) { return true; // No specific patterns specified. Accept everything. } BufferedReader reader = new BufferedReader( new InputStreamReader( new FileInputStream(matrixRun.getLogFile()), matrixRun.getCharset())); try { for (String line = reader.readLine(); line != null; line = reader.readLine()) { for (Pattern pattern : patterns) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { return true; } } } } finally { reader.close(); } return false; }
/** * Waits for the given configurations to finish, retrying any that qualify to be rerun. * * @param execution Provided by the plugin. * @param patterns List of regular expression patterns used to scan the log to determine if a * build should be rerun. * @param retries Mutable map that tracks the number of times a specific configuration has been * retried. * @param configurations The configurations that have already been scheduled to run that should be * waited for to finish. * @return The worst result of all the runs. If a build was rerun, only the result of the rerun is * considered. * @throws InterruptedException * @throws IOException */ private Result waitForMatrixRuns( MatrixBuild.MatrixBuildExecution execution, List<Pattern> patterns, Map<MatrixConfiguration, Integer> retries, LinkedList<MatrixConfiguration> configurations) throws InterruptedException, IOException { BuildListener listener = execution.getListener(); PrintStream logger = listener.getLogger(); Map<String, String> whyBlockedMap = new HashMap< String, String>(); // keep track of why builds are blocked so we can print unique messages when // they change. Result finalResult = Result.SUCCESS; int iteration = 0; boolean continueRetrying = true; while (!configurations.isEmpty()) { ++iteration; MatrixConfiguration configuration = configurations.removeFirst(); if (isBuilding(execution, configuration, whyBlockedMap)) { if (iteration >= configurations.size()) { // Every time we loop through all the configurations, sleep for a bit. // This is to prevent polling too often while everything is still building. iteration = 0; Thread.sleep(1000); } configurations.add(configuration); continue; } Run parentBuild = execution.getBuild(); MatrixRun matrixRun = configuration.getBuildByNumber(parentBuild.getNumber()); Result runResult = matrixRun.getResult(); if (continueRetrying && runResult.isWorseOrEqualTo(getWorseThanOrEqualTo()) && runResult.isBetterOrEqualTo(getBetterThanOrEqualTo())) { if (matchesPattern(matrixRun, patterns)) { int retriedCount = retries.get(configuration); if (retriedCount < getMaxRetries()) { ++retriedCount; retries.put(configuration, retriedCount); // rerun String logMessage = String.format( "%s was %s. Matched pattern to rerun. Rerunning (%d).", matrixRun, runResult, retriedCount); listener.error(logMessage); HealedAction action = parentBuild.getAction(HealedAction.class); if (action == null) { //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (parentBuild.getActions()) { action = parentBuild.getAction(HealedAction.class); if (action == null) { action = new HealedAction(matrixRun.getCharset()); parentBuild.addAction(action); } } } action.addAutoHealedJob(matrixRun); MatrixConfiguration parent = matrixRun.getParent(); if (parent != null) { // I'm paranoid about NPEs parent.removeRun(matrixRun); matrixRun.delete(); } else { LOGGER.severe( "couldn't remove old run, parent was null. This is a Jenkins core bug."); } scheduleConfigurationBuild( execution, configuration, new SelfHealingCause(parentBuild, retriedCount)); configurations.add(configuration); continue; } else { String logMessage = String.format( "%s was %s. Matched pattern to rerun, but the max number of retries (%d) has been met.", matrixRun, runResult, getMaxRetries()); listener.error(logMessage); if (getStopRetryingAfterOneFails()) { listener.error("Not retrying any more builds."); continueRetrying = false; } } } else { String logMessage = String.format( "%s was %s. It did not match the pattern to rerun. Accepting result.", matrixRun, runResult); logger.println(logMessage); } } notifyEndRun(matrixRun, execution.getAggregators(), execution.getListener()); finalResult = finalResult.combine(runResult); } return finalResult; }