/* * The MIT License * * Copyright 2016 CloudBees, Inc. * * 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 jenkins.scm.impl.subversion; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.FilePath; import hudson.Launcher; import hudson.model.Run; import hudson.model.TaskListener; import hudson.scm.SCMRevisionState; import hudson.util.StreamTaskListener; import jenkins.scm.api.SCMHead; import jenkins.scm.api.SCMRevision; import jenkins.scm.api.SCMSource; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; public class SubversionSCMSourceIntegrationTest { @Rule public JenkinsRule r = new JenkinsRule(); @Rule public SubversionSampleRepoRule sampleRepo = new SubversionSampleRepoRule(); @Test public void retrieve() throws Exception { sampleRepo.init(); sampleRepo.write("file", "trunk"); sampleRepo.svnkit("commit", "--message=trunk", sampleRepo.wc()); long trunk = sampleRepo.revision(); assertEquals(3, trunk); sampleRepo.svnkit("copy", "--message=branching", sampleRepo.trunkUrl(), sampleRepo.branchesUrl() + "/dev"); sampleRepo.svnkit("switch", sampleRepo.branchesUrl() + "/dev", sampleRepo.wc()); sampleRepo.write("file", "dev1"); sampleRepo.svnkit("commit", "--message=dev1", sampleRepo.wc()); long dev1 = sampleRepo.revision(); assertEquals(5, dev1); sampleRepo.svnkit("copy", "--message=tagging", sampleRepo.branchesUrl() + "/dev", sampleRepo.tagsUrl() + "/dev-1"); sampleRepo.write("file", "dev2"); sampleRepo.svnkit("commit", "--message=dev2", sampleRepo.wc()); long dev2 = sampleRepo.revision(); assertEquals(7, dev2); SCMSource source = new SubversionSCMSource(null, sampleRepo.prjUrl()); TaskListener listener = StreamTaskListener.fromStdout(); // First check fetching of all heads. SCMHeadObserver.Collector.result is a TreeMap so order is predictable: assertEquals("[SCMHead{'branches/dev'}, SCMHead{'tags/dev-1'}, SCMHead{'trunk'}]", source.fetch(listener).toString()); // SCM.checkout does not permit a null build argument, unfortunately. Run<?,?> run = r.buildAndAssertSuccess(r.createFreeStyleProject()); // Retrieval of heads: assertRevision(source.fetch(new SCMHead("trunk"), listener), "trunk", source, run, listener); assertRevision(source.fetch(new SCMHead("branches/dev"), listener), "dev2", source, run, listener); assertRevision(source.fetch(new SCMHead("tags/dev-1"), listener), "dev1", source, run, listener); // Retrieval of revisions by head name: assertRevision(source.fetch("trunk", listener), "trunk", source, run, listener); assertRevision(source.fetch("trunk/", listener), "trunk", source, run, listener); assertRevision(source.fetch("branches/dev", listener), "dev2", source, run, listener); assertRevision(source.fetch("tags/dev-1", listener), "dev1", source, run, listener); // Retrieval of revisions by revision number: assertRevision(source.fetch("trunk@" + trunk, listener), "trunk", source, run, listener); assertRevision(source.fetch("trunk/@" + trunk, listener), "trunk", source, run, listener); assertRevision(source.fetch("branches/dev@" + dev2, listener), "dev2", source, run, listener); assertRevision(source.fetch("branches/dev@" + dev1, listener), "dev1", source, run, listener); // And nonexistent/bogus stuff: assertRevision(source.fetch("nonexistent", listener), null, source, run, listener); assertRevision(source.fetch("nonexistent/", listener), null, source, run, listener); assertRevision(source.fetch("nonexistent@" + trunk, listener), null, source, run, listener); assertRevision(source.fetch("nonexistent@999", listener), null, source, run, listener); assertRevision(source.fetch("trunk@999", listener), null, source, run, listener); // currently fetch succeeds, but checkout fails // Checks out repo root (means you have trunk/file not file): assertRevision(source.fetch("", listener), null, source, run, listener); // Other oddities: assertRevision(source.fetch("@", listener), null, source, run, listener); assertRevision(source.fetch("/", listener), null, source, run, listener); assertRevision(source.fetch("//", listener), null, source, run, listener); assertRevision(source.fetch("\n", listener), null, source, run, listener); // Completions of revision: assertThat(source.fetchRevisions(listener), hasItems("trunk", "branches/dev", "tags/dev-1")); } private void assertRevision(@CheckForNull SCMRevision rev, @CheckForNull String expectedFile, @NonNull SCMSource source, @NonNull Run<?,?> run, @NonNull TaskListener listener) throws Exception { if (rev == null) { assertNull(expectedFile); return; } FilePath ws = new FilePath(run.getRootDir()).child("tmp"); try { source.build(rev.getHead(), rev).checkout(run, new Launcher.LocalLauncher(listener), ws, listener, null, SCMRevisionState.NONE); } catch (Exception x) { x.printStackTrace(listener.error("could not check out")); assertNull(expectedFile); return; } FilePath file = ws.child("file"); assertEquals(expectedFile, file.exists() ? file.readToString() : null); } }