Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
buildPlugin()

stage("UI tests") {
node('docker && highmem') {
checkout scm
docker.image('jenkins/ath:acceptance-test-harness-1.69').inside('-v /var/run/docker.sock:/var/run/docker.sock --shm-size 2g') {
sh """
mvn clean package -DskipTests # Build .hpi before running ATH so the snapshot is consumed instead of latest released
eval \$(vnc.sh)
mvn test -B -Dmaven.test.failure.ignore=true -DforkCount=1 -Ptest-ath
"""
}
junit '**/target/surefire-reports/**/*.xml'
}
}
150 changes: 148 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<jenkins.version>2.150.3</jenkins.version>
<java.level>8</java.level>
<argLine>-Xmx1024m</argLine>
<!-- Skip ATH test by default -->
<test>!ExternalWorkspaceManagerPluginTest</test>
</properties>

<name>External Workspace Manager Plugin</name>
Expand All @@ -41,8 +43,8 @@
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
<developerConnection>scm:git:[email protected]:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
<url>http://github.com/jenkinsci/${project.artifactId}-plugin</url>
<tag>HEAD</tag>
</scm>
<tag>HEAD</tag>
</scm>

<repositories>
<repository>
Expand Down Expand Up @@ -149,6 +151,150 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci</groupId>
<artifactId>acceptance-test-harness</artifactId>
<version>1.69</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
<exclusion>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
</exclusion>
<exclusion>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</exclusion>
<exclusion>
<groupId>org.sonatype.sisu</groupId>
<artifactId>sisu-guice</artifactId>
</exclusion>
<exclusion>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>remoting</artifactId>
</exclusion>
<exclusion>
<groupId>org.jenkins-ci</groupId>
<artifactId>version-number</artifactId>
</exclusion>
<exclusion>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-unixsocket</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-constants</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
</exclusion>
<exclusion>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>htmlunit-driver</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<profiles>
<profile>
<id>test-ath</id>
<properties>
<test>ExternalWorkspaceManagerPluginTest</test>
</properties>

<!-- Needed by ATH -->
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.0-jre</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.lightbody.bmp</groupId>
<artifactId>browsermob-core</artifactId>
<version>2.1.5</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</exclusion>
<exclusion>
<groupId>com.jcraft</groupId>
<artifactId>jzlib</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.12</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<reuseForks>false</reuseForks>
<environmentVariables>
<!-- Read by ATH -->
<JENKINS_VERSION>${jenkins.version}</JENKINS_VERSION>
<LOCAL_JARS>target/external-workspace-manager.hpi</LOCAL_JARS>
<BROWSER>firefox</BROWSER>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package org.jenkinsci.plugins.ewm.acceptance;

import org.jenkinsci.plugins.ewm.acceptance.config.ExternalGlobalConfig;
import org.jenkinsci.plugins.ewm.acceptance.config.ExternalNodeConfig;
import org.jenkinsci.test.acceptance.junit.AbstractJUnitTest;
import org.jenkinsci.test.acceptance.junit.WithPlugins;
import org.jenkinsci.test.acceptance.plugins.maven.MavenInstallation;
import org.jenkinsci.test.acceptance.po.Build;
import org.jenkinsci.test.acceptance.po.Slave;
import org.jenkinsci.test.acceptance.po.WorkflowJob;
import org.jenkinsci.test.acceptance.slave.LocalSlaveController;
import org.jenkinsci.test.acceptance.slave.SlaveController;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.openqa.selenium.By;

import java.util.concurrent.ExecutionException;

import static org.apache.commons.io.FileUtils.listFiles;
import static org.apache.commons.io.filefilter.FileFilterUtils.directoryFileFilter;
import static org.apache.commons.io.filefilter.FileFilterUtils.nameFileFilter;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertThat;

