/*
* Copyright 2017 ThoughtWorks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.thoughtworks.go.remote.work;
import com.googlecode.junit.ext.JunitExtRunner;
import com.googlecode.junit.ext.RunIf;
import com.thoughtworks.go.config.ConfigCache;
import com.thoughtworks.go.config.CruiseConfig;
import com.thoughtworks.go.config.JobConfig;
import com.thoughtworks.go.config.MagicalGoConfigXmlLoader;
import com.thoughtworks.go.domain.*;
import com.thoughtworks.go.domain.buildcause.BuildCause;
import com.thoughtworks.go.domain.builder.Builder;
import com.thoughtworks.go.helper.ConfigFileFixture;
import com.thoughtworks.go.helper.JobInstanceMother;
import com.thoughtworks.go.helper.StageMother;
import com.thoughtworks.go.junitext.EnhancedOSChecker;
import com.thoughtworks.go.plugin.access.packagematerial.PackageRepositoryExtension;
import com.thoughtworks.go.plugin.access.pluggabletask.TaskExtension;
import com.thoughtworks.go.plugin.access.scm.SCMExtension;
import com.thoughtworks.go.remote.AgentIdentifier;
import com.thoughtworks.go.server.service.AgentRuntimeInfo;
import com.thoughtworks.go.server.service.UpstreamPipelineResolver;
import com.thoughtworks.go.server.service.builders.*;
import com.thoughtworks.go.util.ConfigElementImplementationRegistryMother;
import com.thoughtworks.go.util.FileUtil;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.util.SystemUtil;
import com.thoughtworks.go.util.command.EnvironmentVariableContext;
import com.thoughtworks.go.websocket.MessageEncoding;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static com.thoughtworks.go.domain.JobResult.Failed;
import static com.thoughtworks.go.domain.JobResult.Passed;
import static com.thoughtworks.go.domain.JobState.*;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.DO_NOT_RUN_ON;
import static com.thoughtworks.go.junitext.EnhancedOSChecker.WINDOWS;
import static com.thoughtworks.go.matchers.ConsoleOutMatcher.*;
import static com.thoughtworks.go.matchers.RegexMatcher.matches;
import static com.thoughtworks.go.util.SystemUtil.currentWorkingDirectory;
import static com.thoughtworks.go.util.SystemUtil.isWindows;
import static javax.servlet.http.HttpServletResponse.SC_NOT_ACCEPTABLE;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
@RunWith(JunitExtRunner.class)
public class BuildWorkTest {
public static final String PIPELINE_NAME = "pipeline1";
public static final String PIPELINE_LABEL = "100";
public static final String STAGE_NAME = "mingle";
public static final String JOB_PLAN_NAME = "run-ant";
private BuildWork buildWork;
private AgentIdentifier agentIdentifier;
private static final String NANT = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <nant target=\"-help\"/>\n"
+ " </tasks>\n"
+ "</job>";
private static final String NANT_WITH_WORKINGDIR = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <nant target=\"-help\" workingdir=\"not-exists\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String RAKE = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <rake target=\"--help\"/>\n"
+ " </tasks>\n"
+ "</job>";
private static final String WILL_FAIL = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <ant target=\"something-not-really-exist\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String WILL_PASS = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <ant target=\"-help\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String WITH_ENV_VAR = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <environmentvariables>\n"
+ " <variable name=\"JOB_ENV\">\n"
+ " <value>foobar</value>\n"
+ " </variable>\n"
+ " <variable name=\"" + (isWindows() ? "Path": "PATH") +"\">\n"
+ " <value>/tmp</value>\n"
+ " </variable>\n"
+ " </environmentvariables>\n"
+ " <tasks>\n"
+ " <ant target=\"-help\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String WITH_SECRET_ENV_VAR = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <environmentvariables>\n"
+ " <variable name=\"foo\">\n"
+ " <value>foo(i am a secret)</value>\n"
+ " </variable>\n"
+ " <variable name=\"bar\" secure=\"true\">\n"
+ " <value>i am a secret</value>\n"
+ " </variable>\n"
+ " </environmentvariables>\n"
+ " <tasks>\n"
+ " <ant target=\"-help\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String SOMETHING_NOT_EXIST = "something-not-exist";
private static final String CMD_NOT_EXIST = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <exec command=\"" + SOMETHING_NOT_EXIST + "\" />\n"
+ " </tasks>\n"
+ "</job>";
private static final String WILL_NOT_RUN = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <exec command=\"echo\" args=\"run when status is failed\">\n"
+ " <runif status=\"failed\" />\n"
+ " </exec>\n"
+ " </tasks>\n"
+ "</job>";
private static final String MULTIPLE_TASKS = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <exec command=\"command-not-found\" >\n"
+ " </exec>\n"
+ " <exec command=\"echo\" args=\"run when status is failed\">\n"
+ " <runif status=\"failed\" />\n"
+ " </exec>\n"
+ " <exec command=\"echo\" args=\"run when status is passed\">\n"
+ " <runif status=\"passed\" />\n"
+ " </exec>\n"
+ " <exec command=\"echo\" args=\"run when status is any\">\n"
+ " <runif status=\"any\" />\n"
+ " </exec>\n"
+ " </tasks>\n"
+ "</job>";
private static final String MULTIPLE_RUN_IFS = "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <tasks>\n"
+ " <exec command=\"echo\" args=\"run when status is failed, passed or cancelled\">\n"
+ " <runif status=\"failed\" />\n"
+ " <runif status=\"passed\" />\n"
+ " </exec>\n"
+ " </tasks>\n"
+ "</job>";
private EnvironmentVariableContext environmentVariableContext;
private com.thoughtworks.go.remote.work.BuildRepositoryRemoteStub buildRepository;
private GoArtifactsManipulatorStub artifactManipulator;
private static BuilderFactory builderFactory = new BuilderFactory(new AntTaskBuilder(), new ExecTaskBuilder(), new NantTaskBuilder(), new RakeTaskBuilder(),
new PluggableTaskBuilderCreator(mock(TaskExtension.class)), new KillAllChildProcessTaskBuilder(), new FetchTaskBuilder(), new NullTaskBuilder());
@Mock
private static UpstreamPipelineResolver resolver;
@Mock
private PackageRepositoryExtension packageRepositoryExtension;
@Mock
private SCMExtension scmExtension;
@Mock
private TaskExtension taskExtension;
private static String willUpload(String file) {
return "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <artifacts>\n"
+ " <artifact src=\"something-not-there.txt\" dest=\"dist\" />\n"
+ " <artifact src=\"" + file + "\" dest=\"dist\\test\" />\n"
+ " </artifacts>"
+ " <tasks>\n"
+ " <ant target=\"-help\" />\n"
+ " </tasks>\n"
+ "</job>";
}
private static String willUploadToDest(String file, String dest) {
return "<job name=\"" + JOB_PLAN_NAME + "\">\n"
+ " <artifacts>\n"
+ " <artifact src=\"" + file + "\" dest=\"" + dest + "\" />\n"
+ " </artifacts>"
+ " <tasks>\n"
+ " <ant target=\"-help\" />\n"
+ " </tasks>\n"
+ "</job>";
}
private static final int STAGE_COUNTER = 100;
private static final String SERVER_URL = "somewhere-does-not-matter";
private static final JobIdentifier JOB_IDENTIFIER = new JobIdentifier(PIPELINE_NAME, -3, PIPELINE_LABEL, STAGE_NAME, String.valueOf(STAGE_COUNTER), JOB_PLAN_NAME, 1L);
@Before
public void setUp() throws Exception {
initMocks(this);
agentIdentifier = new AgentIdentifier("localhost", "127.0.0.1", "uuid");
environmentVariableContext = new EnvironmentVariableContext();
artifactManipulator = new GoArtifactsManipulatorStub();
new SystemEnvironment().setProperty("serviceUrl", SERVER_URL);
buildRepository = new com.thoughtworks.go.remote.work.BuildRepositoryRemoteStub();
}
@After
public void tearDown() {
new SystemEnvironment().clearProperty("serviceUrl");
verifyNoMoreInteractions(resolver);
}
@Test
public void shouldReportStatus() throws Exception {
buildWork = (BuildWork) getWork(WILL_FAIL, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(buildRepository.states, containsState(Preparing));
assertThat(buildRepository.states, containsState(Building));
assertThat(buildRepository.states, containsState(Completing));
}
@Test
public void shouldNotRunTaskWhichConditionDoesNotMatch() throws Exception {
buildWork = (BuildWork) getWork(WILL_NOT_RUN, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String actual = artifactManipulator.consoleOut();
assertThat(actual, not(containsString("run when status is failed")));
}
@Test
public void shouldRunTaskWhenConditionMatches() throws Exception {
buildWork = (BuildWork) getWork(MULTIPLE_RUN_IFS, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator,
environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String actual = artifactManipulator.consoleOut();
assertThat(actual, containsString("[go] Task: echo run when status is failed, passed or cancelled"));
assertThat(actual, matches("\\[go] Task status: passed \\(\\d+ ms\\)"));
assertThat(actual, containsString("[go] Current job status: passed"));
assertThat(actual, containsString("run when status is failed, passed or cancelled"));
}
@Test
public void shouldRunTasksBasedOnConditions() throws Exception {
buildWork = (BuildWork) getWork(MULTIPLE_TASKS, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String actual = artifactManipulator.consoleOut();
assertThat(actual, containsString("run when status is failed"));
assertThat(actual, printedExcRunIfInfo("command-not-found", "passed"));
assertThat(actual, containsString("run when status is any"));
assertThat(actual, printedExcRunIfInfo("echo", "run when status is any", "failed"));
assertThat(actual, not(containsString("run when status is passed")));
assertThat(actual, not(printedExcRunIfInfo("echo", "run when status is passed", "failed")));
assertThat(actual, not(containsString("run when status is cancelled")));
assertThat(actual, not(printedExcRunIfInfo("echo", "run when status is cancelled", "failed")));
}
@Test
public void shouldReportBuildIsFailedWhenAntBuildFailed() throws Exception {
buildWork = (BuildWork) getWork(WILL_FAIL, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(buildRepository.results, containsResult(Failed));
}
@Test
public void shouldReportDirectoryNotExists() throws Exception {
buildWork = (BuildWork) getWork(NANT_WITH_WORKINGDIR, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("not-exists\" is not a directory!"));
}
@Test
public void shouldReportUploadMessageWhenUpload() throws Exception {
String destFolder = "dest\\test\\sub-folder";
final String url = String.format("%s/remoting/files/%s/%s/%s/%s/%s/%s?attempt=1&buildId=0", SERVER_URL, PIPELINE_NAME, PIPELINE_LABEL, STAGE_NAME, STAGE_COUNTER, JOB_PLAN_NAME,
destFolder.replaceAll("\\\\", "/"));
buildWork = (BuildWork) getWork(willUploadToDest("cruise-output/log.xml", destFolder), PIPELINE_NAME);
com.thoughtworks.go.remote.work.HttpServiceStub httpService = new com.thoughtworks.go.remote.work.HttpServiceStub(HttpServletResponse.SC_OK);
artifactManipulator = new GoArtifactsManipulatorStub(httpService);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String actual = artifactManipulator.consoleOut();
artifactManipulator.printConsoleOut();
File basedir = new File("pipelines/pipeline1");
assertThat(actual.toLowerCase(), containsString(("Uploading artifacts from " + new File(basedir, "cruise-output/log.xml").getCanonicalPath()).toLowerCase()));
Map<String, File> uploadedFiles = httpService.getUploadedFiles();
assertThat(uploadedFiles.size(), is(1));
assertThat(uploadedFiles.get(url).getAbsolutePath(), containsString("log.xml.zip"));
}
@Test
public void shouldFailTheJobWhenFailedToUploadArtifact() throws Exception {
buildWork = (BuildWork) getWork(willUpload("cruise-output/log.xml"), PIPELINE_NAME);
artifactManipulator = new GoArtifactsManipulatorStub(new HttpServiceStub(SC_NOT_ACCEPTABLE));
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String actual = artifactManipulator.consoleOut();
File basedir = new File("pipelines/pipeline1");
assertThat(actual, printedUploadingFailure(new File(basedir, "cruise-output/log.xml")));
assertThat(buildRepository.results, containsResult(Failed));
}
@Test
public void shouldReportBuildIsFailedWhenAntBuildPassed() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(buildRepository.results, containsResult(Passed));
}
@Test
public void shouldSendAResultStatusToServerWhenAThrowableErrorIsThrown() throws Exception {
JobPlan jobPlan = mock(JobPlan.class);
when(jobPlan.shouldFetchMaterials()).thenThrow(new AssertionError());
when(jobPlan.getIdentifier()).thenReturn(JOB_IDENTIFIER);
createBuildWorkWithJobPlan(jobPlan);
try {
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
fail("Should have thrown an assertion error");
} catch (AssertionError e) {
assertThat(buildRepository.results.isEmpty(), is(true));
assertThat(buildRepository.states.size(), is(1));
assertThat(buildRepository.states.get(0), is(JobState.Preparing));
}
}
@Test
public void shouldSendAResultStatusToServerWhenAnExceptionIsThrown() throws Exception {
JobPlan jobPlan = mock(JobPlan.class);
when(jobPlan.shouldFetchMaterials()).thenThrow(new RuntimeException());
when(jobPlan.getIdentifier()).thenReturn(JOB_IDENTIFIER);
createBuildWorkWithJobPlan(jobPlan);
try {
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
fail("Should have thrown an assertion error");
} catch (AssertionError e) {
assertThat(buildRepository.results.isEmpty(), is(false));
assertThat(buildRepository.results.get(0), is(JobResult.Failed));
}
}
@Test
public void shouldUpdateOnlyStatusWhenBuildIsIgnored() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, "pipeline1");
buildRepository = new com.thoughtworks.go.remote.work.BuildRepositoryRemoteStub(true);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(buildRepository.results.isEmpty(), is(true));
assertThat(buildRepository.states, containsResult(JobState.Completed));
}
@Test
public void shouldUpdateBothStatusAndResultWhenBuildHasPassed() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, "pipeline1");
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(buildRepository.results, containsResult(JobResult.Passed));
assertThat(buildRepository.states, containsResult(JobState.Completed));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {DO_NOT_RUN_ON, WINDOWS})
public void shouldReportErrorWhenComandIsNotExistOnLinux() throws Exception {
buildWork = (BuildWork) getWork(CMD_NOT_EXIST, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext,
new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), printedAppsMissingInfoOnUnix(SOMETHING_NOT_EXIST));
assertThat(buildRepository.results, containsResult(Failed));
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void shouldReportErrorWhenComandIsNotExistOnWindows() throws Exception {
buildWork = (BuildWork) getWork(CMD_NOT_EXIST, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator,
environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), printedAppsMissingInfoOnWindows(SOMETHING_NOT_EXIST));
assertThat(buildRepository.results, containsResult(Failed));
}
@Test
public void shouldReportConsoleout() throws Exception {
buildWork = (BuildWork) getWork(WILL_FAIL, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String consoleOutAsString = artifactManipulator.consoleOut();
String locator = JOB_IDENTIFIER.buildLocator();
assertThat(consoleOutAsString, printedPreparingInfo(locator));
assertThat(consoleOutAsString, printedBuildingInfo(locator));
assertThat(consoleOutAsString, printedUploadingInfo(locator));
assertThat(consoleOutAsString, printedBuildFailed());
}
@Test
@RunIf(value = EnhancedOSChecker.class, arguments = {EnhancedOSChecker.WINDOWS})
public void nantTest() throws Exception {
buildWork = (BuildWork) getWork(NANT, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator,
environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("Usage : NAnt [options] <target> <target> ..."));
}
@Test
public void rakeTest() throws Exception {
buildWork = (BuildWork) getWork(RAKE, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator,
environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("rake [-f rakefile] {options} targets..."));
}
@Test
public void doWork_shouldSkipMaterialUpdateWhenFetchMaterialsIsSetToFalse() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, PIPELINE_NAME, false, false);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("Start to prepare"));
assertThat(artifactManipulator.consoleOut(), not(containsString("Start updating")));
assertThat(artifactManipulator.consoleOut(), containsString("Skipping material update since stage is configured not to fetch materials"));
assertThat(buildRepository.states.contains(JobState.Preparing), is(true));
}
@Test
public void doWork_shouldUpdateMaterialsWhenFetchMaterialsIsTrue() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, PIPELINE_NAME, true, false);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("Start to prepare"));
assertThat(buildRepository.states.contains(JobState.Preparing), is(true));
assertThat(artifactManipulator.consoleOut(), containsString("Start to update materials"));
}
@Test
public void shouldCreateAgentWorkingDirectoryIfNotExist() throws Exception {
String pipelineName = "pipeline" + UUID.randomUUID();
File workingdir = new File("pipelines/" + pipelineName);
if (workingdir.exists()) {
FileUtils.deleteDirectory(workingdir);
}
assertThat(workingdir.exists(), is(false));
buildWork = (BuildWork) getWork(WILL_PASS, pipelineName);
buildWork.doWork(agentIdentifier,
buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(),
not(containsString("Working directory \"" + workingdir.getAbsolutePath() + "\" is not a directory")));
assertThat(buildRepository.results.contains(Passed), is(true));
assertThat(workingdir.exists(), is(true));
FileUtils.deleteDirectory(workingdir);
}
@Test
public void shouldNotBombWhenCreatingWorkingDirectoryIfCleanWorkingDirectoryFlagIsTrue() throws Exception {
String pipelineName = "pipeline" + UUID.randomUUID();
File workingdir = new File("pipelines/" + pipelineName);
if (workingdir.exists()) {
FileUtils.deleteDirectory(workingdir);
}
assertThat(workingdir.exists(), is(false));
buildWork = (BuildWork) getWork(WILL_PASS, pipelineName, true, true);
buildWork.doWork(agentIdentifier,
buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(),
not(containsString("Working directory \"" + workingdir.getAbsolutePath() + "\" is not a directory")));
assertThat(buildRepository.results.contains(Passed), is(true));
assertThat(workingdir.exists(), is(true));
}
@Test
public void shouldCreateAgentWorkingDirectoryIfNotExistWhenFetchMaterialsIsFalse() throws Exception {
String pipelineName = "pipeline" + UUID.randomUUID();
File workingdir = new File("pipelines/" + pipelineName);
if (workingdir.exists()) {
FileUtils.deleteDirectory(workingdir);
}
assertThat(workingdir.exists(), is(false));
buildWork = (BuildWork) getWork(WILL_PASS, pipelineName, false, false);
buildWork.doWork(agentIdentifier,
buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), not(containsString("Working directory \"" + workingdir.getAbsolutePath() + "\" is not a directory")));
assertThat(buildRepository.results.contains(Passed), is(true));
assertThat(workingdir.exists(), is(true));
}
@Test
public void shouldCleanAgentWorkingDirectoryIfExistsWhenCleanWorkingDirIsTrue() throws Exception {
String pipelineName = "pipeline" + UUID.randomUUID();
File workingdir = new File("pipelines/" + pipelineName);
if (workingdir.exists()) {
FileUtils.deleteDirectory(workingdir);
}
workingdir.mkdirs();
createDummyFilesAndDirectories(workingdir);
assertThat(workingdir.listFiles().length, is(2));
buildWork = (BuildWork) getWork(WILL_PASS, pipelineName, false, true);
buildWork.doWork(agentIdentifier,
buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(), containsString("Cleaning working directory \"" + workingdir.getAbsolutePath()));
assertThat(buildRepository.results.contains(Passed), is(true));
assertThat(workingdir.exists(), is(true));
assertThat(workingdir.listFiles().length, is(1));
}
@Test
public void shouldReportCurrentWorkingDirectory() throws Exception {
buildWork = (BuildWork) getWork(WILL_PASS, PIPELINE_NAME);
buildWork.doWork(agentIdentifier,
buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
assertThat(artifactManipulator.consoleOut(),
containsString("[" + SystemUtil.currentWorkingDirectory() + "]"));
}
private void createDummyFilesAndDirectories(File workingdir) {
for (int i = 0; i < 2; i++) {
File directory = new File(workingdir.getPath() + "/dir" + i);
directory.mkdir();
for (int j = 0; j < 10; j++) {
new File(directory.getPath() + "/file" + i);
}
}
}
public static Work getWork(String jobXml, String pipelineName) throws Exception {
return getWork(jobXml, pipelineName, true, false);
}
private static Work getWork(String jobXml, String pipelineName, boolean fetchMaterials, boolean cleanWorkingDir) throws Exception {
CruiseConfig cruiseConfig = new MagicalGoConfigXmlLoader(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins()).loadConfigHolder(FileUtil.readToEnd(IOUtils.toInputStream(ConfigFileFixture.withJob(jobXml, pipelineName)))).config;
JobConfig jobConfig = cruiseConfig.jobConfigByName(pipelineName, STAGE_NAME, JOB_PLAN_NAME, true);
JobPlan jobPlan = JobInstanceMother.createJobPlan(jobConfig, new JobIdentifier(pipelineName, -2, PIPELINE_LABEL, STAGE_NAME, String.valueOf(STAGE_COUNTER), JOB_PLAN_NAME, 0L),
new DefaultSchedulingContext());
jobPlan.setFetchMaterials(fetchMaterials);
jobPlan.setCleanWorkingDir(cleanWorkingDir);
final Stage stage = StageMother.custom(STAGE_NAME, new JobInstance(JOB_PLAN_NAME));
BuildCause buildCause = BuildCause.createWithEmptyModifications();
final Pipeline pipeline = new Pipeline(pipelineName, buildCause, stage);
pipeline.setLabel(PIPELINE_LABEL);
List<Builder> builder = builderFactory.buildersForTasks(pipeline, jobConfig.getTasks(), resolver);
BuildAssignment buildAssignment = BuildAssignment.create(jobPlan,
BuildCause.createWithEmptyModifications(),
builder, pipeline.defaultWorkingFolder()
);
return new BuildWork(buildAssignment);
}
private void createBuildWorkWithJobPlan(JobPlan jobPlan) throws Exception {
CruiseConfig cruiseConfig = new MagicalGoConfigXmlLoader(new ConfigCache(), ConfigElementImplementationRegistryMother.withNoPlugins()).loadConfigHolder(FileUtil.readToEnd(IOUtils.toInputStream(ConfigFileFixture.withJob(CMD_NOT_EXIST)))).config;
JobConfig jobConfig = cruiseConfig.jobConfigByName(PIPELINE_NAME, STAGE_NAME, JOB_PLAN_NAME, true);
final Stage stage = StageMother.custom(STAGE_NAME, new JobInstance(JOB_PLAN_NAME));
BuildCause buildCause = BuildCause.createWithEmptyModifications();
final Pipeline pipeline = new Pipeline(PIPELINE_NAME, buildCause, stage);
List<Builder> builder = builderFactory.buildersForTasks(pipeline, jobConfig.getTasks(), resolver);
BuildAssignment buildAssignment = BuildAssignment.create(jobPlan,
BuildCause.createWithEmptyModifications(),
builder, pipeline.defaultWorkingFolder()
);
buildWork = new BuildWork(buildAssignment);
}
@Test
public void shouldReportEnvironmentVariables() throws Exception {
buildWork = (BuildWork) getWork(WITH_ENV_VAR, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String consoleOut = artifactManipulator.consoleOut();
assertThat(consoleOut, matches("'GO_SERVER_URL' (to|with) value '" + SERVER_URL));
assertThat(consoleOut, matches("'GO_PIPELINE_LABEL' (to|with) value '" + PIPELINE_LABEL));
assertThat(consoleOut, matches("'GO_PIPELINE_NAME' (to|with) value '" + PIPELINE_NAME));
assertThat(consoleOut, matches("'GO_STAGE_NAME' (to|with) value '" + STAGE_NAME));
assertThat(consoleOut, matches("'GO_STAGE_COUNTER' (to|with) value '" + STAGE_COUNTER));
assertThat(consoleOut, matches("'GO_JOB_NAME' (to|with) value '" + JOB_PLAN_NAME));
assertThat(consoleOut, containsString("[go] setting environment variable 'JOB_ENV' to value 'foobar'"));
if (isWindows()) {
assertThat(consoleOut, containsString("[go] overriding environment variable 'Path' with value '/tmp'"));
} else {
assertThat(consoleOut, containsString("[go] overriding environment variable 'PATH' with value '/tmp'"));
}
}
@Test
public void shouldMaskSecretInEnvironmentVarialbeReport() throws Exception {
buildWork = (BuildWork) getWork(WITH_SECRET_ENV_VAR, PIPELINE_NAME);
buildWork.doWork(agentIdentifier, buildRepository, artifactManipulator, environmentVariableContext, new AgentRuntimeInfo(agentIdentifier, AgentRuntimeStatus.Idle, currentWorkingDirectory(), "cookie", false), packageRepositoryExtension, scmExtension, taskExtension);
String consoleOut = artifactManipulator.consoleOut();
assertThat(consoleOut, containsString("[go] setting environment variable 'foo' to value 'foo(******)'"));
assertThat(consoleOut, containsString("[go] setting environment variable 'bar' to value '********'"));
assertThat(consoleOut, not(containsString("i am a secret")));
}
@Test
public void encodeAndDecodeBuildWorkAsMessageData() throws Exception {
Work original = getWork(WILL_FAIL, PIPELINE_NAME);
Work clone = MessageEncoding.decodeWork(MessageEncoding.encodeWork(original));
assertThat(clone, is(original));
}
}