package hudson.plugins.mercurial; import hudson.Launcher; import hudson.Proc; import hudson.matrix.*; import hudson.model.*; import hudson.scm.SCM; import org.jvnet.hudson.test.FakeLauncher; import org.jvnet.hudson.test.PretendSlave; import org.jvnet.hudson.test.TestBuilder; import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.jenkinsci.plugins.multiplescms.MultiSCM; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.JenkinsRule; public class MatrixProjectTest { @Rule public JenkinsRule j = new JenkinsRule(); @Rule public MercurialRule m = new MercurialRule(j); @Rule public TemporaryFolder tmp = new TemporaryFolder(); @Rule public TemporaryFolder tmp2 = new TemporaryFolder(); private File repo; private File repo2; private MatrixProject matrixProject; @Before public void setUp() throws Exception { repo = tmp.getRoot(); createPretendSlave("slave_one"); createPretendSlave("slave_two"); matrixProject = j.createProject(MatrixProject.class, "matrix_test"); matrixProject.setScm(new MercurialSCM(null, repo.getPath(), null, null, null, null, false)); matrixProject.setAxes(new AxisList(new LabelAxis("label", Arrays.asList("slave_one", "slave_two")))); m.hg(repo, "init"); m.touchAndCommit(repo, "a"); } private void setUpMultiSCM() throws Exception { repo2 = tmp.newFolder(); matrixProject.setScm(new MultiSCM(Arrays.<SCM>asList( new MercurialSCM(null, repo2.getPath(), null, null, "r2", null, false), new MercurialSCM(null, repo.getPath(), null, null, "r1", null, false)))); m.hg(repo2, "init"); m.touchAndCommit(repo2, "r2f1"); } @Test public void allRunsBuildSameRevisionOnClone() throws Exception { assertAllMatrixRunsBuildSameMercurialRevision(); } @Test public void allRunsBuildSameRevisionOnUpdate() throws Exception { //schedule an initial build, to test update behavior later in the test j.assertBuildStatusSuccess(matrixProject.scheduleBuild2(0)); m.touchAndCommit(repo, "ab"); assertAllMatrixRunsBuildSameMercurialRevision(); } @Bug(18237) @Test public void multiSCMRunsBuildSameRevisionOnClone() throws Exception { setUpMultiSCM(); assertAllMatrixRunsBuildSameMercurialRevision(); } @Bug(18237) @Test public void multiSCMRunsBuildSameRevisionOnUpdate() throws Exception { setUpMultiSCM(); //schedule an initial build, to test update behavior later in the test j.assertBuildStatusSuccess(matrixProject.scheduleBuild2(0)); m.touchAndCommit(repo, "ab"); assertAllMatrixRunsBuildSameMercurialRevision(); } private void assertAllMatrixRunsBuildSameMercurialRevision() throws Exception { //set the second slave offline, to give us the opportunity to push changes to the original Mercurial repository //between the scheduling of the build and the actual run. Node slaveTwo = j.jenkins.getNode("slave_two"); slaveTwo.toComputer().setTemporarilyOffline(true, null); final CountDownLatch firstBuild = new CountDownLatch(1); matrixProject.getBuildersList().add(new TestBuilder() { @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { firstBuild.countDown(); return true; } }); Future<MatrixBuild> matrixBuildFuture = matrixProject.scheduleBuild2(0); firstBuild.await(5, TimeUnit.SECONDS); //push an extra commit to the central repository m.touchAndCommit(repo, "b"); //let the second slave start the build that was scheduled before this commit slaveTwo.toComputer().setTemporarilyOffline(false, null); MatrixBuild r = matrixBuildFuture.get(); j.assertBuildStatus(Result.SUCCESS, r); List<MatrixRun> runs = r.getRuns(); Set<String> builtIds = new HashSet<String>(); for (MatrixRun run : runs) { MercurialTagAction builtRevision = run.getAction(MercurialTagAction.class); String buildId = builtRevision.getId(); builtIds.add(buildId); } //check that all runs built the same mercurial revision assertEquals("All runs should build the same Mercurial revision, but they built " + builtIds.toString(), 1, builtIds.size()); } private PretendSlave createPretendSlave(String slaveName) throws Exception { PretendSlave slave = new PretendSlave(slaveName, tmp2.getRoot().getAbsolutePath(), "", j.createComputerLauncher(null), new NoopFakeLauncher()); j.jenkins.addNode(slave); return slave; } private static class NoopFakeLauncher implements FakeLauncher { public Proc onLaunch(Launcher.ProcStarter p) throws IOException { return null; } } }