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

Run tests using JUnit5 platform and remove SpockRunner #770

Merged
merged 16 commits into from
Aug 12, 2020

Conversation

anuraaga
Copy link
Contributor

@anuraaga anuraaga commented Jul 23, 2020

I noticed that we're adding junit platform tests in the spring instrumentation and figured it'd be good if we go ahead and upgrade to give us the option of using it. I'm still interested in doing a side-by-side comparison of spock and junit5 just to see :)

This also tries to simplify the tests by removing SpockRunner - only three tests actually depended on its behavior, and it seems OK to let Gradle take care of the classloader isolation instead of using a JUnit runner which constrains options for the future.

@iNikem
Copy link
Contributor

iNikem commented Jul 27, 2020

@anuraaga what are your plans about this?

@anuraaga
Copy link
Contributor Author

I'm going to examine it more - didn't expect content length and exceptions to eat up my days :P

@anuraaga
Copy link
Contributor Author

I'm going to play a bit more with this, most tests work. But some still have the dreaded "SEVERE: java.lang.LinkageError: loader constraint violation: loader 'bootstrap' wants to load class io.opentelemetry.trace.Span$Kind. A different class with the same name was previously loaded by 'app'. (io.opentelemetry.trace.Span$Kind is in unnamed module of loader 'app')" type of error, so may have to give up. Seems to be a difference in behavior of class loading when using the junit5 runner, even when delegating to vintage.

@@ -42,7 +42,7 @@ import static org.junit.Assume.assumeTrue
abstract class HttpClientTest extends AgentTestRunner {
protected static final BODY_METHODS = ["POST", "PUT"]
protected static final CONNECT_TIMEOUT_MS = 1000
protected static final BASIC_AUTH_KEY = "custom authorization header"
protected static final BASIC_AUTH_KEY = "custom-authorization-header"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this PR PlayJavaWEClientTest fails because of invalid header name characters (space) which looks correct to me... The Play tests have a couple other assertions that fail (TimeoutException vs ConnectException) that seem similarly like they should be failing, as if on current master we're not actually running these tests so I need to investigate more what's going on...

Copy link
Member

Choose a reason for hiding this comment

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

as if on current master we're not actually running these tests

oh, wow, they were not, before this PR!!!

cc: @tylerbenson

Copy link
Member

Choose a reason for hiding this comment

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

@anuraaga could you elaborate... which task isn't failing that should be? Any idea why they aren't being executed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't end up digging on the why, but I think it was this test that started failing with this PR

https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/874b157fe5fdaad80fd82f3ece0600b6860924e7/instrumentation/play-ws/play-ws-2.1/src/test/groovy/PlayWSClientTest.groovy

Netty threw a validation error because of the spaces in this header name which seems right to me.

@trask
Copy link
Member

trask commented Aug 4, 2020

it's gone green!!! 🟢🟩🟢🟩🟢

import spock.lang.AutoCleanup
import spock.lang.Shared

@RunWith(SpockRunner)
Copy link
Contributor Author

@anuraaga anuraaga Aug 4, 2020

Choose a reason for hiding this comment

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

When I thought I finally had a good mental model of what's going on in our tests, a grizzly shows up 🐻

I think one of the reasons a couple of test failed is because with JUnit5, there is no way to intercept class loading
junit-team/junit5#201

This is a fundamental aspect of JUnit5 so presumably even when using the vintage engine, the limitation applies.

I noticed only two tests in the entire repo actually seem to rely on this behavior though, so I gave them special treatment. At that point, it seemed SpockRunner doesn't actually do anything anymore, so I tried removing it completely. Everything worked, except for this one test.

@trask if you feel like it, maybe you could look at this test without and with SpockRunner and teach me what function it's serving and why it would only affect this test :)

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that's a tricky one...

There are two things conspiring against that test:

  1. the test code itself gets instrumented, not only the library under test (GrizzlyAsyncHttpClientTest$AsyncCompletionHandlerMock)
  2. the instrumentation that gets injected into that test code uses InstrumentationContext, and tries to put a null value into it

Because AsyncCompletionHandlerMock is a nested class inside of the test, it appears that class is loaded before we install bytebuddy, which means we can only retransform it, which means InstrumentationContext cannot use the (fast) field-backed provider, and instead has to use the WeakMap.

This is fine.

But then comes (2) and tries to put a null value into the WeakMap, which is what then causes the NPE.

Moving AsyncCompletionHandlerMock out into a top-level class resolves the issue.

I'll also open an issue about the WeakMap implementation not supporting null values, though in general we don't use the the WeakMap when running as -javaagent:..., since in that case we are typically able to do initial transform (not structure limited re-transform) and so we can inject a field into the class and use the field-backed provider.

@iNikem
Copy link
Contributor

iNikem commented Aug 5, 2020

@anuraaga can you please summarise the intent of this PR? I mean, you want to run tests with junit5. Ok, but what tests? All tests? Some tests?

@anuraaga anuraaga marked this pull request as ready for review August 5, 2020 07:46
@anuraaga anuraaga changed the title Run tests using JUnit5 platform Run tests using JUnit5 platform and remove SpockRunner Aug 5, 2020
@anuraaga
Copy link
Contributor Author

anuraaga commented Aug 5, 2020

The intent is to run all the tests with JUnit5 - I think it's more future-proof, including if we want to move to Spock 3 which is based on JUnit5 at some point.

I was hoping the vintage runner would work the exact same way but of course hopes don't always pan out :) I'm not married to this PR, it is a significant regression for assumeTrue to not work correctly so I'll need to follow up with JUnit team to get that fixed during the 5.7 milestones. I do lean towards doing it though to keep up with JUnit. But if we don't merge it it's ok too, during investigating this I learned a lot about the agent :D

@iNikem
Copy link
Contributor

iNikem commented Aug 5, 2020

I am confused :) What is a relationship between Spock and Junit? You don't propose to remove Spock, do you?

@anuraaga
Copy link
Contributor Author

anuraaga commented Aug 5, 2020

Nope :)

JUnit is a test runner framework as well as a framework for writing tests
Spock is a framework for writing tests
Sputnik is a JUnit4 custom test runner for running Spock tests (and is the standard way of running them)

So this PR changes from

JUnit4 + Sputnik -> Spock
to
JUnit5 + Vintage Runner + Sputnik -> Spock

And from my reading of Spock 2.0, I think (not sure) sputnik is gone too and it becomes
JUnit5 -> Spock directly (JUnit4 would not be supported)

@@ -24,6 +24,7 @@ ext {
kotlin : "1.3.72",
coroutines : "1.3.0",
springboot : "2.3.1.RELEASE",
junit5 : "5.7.0-M1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a milestone or current stable is enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this milestone fixed a spock issue

testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api'
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine'
testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine'
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need both old and new engines?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need new engine for any Java tests, we have one PatchLoggerTest. If we get to Spock 2.0 we'll remove vintage at that point.

}
}

// Needs a fresh classloader.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No clue :P Filed an issue

@anuraaga anuraaga merged commit 0eafc28 into open-telemetry:master Aug 12, 2020
mabdinur pushed a commit to mabdinur/opentelemetry-java-instrumentation that referenced this pull request Aug 17, 2020
…y#770)

* Run tests with JUnit platform

* Matcher

* Restore

* Don't mix JUnit4 with JUunit5 in spring tests

* Separate out tests that need custom class loader.

* Separate out test for a couple classes that need it, try to remove SpockRunner, but Grizzly?

* Remove SpockRunner

* Fix grizzly

* Remove assumeTrue workaround.

* Comments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants