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

Understand Gradle 4.8 test failure around setup of security policies #31324

Closed
alpar-t opened this issue Jun 14, 2018 · 13 comments
Closed

Understand Gradle 4.8 test failure around setup of security policies #31324

alpar-t opened this issue Jun 14, 2018 · 13 comments
Labels
:Delivery/Build Build or test infrastructure jdk11 >non-issue Team:Delivery Meta label for Delivery team

Comments

@alpar-t
Copy link
Contributor

alpar-t commented Jun 14, 2018

With Gradle 4.8 running on JDK 10 this happens (reformatted for readability):

java.lang.RuntimeException: unable to install test security manager
	at org.elasticsearch.bootstrap.BootstrapForTesting.<clinit>(BootstrapForTesting.java:170)
	at org.elasticsearch.test.ESTestCase.<clinit>(ESTestCase.java:197)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:374)
	at com.carrotsearch.randomizedtesting.RandomizedRunner$2.run(RandomizedRunner.java:592)
Caused by: java.lang.IllegalStateException: codebase property already set: codebase.plugin-classloader -> 
file:/home/alpar/work/elastic/elasticsearch_master_ci/libs/plugin-classloader/build/distributions/plugin-classloader-7.0.0-alpha1-SNAPSHOT.jar, cannot set to 
file:/home/alpar/work/elastic/elasticsearch_master_ci/libs/plugin-classloader/build/distributions/plugin-classloader-7.0.0-alpha1-SNAPSHOT.jar
	at org.elasticsearch.bootstrap.Security.readPolicy(Security.java:233)
	at org.elasticsearch.bootstrap.BootstrapForTesting.<clinit>(BootstrapForTesting.java:145)
	... 4 more

then most other tests fail with something like:

Exception in thread "Thread-3" java.lang.NoClassDefFoundError: Could not initialize class org.elasticsearch.test.ESTestCase
    at java.base/java.lang.Thread.run(Thread.java:844)

The reading of policies from Security is done trough a static {} block in BootstrapForTesting which should guarantee that it is only initialized once. There doesn't seem to be any other code paths that exercise this, the only time Security.readPolicy is in BootstrapForTesting and Bootstrap that starts Elasticsearch, even if the tests were to do that, it doesn't have a chance to run before the tests are bootstrap.

It must be some strange intimacy between Gradle 4.8 and JDK 10 OpenJDK Runtime Environment (build 10.0.1+10) in my case, as the issue only reproduces with:
./gradlew clean check
It does not reproduce with:

  • ./gradlew :server:test
  • ./gradlew :server:test ran 100 times
  • Gradle 4.7
  • Gradle 4.8 with JDK 11ea (OpenJDK Runtime Environment 18.9 (build 11-ea+17))

Gradle seems to change the order of tasks a lot and will run many other tasks, including some tests before the :server:tests ( which probably doesn't make sense ). Not sure this is relevant.

In order to be able to move to the new Gradle version #31271 has a work around.
I'm writhing this up in the hopes of revisiting it to provide more clarity.
Note that as of this writing the Gradle 4.8 PR mentioned above is not merged.

Relates to #31230.

@alpar-t alpar-t added >non-issue :Delivery/Build Build or test infrastructure labels Jun 14, 2018
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 14, 2018

the problem is not reproducible with a change such as to alter task ordering:

diff --git a/build.gradle b/build.gradle
index 43d59e7b249..de1facab3ca 100644
--- a/build.gradle
+++ b/build.gradle
@@ -585,3 +585,15 @@ compareGradleBuilds {
     arguments = ["-Dbuild.compare_friendly=true"]
   }
 }
+
+allprojects {
+    afterEvaluate {
+        tasks.all {
+            try {
+                if (it.getPath().startsWith(":server") == false && it.getPath().startsWith(":client") == false && it.getPath().startsWith(":libs") == false && it.getPath().startsWith(":test") ==false && it.getPath().startsWith(":build-tools") == false ) {
+                    it.mustRunAfter { project(':server').test  }
+                }
+            } catch (e) {println e}
+        }
+    }
+}

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 18, 2018

