Class RealJenkinsRule
- All Implemented Interfaces:
org.junit.rules.TestRule
JenkinsSessionRule
but running Jenkins in a more realistic environment.
Though Jenkins is run in a separate JVM using Winstone (java -jar jenkins.war
),
you can still do “whitebox” testing: directly calling Java API methods, starting from JenkinsRule
or not.
This is because the test code gets sent to the remote JVM and loaded and run there.
(Thus when using Maven, there are at least three JVMs involved:
Maven itself; the Surefire booter with your top-level test code; and the Jenkins controller with test bodies.)
Just as with JenkinsRule
, all plugins found in the test classpath will be enabled,
but with more realistic behavior: class loaders in a graph, pluginFirstClassLoader
and maskClasses
, etc.
“Compile-on-save” style development works for classes and resources in the current plugin:
with a suitable IDE, you can edit a source file, have it be sent to target/classes/
,
and rerun a test without needing to go through a full Maven build cycle.
This is because target/test-classes/the.hpl
is used to load unpacked plugin resources.
Like JenkinsRule
, the controller is started in “development mode”:
the setup wizard is suppressed, the update center is not checked, etc.
Known limitations:
- Execution is a bit slower due to the overhead of launching a new JVM; and class loading overhead cannot be shared between test cases. More memory is needed.
- Remote calls must be serializable. Use methods like
runRemotely(RealJenkinsRule.StepWithReturnAndOneArg, Serializable)
and/orXStreamSerializable
as needed. static
state cannot be shared between the top-level test code and test bodies (though the compiler will not catch this mistake).- When using a snapshot dep on Jenkins core, you must build
jenkins.war
to test core changes (there is no “compile-on-save” support for this). TestExtension
is not available (but tryaddSyntheticPlugin(java.lang.Package)
).LoggerRule
is not available, however additional loggers can be configured viawithLogger(Class, Level)
}.BuildWatcher
is not available, but you can useTailLog
instead.
Systems not yet tested:
- Possibly
Timeout
can be used.
-
Nested Class Summary
Modifier and TypeClassDescriptionstatic final class
static final class
static final class
static class
static final class
static interface
One step to run.static interface
RealJenkinsRule.Step2<T extends Serializable>
static class
static interface
RealJenkinsRule.StepWithFourArgs<A1 extends Serializable,
A2 extends Serializable, A3 extends Serializable, A4 extends Serializable> static interface
RealJenkinsRule.StepWithOneArg<A1 extends Serializable>
static interface
RealJenkinsRule.StepWithReturnAndFourArgs<R extends Serializable,
A1 extends Serializable, A2 extends Serializable, A3 extends Serializable, A4 extends Serializable> static interface
RealJenkinsRule.StepWithReturnAndOneArg<R extends Serializable,
A1 extends Serializable> static interface
RealJenkinsRule.StepWithReturnAndThreeArgs<R extends Serializable,
A1 extends Serializable, A2 extends Serializable, A3 extends Serializable> static interface
RealJenkinsRule.StepWithReturnAndTwoArgs<R extends Serializable,
A1 extends Serializable, A2 extends Serializable> static interface
RealJenkinsRule.StepWithThreeArgs<A1 extends Serializable,
A2 extends Serializable, A3 extends Serializable> static interface
RealJenkinsRule.StepWithTwoArgs<A1 extends Serializable,
A2 extends Serializable> final class
Alternative toaddPlugins(java.lang.String...)
orTestExtension
that lets you build a test-only plugin on the fly. -
Constructor Summary
ConstructorDescriptionRealJenkinsRule
(RealJenkinsRule source) Links this rule to another, withgetHome()
to be initialized by whichever copy starts first. -
Method Summary
Modifier and TypeMethodDescriptionaddPlugins
(String... plugins) Add some plugins to the test classpath.Adds a test-only plugin to the controller based on sources defined in this module.org.junit.runners.model.Statement
apply
(org.junit.runners.model.Statement base, org.junit.runner.Description description) Builds aSSLContext
trusting the current instance.static String
checkResult
(HttpURLConnection conn) createTempDirectory
(String prefix) Creates a temporary directory.org.htmlunit.WebClient
Create a client configured to trust any self-signed certificate used by this instance.void
DeletesJENKINS_HOME
.Set an extra environment variable.getHome()
Obtains the Jenkins home directory.getName()
String[]
getUrl()
Similar toJenkinsRule.getURL()
.https()
Sets up HTTPS for the current instance, and disables plain HTTP.https
(String host, KeyStoreManager keyStoreManager, X509Certificate rootCA) Sets up HTTPS for the current instance, and disables plain HTTP.includeTestClasspathPlugins
(boolean includeTestClasspathPlugins) The intended use case for this is to use the plugins bundled into the warwithWar(File)
instead of the plugins in the pom.boolean
isAlive()
Returns true if the Jenkins process is alive.javaOptions
(String... options) Add some JVM startup options.jenkinsOptions
(String... options) Add some Jenkins (including Winstone) startup options.omitPlugins
(String... plugins) Omit some plugins in the test classpath.prepareHomeLazily
(boolean prepareHomeLazily) AllowsJENKINS_HOME
initialization to be delayed untilstartJenkins()
is called for the first time.void
runRemotely
(RealJenkinsRule.Step... steps) Runs one or more steps on the remote system.<T extends Serializable>
T<A1 extends Serializable,
A2 extends Serializable, A3 extends Serializable, A4 extends Serializable>
voidrunRemotely
(RealJenkinsRule.StepWithFourArgs<A1, A2, A3, A4> s, A1 arg1, A2 arg2, A3 arg3, A4 arg4) <A1 extends Serializable>
voidrunRemotely
(RealJenkinsRule.StepWithOneArg<A1> s, A1 arg1) <R extends Serializable,
A1 extends Serializable, A2 extends Serializable, A3 extends Serializable, A4 extends Serializable>
RrunRemotely
(RealJenkinsRule.StepWithReturnAndFourArgs<R, A1, A2, A3, A4> s, A1 arg1, A2 arg2, A3 arg3, A4 arg4) <R extends Serializable,
A1 extends Serializable>
RrunRemotely
(RealJenkinsRule.StepWithReturnAndOneArg<R, A1> s, A1 arg1) <R extends Serializable,
A1 extends Serializable, A2 extends Serializable, A3 extends Serializable>
RrunRemotely
(RealJenkinsRule.StepWithReturnAndThreeArgs<R, A1, A2, A3> s, A1 arg1, A2 arg2, A3 arg3) <R extends Serializable,
A1 extends Serializable, A2 extends Serializable>
RrunRemotely
(RealJenkinsRule.StepWithReturnAndTwoArgs<R, A1, A2> s, A1 arg1, A2 arg2) <A1 extends Serializable,
A2 extends Serializable, A3 extends Serializable>
voidrunRemotely
(RealJenkinsRule.StepWithThreeArgs<A1, A2, A3> s, A1 arg1, A2 arg2, A3 arg3) <A1 extends Serializable,
A2 extends Serializable>
voidrunRemotely
(RealJenkinsRule.StepWithTwoArgs<A1, A2> s, A1 arg1, A2 arg2) void
Switch the Jenkins home directory.void
void
Stops Jenkins and releases any system resources associated with it.void
Stops Jenkins abruptly, without giving it a chance to shut down cleanly.void
then
(RealJenkinsRule.Step... steps) Run one Jenkins session, send one or more test thunks, and shut down.<T extends Serializable>
Tthen
(RealJenkinsRule.Step2<T> s) Run one Jenkins session, send a test thunk, and shut down.withBootClasspath
(File... files) Applies ANSI coloration to log lines produced by this instance, complementingwithName(java.lang.String)
.withDebugPort
(int debugPort) Allows usage of a static debug port instead of a random one.withDebugServer
(boolean debugServer) Allows to use debug in server mode or client mode.withDebugSuspend
(boolean debugSuspend) Whether to suspend the controller VM on startup until debugger is connected.UsewithFIPSEnabled(FIPSTestBundleProvider)
with default value ofFIPSTestBundleProvider.get()
withFIPSEnabled
(io.jenkins.test.fips.FIPSTestBundleProvider fipsTestBundleProvider) +Sets a custom host name for the Jenkins root URL.withHttpListenAddress
(String httpListenAddress) Provides a custom interface to listen to.withJavaHome
(String JavaHome) Allows to specify a java home, defaults to JAVA_HOME if not usedwithLogger
(Class<?> clazz, Level level) withLogger
(String logger, Level level) Sets a name for this instance, which will be prefixed to log messages to simplify debugging.withPackageLogger
(Class<?> clazz, Level level) withPort
(int port) Provides a custom fixed port instead of a random one.withTimeout
(int timeout) Adjusts the test timeout.Sets a custom WAR file to be used by the rule instead of the one in the path orwar/target/jenkins.war
in case of core.
-
Constructor Details
-
RealJenkinsRule
public RealJenkinsRule() -
RealJenkinsRule
Links this rule to another, withgetHome()
to be initialized by whichever copy starts first. Also copies configuration related to the setup of that directory:includeTestClasspathPlugins(boolean)
,addPlugins(java.lang.String...)
,addSyntheticPlugin(java.lang.Package)
, andomitPlugins(java.lang.String...)
. Other configuration such asjavaOptions(String...)
may be applied to both, but that is your choice.
-
-
Method Details
-
addPlugins
Add some plugins to the test classpath.- Parameters:
plugins
- Filenames of the plugins to install. These are expected to be absolute test classpath resources, such asplugins/workflow-job.hpi
for example.For small fake plugins built for this purpose and exercising some bit of code, use
addSyntheticPlugin(java.lang.Package)
. If you wish to test with larger archives of real plugins, this is possible for example by bindingdependency:copy
to theprocess-test-resources
phase.In most cases you do not need this method. Simply add whatever plugins you are interested in testing against to your POM in
test
scope. These, and their transitive dependencies, will be loaded in allRealJenkinsRule
tests. This method is useful if only a particular test may load the tested plugin, or if the tested plugin is not available in a repository for use as a test dependency.
-
addSyntheticPlugin
Adds a test-only plugin to the controller based on sources defined in this module. Useful when you wish to define some types, register someExtension
s, etc. and there is no existing plugin that does quite what you want (that you are comfortable adding to the test classpath and maintaining the version of).If you also have some test suites based on
JenkinsRule
, you may not want to useExtension
since (unlikeTestExtension
) it would be loaded in all such tests. Instead create apackage-info.java
specifying an@OptionalPackage
whoserequirePlugins
lists the sameRealJenkinsRule.SyntheticPlugin.shortName(String)
. (You will need to.header("Plugin-Dependencies", "variant:0")
to use this API.) Then use@OptionalExtension
on all your test extensions. These will then be loaded only inRealJenkinsRule
-based tests requesting this plugin.- Parameters:
pkg
- the Java package containing any classes and resources you want included- Returns:
- a builder
-
omitPlugins
Omit some plugins in the test classpath.- Parameters:
plugins
- one or more code names, liketoken-macro
-
javaOptions
Add some JVM startup options.- Parameters:
options
- one or more options, like-Dorg.jenkinsci.Something.FLAG=true
-
jenkinsOptions
Add some Jenkins (including Winstone) startup options. You probably meant to usejavaOptions(String...)
.- Parameters:
options
- one or more options, like--webroot=/tmp/war --pluginroot=/tmp/plugins
-
extraEnv
Set an extra environment variable.- Parameters:
value
- null to cancel a previously set variable
-
withTimeout
Adjusts the test timeout. The timer starts whenstartJenkins()
completes andrunRemotely(org.jvnet.hudson.test.RealJenkinsRule.Step...)
is ready. The default is currently set to 600 (10m).- Parameters:
timeout
- number of seconds before exiting, or zero to disable
-
withHost
Sets a custom host name for the Jenkins root URL.By default, this is just
localhost
. But you may wish to set it to something else that resolves to localhost, such assome-id.localtest.me
. This is particularly useful when running multiple copies of Jenkins (and/or other services) in one test case, since browser cookies are sensitive to host but not port and so otherwiseHttpServletRequest.getSession(boolean)
might accidentally be shared across otherwise distinct services.Calling this method does not change the fact that Jenkins will be configured to listen only on localhost for security reasons (so others in the same network cannot access your system under test, especially if it lacks authentication).
When using HTTPS, use
https(String,KeyStoreManager, X509Certificate)
instead. -
withWar
Sets a custom WAR file to be used by the rule instead of the one in the path orwar/target/jenkins.war
in case of core. -
withJavaHome
Allows to specify a java home, defaults to JAVA_HOME if not used -
withLogger
-
withPackageLogger
-
withLogger
-
withName
Sets a name for this instance, which will be prefixed to log messages to simplify debugging. -
getName
-
withColor
Applies ANSI coloration to log lines produced by this instance, complementingwithName(java.lang.String)
. Ignored when on CI. -
withPort
Provides a custom fixed port instead of a random one.- Parameters:
port
- a custom port to use instead of a random one.
-
withHttpListenAddress
Provides a custom interface to listen to.Important: for security reasons this should be overridden only in special scenarios, such as testing inside a Docker container. Otherwise a developer running tests could inadvertently expose a Jenkins service without password protection, allowing remote code execution.
- Parameters:
httpListenAddress
- network interface such as0.0.0.0
. Defaults to127.0.0.1
.
-
withDebugPort
Allows usage of a static debug port instead of a random one.This allows to use predefined debug configurations in the IDE.
Typical usage is in a base test class where multiple named controller instances are defined with fixed ports
public RealJenkinsRule cc1 = new RealJenkinsRule().withName("cc1").withDebugPort(4001).withDebugServer(false); public RealJenkinsRule cc2 = new RealJenkinsRule().withName("cc2").withDebugPort(4002).withDebugServer(false);
Then have debug configurations in the IDE set for ports- 5005 (test VM) - debugger mode "attach to remote vm"
- 4001 (cc1) - debugger mode "listen to remote vm"
- 4002 (cc2) - debugger mode "listen to remote vm"
This allows for debugger to reconnect in scenarios where restarts of controllers are involved.
- Parameters:
debugPort
- the TCP port to use for debugging this Jenkins instance. Between 0 (random) and 65536 (excluded).
-
withDebugServer
Allows to use debug in server mode or client mode. Client mode is friendlier to controller restarts.- Parameters:
debugServer
- true to use server=y, false to use server=n- See Also:
-
withDebugSuspend
Whether to suspend the controller VM on startup until debugger is connected. Defaults to false.- Parameters:
debugSuspend
- true to suspend the controller VM on startup until debugger is connected.
-
includeTestClasspathPlugins
The intended use case for this is to use the plugins bundled into the warwithWar(File)
instead of the plugins in the pom. A typical scenario for this feature is a test which does not live inside a plugin's src/test/java- Parameters:
includeTestClasspathPlugins
- false if plugins from pom should not be used (default true)
-
prepareHomeLazily
AllowsJENKINS_HOME
initialization to be delayed untilstartJenkins()
is called for the first time.This allows methods such as
addPlugins(java.lang.String...)
to be called dynamically inside of test methods, which enables related tests that need to configureRealJenkinsRule
in different ways to be defined in the same class using only a single instance ofRealJenkinsRule
. -
withFIPSEnabled
UsewithFIPSEnabled(FIPSTestBundleProvider)
with default value ofFIPSTestBundleProvider.get()
-
withFIPSEnabled
public RealJenkinsRule withFIPSEnabled(io.jenkins.test.fips.FIPSTestBundleProvider fipsTestBundleProvider) +- Parameters:
fipsTestBundleProvider
- theFIPSTestBundleProvider
to use for testing
-
withBootClasspath
- Parameters:
files
- add someFile
to bootclasspath
-
getJacocoAgentOptions
-
apply
public org.junit.runners.model.Statement apply(org.junit.runners.model.Statement base, org.junit.runner.Description description) - Specified by:
apply
in interfaceorg.junit.rules.TestRule
-
deprovision
DeletesJENKINS_HOME
. This method does not need to be invoked when using@Rule
or@ClassRule
to runRealJenkinsRule
.- Throws:
Exception
-
createTempDirectory
Creates a temporary directory. UnlikeFiles.createTempDirectory(String, FileAttribute...)
this will be cleaned up after the test exits (likeTemporaryFolder
), and will honorjava.io.tmpdir
set by Surefire afterStaticProperty.JAVA_IO_TMPDIR
has been initialized.- Throws:
IOException
-
isAlive
public boolean isAlive()Returns true if the Jenkins process is alive. -
getTruststoreJavaOptions
-
then
Run one Jenkins session, send one or more test thunks, and shut down.- Throws:
Throwable
-
then
Run one Jenkins session, send a test thunk, and shut down.- Throws:
Throwable
-
getUrl
Similar toJenkinsRule.getURL()
. Requires Jenkins to be started before usingstartJenkins()
.- Throws:
MalformedURLException
-
https
Sets up HTTPS for the current instance, and disables plain HTTP. This generates a self-signed certificate for localhost. The corresponding root CA that needs to be trusted by HTTP client can be obtained usinggetRootCA()
.- Returns:
- the current instance
- See Also:
-
https
public RealJenkinsRule https(@NonNull String host, @NonNull KeyStoreManager keyStoreManager, @NonNull X509Certificate rootCA) Sets up HTTPS for the current instance, and disables plain HTTP.You don't need to call
withHost(String)
when calling this method.- Parameters:
host
- the host name to use in the certificatekeyStoreManager
- a key store manager containing the key and certificate to use for HTTPS. It needs to be valid for the given hostrootCA
- the certificate that needs to be trusted by callers.- Returns:
- the current instance
- See Also:
-
getRootCA
- Returns:
- the current autogenerated root CA or null if
https()
has not been called.
-
buildSSLContext
Builds aSSLContext
trusting the current instance.- Throws:
NoSuchAlgorithmException
-
getHome
Obtains the Jenkins home directory. Normally it will suffice to useLocalData
to populate files. -
setHome
Switch the Jenkins home directory. Will affect subsequent startups of this rule, but not other copies linked viaRealJenkinsRule(RealJenkinsRule)
. Normally unnecessary but could be used to simulate running on the wrong home. -
createWebClient
public org.htmlunit.WebClient createWebClient()Create a client configured to trust any self-signed certificate used by this instance. -
startJenkins
- Throws:
Throwable
-
checkResult
- Throws:
IOException
-
stopJenkins
Stops Jenkins and releases any system resources associated with it. If Jenkins is already stopped then invoking this method has no effect.- Throws:
Throwable
-
stopJenkinsForcibly
public void stopJenkinsForcibly()Stops Jenkins abruptly, without giving it a chance to shut down cleanly. If Jenkins is already stopped then invoking this method has no effect. -
runRemotely
Runs one or more steps on the remote system. (Compared to multiple calls, passing a series of steps is slightly more efficient as only one network call is made.)- Throws:
Throwable
-
runRemotely
- Throws:
Throwable
-
runRemotely
public <A1 extends Serializable> void runRemotely(RealJenkinsRule.StepWithOneArg<A1> s, A1 arg1) throws Throwable - Throws:
Throwable
-
runRemotely
public <A1 extends Serializable,A2 extends Serializable> void runRemotely(RealJenkinsRule.StepWithTwoArgs<A1, A2> s, A1 arg1, A2 arg2) throws Throwable- Throws:
Throwable
-
runRemotely
public <A1 extends Serializable,A2 extends Serializable, void runRemotelyA3 extends Serializable> (RealJenkinsRule.StepWithThreeArgs<A1, A2, throws ThrowableA3> s, A1 arg1, A2 arg2, A3 arg3) - Throws:
Throwable
-
runRemotely
public <A1 extends Serializable,A2 extends Serializable, void runRemotelyA3 extends Serializable, A4 extends Serializable> (RealJenkinsRule.StepWithFourArgs<A1, A2, throws ThrowableA3, A4> s, A1 arg1, A2 arg2, A3 arg3, A4 arg4) - Throws:
Throwable
-
runRemotely
public <R extends Serializable,A1 extends Serializable> R runRemotely(RealJenkinsRule.StepWithReturnAndOneArg<R, A1> s, A1 arg1) throws Throwable- Throws:
Throwable
-
runRemotely
public <R extends Serializable,A1 extends Serializable, R runRemotelyA2 extends Serializable> (RealJenkinsRule.StepWithReturnAndTwoArgs<R, A1, throws ThrowableA2> s, A1 arg1, A2 arg2) - Throws:
Throwable
-
runRemotely
public <R extends Serializable,A1 extends Serializable, R runRemotelyA2 extends Serializable, A3 extends Serializable> (RealJenkinsRule.StepWithReturnAndThreeArgs<R, A1, throws ThrowableA2, A3> s, A1 arg1, A2 arg2, A3 arg3) - Throws:
Throwable
-
runRemotely
public <R extends Serializable,A1 extends Serializable, R runRemotelyA2 extends Serializable, A3 extends Serializable, A4 extends Serializable> (RealJenkinsRule.StepWithReturnAndFourArgs<R, A1, throws ThrowableA2, A3, A4> s, A1 arg1, A2 arg2, A3 arg3, A4 arg4) - Throws:
Throwable
-