-
Notifications
You must be signed in to change notification settings - Fork 345
Bind PackageServer to ephemeral port to avoid port conflicts #227
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
Conversation
9bc511f to
17b25d9
Compare
e8b8074 to
e210fe9
Compare
46c6edd to
a370e41
Compare
99efc41 to
d06dfb7
Compare
|
@bioball Rebased and ready for review. |
bioball
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, this is looking great! I have some minor comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem very useful to validate given it's a test flag, and it's also provisioned by the OS. Do we know it's going to be in this range?
| .validate { it in 1024..65535 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not terribly important to have this validated, but ephemeral ports are guaranteed to be high ports (1024-65535).
https://en.wikipedia.org/wiki/Ephemeral_port#Range
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, thanks for the link. Let's still remove this, though; it adds some unnecessary brittleness to our tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * listening port. | |
| * listening port. | |
| * | |
| * <p>This is an internal option used for testing purposes only. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling this option "internal" felt strange because HttpClient is a public API and we don't have a way to hide testPort. It's also harmless. Should replace 12210 with 0 in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the same with org.pkl.commons.cli.CliBaseOptions; both are public APIs but expose flags that are only meant for test purposes (e.g. testMode, testPort added by this PR) and we call them "internal" in the doc comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| throw new AssertionError(e); // only port changed | |
| throw PklBugException.unreachableCode(); // only port changed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. org.pkl.core.util depending on org.pkl.core seems problematic. But since PklBugException is already used in org.pkl.core.util, it's not making things worse.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * @param testPort API equivalent of the {@code --test-port} CLI option | |
| * @param testPort Internal option used for testing purposes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this param from the public API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since testPort is an internal test-only option, we should have another constructor that doesn't have it as an option, and sets testPort to -1.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably address the root cause and provide a builder for ExecutorOptions2. For example, almost nobody will want to pass certificates either.
I thought about modernizing the pkl-executor API to look more like Evaluator and language bindings. But then I realized that my time is better spent on Java language bindings, which have the potential to make pkl-executor unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a builder and removed testPort from public API. See commit message for details.
|
@bioball Ready from my side. See latest commit message for details. Quite happy with the cleanup. |
bioball
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple minor comments, but this is pretty close!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea with the builder!
We have an existing pattern of having unconfigured() and preconfigured() builders; see EvaluatorBuilder, ConfigEvaluatorBuilder, ValueMapperBuilder, etc. I think let's follow that.
| public static Builder builder() { | |
| return new Builder(); | |
| } | |
| // keep in sync with SecurityManagers.defaultAllowedModules | |
| /// Returns the allowed module patterns that the CLI uses by default. | |
| public static final List<String> defaultAllowedModules = | |
| List.of( | |
| "repl:", | |
| "file:", | |
| "jar:file:", | |
| "modulepath:", | |
| "https:", | |
| "pkl:", | |
| "package:", | |
| "projectpackage:" | |
| ); | |
| // keep in sync with SecurityManagers.defaultAllowedResources | |
| /// Returns the allowed resources patterns that the CLI uses by default. | |
| public static final List<String> defaultAllowedResources = | |
| List.of( | |
| "prop:", | |
| "env:", | |
| "file:", | |
| "modulepath:", | |
| "package:", | |
| "projectpackage:", | |
| "https:"); | |
| /** | |
| * Creates a builder that has no options set. | |
| */ | |
| public static Builder unconfigured() { | |
| return new Builder(); | |
| } | |
| /** | |
| * Creates a builder configured with: | |
| * | |
| * <ul> | |
| * <li>{@link #defaultAllowedModules}</li> | |
| * <li>{@link #defaultAllowedResources}</li> | |
| * <li>System environment variables</li> | |
| * <li>System properties</li> | |
| * </ul> | |
| */ | |
| public static Builder preconfigured() { | |
| //noinspection unchecked,rawtypes | |
| return unconfigured() | |
| .allowedModules(defaultAllowedModules) | |
| .allowedResources(defaultAllowedResources) | |
| .environmentVariables(System.getenv()) | |
| .externalProperties((Map) System.getProperties()); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha, thanks for the link. Let's still remove this, though; it adds some unnecessary brittleness to our tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the same with org.pkl.commons.cli.CliBaseOptions; both are public APIs but expose flags that are only meant for test purposes (e.g. testMode, testPort added by this PR) and we call them "internal" in the doc comments.
According to the Javadoc, Apart from adding
Removed.
There is a big difference: |
I don't see any issues with the set of options provided by |
What is |
d32d02c to
0cb0030
Compare
This is a comprehensive solution to the "flaky PackageServer tests" problem. It rules out port conflicts and imposes no limits on test parallelism. The same solution can be used for other test servers in the future. Major changes: - Turn `PackageServer` from a singleton into a class that is instantiated per test class or test method. - Start the server the first time its `port` property is read. Bind the server to an ephemeral port instead of port 12110. - For every test that uses `PackageServer`, pass the server port to `--test-port`, `HttpClient.Builder.setTestPort`, the `CliBaseOptions` or `ExecutorOptions` constructor, or the Gradle plugin's `testPort` property. Wire all of these to `RequestRewritingClient`'s `testPort` constructor parameter. - Enhance `RequestRewritingClient` to replace port 12110 with `testPort` in request URIs unless `testPort` is -1 (its default). - Introduce `ExecutorOptions.Builder`. This makes executor options more comfortable to create and allows to hide options such as `testPort`. - Deprecate the `ExecutorOptions` constructor to steer users towards the builder. - Get rid of `ExecutorOptions2`, which is no longer needed. - Clean up `EmbeddedExecutorTest` with the help of the builder.
|
I've made 2 out of 3 requested changes and have squashed my commits. I'll leave any builder changes to you. I've also rebased my Gradle 8.6 PR, which I'd love to land by the end of the week. |
|
The executor API is typically meant for services that need to evaluate 3rd party Pkl code. For instance, if you are a service that accepts Pkl files as configuration. And, like you said, in those cases, you wouldn't want to pass your own env vars or system properties to Pkl. The core thing that the executor provides that Thought about this a little more--yeah, there's probably not much of a use-case for |
Here is my take on how to best solve the "flaky PackageServer tests" problem.
It is ready to be merged after #217 .
See commit message for details.
If you prefer a different solution, perhaps this can serve as inspiration.