├── .gitignore ├── Jenkinsfile ├── README ├── .github └── workflows │ └── jenkins-security-scan.yml ├── LICENSE ├── src ├── test │ ├── resources │ │ ├── auto │ │ │ └── Xvfb │ │ ├── default │ │ │ └── Xvfb │ │ ├── working │ │ │ └── Xvfb │ │ └── failing │ │ │ └── Xvfb │ └── java │ │ └── org │ │ └── jenkinsci │ │ └── plugins │ │ └── xvfb │ │ ├── AutoDisplayNameFilterStreamTest.java │ │ ├── BaseXvfbTest.java │ │ ├── XvfbBuildWrapperWorkflowTest.java │ │ ├── XvfbBuildWrapperInstallationDefaultsTest.java │ │ └── XvfbBuildWrapperTest.java └── main │ ├── resources │ ├── org │ │ └── jenkinsci │ │ │ └── plugins │ │ │ └── xvfb │ │ │ ├── XvfbInstallation │ │ │ ├── help-name.html │ │ │ ├── help-home.html │ │ │ └── config.jelly │ │ │ ├── Xvfb │ │ │ ├── help-installationName.html │ │ │ ├── help-additionalOptions.html │ │ │ ├── help-shutdownWithBuild.html │ │ │ ├── help-debug.html │ │ │ ├── help-screen.html │ │ │ ├── help-displayNameOffset.html │ │ │ ├── help-assignedLabels.html │ │ │ ├── help-autoDisplayName.html │ │ │ ├── help-displayName.html │ │ │ ├── help-timeout.html │ │ │ ├── help-parallelBuild.html │ │ │ └── config.jelly │ │ │ └── Messages.properties │ └── index.jelly │ ├── webapp │ └── help-globalConfig.html │ └── java │ └── org │ └── jenkinsci │ └── plugins │ └── xvfb │ ├── XvfbDisposer.java │ ├── XvfbEnvironment.java │ ├── XvfbEnvironmentConverter.java │ ├── AutoDisplayNameFilterStream.java │ ├── XvfbInstallation.java │ └── Xvfb.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings 2 | /.classpath 3 | /.project 4 | target 5 | /work -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | /* `buildPlugin` step provided by: https://github.com/jenkins-infra/pipeline-library */ 4 | buildPlugin() 5 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a plugin for Jenkins-CI (http://jenkins-ci.org) that starts Xvfb (http://www.x.org/archive/current/doc/man/man1/Xvfb.1.xhtml) with the start of the job, and stops it when the job is done. 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/jenkins-security-scan.yml: -------------------------------------------------------------------------------- 1 | name: Jenkins Security Scan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ opened, synchronize, reopened ] 9 | workflow_dispatch: 10 | 11 | permissions: 12 | security-events: write 13 | contents: read 14 | actions: read 15 | 16 | jobs: 17 | security-scan: 18 | uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2 19 | with: 20 | java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate. 21 | # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default. 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Zoran Regvart All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 14 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 15 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 16 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 17 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 18 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 19 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 20 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 21 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 22 | SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /src/test/resources/auto/Xvfb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Copyright © 2012, Zoran Regvart 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | # The views and conclusions contained in the software and documentation are those 27 | # of the authors and should not be interpreted as representing official policies, 28 | # either expressed or implied, of the FreeBSD Project. 29 | # 30 | 31 | echo 42 >&2 32 | tail -f /dev/null 33 | -------------------------------------------------------------------------------- /src/test/resources/default/Xvfb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Copyright © 2012, Zoran Regvart 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | # The views and conclusions contained in the software and documentation are those 27 | # of the authors and should not be interpreted as representing official policies, 28 | # either expressed or implied, of the FreeBSD Project. 29 | # 30 | 31 | echo $* 32 | tail -f /dev/null 33 | -------------------------------------------------------------------------------- /src/test/resources/working/Xvfb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Copyright © 2012, Zoran Regvart 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | # The views and conclusions contained in the software and documentation are those 27 | # of the authors and should not be interpreted as representing official policies, 28 | # either expressed or implied, of the FreeBSD Project. 29 | # 30 | 31 | echo $* 32 | tail -f /dev/null 33 | -------------------------------------------------------------------------------- /src/test/resources/failing/Xvfb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | # Copyright © 2012, Zoran Regvart 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions are met: 8 | # 9 | # 1. Redistributions of source code must retain the above copyright notice, this 10 | # list of conditions and the following disclaimer. 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | # 26 | # The views and conclusions contained in the software and documentation are those 27 | # of the authors and should not be interpreted as representing official policies, 28 | # either expressed or implied, of the FreeBSD Project. 29 | # 30 | 31 | echo This Xvfb will fail 32 | exit 1 33 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/XvfbInstallation/help-name.html: -------------------------------------------------------------------------------- 1 | 31 |
Name of the installation.
32 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-installationName.html: -------------------------------------------------------------------------------- 1 | 31 |
The name of the Xvfb tool installation that Jenkins 32 | administrator set up.
33 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-additionalOptions.html: -------------------------------------------------------------------------------- 1 | 31 |
Additional options to be added with the options above to the 32 | Xvfb command line.
33 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-shutdownWithBuild.html: -------------------------------------------------------------------------------- 1 | 31 |
Should the display be kept until the whole job ends 32 | (including the post build steps).
33 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-debug.html: -------------------------------------------------------------------------------- 1 | 31 |
If Xvfb output should appear in console log of this job, 32 | useful only if debugging Xvfb interaction.
33 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/XvfbInstallation/help-home.html: -------------------------------------------------------------------------------- 1 | 31 |
Path to the directory in which Xvfb executable resides, it 32 | can be empty -- then PATH will be consulted.
-------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-screen.html: -------------------------------------------------------------------------------- 1 | 31 |
32 | Resolution and color depth of the created virtual frame buffer in the 33 | format WxHxD. For example: 34 | 1024x758x16 35 |
36 | -------------------------------------------------------------------------------- /src/main/resources/index.jelly: -------------------------------------------------------------------------------- 1 | 31 | 32 |
33 | This plugin starts before build, and stops after the build the 34 | Xvfb 35 | virtual framebuffer X11 server. 36 |
37 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-displayNameOffset.html: -------------------------------------------------------------------------------- 1 | 31 |
Offset for display names, default is 1. Display names are 32 | taken from build executor’s number, i.e. if the build is performed by 33 | executor 4, and offset is 100, display name will be 104.
34 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-assignedLabels.html: -------------------------------------------------------------------------------- 1 | 31 |
32 | If you want to start Xvfb only on specific nodes specify its name or 33 | label. See the Restrict where this project can be run option for 34 | label expressions that you can use. 35 |
36 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-autoDisplayName.html: -------------------------------------------------------------------------------- 1 | 31 |
Uses the -displayfd option of Xvfb by which it chooses its 32 | own display name by scanning for an available one. This option requires 33 | a recent version of xserver, check your installation for support.
34 | -------------------------------------------------------------------------------- /src/main/webapp/help-globalConfig.html: -------------------------------------------------------------------------------- 1 | 31 |
32 | This HTML fragment will be injected into the configuration screen 33 | when the user clicks the 'help' icon. See global.jelly for how the 34 | form decides which page to load. 35 | You can have any HTML fragment here. 36 |
37 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-displayName.html: -------------------------------------------------------------------------------- 1 | 31 |
Ordinal of the display Xvfb will be running on, if left empty 32 | (default) chosen based on current build executor number. Use only 33 | if you know what you’re doing, could lead to clashes with other 34 | builds.
35 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-timeout.html: -------------------------------------------------------------------------------- 1 | 31 |
A timeout of given seconds to wait before returning control 32 | to the job, this allows Xvfb to start before there is a need for it. By 33 | default set to 0, not to delay the build, since it usually takes just a 34 | few seconds for Xvfb to start, and outputting to display is not the 35 | first thing a job does.
36 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/XvfbInstallation/config.jelly: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/help-parallelBuild.html: -------------------------------------------------------------------------------- 1 | 31 |
When running multiple Jenkins nodes on the same machine this 32 | setting influences the display number generation. The display number 33 | will be based upon node position in the list of nodes multiplied by 100 34 | to which current executor number and any given offset will be added. 35 | Using this with offset set to 0 there is a limit of 595 nodes and 35 36 | executors on a node, having more nodes or executors is not compatible 37 | with this option.
38 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/XvfbDisposer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.IOException; 32 | 33 | import hudson.FilePath; 34 | import hudson.Launcher; 35 | import hudson.model.Run; 36 | import hudson.model.TaskListener; 37 | import jenkins.tasks.SimpleBuildWrapper.Disposer; 38 | 39 | public class XvfbDisposer extends Disposer { 40 | 41 | private static final long serialVersionUID = 1L; 42 | 43 | private final XvfbEnvironment xvfb; 44 | 45 | public XvfbDisposer(final XvfbEnvironment xvfb) { 46 | this.xvfb = xvfb; 47 | } 48 | 49 | @Override 50 | public void tearDown(final Run run, final FilePath workspace, final Launcher launcher, final TaskListener listener) throws IOException, InterruptedException { 51 | if (!xvfb.shutdownWithBuild) { 52 | Xvfb.shutdownAndCleanup(xvfb, launcher, listener); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/XvfbEnvironment.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.Serializable; 32 | 33 | import hudson.model.InvisibleAction; 34 | 35 | public class XvfbEnvironment extends InvisibleAction implements Serializable { 36 | 37 | private static final long serialVersionUID = 1L; 38 | 39 | /** Remote path of the frame buffer dir */ 40 | public final String frameBufferDir; 41 | 42 | /** Actual display name used */ 43 | public final int displayName; 44 | 45 | /** The shutdownWithBuild indicator from the job configuration. */ 46 | public final boolean shutdownWithBuild; 47 | 48 | /** Random value identifying the Xvfb process. */ 49 | public String cookie; 50 | 51 | public XvfbEnvironment(final String cookie, final String frameBufferDir, final int displayName, final boolean shutdownWithBuild) { 52 | this.cookie = cookie; 53 | this.frameBufferDir = frameBufferDir; 54 | this.displayName = displayName; 55 | this.shutdownWithBuild = shutdownWithBuild; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Messages.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright © 2012, Zoran Regvart 3 | # All rights reserved. 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # 14 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | # 25 | # The views and conclusions contained in the software and documentation are those 26 | # of the authors and should not be interpreted as representing official policies, 27 | # either expressed or implied, of the FreeBSD Project. 28 | # 29 | 30 | XvfbBuildWrapper.DisplayName = Start Xvfb before the build, and shut it down after. 31 | XvfbBuildWrapper.NotUnix = System is not Unix, Xvfb will not be started 32 | XvfbBuildWrapper.Starting = Xvfb starting 33 | XvfbBuildWrapper.Stopping = Xvfb stopping 34 | XvfbBuildWrapper.NoInstallationsConfigured = No Xvfb installations defined, please define one in the configuration. Once defined you\u2019ll need to choose one under Advanced options for Xvfb plugin job settings and save job configuration. 35 | XvfbBuildWrapper.FailedToStart = Xvfb failed to start, consult the lines above for errors 36 | XvfbBuildWrapper.KillingZombies = Trying to kill zombie Xvfb process that\u2019s occupying display name: {0} and frame buffer directory: {1} 37 | XvfbBuildWrapper.ZombieSlainFailed = Unable to kill zombie Xvfb process, you\u2019ll need to do your own slaying. 38 | XvfbBuildWrapper.AssignedLabelString.InvalidBooleanExpression = Invalid boolean expression: {0} 39 | XvfbBuildWrapper.AssignedLabelString.NoMatch.DidYouMean = There\u2019s no slave/cloud that matches this assignment. Did you mean \u2018{1}\u2019 instead of \u2018{0}\u2019? 40 | XvfbBuildWrapper.AssignedLabelString.NoMatch = There\u2019s no slave/cloud that matches this assignment 41 | XvfbBuildWrapper.LabelLink = Slaves in label: {2} 42 | 43 | XvfbInstallation.DisplayName = Xvfb installation 44 | XvfbInstallation.HomeNotDirectory = Home path is not a directory: {0} 45 | XvfbInstallation.HomeDoesntContainXvfb = Home path does not contain Xvfb executable: {0} 46 | XvfbInstallation.XvfbIsNotExecutable = Home path contains Xvfb executable but it is not executable: {0} 47 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/XvfbEnvironmentConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import com.thoughtworks.xstream.converters.Converter; 32 | import com.thoughtworks.xstream.converters.MarshallingContext; 33 | import com.thoughtworks.xstream.converters.UnmarshallingContext; 34 | import com.thoughtworks.xstream.io.HierarchicalStreamReader; 35 | import com.thoughtworks.xstream.io.HierarchicalStreamWriter; 36 | 37 | public class XvfbEnvironmentConverter implements Converter { 38 | 39 | private static final String COOKIE = "cookie"; 40 | 41 | private static final String REMOTE_FRAME_BUFFER_DIR_ATTR = "remoteFrameBufferDir"; 42 | 43 | private static final String DISPLAY_NAME_USED_ATTR = "displayNameUsed"; 44 | 45 | @Override 46 | public boolean canConvert(@SuppressWarnings("rawtypes") final Class type) { 47 | return type != null && XvfbEnvironment.class.isAssignableFrom(type); 48 | } 49 | 50 | @Override 51 | public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { 52 | final XvfbEnvironment xvfbEnvironment = (XvfbEnvironment) source; 53 | 54 | writer.addAttribute(COOKIE, xvfbEnvironment.cookie); 55 | writer.addAttribute(DISPLAY_NAME_USED_ATTR, String.valueOf(xvfbEnvironment.displayName)); 56 | writer.addAttribute(REMOTE_FRAME_BUFFER_DIR_ATTR, xvfbEnvironment.frameBufferDir); 57 | } 58 | 59 | @Override 60 | public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { 61 | final String cookie = reader.getAttribute(COOKIE); 62 | 63 | final String frameBufferDir = reader.getAttribute(REMOTE_FRAME_BUFFER_DIR_ATTR); 64 | 65 | final int displayNameUsed = Integer.parseInt(reader.getAttribute(DISPLAY_NAME_USED_ATTR)); 66 | 67 | final XvfbEnvironment xvfbEnvironment = new XvfbEnvironment(cookie, frameBufferDir, displayNameUsed, false); 68 | 69 | return xvfbEnvironment; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/AutoDisplayNameFilterStream.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.FilterOutputStream; 32 | import java.io.IOException; 33 | import java.io.OutputStream; 34 | import java.util.concurrent.Semaphore; 35 | import java.util.concurrent.TimeUnit; 36 | 37 | public class AutoDisplayNameFilterStream extends FilterOutputStream { 38 | 39 | private final Semaphore received = new Semaphore(1); 40 | 41 | private final char[] lastLine = new char[1024]; 42 | 43 | private int idx; 44 | 45 | private int displayNumber; 46 | 47 | private final long waitTime; 48 | 49 | protected AutoDisplayNameFilterStream(final OutputStream decorated) { 50 | this(decorated, 30); 51 | } 52 | 53 | protected AutoDisplayNameFilterStream(final OutputStream decorated, final int waitTime) { 54 | super(decorated); 55 | 56 | this.waitTime = waitTime; 57 | 58 | try { 59 | received.acquire(); 60 | } catch (final InterruptedException e) { 61 | throw new IllegalStateException("Unable to acquire semaphore upon creation", e); 62 | } 63 | 64 | } 65 | 66 | @Override 67 | public void close() throws IOException { 68 | received.release(); 69 | super.close(); 70 | } 71 | 72 | public int getDisplayNumber() throws InterruptedException { 73 | if (received.tryAcquire(waitTime, TimeUnit.SECONDS)) { 74 | return displayNumber; 75 | } 76 | 77 | throw new IllegalStateException("No display name received from Xvfb within " + waitTime + " seconds"); 78 | } 79 | 80 | @Override 81 | public void write(final int ch) throws IOException { 82 | if (ch == '\n' || ch == '\r') { 83 | if (idx != 0) { 84 | final String line = new String(lastLine, 0, idx); 85 | if (line.matches("\\d+")) { 86 | displayNumber = Integer.parseInt(line); 87 | received.release(); 88 | } 89 | } 90 | 91 | idx = 0; 92 | } 93 | else if (idx < lastLine.length - 1) { 94 | lastLine[idx++] = (char) ch; 95 | } 96 | 97 | super.write(ch); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/resources/org/jenkinsci/plugins/xvfb/Xvfb/config.jelly: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/xvfb/AutoDisplayNameFilterStreamTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.ByteArrayOutputStream; 32 | import java.io.PrintStream; 33 | 34 | import org.junit.Assert; 35 | import org.junit.Test; 36 | 37 | public class AutoDisplayNameFilterStreamTest { 38 | 39 | @Test 40 | public void shouldParseDisplayNumber() throws InterruptedException { 41 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 42 | final AutoDisplayNameFilterStream stream = new AutoDisplayNameFilterStream(out); 43 | 44 | final PrintStream printer = new PrintStream(stream); 45 | 46 | printer.println("hello world"); 47 | printer.println("the display number is next"); 48 | printer.println("1234"); 49 | printer.println("that was the display number"); 50 | 51 | printer.flush(); 52 | printer.close(); 53 | 54 | Assert.assertEquals("display number should be parsed", 1234, stream.getDisplayNumber()); 55 | Assert.assertTrue("should contain all that is written", 56 | new String(out.toByteArray()).matches("hello world[\\n\\r]the display number is next[\\n\\r]1234[\\n\\r]that was the display number[\\n\\r]")); 57 | } 58 | 59 | @Test 60 | public void shouldWaitAndReceiveDisplayNumber() throws InterruptedException { 61 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 62 | final AutoDisplayNameFilterStream stream = new AutoDisplayNameFilterStream(out, 1); 63 | 64 | final PrintStream printer = new PrintStream(stream); 65 | 66 | printer.println("hello world"); 67 | printer.println("the display number is next"); 68 | printer.println("that was the display number"); 69 | 70 | try { 71 | stream.getDisplayNumber(); 72 | Assert.fail("No IllegalStateException received!"); 73 | } catch (final IllegalStateException ignore) { 74 | } 75 | 76 | printer.println("42"); 77 | 78 | Assert.assertEquals("display number should be 42", 42, stream.getDisplayNumber()); 79 | 80 | printer.flush(); 81 | printer.close(); 82 | } 83 | 84 | @Test(expected = IllegalStateException.class) 85 | public void shouldWaitForDisplayNumber() throws InterruptedException { 86 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 87 | final AutoDisplayNameFilterStream stream = new AutoDisplayNameFilterStream(out, 1); 88 | 89 | final PrintStream printer = new PrintStream(stream); 90 | 91 | printer.println("hello world"); 92 | printer.println("the display number is next"); 93 | printer.println("that was the display number"); 94 | 95 | stream.getDisplayNumber(); 96 | 97 | printer.flush(); 98 | printer.close(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/xvfb/BaseXvfbTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.File; 32 | import java.io.FileNotFoundException; 33 | import java.io.FileOutputStream; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | 37 | import org.junit.rules.TemporaryFolder; 38 | import org.jvnet.hudson.test.JenkinsRule; 39 | 40 | import com.google.common.io.ByteStreams; 41 | import com.google.common.io.Closeables; 42 | 43 | import hudson.DescriptorExtensionList; 44 | import hudson.model.Descriptor; 45 | import hudson.model.FreeStyleBuild; 46 | import hudson.model.FreeStyleProject; 47 | import hudson.tasks.BuildWrapper; 48 | import hudson.tools.ToolInstallation; 49 | import hudson.util.DescribableList; 50 | import jenkins.model.Jenkins; 51 | 52 | public abstract class BaseXvfbTest { 53 | 54 | protected static FreeStyleProject createFreeStyleJob(final JenkinsRule system, final String name) throws IOException { 55 | return system.jenkins.createProject(FreeStyleProject.class, name); 56 | } 57 | 58 | protected static XvfbInstallation createInstallation(final String nameAndPath, final TemporaryFolder tempDir) throws IOException, FileNotFoundException { 59 | final File xvfbDir = tempDir.newFolder(nameAndPath); 60 | final File xvfb = new File(xvfbDir, "Xvfb"); 61 | 62 | InputStream xvfbFrom = null; 63 | FileOutputStream xvfbTo = null; 64 | try { 65 | xvfbFrom = XvfbBuildWrapperTest.class.getResourceAsStream("/" + nameAndPath + "/Xvfb"); 66 | xvfbTo = new FileOutputStream(xvfb); 67 | ByteStreams.copy(xvfbFrom, xvfbTo); 68 | } finally { 69 | Closeables.closeQuietly(xvfbFrom); 70 | Closeables.closeQuietly(xvfbTo); 71 | } 72 | xvfb.setExecutable(true); 73 | 74 | return new XvfbInstallation(nameAndPath, xvfbDir.getAbsolutePath(), null); 75 | } 76 | 77 | protected static FreeStyleBuild runFreestyleJobWith(final JenkinsRule system, final Xvfb xvfb) throws IOException, Exception { 78 | final FreeStyleProject project = createFreeStyleJob(system, "xvfbFreestyleJob"); 79 | setupXvfbOn(project, xvfb); 80 | 81 | return system.buildAndAssertSuccess(project); 82 | } 83 | 84 | protected static void setupXvfbOn(final FreeStyleProject project, final Xvfb xvfb) { 85 | final DescribableList> buildWrappers = project.getBuildWrappersList(); 86 | 87 | buildWrappers.add(xvfb); 88 | } 89 | 90 | protected void setupXvfbInstallations(final Jenkins jenkins, final TemporaryFolder tempDir) throws IOException { 91 | final XvfbInstallation.DescriptorImpl installations = new XvfbInstallation.DescriptorImpl(); 92 | 93 | installations.setInstallations(createInstallation("working", tempDir), createInstallation("failing", tempDir), createInstallation("auto", tempDir)); 94 | 95 | final DescriptorExtensionList> toolInstallations = jenkins.getDescriptorList(ToolInstallation.class); 96 | toolInstallations.add(installations); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/XvfbInstallation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.File; 32 | import java.io.IOException; 33 | import java.util.List; 34 | 35 | import org.jenkinsci.Symbol; 36 | import org.kohsuke.stapler.DataBoundConstructor; 37 | import org.kohsuke.stapler.QueryParameter; 38 | import org.kohsuke.stapler.StaplerRequest; 39 | 40 | import hudson.EnvVars; 41 | import hudson.Extension; 42 | import hudson.model.EnvironmentSpecific; 43 | import hudson.model.Node; 44 | import hudson.model.TaskListener; 45 | import hudson.slaves.NodeSpecific; 46 | import hudson.tools.ToolDescriptor; 47 | import hudson.tools.ToolInstallation; 48 | import hudson.tools.ToolProperty; 49 | import hudson.util.FormValidation; 50 | import jenkins.model.Jenkins; 51 | import net.sf.json.JSONObject; 52 | 53 | @SuppressWarnings("serial") 54 | public class XvfbInstallation extends ToolInstallation implements NodeSpecific, EnvironmentSpecific { 55 | 56 | @Extension 57 | @Symbol("xvfb") 58 | public static class DescriptorImpl extends ToolDescriptor { 59 | 60 | @Override 61 | public boolean configure(final StaplerRequest req, final JSONObject json) throws FormException { 62 | final List boundList = req.bindJSONToList(XvfbInstallation.class, json.get("tool")); 63 | 64 | setInstallations(boundList.toArray(new XvfbInstallation[boundList.size()])); 65 | 66 | return true; 67 | } 68 | 69 | @Override 70 | public FormValidation doCheckHome(@QueryParameter final File value) { 71 | // this can be used to check the existence of a file on the server, so needs to be protected 72 | if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { 73 | return FormValidation.ok(); 74 | } 75 | 76 | if ("".equals(value.getPath())) { 77 | // will try path 78 | return FormValidation.ok(); 79 | } 80 | 81 | if (!value.isDirectory()) { 82 | return FormValidation.error(Messages.XvfbInstallation_HomeNotDirectory(value)); 83 | } 84 | 85 | final File xvfbExecutable = new File(value, "Xvfb"); 86 | if (!xvfbExecutable.exists()) { 87 | return FormValidation.error(Messages.XvfbInstallation_HomeDoesntContainXvfb(value)); 88 | } 89 | 90 | if (!xvfbExecutable.canExecute()) { 91 | return FormValidation.error(Messages.XvfbInstallation_XvfbIsNotExecutable(value)); 92 | } 93 | 94 | return FormValidation.ok(); 95 | } 96 | 97 | @Override 98 | public FormValidation doCheckName(@QueryParameter final String value) { 99 | return FormValidation.validateRequired(value); 100 | } 101 | 102 | @Override 103 | public String getDisplayName() { 104 | return Messages.XvfbInstallation_DisplayName(); 105 | } 106 | 107 | @Override 108 | public XvfbInstallation[] getInstallations() { 109 | return Jenkins.get().getDescriptorByType(Xvfb.XvfbBuildWrapperDescriptor.class).getInstallations(); 110 | } 111 | 112 | public DescriptorImpl getToolDescriptor() { 113 | return ToolInstallation.all().get(DescriptorImpl.class); 114 | } 115 | 116 | @Override 117 | public void setInstallations(final XvfbInstallation... installations) { 118 | Jenkins.get().getDescriptorByType(Xvfb.XvfbBuildWrapperDescriptor.class).setInstallations(installations); 119 | } 120 | } 121 | 122 | @DataBoundConstructor 123 | public XvfbInstallation(final String name, final String home, final List> properties) { 124 | super(name, home, properties); 125 | } 126 | 127 | @Override 128 | public XvfbInstallation forEnvironment(final EnvVars environment) { 129 | return new XvfbInstallation(getName(), environment.expand(getHome()), getProperties().toList()); 130 | } 131 | 132 | @Override 133 | public XvfbInstallation forNode(final Node node, final TaskListener log) throws IOException, InterruptedException { 134 | return new XvfbInstallation(getName(), translateFor(node, log), getProperties().toList()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/xvfb/XvfbBuildWrapperWorkflowTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 32 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 33 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 34 | import org.jenkinsci.plugins.workflow.steps.CoreWrapperStep; 35 | import org.jenkinsci.plugins.workflow.steps.StepConfigTester; 36 | import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; 37 | import org.junit.Rule; 38 | import org.junit.Test; 39 | import org.junit.rules.TemporaryFolder; 40 | import org.jvnet.hudson.test.JenkinsRule; 41 | import org.jvnet.hudson.test.RestartableJenkinsRule; 42 | 43 | public class XvfbBuildWrapperWorkflowTest extends BaseXvfbTest { 44 | 45 | @Rule 46 | public RestartableJenkinsRule restartableSystem = new RestartableJenkinsRule(); 47 | 48 | @Rule 49 | public TemporaryFolder tempDir = new TemporaryFolder(); 50 | 51 | @Test 52 | public void configurationShouldRoundTrip() { 53 | restartableSystem.then(new RestartableJenkinsRule.Step() { 54 | 55 | @Override 56 | public void run(final JenkinsRule rule) throws Throwable { 57 | final Xvfb xvfb = new Xvfb(); 58 | xvfb.setAssignedLabels(""); 59 | xvfb.setAdditionalOptions(""); 60 | 61 | final CoreWrapperStep wrapperStep = new CoreWrapperStep(xvfb); 62 | 63 | final CoreWrapperStep testerStep = new StepConfigTester(restartableSystem.j).configRoundTrip(wrapperStep); 64 | 65 | restartableSystem.j.assertEqualDataBoundBeans(xvfb, testerStep.getDelegate()); 66 | } 67 | }); 68 | } 69 | 70 | @Test 71 | public void shouldAllowWorkflowRestarts() { 72 | restartableSystem.then(new RestartableJenkinsRule.Step() { 73 | 74 | @Override 75 | public void run(final JenkinsRule rule) throws Throwable { 76 | setupXvfbInstallations(restartableSystem.j.jenkins, tempDir); 77 | 78 | final WorkflowJob workflowJob = restartableSystem.j.jenkins.createProject(WorkflowJob.class, "shouldAllowWorkflowRestarts"); 79 | 80 | workflowJob.setDefinition(new CpsFlowDefinition(""// 81 | + "node {\n"// 82 | + " wrap([$class: 'Xvfb', installationName: 'working']) {\n"// 83 | + " semaphore 'shouldAllowWorkflowRestarts'\n"// 84 | + " sh 'echo DISPLAY=$DISPLAY'\n"// 85 | + " }\n"// 86 | + "}", true)); 87 | 88 | final WorkflowRun workflowRun = workflowJob.scheduleBuild2(0).waitForStart(); 89 | 90 | SemaphoreStep.waitForStart("shouldAllowWorkflowRestarts/1", workflowRun); 91 | } 92 | 93 | }); 94 | 95 | restartableSystem.then(new RestartableJenkinsRule.Step() { 96 | 97 | @Override 98 | public void run(final JenkinsRule rule) throws Throwable { 99 | SemaphoreStep.success("shouldAllowWorkflowRestarts/1", null); 100 | 101 | final WorkflowJob workflowProject = restartableSystem.j.jenkins.getItemByFullName("shouldAllowWorkflowRestarts", WorkflowJob.class); 102 | 103 | final WorkflowRun workflowRun = workflowProject.getBuildByNumber(1); 104 | 105 | restartableSystem.j.assertBuildStatusSuccess(restartableSystem.j.waitForCompletion(workflowRun)); 106 | 107 | restartableSystem.j.assertLogContains("DISPLAY=:", workflowRun); 108 | } 109 | 110 | }); 111 | } 112 | 113 | @Test 114 | public void shouldSupportWorkflow() { 115 | restartableSystem.then(new RestartableJenkinsRule.Step() { 116 | 117 | @Override 118 | public void run(final JenkinsRule rule) throws Throwable { 119 | setupXvfbInstallations(restartableSystem.j.jenkins, tempDir); 120 | 121 | final WorkflowJob workflowJob = restartableSystem.j.jenkins.createProject(WorkflowJob.class, "shouldSupportWorkflow"); 122 | 123 | workflowJob.setDefinition(new CpsFlowDefinition(""// 124 | + "node {\n"// 125 | + " wrap([$class: 'Xvfb', installationName: 'working']) {\n"// 126 | + " sh 'echo DISPLAY=$DISPLAY'\n"// 127 | + " }\n"// 128 | + "}", true)); 129 | 130 | final WorkflowRun workflowRun = workflowJob.scheduleBuild2(0).waitForStart(); 131 | 132 | restartableSystem.j.assertBuildStatusSuccess(restartableSystem.j.waitForCompletion(workflowRun)); 133 | 134 | restartableSystem.j.assertLogContains("DISPLAY=:", workflowRun); 135 | } 136 | 137 | }); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/xvfb/XvfbBuildWrapperInstallationDefaultsTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; 32 | import org.jenkinsci.plugins.workflow.job.WorkflowJob; 33 | import org.jenkinsci.plugins.workflow.job.WorkflowRun; 34 | import org.junit.Rule; 35 | import org.junit.Test; 36 | import org.junit.rules.TemporaryFolder; 37 | import org.jvnet.hudson.test.JenkinsRule; 38 | import org.jvnet.hudson.test.RestartableJenkinsRule; 39 | 40 | import hudson.DescriptorExtensionList; 41 | import hudson.model.Descriptor; 42 | import hudson.tools.ToolInstallation; 43 | 44 | public class XvfbBuildWrapperInstallationDefaultsTest extends BaseXvfbTest { 45 | 46 | @Rule 47 | public RestartableJenkinsRule restartableSystem = new RestartableJenkinsRule(); 48 | 49 | @Rule 50 | public TemporaryFolder tempDir = new TemporaryFolder(); 51 | 52 | @Test 53 | public void shouldUseTheDefaultInstalationIfNoExplicitNameSpecified() { 54 | restartableSystem.then(new RestartableJenkinsRule.Step() { 55 | 56 | @Override 57 | public void run(final JenkinsRule rule) throws Throwable { 58 | final XvfbInstallation.DescriptorImpl installations = new XvfbInstallation.DescriptorImpl(); 59 | 60 | installations.setInstallations(createInstallation("default", tempDir), createInstallation("failing", tempDir)); 61 | 62 | final DescriptorExtensionList> toolInstallations = restartableSystem.j.jenkins.getDescriptorList(ToolInstallation.class); 63 | toolInstallations.add(installations); 64 | 65 | final Xvfb xvfb = new Xvfb(); 66 | 67 | runFreestyleJobWith(restartableSystem.j, xvfb); 68 | } 69 | }); 70 | } 71 | 72 | @Test 73 | public void shouldUseTheDefaultInstallationInWorkflow() { 74 | restartableSystem.then(new RestartableJenkinsRule.Step() { 75 | 76 | @Override 77 | public void run(final JenkinsRule rule) throws Throwable { 78 | final XvfbInstallation.DescriptorImpl installations = new XvfbInstallation.DescriptorImpl(); 79 | 80 | installations.setInstallations(createInstallation("default", tempDir), createInstallation("working", tempDir)); 81 | 82 | final DescriptorExtensionList> toolInstallations = restartableSystem.j.jenkins.getDescriptorList(ToolInstallation.class); 83 | toolInstallations.add(installations); 84 | 85 | final WorkflowJob workflowJob = restartableSystem.j.jenkins.createProject(WorkflowJob.class, "shouldUseTheOnlyInstallationInWorkflow"); 86 | 87 | workflowJob.setDefinition(new CpsFlowDefinition(""// 88 | + "node {\n"// 89 | + " wrap([$class: 'Xvfb']) {\n"// 90 | + " sh 'echo DISPLAY=$DISPLAY'\n"// 91 | + " }\n"// 92 | + "}", true)); 93 | 94 | final WorkflowRun workflowRun = workflowJob.scheduleBuild2(0).waitForStart(); 95 | 96 | restartableSystem.j.assertBuildStatusSuccess(restartableSystem.j.waitForCompletion(workflowRun)); 97 | 98 | restartableSystem.j.assertLogContains("DISPLAY=:", workflowRun); 99 | } 100 | }); 101 | } 102 | 103 | @Test 104 | public void shouldUseTheOnlyInstalationIfNoExplicitNameSpecified() { 105 | restartableSystem.then(new RestartableJenkinsRule.Step() { 106 | 107 | @Override 108 | public void run(final JenkinsRule rule) throws Throwable { 109 | final XvfbInstallation.DescriptorImpl installations = new XvfbInstallation.DescriptorImpl(); 110 | 111 | installations.setInstallations(createInstallation("working", tempDir)); 112 | 113 | final DescriptorExtensionList> toolInstallations = restartableSystem.j.jenkins.getDescriptorList(ToolInstallation.class); 114 | toolInstallations.add(installations); 115 | 116 | final Xvfb xvfb = new Xvfb(); 117 | 118 | runFreestyleJobWith(restartableSystem.j, xvfb); 119 | } 120 | }); 121 | } 122 | 123 | @Test 124 | public void shouldUseTheOnlyInstallationInWorkflow() { 125 | restartableSystem.then(new RestartableJenkinsRule.Step() { 126 | 127 | @Override 128 | public void run(final JenkinsRule rule) throws Throwable { 129 | final XvfbInstallation.DescriptorImpl installations = new XvfbInstallation.DescriptorImpl(); 130 | 131 | installations.setInstallations(createInstallation("working", tempDir)); 132 | 133 | final DescriptorExtensionList> toolInstallations = restartableSystem.j.jenkins.getDescriptorList(ToolInstallation.class); 134 | toolInstallations.add(installations); 135 | 136 | final WorkflowJob workflowJob = restartableSystem.j.jenkins.createProject(WorkflowJob.class, "shouldUseTheOnlyInstallationInWorkflow"); 137 | 138 | workflowJob.setDefinition(new CpsFlowDefinition(""// 139 | + "node {\n"// 140 | + " wrap([$class: 'Xvfb']) {\n"// 141 | + " sh 'echo DISPLAY=$DISPLAY'\n"// 142 | + " }\n"// 143 | + "}", true)); 144 | 145 | final WorkflowRun workflowRun = workflowJob.scheduleBuild2(0).waitForStart(); 146 | 147 | restartableSystem.j.assertBuildStatusSuccess(restartableSystem.j.waitForCompletion(workflowRun)); 148 | 149 | restartableSystem.j.assertLogContains("DISPLAY=:", workflowRun); 150 | } 151 | }); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 31 | 32 | 4.0.0 33 | 34 | org.jenkins-ci.plugins 35 | plugin 36 | 4.19 37 | 38 | 39 | 40 | xvfb 41 | 1.3-SNAPSHOT 42 | hpi 43 | Jenkins Xvfb plugin 44 | Starts and stopps Xvfb with the build 45 | http://wiki.jenkins-ci.org/display/JENKINS/Xvfb+Plugin 46 | 2012 47 | 48 | 49 | 50 | 2-clause BSD license 51 | repo 52 | http://www.opensource.org/licenses/bsd-license.php 53 | 54 | 55 | 56 | 57 | 58 | zregvart 59 | Zoran Regvart 60 | zregvart+xvfbjenkins@gmail.com 61 | 62 | 63 | 64 | 65 | scm:git:git://github.com/jenkinsci/xvfb-plugin.git 66 | scm:git:https://github.com/jenkinsci/xvfb-plugin.git 67 | https://github.com/jenkinsci/xvfb-plugin/ 68 | HEAD 69 | 70 | 71 | 72 | 1.2 73 | -SNAPSHOT 74 | 75 | 2.222 76 | ${jenkins.baseline}.4 77 | 8 78 | 79 | 80 | 81 | 82 | repo.jenkins-ci.org 83 | https://repo.jenkins-ci.org/public/ 84 | 85 | 86 | 87 | 88 | 89 | repo.jenkins-ci.org 90 | https://repo.jenkins-ci.org/public/ 91 | 92 | 93 | 94 | 95 | 96 | 97 | com.mycila 98 | license-maven-plugin 99 | 2.11 100 | 101 |
com/mycila/maven/plugin/license/templates/BSD-2.txt
102 | 103 | Zoran Regvart 104 | 105 | 106 | README 107 | LICENSE 108 | work/** 109 | 110 | 111 | XML_STYLE 112 | SCRIPT_STYLE 113 | 114 |
115 | 116 | 117 | 118 | check 119 | 120 | 121 | 122 |
123 |
124 |
125 | 126 | 127 | 128 | 129 | io.jenkins.tools.bom 130 | bom-${jenkins.baseline}.x 131 | 29 132 | import 133 | pom 134 | 135 | 136 | 137 | 138 | 139 | 140 | org.jenkins-ci.plugins 141 | structs 142 | 143 | 144 | org.jenkins-ci.plugins.workflow 145 | workflow-job 146 | test 147 | 148 | 149 | org.jenkins-ci.plugins.workflow 150 | workflow-basic-steps 151 | test 152 | 153 | 154 | org.jenkins-ci.plugins.workflow 155 | workflow-cps 156 | test 157 | 158 | 159 | org.jenkins-ci.plugins.workflow 160 | workflow-durable-task-step 161 | test 162 | 163 | 164 | org.jenkins-ci.plugins.workflow 165 | workflow-step-api 166 | tests 167 | test 168 | 169 | 170 | org.jenkins-ci.plugins.workflow 171 | workflow-support 172 | tests 173 | test 174 | 175 | 176 | 177 |
178 | -------------------------------------------------------------------------------- /src/test/java/org/jenkinsci/plugins/xvfb/XvfbBuildWrapperTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import static com.google.common.collect.Iterables.filter; 32 | import static org.hamcrest.MatcherAssert.assertThat; 33 | import static org.hamcrest.Matchers.contains; 34 | import static org.hamcrest.Matchers.containsInAnyOrder; 35 | import static org.hamcrest.Matchers.containsString; 36 | import static org.hamcrest.Matchers.empty; 37 | import static org.hamcrest.Matchers.greaterThanOrEqualTo; 38 | import static org.hamcrest.Matchers.hasItems; 39 | import static org.hamcrest.Matchers.hasSize; 40 | import static org.hamcrest.Matchers.instanceOf; 41 | import static org.hamcrest.Matchers.is; 42 | import static org.hamcrest.core.IsNot.not; 43 | 44 | import java.io.ByteArrayOutputStream; 45 | import java.io.File; 46 | import java.io.IOException; 47 | import java.io.OutputStream; 48 | import java.util.Arrays; 49 | import java.util.List; 50 | 51 | import org.junit.After; 52 | import org.junit.Before; 53 | import org.junit.Rule; 54 | import org.junit.Test; 55 | import org.junit.rules.TemporaryFolder; 56 | import org.jvnet.hudson.test.Issue; 57 | import org.jvnet.hudson.test.JenkinsRule; 58 | 59 | import com.google.common.base.Function; 60 | import com.google.common.base.Joiner; 61 | import com.google.common.base.Predicate; 62 | import com.google.common.base.Predicates; 63 | import com.google.common.collect.Iterables; 64 | 65 | import hudson.FilePath; 66 | import hudson.Launcher; 67 | import hudson.Launcher.LocalLauncher; 68 | import hudson.model.AbstractBuild; 69 | import hudson.model.Computer; 70 | import hudson.model.FreeStyleBuild; 71 | import hudson.model.FreeStyleProject; 72 | import hudson.model.Label; 73 | import hudson.model.Node; 74 | import hudson.model.Result; 75 | import hudson.model.StreamBuildListener; 76 | import hudson.model.queue.QueueTaskFuture; 77 | import hudson.tasks.BuildWrapper.Environment; 78 | import hudson.util.ArgumentListBuilder; 79 | import hudson.util.ProcessTree; 80 | import hudson.util.ProcessTree.OSProcess; 81 | 82 | public class XvfbBuildWrapperTest extends BaseXvfbTest { 83 | 84 | @Rule 85 | public JenkinsRule system = new JenkinsRule(); 86 | 87 | @Rule 88 | public TemporaryFolder tempDir = new TemporaryFolder(); 89 | 90 | @Test 91 | public void byDefaultBuildnumbersShouldBeBasedOnExecutorNumber() throws Exception { 92 | system.jenkins.setNumExecutors(3); 93 | 94 | final Xvfb xvfb = new Xvfb(); 95 | xvfb.setInstallationName("working"); 96 | 97 | final FreeStyleProject project1 = createFreeStyleJob(system, "byDefaultBuildnumbersShouldBeBasedOnExecutorNumber1"); 98 | setupXvfbOn(project1, xvfb); 99 | 100 | final FreeStyleProject project2 = createFreeStyleJob(system, "byDefaultBuildnumbersShouldBeBasedOnExecutorNumber2"); 101 | setupXvfbOn(project2, xvfb); 102 | 103 | final FreeStyleProject project3 = createFreeStyleJob(system, "byDefaultBuildnumbersShouldBeBasedOnExecutorNumber3"); 104 | setupXvfbOn(project3, xvfb); 105 | 106 | final QueueTaskFuture build1Result = project1.scheduleBuild2(0); 107 | final QueueTaskFuture build2Result = project2.scheduleBuild2(0); 108 | final QueueTaskFuture build3Result = project3.scheduleBuild2(0); 109 | 110 | final FreeStyleBuild build1 = build1Result.get(); 111 | final FreeStyleBuild build2 = build2Result.get(); 112 | final FreeStyleBuild build3 = build3Result.get(); 113 | 114 | final int display1 = build1.getAction(XvfbEnvironment.class).displayName; 115 | final int display2 = build2.getAction(XvfbEnvironment.class).displayName; 116 | final int display3 = build3.getAction(XvfbEnvironment.class).displayName; 117 | 118 | final List displayNumbersUsed = Arrays.asList(display1, display2, display3); 119 | assertThat("By default display numbers should be based on executor number, they were: " + displayNumbersUsed, displayNumbersUsed, containsInAnyOrder(1, 2, 3)); 120 | } 121 | 122 | @Test 123 | @Issue("JENKINS-26848") 124 | public void inParallelBuildsBuildnumbersShouldBeOffsettedByComputerNumber() throws Exception { 125 | system.createSlave("label1", null); 126 | 127 | final Xvfb xvfb = new Xvfb(); 128 | xvfb.setInstallationName("working"); 129 | xvfb.setParallelBuild(true); 130 | 131 | final FreeStyleProject project = createFreeStyleJob(system, "inParallelBuildsBuildnumbersShouldBeOffsettedByComputerNumber"); 132 | setupXvfbOn(project, xvfb); 133 | project.setAssignedLabel(Label.get("label1")); 134 | 135 | final FreeStyleBuild build = system.buildAndAssertSuccess(project); 136 | 137 | assertThat("For parallel builds display name should be based on computer number 100 * computer index offset", build.getAction(XvfbEnvironment.class).displayName, is(101)); 138 | } 139 | 140 | @Before 141 | public void setupXvfbInstallations() throws IOException { 142 | setupXvfbInstallations(system.jenkins, tempDir); 143 | } 144 | 145 | @Test 146 | public void shouldCreateCommandLineArguments() throws IOException { 147 | final Xvfb xvfb = new Xvfb(); 148 | xvfb.setInstallationName("cmd"); 149 | xvfb.setDisplayName(42); 150 | 151 | final XvfbInstallation installation = new XvfbInstallation("cmd", "/usr/local/cmd-xvfb", null); 152 | 153 | final File tempDirRoot = tempDir.getRoot(); 154 | final ArgumentListBuilder arguments = xvfb.createCommandArguments(installation, new FilePath(tempDirRoot), 42); 155 | 156 | assertThat(arguments.toList(), contains("/usr/local/cmd-xvfb/Xvfb", ":42", "-screen", "0", Xvfb.DEFAULT_SCREEN, "-fbdir", tempDirRoot.getAbsolutePath())); 157 | } 158 | 159 | @Test 160 | @Issue("JENKINS-32039") 161 | public void shouldCreateCommandLineArgumentsWithoutScreenIfEmpty() throws IOException { 162 | final Xvfb xvfb = new Xvfb(); 163 | xvfb.setInstallationName("cmd"); 164 | xvfb.setDisplayName(42); 165 | xvfb.setScreen(""); 166 | 167 | final XvfbInstallation installation = new XvfbInstallation("cmd", "/usr/local/cmd-xvfb", null); 168 | 169 | final File tempDirRoot = tempDir.getRoot(); 170 | final ArgumentListBuilder arguments = xvfb.createCommandArguments(installation, new FilePath(tempDirRoot), 42); 171 | 172 | assertThat(arguments.toList(), contains("/usr/local/cmd-xvfb/Xvfb", ":42", "-fbdir", tempDirRoot.getAbsolutePath())); 173 | } 174 | 175 | @Test 176 | @Issue("JENKINS-32039") 177 | public void shouldCreateCommandLineArgumentsWithoutScreenIfNotGiven() throws IOException { 178 | final Xvfb xvfb = new Xvfb(); 179 | xvfb.setInstallationName("cmd"); 180 | xvfb.setDisplayName(42); 181 | xvfb.setScreen(null); 182 | 183 | final XvfbInstallation installation = new XvfbInstallation("cmd", "/usr/local/cmd-xvfb", null); 184 | 185 | final File tempDirRoot = tempDir.getRoot(); 186 | final ArgumentListBuilder arguments = xvfb.createCommandArguments(installation, new FilePath(tempDirRoot), 42); 187 | 188 | assertThat(arguments.toList(), contains("/usr/local/cmd-xvfb/Xvfb", ":42", "-fbdir", tempDirRoot.getAbsolutePath())); 189 | } 190 | 191 | @SuppressWarnings("unchecked") 192 | @Test 193 | public void shouldFailIfInstallationIsNotFound() throws Exception { 194 | final Xvfb xvfb = new Xvfb(); 195 | xvfb.setInstallationName("nonexistant"); 196 | 197 | final FreeStyleProject project = createFreeStyleJob(system, "shouldFailIfInstallationIsNotFound"); 198 | setupXvfbOn(project, xvfb); 199 | 200 | final QueueTaskFuture buildResult = project.scheduleBuild2(0); 201 | 202 | final FreeStyleBuild build = buildResult.get(); 203 | 204 | system.assertBuildStatus(Result.FAILURE, build); 205 | 206 | final List logLines = build.getLog(10); 207 | 208 | assertThat("If no Xvfb installations defined for use log should note that", logLines, hasItems(containsString("No Xvfb installations defined, please define one in the configuration"))); 209 | } 210 | 211 | @SuppressWarnings("unchecked") 212 | @Test 213 | public void shouldFailIfNoInstallationIsDefined() throws Exception { 214 | final Xvfb xvfb = new Xvfb(); 215 | 216 | final FreeStyleProject project = createFreeStyleJob(system, "shouldFailIfNoInstallationIsDefined"); 217 | setupXvfbOn(project, xvfb); 218 | 219 | final QueueTaskFuture buildResult = project.scheduleBuild2(0); 220 | 221 | final FreeStyleBuild build = buildResult.get(); 222 | 223 | system.assertBuildStatus(Result.FAILURE, build); 224 | 225 | final List logLines = build.getLog(10); 226 | 227 | assertThat("If no Xvfb installations defined for use log should note that", logLines, hasItems(containsString("No Xvfb installations defined, please define one in the configuration"))); 228 | } 229 | 230 | @SuppressWarnings("unchecked") 231 | @Test 232 | @Issue("JENKINS-18094") 233 | public void shouldFailIfXvfbFailsToStart() throws Exception { 234 | final Xvfb xvfb = new Xvfb(); 235 | xvfb.setInstallationName("failing"); 236 | xvfb.setTimeout(10); 237 | 238 | final FreeStyleProject project = createFreeStyleJob(system, "shouldFailIfXvfbFailsToStart"); 239 | setupXvfbOn(project, xvfb); 240 | 241 | final QueueTaskFuture buildResult = project.scheduleBuild2(0); 242 | 243 | final FreeStyleBuild build = buildResult.get(); 244 | 245 | system.assertBuildStatus(Result.FAILURE, build); 246 | 247 | final List logLines = build.getLog(10); 248 | 249 | assertThat("If Xvfb fails to start log should indicate that", logLines, 250 | hasItems(containsString("This Xvfb will fail"), containsString("Xvfb failed to start, consult the lines above for errors"))); 251 | 252 | } 253 | 254 | @Test 255 | public void shouldHonourSpecifiedDisplayNameOffset() throws Exception { 256 | final Xvfb xvfb = new Xvfb(); 257 | xvfb.setInstallationName("working"); 258 | xvfb.setDisplayNameOffset(100); 259 | 260 | final FreeStyleBuild build = runFreestyleJobWith(system, xvfb); 261 | 262 | assertThat("DISPLAY environment variable should be larger than 100 as is specified by offset of 100", build.getAction(XvfbEnvironment.class).displayName, greaterThanOrEqualTo(100)); 263 | } 264 | 265 | @After 266 | public void shouldNotLeakProcesses() throws Exception { 267 | final String testXvfbDir = tempDir.getRoot().getName(); 268 | 269 | final Iterable leaks = Iterables.transform(filter(ProcessTree.get(), new Predicate() { 270 | @Override 271 | public boolean apply(final OSProcess process) { 272 | final List arguments = process.getArguments(); 273 | return Iterables.any(arguments, Predicates.containsPattern(testXvfbDir + "/\\w+/Xvfb")); 274 | } 275 | }), new Function() { 276 | 277 | @Override 278 | public Integer apply(final OSProcess process) { 279 | return process.getPid(); 280 | } 281 | }); 282 | 283 | assertThat("Found leaked processes, PIDs: " + Joiner.on(',').join(leaks), leaks.iterator().hasNext(), is(false)); 284 | } 285 | 286 | @Test 287 | @Issue("JENKINS-14483") 288 | public void shouldNotRunOnNonUnixNodes() throws IOException, InterruptedException { 289 | final Xvfb xvfb = new Xvfb(); 290 | 291 | final LocalLauncher launcher = new Launcher.LocalLauncher(system.createTaskListener()) { 292 | @Override 293 | public boolean isUnix() { 294 | return false; 295 | } 296 | }; 297 | 298 | final OutputStream out = new ByteArrayOutputStream(); 299 | 300 | final FreeStyleProject project = system.createFreeStyleProject(); 301 | 302 | @SuppressWarnings("rawtypes") 303 | final Environment environment = xvfb.setUp((AbstractBuild) new FreeStyleBuild(project), launcher, new StreamBuildListener(out)); 304 | 305 | assertThat("Environment should not be setup", environment, not(instanceOf(XvfbEnvironment.class))); 306 | } 307 | 308 | @Test 309 | @Issue("JENKINS-23155") 310 | public void shouldNotRunOnUnLabeledNodes() throws Exception { 311 | final FreeStyleProject project = createFreeStyleJob(system, "shouldNotRunOnUnLabeledNodes"); 312 | 313 | final Xvfb xvfb = new Xvfb(); 314 | xvfb.setInstallationName("working"); 315 | xvfb.setAssignedLabels("label1"); 316 | 317 | setupXvfbOn(project, xvfb); 318 | 319 | final FreeStyleBuild build = system.buildAndAssertSuccess(project); 320 | assertThat("Xvfb should not be started if label is not matched", build.getActions(XvfbEnvironment.class), empty()); 321 | } 322 | 323 | @SuppressWarnings("unchecked") 324 | @Test 325 | @Issue("JENKINS-13046") 326 | public void shouldPassOnAdditionalCommandLineArguments() throws Exception { 327 | final Xvfb xvfb = new Xvfb(); 328 | xvfb.setInstallationName("working"); 329 | xvfb.setDisplayName(42); 330 | xvfb.setAdditionalOptions("additional options"); 331 | 332 | final FreeStyleBuild build = runFreestyleJobWith(system, xvfb); 333 | 334 | final List logLines = build.getLog(10); 335 | 336 | assertThat("Additional command line options should be passed to Xvfb", logLines, hasItems(containsString("additional options"))); 337 | } 338 | 339 | @Test 340 | public void shouldPickupXvfbAutoDeterminedDisplayNumber() throws Exception { 341 | final Xvfb xvfb = new Xvfb(); 342 | xvfb.setInstallationName("auto"); 343 | xvfb.setAutoDisplayName(true); 344 | 345 | final FreeStyleBuild build = runFreestyleJobWith(system, xvfb); 346 | 347 | assertThat("DISPLAY environment variable should be 42, as it was determined automatically by Xvfb", build.getAction(XvfbEnvironment.class).displayName, is(42)); 348 | } 349 | 350 | @Test 351 | @Issue("JENKINS-23155") 352 | public void shouldRunOnLabeledNodes() throws Exception { 353 | final Computer computer = system.jenkins.createComputer(); 354 | final Node node = computer.getNode(); 355 | node.setLabelString("label1"); 356 | 357 | final FreeStyleProject project = createFreeStyleJob(system, "shouldRunOnLabeledNodes"); 358 | project.setAssignedNode(node); 359 | 360 | final Xvfb xvfb = new Xvfb(); 361 | xvfb.setInstallationName("working"); 362 | xvfb.setAssignedLabels("label1"); 363 | 364 | setupXvfbOn(project, xvfb); 365 | 366 | final FreeStyleBuild build = system.buildAndAssertSuccess(project); 367 | assertThat("Xvfb should be started if label is matched", build.getActions(XvfbEnvironment.class), hasSize(1)); 368 | } 369 | 370 | @Test 371 | @Issue("JENKINS-14483") 372 | public void shouldRunOnUnixNodes() throws Exception { 373 | final Xvfb xvfb = new Xvfb(); 374 | xvfb.setInstallationName("working"); 375 | 376 | final FreeStyleProject project = createFreeStyleJob(system, "shouldRunOnUnixNodes"); 377 | setupXvfbOn(project, xvfb); 378 | 379 | final FreeStyleBuild build = system.buildAndAssertSuccess(project); 380 | 381 | final Launcher launcher = build.getBuiltOn().createLauncher(system.createTaskListener()); 382 | 383 | assertThat("Launcher should be on Unix", launcher.isUnix(), is(true)); 384 | 385 | assertThat("Environment should be setup", build.getActions(XvfbEnvironment.class), hasSize(1)); 386 | } 387 | 388 | @Test 389 | public void shouldShutdownWithBuild() throws Exception { 390 | final Xvfb xvfb = new Xvfb(); 391 | xvfb.setInstallationName("working"); 392 | xvfb.setShutdownWithBuild(true); 393 | 394 | runFreestyleJobWith(system, xvfb); 395 | 396 | } 397 | 398 | @Test 399 | public void shouldUseSpecifiedDisplayName() throws Exception { 400 | final Xvfb xvfb = new Xvfb(); 401 | xvfb.setInstallationName("working"); 402 | xvfb.setDisplayName(42); 403 | 404 | final FreeStyleBuild build = runFreestyleJobWith(system, xvfb); 405 | 406 | assertThat("DISPLAY environment variable should be 42, as is specified by configuration", build.getAction(XvfbEnvironment.class).displayName, is(42)); 407 | } 408 | } 409 | -------------------------------------------------------------------------------- /src/main/java/org/jenkinsci/plugins/xvfb/Xvfb.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2012, Zoran Regvart 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * The views and conclusions contained in the software and documentation are those 26 | * of the authors and should not be interpreted as representing official policies, 27 | * either expressed or implied, of the FreeBSD Project. 28 | */ 29 | package org.jenkinsci.plugins.xvfb; 30 | 31 | import java.io.ByteArrayOutputStream; 32 | import java.io.File; 33 | import java.io.IOException; 34 | import java.io.OutputStream; 35 | import java.util.ArrayList; 36 | import java.util.Arrays; 37 | import java.util.Collections; 38 | import java.util.Comparator; 39 | import java.util.Iterator; 40 | import java.util.List; 41 | import java.util.Map; 42 | import java.util.Set; 43 | import java.util.UUID; 44 | import java.util.concurrent.ConcurrentHashMap; 45 | import java.util.concurrent.CopyOnWriteArrayList; 46 | 47 | import org.kohsuke.stapler.AncestorInPath; 48 | import org.kohsuke.stapler.DataBoundConstructor; 49 | import org.kohsuke.stapler.DataBoundSetter; 50 | import org.kohsuke.stapler.QueryParameter; 51 | import org.kohsuke.stapler.StaplerRequest; 52 | 53 | import com.google.common.base.Optional; 54 | import com.thoughtworks.xstream.XStream; 55 | 56 | import antlr.ANTLRException; 57 | import hudson.CopyOnWrite; 58 | import hudson.EnvVars; 59 | import hudson.Extension; 60 | import hudson.FilePath; 61 | import hudson.Launcher; 62 | import hudson.Launcher.ProcStarter; 63 | import hudson.Proc; 64 | import hudson.Util; 65 | import hudson.XmlFile; 66 | import hudson.init.InitMilestone; 67 | import hudson.init.Initializer; 68 | import hudson.model.AbstractProject; 69 | import hudson.model.AutoCompletionCandidates; 70 | import hudson.model.Computer; 71 | import hudson.model.Executor; 72 | import hudson.model.Items; 73 | import hudson.model.Label; 74 | import hudson.model.Node; 75 | import hudson.model.Run; 76 | import hudson.model.TaskListener; 77 | import hudson.model.Run.RunnerAbortedException; 78 | import hudson.model.labels.LabelAtom; 79 | import hudson.model.listeners.RunListener; 80 | import hudson.remoting.Channel; 81 | import hudson.remoting.ChannelClosedException; 82 | import hudson.slaves.ComputerListener; 83 | import hudson.tasks.BuildWrapper; 84 | import hudson.tasks.BuildWrapperDescriptor; 85 | import hudson.tools.ToolInstallation; 86 | import hudson.util.ArgumentListBuilder; 87 | import hudson.util.FormValidation; 88 | import hudson.util.ProcessTree; 89 | import hudson.util.ProcessTree.OSProcess; 90 | import hudson.util.XStream2; 91 | import jenkins.model.Jenkins; 92 | import jenkins.security.MasterToSlaveCallable; 93 | import jenkins.tasks.SimpleBuildWrapper; 94 | import net.sf.json.JSONObject; 95 | 96 | public class Xvfb extends SimpleBuildWrapper { 97 | 98 | private static final class ComputerNameComparator implements Comparator { 99 | 100 | private static final ComputerNameComparator INSTANCE = new ComputerNameComparator(); 101 | 102 | @Override 103 | public int compare(final Computer left, final Computer right) { 104 | return left.getName().compareTo(right.getName()); 105 | } 106 | 107 | } 108 | 109 | @Extension(ordinal = Double.MAX_VALUE) 110 | public static class XvfbBuildWrapperDescriptor extends BuildWrapperDescriptor { 111 | 112 | @Initializer(before = InitMilestone.PLUGINS_LISTED) 113 | public static void setupBackwardCompatibility() { 114 | setupBackwardCompatibilityOn(Items.XSTREAM2); 115 | final XStream xstream = new XmlFile(new File("mapping")).getXStream(); 116 | if (xstream instanceof XStream2) { 117 | setupBackwardCompatibilityOn((XStream2) xstream); 118 | } 119 | } 120 | 121 | private static void setupBackwardCompatibilityOn(final XStream2 instance) { 122 | instance.addCompatibilityAlias("org.jenkinsci.plugins.xvfb.XvfbBuildWrapper", Xvfb.class); 123 | instance.addCompatibilityAlias("org.jenkinsci.plugins.xvfb.XvfbBuildWrapper$XvfbBuildWrapperDescriptor", Xvfb.XvfbBuildWrapperDescriptor.class); 124 | } 125 | 126 | /** Xvfb installations, this descriptor persists all installations configured. */ 127 | @CopyOnWrite 128 | private volatile XvfbInstallation[] installations = new XvfbInstallation[0]; 129 | 130 | public XvfbBuildWrapperDescriptor() { 131 | load(); 132 | } 133 | 134 | /** adopted from @see hudson.model.AbstractProject.AbstractProjectDescriptor#doAutoCompleteAssignedLabels */ 135 | public AutoCompletionCandidates doAutoCompleteAssignedLabels(@AncestorInPath final AbstractProject project, @QueryParameter final String value) { 136 | final AutoCompletionCandidates candidates = new AutoCompletionCandidates(); 137 | final Set