下面列出了怎么用hudson.model.Slave的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Verifies that affected source files are copied to Jenkins build folder, even if the master - agent security
* is active, see JENKINS-56007 for details.
*/
@Test @org.jvnet.hudson.test.Issue("JENKINS-56007")
public void shouldCopySourcesIfMasterAgentSecurityIsActive() {
Slave agent = createAgentWithEnabledSecurity("agent");
WorkflowJob project = createPipeline();
createFileInAgentWorkspace(agent, project, "Test.java", JAVA_CONTENT);
project.setDefinition(new CpsFlowDefinition("node('agent') {\n"
+ " echo '[javac] Test.java:39: warning: Test Warning'\n"
+ " recordIssues tool: java()\n"
+ "}", true));
AnalysisResult result = scheduleSuccessfulBuild(project);
assertThat(result).hasNoErrorMessages();
assertThat(result).hasTotalSize(1);
assertThat(getConsoleLog(result)).contains("1 copied", "0 not in workspace", "0 not-found", "0 with I/O error");
// TODO: check for the links in the table model
assertThat(getSourceCode(result, 0)).contains(JAVA_CONTENT);
}
/**
* Verifies that the affected files will be copied even if the file name uses the wrong case (Windows only).
*/
@Test
@Issue("JENKINS-58824")
public void shouldMapIssueToAffectedFileIfPathIsInWrongCase() {
assumeThat(isWindows()).as("Running not on Windows").isTrue();
Slave agent = createAgentWithWrongWorkspaceFolder();
FreeStyleProject project = createJobForAgent(agent);
FilePath folder = createFolder(agent, project);
createFileInAgentWorkspace(agent, project, "Folder/Test.java", SOURCE_CODE);
createFileInAgentWorkspace(agent, project, "warnings.txt",
"[javac] " + getAbsolutePathInLowerCase(folder) + ":1: warning: Test Warning for Jenkins");
Java javaJob = new Java();
javaJob.setPattern("warnings.txt");
enableWarnings(project, javaJob);
AnalysisResult result = scheduleSuccessfulBuild(project);
assertThat(result).hasTotalSize(1);
assertThat(result).hasInfoMessages("-> resolved paths in source directory (1 found, 0 not found)");
assertThat(result).doesNotHaveInfoMessages("-> 0 copied, 1 not in workspace, 0 not-found, 0 with I/O error");
}
@SuppressWarnings("checkstyle:IllegalCatch")
private Slave createAgentWithWrongWorkspaceFolder() {
try {
JenkinsRule jenkinsRule = getJenkins();
int size = jenkinsRule.jenkins.getNodes().size();
DumbSlave slave = new DumbSlave("slave" + size,
agentWorkspace.getRoot().getPath().toLowerCase(Locale.ENGLISH),
jenkinsRule.createComputerLauncher(null));
slave.setLabelString("agent");
jenkinsRule.jenkins.addNode(slave);
jenkinsRule.waitOnline(slave);
return slave;
}
catch (Exception e) {
throw new AssertionError(e);
}
}
/**
* Creates an {@link DumbSlave agent} with the specified label. Master - agent security will be enabled.
*
* @param label
* the label of the agent
*
* @return the agent
*/
protected Slave createAgentWithEnabledSecurity(final String label) {
try {
Slave agent = createAgent(label);
FilePath child = getJenkins().getInstance()
.getRootPath()
.child("secrets/filepath-filters.d/30-default.conf");
child.delete();
child.write("", "ISO_8859_1");
Objects.requireNonNull(getJenkins().jenkins.getInjector())
.getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false);
getJenkins().jenkins.save();
return agent;
}
catch (IOException | InterruptedException e) {
throw new AssertionError(e);
}
}
@Test
@Issue("JENKINS-49779")
public void sequentialParallelStagesWithPost() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "sequentialParallelWithPost.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setNumExecutors(2);
// Run until completed
j.buildAndAssertSuccess(p);
List<Map> nodes = get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/", List.class);
assertEquals(9, nodes.size());
Optional<Map> thirdSeqStage = nodes.stream()
.filter(map -> map.get("displayName")
.equals("third-sequential-stage")).findFirst();
assertTrue(thirdSeqStage.isPresent());
List<Map> steps = get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/" + thirdSeqStage.get().get("id") + "/steps/", List.class);
assertEquals(2, steps.size());
assertEquals("echo 'dummy text third-sequential-stage'", steps.get(0).get("displayDescription"));
assertEquals("echo 'dummy text post multiple-stages'", steps.get(1).get("displayDescription"));
}
@Test
public void nestedStagesGroups() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "nestedStagesGroups.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setLabelString("foo");
s.setNumExecutors(4);
// Run until completed
WorkflowRun run = p.scheduleBuild2(0).waitForStart();
j.waitForCompletion(run);
PipelineNodeGraphVisitor pipelineNodeGraphVisitor = new PipelineNodeGraphVisitor(run);
assertTrue(pipelineNodeGraphVisitor.isDeclarative());
List<FlowNodeWrapper> wrappers = pipelineNodeGraphVisitor.getPipelineNodes();
assertEquals(7, wrappers.size());
}
@Test
@Issue("JENKINS-49050")
public void parallelStagesNonNested() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "parallelStagesNonNested.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setLabelString("foo");
s.setNumExecutors(2);
// Run until completed
WorkflowRun run = p.scheduleBuild2(0).waitForStart();
j.waitForCompletion(run);
PipelineNodeGraphVisitor pipelineNodeGraphVisitor = new PipelineNodeGraphVisitor(run);
List<FlowNodeWrapper> wrappers = pipelineNodeGraphVisitor.getPipelineNodes();
assertEquals(3, wrappers.size());
List<Map> nodes = get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/", List.class);
assertEquals(3, nodes.size());
}
/**
* Waits for a newly created slave to come online.
* @see #createSlave()
*/
public void waitOnline(Slave s) throws Exception {
Computer computer = s.toComputer();
AtomicBoolean run = new AtomicBoolean(true);
AnnotatedLargeText<?> logText = computer.getLogText();
Computer.threadPoolForRemoting.submit(() -> {
long pos = 0;
while (run.get() && !logText.isComplete()) {
pos = logText.writeLogTo(pos, System.out);
Thread.sleep(100);
}
return null;
});
try {
if (s.getLauncher().isLaunchSupported()) {
computer.connect(false).get();
} else {
while (!computer.isOnline()) {
Thread.sleep(100);
}
}
} finally {
run.set(false);
}
}
private FreeStyleProject createJobForAgent(final Slave agent) {
try {
FreeStyleProject project = createFreeStyleProject();
project.setAssignedNode(agent);
return project;
}
catch (IOException exception) {
throw new AssertionError(exception);
}
}
private FilePath createFolder(final Slave agent, final FreeStyleProject project) {
try {
FilePath folder = getAgentWorkspace(agent, project).child("Folder");
folder.mkdirs();
return folder;
}
catch (IOException | InterruptedException exception) {
throw new AssertionError(exception);
}
}
/**
* Creates an {@link DumbSlave agent} with the specified label.
*
* @param label
* the label of the agent
*
* @return the agent
*/
@SuppressWarnings("illegalcatch")
protected Slave createAgent(final String label) {
try {
return getJenkins().createOnlineSlave(new LabelAtom(label));
}
catch (Exception e) {
throw new AssertionError(e);
}
}
@Issue("JENKINS-56647")
@Test
public void testOnUpdated() throws Exception {
Slave slave = j.createOnlineSlave();
HtmlForm form = j.createWebClient().getPage(slave, "configure").getFormByName("config");
HtmlInput element = form.getInputByName("_.name");
element.setValueAttribute("newSlaveName");
j.submit(form);
List<LogEvent> events = app.getEvents();
assertThat(events).hasSize(2);
assertThat(events).extracting(event -> ((AuditMessage) event.getMessage()).getId().toString()).contains("createNode", "updateNode");
}
@Test
@Issue("JENKINS-49050")
public void parallelStagesGroupsAndNestedStages() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "parallelStagesGroupsAndStages.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setLabelString("foo");
s.setNumExecutors(2);
// Run until completed
WorkflowRun run = p.scheduleBuild2(0).waitForStart();
j.waitForCompletion(run);
PipelineNodeGraphVisitor pipelineNodeGraphVisitor = new PipelineNodeGraphVisitor(run);
assertTrue(pipelineNodeGraphVisitor.isDeclarative());
List<FlowNodeWrapper> wrappers = pipelineNodeGraphVisitor.getPipelineNodes();
FlowNodeWrapper flowNodeWrapper = wrappers.get(0);
assertEquals("top", flowNodeWrapper.getDisplayName());
assertEquals(2, flowNodeWrapper.edges.size());
flowNodeWrapper = wrappers.get(1);
assertEquals("first", flowNodeWrapper.getDisplayName());
assertEquals(1, flowNodeWrapper.edges.size());
assertEquals(1, flowNodeWrapper.getParents().size());
assertEquals("first-inner-first", flowNodeWrapper.edges.get(0).getDisplayName());
assertEquals(7, wrappers.size());
List<Map> nodes = get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/", List.class);
assertEquals(7, nodes.size());
}
@Test
public void runsOnCorrectSlave() throws Exception {
DockerTestUtil.assumeDocker();
Slave s = j.createOnlineSlave();
s.setLabelString("notthis");
env(s).put("DOCKER_INDICATOR", "WRONG").set();
s = j.createOnlineSlave();
s.setLabelString("thisone");
env(s).put("DOCKER_INDICATOR", "CORRECT").set();
GlobalConfig.get().setDockerLabel("thisone");
GlobalConfig.get().setRegistry(null);
expect("org/jenkinsci/plugins/docker/workflow/declarative/agentDockerEnvTest").runFromRepo(false).logContains("Running on assumed Docker agent").go();
}
@Test
public void runsOnSpecifiedSlave() throws Exception {
DockerTestUtil.assumeDocker();
Slave s = j.createOnlineSlave();
s.setLabelString("thisspec");
env(s).put("DOCKER_INDICATOR", "SPECIFIED").set();
s = j.createOnlineSlave();
s.setLabelString("thisone");
env(s).put("DOCKER_INDICATOR", "CORRECT").set();
GlobalConfig.get().setDockerLabel("thisone");
GlobalConfig.get().setRegistry(null);
expect("org/jenkinsci/plugins/docker/workflow/declarative/agentDockerEnvSpecLabel").runFromRepo(false).logContains("Running on assumed Docker agent").go();
}
@Override
public void afterContainerCreate(DockerClient client, String containerId) throws IOException {
// upload archive
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
TarArchiveOutputStream tarOut = new TarArchiveOutputStream(byteArrayOutputStream)) {
// @see hudson.model.Slave.JnlpJar.getURL()
// byte[] slavejar = IOUtils.toByteArray(Jenkins.getInstance().servletContext.getResourceAsStream("/WEB-INF/slave.jar"));
// if (isNull(null)) {
// // during the development this path doesn't have the files.
// slavejar = Files.readAllBytes(Paths.get("./target/jenkins/WEB-INF/slave.jar"));
// }
byte[] slaveJar = new Slave.JnlpJar("slave.jar").readFully();
TarArchiveEntry entry = new TarArchiveEntry(SLAVE_JAR);
entry.setSize(slaveJar.length);
entry.setMode(0664);
tarOut.putArchiveEntry(entry);
tarOut.write(slaveJar);
tarOut.closeArchiveEntry();
tarOut.close();
try (InputStream is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) {
client.copyArchiveToContainerCmd(containerId)
.withTarInputStream(is)
.withRemotePath("/")
.exec();
}
}
}
@Ignore("Fails on ci.jenkins.io but not locally. Reasons unclear. Likely a timing issue.")
@Test
public void sequentialParallelStagesLongRun() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "sequential_parallel_stages_long_run_time.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setNumExecutors(3);
WorkflowRun run = p.scheduleBuild2(0).waitForStart();
j.waitForCompletion(run);
List<String> watchedStages = Arrays.asList("first-sequential-stage", "second-sequential-stage", "third-sequential-stage");
run = p.scheduleBuild2(0).waitForStart();
Thread.sleep(1000);
long loopCount = 0;
while (run.isBuilding()) {
PipelineNodeContainerImpl pipelineNodeContainer = new PipelineNodeContainerImpl(run, new Link("foo"));
List<BluePipelineNode> nodes = pipelineNodeContainer.getNodes();
for (BluePipelineNode node : nodes) {
if (StringUtils.isEmpty(node.getFirstParent())
&& watchedStages.contains(node.getDisplayName())) {
LOGGER.error("node {} has getFirstParent null", node);
fail("node with getFirstParent null:" + node);
}
// we try to find edges with id for a non existing node in the list
List<BluePipelineNode.Edge> emptyEdges =
node.getEdges().stream().filter(edge ->
!nodes.stream()
.filter(bluePipelineNode -> bluePipelineNode.getId().equals(edge.getId()))
.findFirst().isPresent()
).collect(Collectors.toList());
if (!emptyEdges.isEmpty()) {
// TODO remove this weird if but it's only to have breakpoint in IDE
assertTrue("edges with unknown nodes" + nodes, !emptyEdges.isEmpty());
}
}
LOGGER.debug("nodes size {}", nodes.size());
if (nodes.size() != 9) {
LOGGER.info("loop: " + loopCount + ", nodes size {}", nodes.size());
LOGGER.info("nodes != 9 {}", nodes);
fail("nodes != 9: " + nodes);
}
Thread.sleep(100);
}
}
@Test
@Issue("JENKINS-49050")
public void sequentialParallelStages() throws Exception {
WorkflowJob p = createWorkflowJobWithJenkinsfile(getClass(), "sequentialParallel.jenkinsfile");
Slave s = j.createOnlineSlave();
s.setNumExecutors(2);
// Run until completed
WorkflowRun run = p.scheduleBuild2(0).waitForStart();
j.waitForCompletion(run);
PipelineNodeGraphVisitor pipelineNodeGraphVisitor = new PipelineNodeGraphVisitor(run);
assertTrue(pipelineNodeGraphVisitor.isDeclarative());
List<FlowNodeWrapper> wrappers = pipelineNodeGraphVisitor.getPipelineNodes();
assertEquals(9, wrappers.size());
Optional<FlowNodeWrapper> optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getDisplayName().equals("first-sequential-stage"))
.findFirst();
// we ensure "multiple-stages" is parent of "first-sequential-stage"
assertTrue(optionalFlowNodeWrapper.isPresent());
assertEquals(1, optionalFlowNodeWrapper.get().edges.size());
assertEquals("second-sequential-stage", optionalFlowNodeWrapper.get().edges.get(0).getDisplayName());
final String parentId = optionalFlowNodeWrapper.get().getFirstParent().getId();
optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getId().equals(parentId))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
assertEquals("multiple-stages", optionalFlowNodeWrapper.get().getDisplayName());
assertEquals(1, optionalFlowNodeWrapper.get().edges.size());
optionalFlowNodeWrapper.get().edges.stream()
.filter(nodeWrapper -> nodeWrapper.getDisplayName().equals("first-sequential-stage"))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getDisplayName().equals("other-single-stage"))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
final String otherParentId = optionalFlowNodeWrapper.get().getFirstParent().getId();
optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getId().equals(otherParentId))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
assertEquals("parent", optionalFlowNodeWrapper.get().getDisplayName());
assertEquals(3, optionalFlowNodeWrapper.get().edges.size());
optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getDisplayName().equals("second-sequential-stage"))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
assertEquals(1, optionalFlowNodeWrapper.get().edges.size());
assertEquals("third-sequential-stage", optionalFlowNodeWrapper.get().edges.get(0).getDisplayName());
optionalFlowNodeWrapper =
wrappers.stream().filter(nodeWrapper -> nodeWrapper.getDisplayName().equals("third-sequential-stage"))
.findFirst();
assertTrue(optionalFlowNodeWrapper.isPresent());
assertEquals(1, optionalFlowNodeWrapper.get().edges.size());
assertEquals("second-solo", optionalFlowNodeWrapper.get().edges.get(0).getDisplayName());
List<Map> nodes = get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/", List.class);
assertEquals(9, nodes.size());
Optional<Map> firstSeqStage = nodes.stream()
.filter(map -> map.get("displayName")
.equals("first-sequential-stage")).findFirst();
assertTrue(firstSeqStage.isPresent());
String firstParentId = (String) firstSeqStage.get().get("firstParent");
Optional<Map> parentStage = nodes.stream()
.filter(map -> map.get("id")
.equals(firstParentId)).findFirst();
assertTrue(parentStage.isPresent());
assertEquals("multiple-stages", parentStage.get().get("displayName"));
// ensure no issue getting steps for each node
for (Map<String, String> node : nodes) {
String id = node.get("id");
List<Map> steps =
get("/organizations/jenkins/pipelines/" + p.getName() + "/runs/1/nodes/" + id + "/steps/", List.class);
assertFalse(steps.get(0).isEmpty());
}
}
public EC2FleetNodeComputer(final Slave slave, @Nonnull final String name, @Nonnull final EC2FleetCloud cloud) {
super(slave);
this.name = name;
this.cloud = cloud;
}
/**
* Same as {@link #showAgentLogs(Slave, Map)} but taking a preconfigured list of loggers as a convenience.
*/
public void showAgentLogs(Slave s, LoggerRule loggerRule) throws Exception {
showAgentLogs(s, loggerRule.getRecordedLevels());
}
/**
* Copies the specified files to the workspace of the specified agent. Uses the specified new file name in the
* workspace.
*
* @param agent
* the agent to get the workspace for
* @param job
* the job to get the workspace for
* @param from
* the file to copy
* @param to
* the file name in the workspace
*/
protected void copySingleFileToAgentWorkspace(final Slave agent, final TopLevelItem job,
final String from, final String to) {
FilePath workspace = getAgentWorkspace(agent, job);
copySingleFileToWorkspace(workspace, from, to);
}
/**
* Creates the specified file with the given content to the workspace of the specified agent.
*
* @param agent
* the agent to get the workspace for
* @param job
* the job to get the workspace for
* @param fileName
* the file name
* @param content
* the content to write
*/
protected void createFileInAgentWorkspace(final Slave agent, final TopLevelItem job, final String fileName,
final String content) {
try {
FilePath workspace = getAgentWorkspace(agent, job);
FilePath child = workspace.child(fileName);
child.copyFrom(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
}
catch (IOException | InterruptedException e) {
throw new AssertionError(e);
}
}
/**
* Returns the agent workspace of a job.
*
* @param agent
* the agent
* @param job
* the job
*
* @return path to the workspace
*/
protected FilePath getAgentWorkspace(final Slave agent, final TopLevelItem job) {
FilePath workspace = agent.getWorkspaceFor(job);
assertThat(workspace).isNotNull();
return workspace;
}
/**
* Forward agent logs to standard error of the test process.
* Otherwise log messages would be sent only to {@link Computer#getLogText} etc.,
* or discarded entirely (if below {@link Level#INFO}).
* @param s an <em>online</em> agent
* @param loggers {@link Logger#getName} tied to log level
*/
public void showAgentLogs(Slave s, Map<String, Level> loggers) throws Exception {
s.getChannel().call(new RemoteLogDumper(s.getNodeName(), loggers));
}