/**
* Acceptance tests for External Workspace Manager Plugin.
*
* @author Alexandru Somai
*/
@WithPlugins({"workflow-aggregator", "external-workspace-manager", "run-selector", "ws-cleanup", "git"})
public class ExternalWorkspaceManagerPluginTest extends AbstractJUnitTest {

@ClassRule
public static TemporaryFolder tmp = new TemporaryFolder();

private static final String DISK_POOL_ID = "diskpool1";
private static final String DISK_ONE = "disk1";
private static final String DISK_TWO = "disk2";
private static final String MOUNT_FROM_MASTER_TO_DISK_ONE = "/fake-mount-point-1";
private static final String MOUNT_FROM_MASTER_TO_DISK_TWO = "/fake-mount-point-2";

private String fakeNodeMountingPoint;

@Before
public void setUp() throws Exception {
MavenInstallation.installMaven(jenkins, "M3", "3.1.0");

setUpGlobalConfig();

fakeNodeMountingPoint = tmp.newFolder().getAbsolutePath();
setUpNode("linux", fakeNodeMountingPoint);
setUpNode("test", fakeNodeMountingPoint);
}

@Test
public void shareWorkspaceOneJobTwoNodes() {
WorkflowJob job = createWorkflowJob(String.format(
"def extWorkspace = exwsAllocate '%s' \n" +
"node ('linux') { \n" +
" exws (extWorkspace) { \n" +
" writeFile file: 'marker', text: 'content' \n" +
" } \n" +
"} \n" +
"node ('test') { \n" +
" exws (extWorkspace) { \n" +
" def content = readFile(file: 'marker') \n" +
" if (content != 'content') error('Content mismatch: ' + content) \n" +
" } \n" +
"}", DISK_POOL_ID));

Build build = job.startBuild();
build.shouldSucceed();
assertThat(build.getConsole(), containsString(String.format("Running in %s/%s/%s", fakeNodeMountingPoint, job.name, build.getNumber())));

verifyExternalWorkspacesAction(job.name, build);
}

@Test
public void shareWorkspaceTwoJobsTwoNodes() {
WorkflowJob upstreamJob = createWorkflowJob(String.format(
"def extWorkspace = exwsAllocate '%s' \n" +
"node ('linux') { \n" +
" exws (extWorkspace) { \n" +
" writeFile file: 'marker', text: 'content' \n " +
" } \n" +
"}", DISK_POOL_ID));

Build upstreamBuild = upstreamJob.startBuild();
upstreamBuild.shouldSucceed();
assertThat(upstreamBuild.getConsole(), containsString(String.format("Running in %s/%s/%s", fakeNodeMountingPoint, upstreamJob.name, upstreamBuild.getNumber())));
verifyExternalWorkspacesAction(upstreamJob.name, upstreamBuild);

WorkflowJob downstreamJob = createWorkflowJob(String.format("" +
"def run = selectRun '%s' \n" +
"def extWorkspace = exwsAllocate selectedRun: run \n" +
"node ('test') { \n" +
" exws (extWorkspace) { \n" +
" def content = readFile(file: 'marker') \n" +
" if (content != 'content') error('Content mismatch: ' + content) \n" +
" } \n" +
"}", upstreamJob.name));

Build downstreamBuild = downstreamJob.startBuild();
downstreamBuild.shouldSucceed();
assertThat(downstreamBuild.getConsole(), containsString(String.format("Running in %s/%s/%s", fakeNodeMountingPoint, upstreamJob.name, upstreamBuild.getNumber())));
verifyExternalWorkspacesAction(upstreamJob.name, downstreamBuild);
}

@Test
public void externalWorkspaceCleanup() {
WorkflowJob job = createWorkflowJob(String.format("" +
"def extWorkspace = exwsAllocate '%s' \n" +
"node ('linux') { \n" +
" exws (extWorkspace) { \n" +
" try { \n" +
" writeFile file: 'foobar.txt', text: 'any' \n" +
" } finally { \n" +
" step ([$class: 'WsCleanup']) \n" +
" } \n" +
" } \n" +
"}", DISK_POOL_ID));

Build build = job.startBuild();
build.shouldSucceed();
String console = build.getConsole();
assertThat(console, containsString(String.format("Running in %s/%s/%s", fakeNodeMountingPoint, job.name, build.getNumber())));
assertThat(console, containsString("[WS-CLEANUP] Deleting project workspace"));
assertThat(console, containsString("[WS-CLEANUP] done"));
assertThat(listFiles(tmp.getRoot(), nameFileFilter("foobar.txt"), directoryFileFilter()), hasSize(0));
}

private void setUpGlobalConfig() {
jenkins.configure();
ExternalGlobalConfig globalConfig = new ExternalGlobalConfig(jenkins.getConfigPage());
globalConfig.addDiskPool(DISK_POOL_ID, DISK_ONE, DISK_TWO, MOUNT_FROM_MASTER_TO_DISK_ONE, MOUNT_FROM_MASTER_TO_DISK_TWO);
jenkins.save();
}

private void setUpNode(String label, String fakeMountingPoint) throws ExecutionException, InterruptedException {
SlaveController controller = new LocalSlaveController();
Slave linuxSlave = controller.install(jenkins).get();
linuxSlave.configure();
linuxSlave.setLabels(label);

ExternalNodeConfig nodeConfig = new ExternalNodeConfig(linuxSlave);
nodeConfig.setConfig(DISK_POOL_ID, DISK_ONE, DISK_TWO, fakeMountingPoint);
linuxSlave.save();
}

private WorkflowJob createWorkflowJob(String script) {
WorkflowJob job = jenkins.jobs.create(WorkflowJob.class);
job.script.set(script);
job.save();

return job;
}

private void verifyExternalWorkspacesAction(String jobName, Build build) {
build.visit("exwsAllocate");
String exwsAllocateText = driver.findElement(By.id("main-panel")).getText();
assertThat(exwsAllocateText, containsString(String.format("Disk Pool ID: %s", DISK_POOL_ID)));
assertThat(exwsAllocateText, containsString(String.format("Disk ID: %s", DISK_ONE)));
assertThat(exwsAllocateText, containsString(String.format("Workspace path on %s: %s/%s", DISK_ONE, jobName, build.getNumber())));
assertThat(exwsAllocateText, containsString(String.format("Complete workspace path on %s (from Jenkins master): %s/%s/%s",
DISK_ONE, MOUNT_FROM_MASTER_TO_DISK_ONE, jobName, build.getNumber())));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.jenkinsci.plugins.ewm.acceptance.config;

import org.jenkinsci.test.acceptance.po.JenkinsConfig;
import org.jenkinsci.test.acceptance.po.PageAreaImpl;

/**
* Helper class for interacting with External Workspace Manager Plugin global config page.
*
* @author Alexandru Somai
*/
public class ExternalGlobalConfig extends PageAreaImpl {

public ExternalGlobalConfig(JenkinsConfig context) {
super(context, "/org-jenkinsci-plugins-ewm-steps-ExwsAllocateStep");
}

public void addDiskPool(String diskPoolId, String diskOneId, String diskTwoId,
String mountToDiskOne, String mountToDiskTwo) {
// add disk pool
control("repeatable-add").click();
control("diskPools/diskPoolId").set(diskPoolId);

// add first disk
control("diskPools/repeatable-add").click();
control("diskPools/disks/diskId").set(diskOneId);
control("diskPools/disks/masterMountPoint").set(mountToDiskOne);

// add second disk
control("diskPools/repeatable-add").click();
control("diskPools/disks[1]/diskId").set(diskTwoId);
control("diskPools/disks[1]/masterMountPoint").set(mountToDiskTwo);
}
}
Loading