/*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Alan Harder
*
* 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 hudson.plugins.copyartifact;
import hudson.FilePath;
import hudson.Launcher;
import hudson.matrix.Axis;
import hudson.matrix.AxisList;
import hudson.matrix.Combination;
import hudson.matrix.MatrixBuild;
import hudson.matrix.MatrixProject;
import hudson.matrix.MatrixRun;
import hudson.model.AbstractBuild;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Cause.UserCause;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.ParametersAction;
import hudson.model.Result;
import hudson.model.StringParameterValue;
import hudson.slaves.DumbSlave;
import hudson.slaves.SlaveComputer;
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.Builder;
import java.io.IOException;
import java.util.Collections;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.UnstableBuilder;
/**
* Test interaction of copyartifact plugin with Hudson core.
* @author Alan Harder
*/
public class CopyArtifactTest extends HudsonTestCase {
private FreeStyleProject createProject(String otherProject, String filter,
String target, boolean stable, boolean flatten, boolean optional)
throws IOException {
FreeStyleProject p = createFreeStyleProject();
p.getBuildersList().add(new CopyArtifact(otherProject,
new StatusBuildSelector(stable), filter, target, flatten, optional));
return p;
}
private static class ArtifactBuilder extends Builder {
@Override public boolean perform(
AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
// Make some files to archive as artifacts
FilePath ws = build.getWorkspace();
ws.child("foo.txt").touch(System.currentTimeMillis());
ws.child("subdir").mkdirs();
ws.child("subdir/subfoo.txt").touch(System.currentTimeMillis());
ws.child("deepfoo/a/b").mkdirs();
ws.child("deepfoo/a/b/c.log").touch(System.currentTimeMillis());
// For matrix tests write one more file:
String foo = build.getBuildVariables().get("FOO");
if (foo != null) ws.child(foo + ".txt").touch(System.currentTimeMillis());
return true;
}
}
private FreeStyleProject createArtifactProject() throws IOException {
FreeStyleProject p = createFreeStyleProject();
p.getBuildersList().add(new ArtifactBuilder());
p.getPublishersList().add(new ArtifactArchiver("**", "", false));
return p;
}
private MatrixProject createMatrixArtifactProject() throws IOException {
MatrixProject p = createMatrixProject();
p.setAxes(new AxisList(new Axis("FOO", "one", "two")));
p.getBuildersList().add(new ArtifactBuilder());
p.getPublishersList().add(new ArtifactArchiver("**", "", false));
return p;
}
private static void assertFile(boolean exists, String path, Build b)
throws IOException, InterruptedException {
if (b.getWorkspace().child(path).exists() != exists)
assertEquals(path + ": " + getLog(b), exists, !exists);
}
public void testMissingProject() throws Exception {
FreeStyleProject p = createProject("invalid", "", "", false, false, false);
assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0, new UserCause()).get());
}
public void testMissingBuild() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "", "", false, false, false);
assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0, new UserCause()).get());
}
public void testMissingStableBuild() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "", "", true, false, false);
// Make an unstable build in "other"
other.getBuildersList().add(new UnstableBuilder());
assertBuildStatus(Result.UNSTABLE, other.scheduleBuild2(0, new UserCause()).get());
assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0, new UserCause()).get());
}
public void testMissingArtifact() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "*.txt", "", false, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0, new UserCause()).get());
}
public void testCopyAll() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createProject(other.getName(), "", "", false, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);
assertFile(true, "subdir/subfoo.txt", b);
assertFile(true, "deepfoo/a/b/c.log", b);
}
public void testCopyWithFilter() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createProject(other.getName(), "**/bogus*, **/sub*, bogus/**", "",
false, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(false, "foo.txt", b);
assertFile(true, "subdir/subfoo.txt", b);
assertFile(false, "deepfoo/a/b/c.log", b);
}
public void testCopyToTarget() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createProject(other.getName(), "deep*/**", "new/deep/dir",
true, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(false, "foo.txt", b);
assertFile(false, "new/deep/dir/foo.txt", b);
assertFile(true, "new/deep/dir/deepfoo/a/b/c.log", b);
}
public void testCopyToSlave() throws Exception {
DumbSlave node = createSlave();
SlaveComputer c = node.getComputer();
c.connect(false).get(); // wait until it's connected
if(c.isOffline())
fail("Slave failed to go online: " + c.getLog());
FreeStyleProject other = createArtifactProject(),
p = createProject(other.getName(), "", "", false, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
p.setAssignedLabel(node.getSelfLabel());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertSame(node, b.getBuiltOn());
assertFile(true, "foo.txt", b);
assertFile(true, "subdir/subfoo.txt", b);
assertFile(true, "deepfoo/a/b/c.log", b);
}
public void testParameters() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createProject("$PROJSRC", "$BASE/*.txt", "$TARGET/bar",
false, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause(),
new ParametersAction(new StringParameterValue("PROJSRC", other.getName()),
new StringParameterValue("BASE", "*r"),
new StringParameterValue("TARGET", "foo"))).get();
assertBuildStatusSuccess(b);
assertFile(false, "foo/bar/foo.txt", b);
assertFile(true, "foo/bar/subdir/subfoo.txt", b);
}
/** Test copying artifacts from a particluar configuration of a matrix job */
public void testMatrixJob() throws Exception {
MatrixProject other = createMatrixArtifactProject();
FreeStyleProject p = createProject(other.getName() + "/FOO=two", "", "",
true, false, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);
assertFile(true, "two.txt", b);
assertFile(true, "subdir/subfoo.txt", b);
assertFile(true, "deepfoo/a/b/c.log", b);
}
/** Test artfiact copy between matrix jobs, for artifact from matching axis */
public void testMatrixToMatrix() throws Exception {
MatrixProject other = createMatrixArtifactProject(),
p = createMatrixProject();
p.setAxes(new AxisList(new Axis("FOO", "one", "two"))); // should match other job
p.getBuildersList().add(new CopyArtifact(other.getName() + "/FOO=$FOO",
new StatusBuildSelector(true), "", "", false, false));
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
MatrixBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
MatrixRun r = b.getRun(new Combination(Collections.singletonMap("FOO", "one")));
assertFile(true, "one.txt", r);
assertFile(false, "two.txt", r);
r = b.getRun(new Combination(Collections.singletonMap("FOO", "two")));
assertFile(false, "one.txt", r);
assertFile(true, "two.txt", r);
}
/** projectName in CopyArtifact build steps should be updated if a job is renamed */
public void testJobRename() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "", "", true, false, false);
assertEquals("before", other.getName(),
((CopyArtifact)p.getBuilders().get(0)).getProjectName());
String newName = other.getName() + "-new";
other.renameTo(newName);
assertEquals("after", newName,
((CopyArtifact)p.getBuilders().get(0)).getProjectName());
// Test reference to a matrix configuration
MatrixProject otherm = createMatrixProject(),
mp = createMatrixProject();
mp.getBuildersList().add(new CopyArtifact(otherm.getName() + "/FOO=$FOO",
new SavedBuildSelector(), "", "", false, false));
assertEquals("before", otherm.getName() + "/FOO=$FOO",
((CopyArtifact)mp.getBuilders().get(0)).getProjectName());
otherm.renameTo(newName = otherm.getName() + "-new");
assertEquals("after", newName + "/FOO=$FOO",
((CopyArtifact)mp.getBuilders().get(0)).getProjectName());
}
public void testSavedBuildSelector() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createFreeStyleProject();
p.getBuildersList().add(new CopyArtifact(other.getName(),
new SavedBuildSelector(), "*.txt", "", false, false));
FreeStyleBuild b = other.scheduleBuild2(0, new UserCause(),
new ParametersAction(new StringParameterValue("FOO", "buildone"))).get();
assertBuildStatusSuccess(b);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()));
b.keepLog(true);
b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);
assertFile(true, "buildone.txt", b);
assertFile(false, "subdir/subfoo.txt", b);
}
public void testSpecificBuildSelector() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createFreeStyleProject();
p.getBuildersList().add(new CopyArtifact(other.getName(),
new SpecificBuildSelector("1"), "*.txt", "", false, false));
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause(),
new ParametersAction(new StringParameterValue("FOO", "buildone"))).get());
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()));
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);
assertFile(true, "buildone.txt", b);
assertFile(false, "subdir/subfoo.txt", b);
}
public void testSpecificBuildSelectorParameter() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createFreeStyleProject();
p.getBuildersList().add(new CopyArtifact(other.getName(),
new SpecificBuildSelector("$FOO"), "*.txt", "", false, false));
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause(),
new ParametersAction(new StringParameterValue("FOO", "1"))).get());
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()));
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "foo.txt", b);
assertFile(true, "buildone.txt", b);
assertFile(false, "subdir/subfoo.txt", b);
}
public void testFlatten() throws Exception {
FreeStyleProject other = createArtifactProject(),
p = createProject(other.getName(), "", "newdir", false, true, false);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
FreeStyleBuild b = p.scheduleBuild2(0, new UserCause()).get();
assertBuildStatusSuccess(b);
assertFile(true, "newdir/foo.txt", b);
assertFile(true, "newdir/subfoo.txt", b);
assertFile(true, "newdir/c.log", b);
}
public void testOptional_MissingProject() throws Exception {
// Missing project still fails even when copy is optional
FreeStyleProject p = createProject("invalid", "", "", false, false, true);
assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0, new UserCause()).get());
}
public void testOptional_MissingBuild() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "", "", false, false, true);
assertBuildStatusSuccess(p.scheduleBuild2(0, new UserCause()).get());
}
public void testOptional_MissingArtifact() throws Exception {
FreeStyleProject other = createFreeStyleProject(),
p = createProject(other.getName(), "*.txt", "", false, false, true);
assertBuildStatusSuccess(other.scheduleBuild2(0, new UserCause()).get());
assertBuildStatusSuccess(p.scheduleBuild2(0, new UserCause()).get());
}
}