Java tutorial
/* * The MIT License * * Copyright 2011, 2015 Sony Mobile Communications Inc. All rights reserved. * Copyright 2014 rinrinne All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.sonyericsson.hudson.plugins.gerrit.trigger.mock; import com.sonyericsson.hudson.plugins.gerrit.trigger.PluginImpl; import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritCause; import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.GerritTrigger; import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.Branch; import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.CompareType; import com.sonyericsson.hudson.plugins.gerrit.trigger.hudsontrigger.data.GerritProject; import com.sonymobile.tools.gerrit.gerritevents.dto.events.ChangeBasedEvent; import hudson.matrix.MatrixProject; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.sonyericsson.hudson.plugins.gerrit.trigger.events.lifecycle.GerritEventLifecycle; import com.sonymobile.tools.gerrit.gerritevents.dto.GerritEvent; import hudson.model.Cause; import hudson.model.FreeStyleProject; import hudson.model.Job; import hudson.model.Run; import hudson.model.TopLevelItem; import org.apache.commons.lang.NotImplementedException; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jvnet.hudson.test.JenkinsRule; import static org.apache.commons.lang.StringUtils.isBlank; /** * A utility class for test. * * @author rinrinne (rinrin.ne@gmail.com) */ public final class TestUtils { /** * Default build wait time in ms. */ public static final int DEFAULT_WAIT_BUILD_MS = 30000; private static final int SLEEP_DURATION = 1000; /** * Utility constructor. */ private TestUtils() { } /** * Finds the form in the html document that performs the provided action. * * @param action the action to search for. * @param forms the html forms in the document. * @return the form, or null of there is none. */ public static HtmlForm getFormWithAction(String action, List<HtmlForm> forms) { for (HtmlForm f : forms) { if (f.getActionAttribute().equalsIgnoreCase(action)) { return f; } } return null; } /** * Get the future build to start as reference. * * @param event the event to monitor. * @return the reference of future build to start. */ public static AtomicReference<Run> getFutureBuildToStart(GerritEventLifecycle event) { final AtomicReference<Run> reference = new AtomicReference<Run>(); event.addListener(new GerritEventLifeCycleAdaptor() { @Override public void buildStarted(GerritEvent event, Run build) { reference.getAndSet(build); } }); return reference; } /** * Get the future build to start as reference. * * @param event the event to monitor. * @return the reference of future build to start. */ public static AtomicReference<Run> getFutureBuildToStart2(GerritEventLifecycle event) { final AtomicReference<Run> reference = new AtomicReference<Run>(); event.addListener(new GerritEventLifeCycleAdaptor() { @Override public void buildStarted(GerritEvent event, Run build) { reference.getAndSet(build); } }); return reference; } /** * Waits until the build is started, or the default timeout has expired. * * @param reference the reference of future build to start. * @return the build that started. */ public static Run waitForBuildToStart(AtomicReference<Run> reference) { return waitForBuildToStart(reference, DEFAULT_WAIT_BUILD_MS); } /** * Waits until the build is started, or the timeout has expired. * * @param reference the reference of future build to start. * @param timeoutMs the maximum time in ms to wait for the build to start. * @return the build that started. */ public static Run waitForBuildToStart(AtomicReference<Run> reference, int timeoutMs) { long startTime = System.currentTimeMillis(); while (reference.get() == null) { if (System.currentTimeMillis() - startTime >= timeoutMs) { throw new RuntimeException("Timeout!"); } try { Thread.sleep(SLEEP_DURATION); } catch (InterruptedException e) { System.err.println("Interrupted while waiting!"); } } return reference.get(); } /** * Waits until a build has started, which is Gerrit-triggered but not manually triggered. * * @param project the project which is to be built. * @param cbe the event that shall be triggered. * @param timeoutMs the timeout in ms for how long to wait. * @return The build that has started, or null if it hasn't started yet. */ public static AbstractBuild waitForNonManualBuildToStart(AbstractProject project, ChangeBasedEvent cbe, int timeoutMs) { AbstractBuild returnBuild = null; long startTime = System.currentTimeMillis(); while (returnBuild == null) { if (System.currentTimeMillis() - startTime >= timeoutMs) { throw new RuntimeException("Timeout!"); } try { Thread.sleep(SLEEP_DURATION); } catch (InterruptedException e) { System.err.println("Interrupted while waiting!"); } final Iterator<Run> iterator = project._getRuns().iterator(); while (iterator.hasNext()) { final Run next = iterator.next(); Cause cause = next.getCause(GerritCause.class); if (cause != null && cause instanceof GerritCause) { if (cbe.equals(((GerritCause) cause).getEvent())) { if (next.isBuilding()) { returnBuild = (AbstractBuild) next; } } } } } return returnBuild; } /** * Waits until the expected number of build are done, or the default timeout has expired. * * @param project the project to check * @param number the build number to wait for. */ public static void waitForBuilds(Job project, int number) { waitForBuilds(project, number, DEFAULT_WAIT_BUILD_MS); } /** * Waits until the expected number of build are done, or the timeout has expired. * * @param project the project to check * @param number the build number to wait for. * @param timeoutMs the timeout in ms. */ public static void waitForBuilds(Job project, int number, int timeoutMs) { long startTime = System.currentTimeMillis(); while (project.getLastCompletedBuild() == null || project.getLastCompletedBuild().getNumber() != number) { if (System.currentTimeMillis() - startTime >= timeoutMs) { throw new RuntimeException("Timeout!"); } try { Thread.sleep(SLEEP_DURATION); } catch (InterruptedException e) { System.err.println("Interrupted while waiting!"); } } } /** * A builder to create Jobs with a {@link GerritTrigger} configured. */ public static class JobBuilder { private static final String DEFAULT_JOB_NAME = "gerritProjectX"; private JenkinsRule j; private String jobName; private List<GerritProject> projects = new ArrayList<GerritProject>(); private String serverName = PluginImpl.DEFAULT_SERVER_NAME; private boolean silentMode = false; private boolean silentStartMode = false; private boolean escapeQuotes = true; private boolean dynamicTriggerConfiguration = false; /** * Creates a builder with the default project name. * @param j the rule that rules it all */ public JobBuilder(JenkinsRule j) { this.j = j; this.jobName = DEFAULT_JOB_NAME; } /** * Sets the job name. * @param name the name of the job to create * @return this */ public JobBuilder name(String name) { this.jobName = name; return this; } /** * Adds a {@link GerritProject} configuration to trigger on. * @param compareType the compareType * @param pattern the pattern * @param branches the branch patterns to trigger on. * If none is provided one with {@link CompareType#ANT} and pattern: '**' is added as default. * @return this */ public JobBuilder project(CompareType compareType, String pattern, Branch... branches) { List<Branch> bs = new ArrayList<Branch>(); if (branches == null || branches.length <= 0) { bs.add(new Branch(CompareType.ANT, "**")); } else { Collections.addAll(bs, branches); } projects.add(new GerritProject(compareType, pattern, bs, null, null, null, false)); return this; } /** * Sets the name of the {@link com.sonyericsson.hudson.plugins.gerrit.trigger.GerritServer} to trigger on. * @param name the server name * @return this */ public JobBuilder serverName(String name) { this.serverName = name; return this; } /** * Sets {@link GerritTrigger#setSilentMode(boolean)}. * @param mode the silent mode * @return this */ public JobBuilder silentMode(boolean mode) { this.silentMode = mode; return this; } /** * Sets {@link GerritTrigger#setSilentStartMode(boolean)}. * @param mode the silent start mode * @return this */ public JobBuilder silentStartMode(boolean mode) { this.silentStartMode = mode; return this; } /** * Sets {@link GerritTrigger#setEscapeQuotes(boolean)}. * @param escape escape quotes * @return this */ public JobBuilder escapeQuotes(boolean escape) { this.escapeQuotes = escape; return this; } /** * Sets {@link GerritTrigger#setDynamicTriggerConfiguration(boolean)}. * @param dynamicTrigger dynamicTriggerConfiguration * @return this */ public JobBuilder dynamicTriggerConfiguration(boolean dynamicTrigger) { this.dynamicTriggerConfiguration = dynamicTrigger; return this; } /** * Builds a {@link FreeStyleProject}. * @return the job * @throws Exception if so */ public FreeStyleProject build() throws Exception { return build(FreeStyleProject.class); } /** * Builds a Job of the provided type. * Due to how {@link FreeStyleProject#addTrigger(hudson.triggers.Trigger)} is defined in all job types * it currently only supports {@link FreeStyleProject}, {@link MatrixProject} and {@link WorkflowJob}. * Any other job types should be added on an as needed basis. * * @param jobType the type of job to create * @param <T> the type of job to create * @return the created job * @throws Exception if so * @see JenkinsRule#createProject(Class) * @see JenkinsRule#configRoundtrip(Job) */ public <T extends Job & TopLevelItem> T build(Class<? extends T> jobType) throws Exception { if (isBlank(jobName)) { jobName = DEFAULT_JOB_NAME; } T job = j.createProject(jobType, jobName); GerritTrigger trigger = new GerritTrigger(projects); if (projects.isEmpty()) { project(CompareType.ANT, "**"); } if (isBlank(serverName)) { trigger.setServerName(PluginImpl.DEFAULT_SERVER_NAME); } else { trigger.setServerName(serverName); } trigger.setSilentMode(silentMode); trigger.setSilentStartMode(silentStartMode); trigger.setEscapeQuotes(escapeQuotes); trigger.setDynamicTriggerConfiguration(dynamicTriggerConfiguration); if (job instanceof FreeStyleProject) { ((FreeStyleProject) job).addTrigger(trigger); } else if (job instanceof MatrixProject) { ((MatrixProject) job).addTrigger(trigger); } else if (job instanceof WorkflowJob) { ((WorkflowJob) job).addTrigger(trigger); } else { throw new NotImplementedException( job.getClass().getName() + "Is not a supported test class, " + "implement here."); } return j.configRoundtrip(job); } } }