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

Remove random when using HLRC sync and async calls #48211

Merged
merged 5 commits into from
Oct 24, 2019

Conversation

hub-cap
Copy link
Contributor

@hub-cap hub-cap commented Oct 17, 2019

This commit removes the randomization used by every execute call in the
high level rest tests. Previously every execute call, which can be many
calls per single test, would rely on a random boolean to determine if
they should use the sync or async methods provided to the execute
method. This commit runs the tests twice, using two different clusters,
both of them providing the value one time via a sysprop. This ensures
that the whole suite of tests is run using the sync and async code
paths.

Closes #39667

This commit removes the randomization used by every execute call in the
high level rest tests. Previously every execute call, which can be many
calls per single test, would rely on a random boolean to determine if
they should use the sync or async methods provided to the execute
method. This commit runs the tests twice, using two different clusters,
both of them providing the value one time via a sysprop. This ensures
that the whole suite of tests is run using the sync and async code
paths.

Closes elastic#39667
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-features (:Core/Features/Java High Level REST Client)

@hub-cap
Copy link
Contributor Author

hub-cap commented Oct 17, 2019

@elasticmachine run elasticsearch-ci/1

Copy link
Member

@martijnvg martijnvg left a comment

Choose a reason for hiding this comment

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

LGTM, I left one nit.