@nik9000 Has some comments on #31271 around this: not reproducible with older versions of Gradle, we may be running the tests with the Gradle runner instead of the RandomizedTestRunner, definitely a must-fix to get this in.

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 18, 2018

I can confirm the root issue is indeed that we are running the tests with the Gradle runner. In fact all the test tasks are with the Gradle runner instead of RandomizedTestingTask.

@nik9000
Copy link
Member

nik9000 commented Jun 18, 2018

Really!? Some of them looked right to me. Weird!

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 19, 2018

I extended the randomized test runner plugin to include a sanity check (commit is d6e4c56, not pushed as of this writing) with this, the problem reproduces in ~15 seconds. I then tried to isolate it in https://github.com/atorok/gradle48_jdk11_replace_task and with this I found that it also reproduces on JDK 10, but apparently less frequently. That means we should have seen it in CI already. I'm not sure why we didn't. Maybe it was such a rare occurrence that it was discounted, or the frequency at which it occurs for the ES build vs. my isolated build is much lower. I'll submit an issue for Gradle, but from the forums I take it that the task replacement is fuzzy and bound to break, there are some APIs but it's not quite a finished feature.

@nik9000 My previous comment is not quite right. I assumed many = all, but it's the case, e.x. from 3 runs I just did, first one had 44 wrong test task, the second one had none, the third one had 42.

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 19, 2018

The reason we are not seeing this in CI is that it's specific to Gradle 4.8

@alpar-t alpar-t changed the title Understand Gradle 4.8 + JDK 10 test failure around setup of security policies Understand Gradle 4.8 test failure around setup of security policies Jun 19, 2018
@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 19, 2018

Maybe we should be thinking of creating a task with a different name than test for the randomized tests. I.e. move to have say utest and integTest tasks. We can have test.dependsOn utest just so running gradle test runs them, because old habits die hard. I don't think it makes sense to replace the original test task, since the configuration of the randomized test is so different, it's obviously a different thing, not compatible at all. Seeing configuration applied to utest rather than test will hint that something different is used. I was able to quickly assemble a proof of concept of how this will work.

Ideally to make this totally clean, it would be nice to rename the source sets and create source sets for integration tests as well. So we have src/utest/java and src/integTest/java and use the java-base so we can still use source sets but avoid the original test tasks to be generated at all.

@nik9000
Copy link
Member

nik9000 commented Jun 19, 2018

Making a utest task seems like a fairly drastic solution to gradle's problem. I think we'd want to think a long while before moving all of the source sets around too. We share code between integration and unit tests and the mechanism that we have now gets the job done fairly well.

If we're doing something fundamentally against the way gradle wants to work then I think it'd be worth looking into but I don't think we are.

@nik9000
Copy link
Member

nik9000 commented Jun 19, 2018

Hmmm. I wonder if we could stop the java task from adding the test task in the first place. Moving the source sets would do it but it seems like a big change for what ought to be a smaller problem. But gradle....

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 19, 2018 via email

@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 20, 2018

java-base doesn't help much as it only brings the concept of source sets. Looking at how the Java plugin is implemented, there's no way to prevent it from creating test, however I did find that Gradle 4.8 uses the "lazy task" API 'tasks.createLatherwhereas .7 hadtasks.create`. This helped me find gradle/gradle-native#710. The mechanism proposed there will not work for us, as it proposes to reduce replace functionality to being able to replace only with tasks of a compatible interface.
So I do think it's the case that we are doing something Gradle doesn't want us to do.
I also think it's not a best practice to replace tasks, especially the ones in the gradle API with others implementing a different interface. Replacing task actions, or tasks that don't have an interface for configuration would be a different matter.

