Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Advertise lambdas as arguments to then / runRemotely #882

Merged
merged 13 commits into from
Dec 18, 2024
14 changes: 11 additions & 3 deletions src/main/java/org/jvnet/hudson/test/RealJenkinsRule.java
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,8 @@ public String[] getTruststoreJavaOptions() {
/**
* One step to run.
* <p>Since this thunk will be sent to a different JVM, it must be serializable.
* The test class will certainly not be serializable, so you cannot use an anonymous inner class,
* and regular lambdas also risk accidentally capturing non-serializable objects from scope.
* The friendliest idiom is a static method reference:
* The test class will certainly not be serializable, so you cannot use an anonymous inner class.
* One idiom is a static method reference:
* <pre>
* &#64;Test public void stuff() throws Throwable {
* rr.then(YourTest::_stuff);
Expand All @@ -759,6 +758,15 @@ public String[] getTruststoreJavaOptions() {
* If you need to pass and/or return values, you can still use a static method reference:
* try {@link #runRemotely(Step2)} or {@link #runRemotely(StepWithReturnAndOneArg, Serializable)} etc.
* (using {@link XStreamSerializable} as needed).
* <p>
* Alternately, you could use a lambda (taking care not to capture non-serializable objects from scope):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, this is pretty difficult to assess once you experience an issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be. Noted in #881 (comment). The difference is that (anonymous) inner classes will always capture variables in lexical scope, whereas lambdas usually will not. Noted another caveat in b9e40f5.

* <pre>
* &#64;Test public void stuff() throws Throwable {
* rr.then(r -> {
* // as needed
* });
* }
* </pre>
*/
@FunctionalInterface
public interface Step extends Serializable {
Expand Down
18 changes: 13 additions & 5 deletions src/test/java/org/jvnet/hudson/test/RealJenkinsRuleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,19 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
// Neither ParametersDefinitionProperty nor ParametersAction could be passed directly.
// (In this case, ParameterDefinition and ParameterValue could have been used raw.
// But even List<ParameterValue> cannot be typed here, only e.g. ArrayList<ParameterValue>.)
var a = rr.runRemotely(RealJenkinsRuleTest::_xStreamSerializable, XStreamSerializable.of(new ParametersDefinitionProperty(new StringParameterDefinition("X", "dflt"))));
assertThat(a.object().getAllParameters(), hasSize(1));
}

private static XStreamSerializable<ParametersAction> _xStreamSerializable(JenkinsRule r, XStreamSerializable<JobProperty<? super FreeStyleProject>> prop) throws Throwable {
var prop = XStreamSerializable.of(new ParametersDefinitionProperty(new StringParameterDefinition("X", "dflt")));
// Static method handle idiom:
assertThat(rr.runRemotely(RealJenkinsRuleTest::_xStreamSerializable, prop).object().getAllParameters(), hasSize(1));
// Lambda idiom:
assertThat(rr.runRemotely(r -> {
var p = r.createFreeStyleProject();
p.addProperty(prop.object());
var b = r.buildAndAssertSuccess(p);
return XStreamSerializable.of(b.getAction(ParametersAction.class));
}).object().getAllParameters(), hasSize(1));
}

private static XStreamSerializable<ParametersAction> _xStreamSerializable(JenkinsRule r, XStreamSerializable<? extends JobProperty<? super FreeStyleProject>> prop) throws Throwable {
var p = r.createFreeStyleProject();
p.addProperty(prop.object());
var b = r.buildAndAssertSuccess(p);
Expand Down
Loading