/**
* Executes the provided request using either the sync method or its async variant, both provided as functions
*/
protected static <Req, Resp> Resp execute(Req request, SyncMethod<Req, Resp> syncMethod,
AsyncMethod<Req, Resp> asyncMethod, RequestOptions options) throws IOException {
if (randomBoolean()) {
final boolean async = Booleans.parseBoolean(System.getProperty("tests.rest.async", "false"));
Copy link
Member

Choose a reason for hiding this comment

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

I think we can read this system property as a constant?
We either runs all tests with this set to false or true.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea def.

extraConfigFile nodeCert.name, nodeCert
extraConfigFile nodeTrustStore.name, nodeTrustStore
extraConfigFile pkiTrustCert.name, pkiTrustCert
// TODO: we can't use task avoidance here because RestIntegTestTask does the testcluster creation
Copy link
Contributor

Choose a reason for hiding this comment

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

The use of RestTestRunnerTask would be preferable here.
You can have two tasks use the same cluster ( even trough right now it disabled the build cache ).
Just need to add useCluster testClusters.integTest to the task, and it can use task avoidance too.
No need for the asyncIntegTest as it won't really be used at the same time.
Assuming cleanup works as it should, we should be able to run the tests against the same cluster.

Another approach is to add sub-projects so the tests can run in parallel.
The downside is that we don't have a generic solution to wire the tests up to the sub-projects ( even trough we have examples elsewhere in the code )

@mark-vieira might also have an opinion on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Id love some better advice here, especially if it does not double the build time for this heh

Copy link
Contributor

Choose a reason for hiding this comment

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

If time is the primary concern, then sub-projects are the way to go.
That will matter when running a small number of tasks, like running the tests for the client only so there are resources to spare on the machine, it won't matter as much for large runs that run everything in CI where there are plenty of projects to compete for the available resources.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should do subprojects until we have a simple and clear way to set this up via a gradle plugin. There is complexity involved in properly transfering the test classes via a jar, extracting them, then convincing the test runner in the subproject to use the extracted class files. Another task here is fine (and I think another cluster is fine too, we don't need to share, since we link the main directories there is minimal that is copied, and the setup here is minimal since it is not a rest test). It matches what we did for transport-netty4 with pooled/unpooled tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should use two clusters and two tasks. Having multiple tasks targeting the same cluster disables caching. Having multiple clusters that are technically identical doesn't actually have much in the way of overhead due to the way we set these up with hardlinks but the benefit of being able to cache these tests is potentially significant.

I don't completely understand this comment:

TODO: we can't use task avoidance here because RestIntegTestTask does the testcluster creation

This is technically correct, creating a RestIntegTestTask creates the corresponding cluster but this doesn't affect build avoidance in any way. Everything is still wired up in a cacheable way.

Also, -1 to multiple subprojects. These test executions are identical in every way except for a single system property set on the test executor itself. There's absolutely no reason to create subprojects except for the fact that would facilitate running these suites in parallel which I don't think is very compelling given the way our builds are structured and already highly parallelizable.

Copy link
Contributor

Choose a reason for hiding this comment

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

I do think that this argument is compelling. It's so unfortunate that there's no way to run test tasks in parallel for the same project!
For someone developing the client who has to run these tests often it will make a big difference as it's likely to cut the time it takes in half. I do agree it doesn't make a bug difference for larger runs in CI running tests for a large number of projects.
I 100% agree that we should have a plugin if we are to go with the sub-project route, now is as good of a time as any.
Just to be clear @hub-cap , I don't think there's anything here to prevent mergin the PR I'm just happy it triggered the discussion.

Copy link
Contributor

Choose a reason for hiding this comment

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

I do think that this argument is compelling. It's so unfortunate that there's no way to run test tasks in parallel for the same project!

This is better solved in Gradle core by moving test executing to the worker API. I know this is something they want to do but not sure where it stacks up on the roadmap. I'm still highly annoyed that they got rid of @ParallelizableTask in Gradle 4.0 w/o a proper replacement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review friends, so from what I gather I can leave it as is (sans fixing the nits of course).

as for the comment @mark-vieira, it was copied from an earlier comment in some other code that did something similar, I just did not want to lose whatever reference to what was in the original authors head. But it sounds like I can just remove this comment in both places from your comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you are referring to this comment. I would say yes. I believe that comment predates some things we've done around RestIntegTestTask to make it reliably cacheable. In scenarios where the tests cannot be cached the build will "detect" this automatically and disable it so there's not need to explicitly document such scenarios.

+1 on removing that comment in both places.

Copy link
Contributor

@mark-vieira mark-vieira left a comment

Choose a reason for hiding this comment

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

A big +1 to removing our reliance on random testing and instead making testing of async/sync explicit. We should do this in more places.


check.dependsOn(asyncIntegTest)

['integTest', 'asyncIntegTest'].each { integName ->
Copy link
Contributor

Choose a reason for hiding this comment

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

Since the async system prop is for the tests not the cluster itself these clusters are identical. We can replace this with testClusters.all { // your config }.

extraConfigFile nodeCert.name, nodeCert
extraConfigFile nodeTrustStore.name, nodeTrustStore
extraConfigFile pkiTrustCert.name, pkiTrustCert
// TODO: we can't use task avoidance here because RestIntegTestTask does the testcluster creation
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should use two clusters and two tasks. Having multiple tasks targeting the same cluster disables caching. Having multiple clusters that are technically identical doesn't actually have much in the way of overhead due to the way we set these up with hardlinks but the benefit of being able to cache these tests is potentially significant.

I don't completely understand this comment:

TODO: we can't use task avoidance here because RestIntegTestTask does the testcluster creation

This is technically correct, creating a RestIntegTestTask creates the corresponding cluster but this doesn't affect build avoidance in any way. Everything is still wired up in a cacheable way.

Also, -1 to multiple subprojects. These test executions are identical in every way except for a single system property set on the test executor itself. There's absolutely no reason to create subprojects except for the fact that would facilitate running these suites in parallel which I don't think is very compelling given the way our builds are structured and already highly parallelizable.

@hub-cap
Copy link
Contributor Author

hub-cap commented Oct 22, 2019

comments addressed, I will assume there is no one stopping me from merging this w/ mvg's +1

@hub-cap
Copy link
Contributor Author

hub-cap commented Oct 23, 2019

@elasticmachine run elasticsearch-ci/packaging-sample-matrix

@hub-cap hub-cap merged commit 18d87e3 into elastic:master Oct 24, 2019
hub-cap added a commit that referenced this pull request Oct 24, 2019
This commit removes the randomization used by every execute call in the
high level rest tests. Previously every execute call, which can be many
calls per single test, would rely on a random boolean to determine if
they should use the sync or async methods provided to the execute
method. This commit runs the tests twice, using two different clusters,
both of them providing the value one time via a sysprop. This ensures
that the whole suite of tests is run using the sync and async code
paths.

Closes #39667
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

High level REST client test framework encourages using randomness for test coverage
7 participants