I think the best way forward is to disable the test task and create the randomized test runner as utest, making test depend on utest so one can still run ./gradlew test for convenience. Build scripts will configure utest instead of test - a change for the better imho as it makes things explicit.

alpar-t added a commit that referenced this issue Jun 20, 2018
Relates to #31324. It seems like Gradle has an inconsistent behavior and
the taks is not always replaced.
alpar-t added a commit that referenced this issue Jun 20, 2018
Closes #31324. The issue has full context in comments.

With this change the `test` task becomes nothing more than an alias for `utest`.
Some of the stand alone tests that had a `test` task now have `integTest`, and a
few of them that used to have `integTest` to run multiple tests now only
have `check`.
This will also help separarate unit/micro tests from integration tests.
alpar-t added a commit that referenced this issue Jun 21, 2018
Based on information from gradle/gradle#5730 replace the task taking
into account the task providres.
Closes #31324.
@alpar-t
Copy link
Contributor Author

alpar-t commented Jun 21, 2018

Thanks to additional diagnostics and information provided by gradle/gradle#5730, we now have a working implementation that replaces the test task. #31496 will help us move in the direction of using the Gradle runner.

alpar-t added a commit to alpar-t/elasticsearch that referenced this issue Jun 22, 2018
Relates to elastic#31324. It seems like Gradle has an inconsistent behavior and
the taks is not always replaced.
alpar-t added a commit to alpar-t/elasticsearch that referenced this issue Jun 22, 2018
Closes elastic#31324. The issue has full context in comments.

With this change the `test` task becomes nothing more than an alias for `utest`.
Some of the stand alone tests that had a `test` task now have `integTest`, and a
few of them that used to have `integTest` to run multiple tests now only
have `check`.
This will also help separarate unit/micro tests from integration tests.
alpar-t added a commit to alpar-t/elasticsearch that referenced this issue Jun 22, 2018
Based on information from gradle/gradle#5730 replace the task taking
into account the task providres.
Closes elastic#31324.
alpar-t added a commit that referenced this issue Jun 28, 2018
* Move to Gradle 4.8 RC1

* Use latest version of plugin

The current does not work with Gradle 4.8 RC1

* Switch to Gradle GA

* Add and configure build compare plugin

* add work-around for gradle/gradle#5692

* work around gradle/gradle#5696

* Make use of Gradle build compare with reference project

* Make the manifest more compare friendly

* Clear the manifest in compare friendly mode

* Remove animalsniffer from buildscript classpath

* Fix javadoc errors

* Fix doc issues

* reference Gradle issues in comments

* Conditionally configure build compare

* Fix some more doclint issues

* fix typo in build script

* Add sanity check to make sure the test task was replaced

Relates to #31324. It seems like Gradle has an inconsistent behavior and
the taks is not always replaced.

* Include number of non conforming tasks in the exception.

* No longer replace test task, create implicit instead

Closes #31324. The issue has full context in comments.

With this change the `test` task becomes nothing more than an alias for `utest`.
Some of the stand alone tests that had a `test` task now have `integTest`, and a
few of them that used to have `integTest` to run multiple tests now only
have `check`.
This will also help separarate unit/micro tests from integration tests.

* Revert "No longer replace test task, create implicit instead"

This reverts commit f1ebaf7.

* Fix replacement of the test task

Based on information from gradle/gradle#5730 replace the task taking
into account the task providres.
Closes #31324.

* Only apply build comapare plugin if needed

* Make sure test runs before integTest

* Fix doclint aftter merge

* PR review comments

* Switch to Gradle 4.8.1 and remove workaround

* PR review comments

* Consolidate task ordering
@mark-vieira mark-vieira added the Team:Delivery Meta label for Delivery team label Nov 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Delivery/Build Build or test infrastructure jdk11 >non-issue Team:Delivery Meta label for Delivery team
Projects
None yet
Development

No branches or pull requests

4 participants