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

Sporadic EOFException when running tests in Eclipse with jacoco extension #18571

Closed
famod opened this issue Jul 9, 2021 · 12 comments · Fixed by #21296
Closed

Sporadic EOFException when running tests in Eclipse with jacoco extension #18571

famod opened this issue Jul 9, 2021 · 12 comments · Fixed by #21296
Labels
area/testing kind/bug Something isn't working
Milestone

Comments

@famod
Copy link
Member

famod commented Jul 9, 2021

Describe the bug

I'm seeing this frequently (but not always) in Eclipse at the end of a test execution:

Failed to generate Jacoco reports
java.io.EOFException
	at java.base/java.io.DataInputStream.readUnsignedShort(DataInputStream.java:345)
	at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:594)
	at java.base/java.io.DataInputStream.readUTF(DataInputStream.java:569)
	at org.jacoco.core.data.ExecutionDataReader.readExecutionData(ExecutionDataReader.java:149)
	at org.jacoco.core.data.ExecutionDataReader.readBlock(ExecutionDataReader.java:116)
	at org.jacoco.core.data.ExecutionDataReader.read(ExecutionDataReader.java:93)
	at org.jacoco.core.tools.ExecFileLoader.load(ExecFileLoader.java:60)
	at org.jacoco.core.tools.ExecFileLoader.load(ExecFileLoader.java:74)
	at io.quarkus.jacoco.runtime.ReportCreator.run(ReportCreator.java:72)
	at java.base/java.lang.Thread.run(Thread.java:829)

This doesn't make the test fail, it only looks scary.

Expected behavior

No such exception

Actual behavior

Exception is logged (not sure about the integrity of the report, though).

To Reproduce

No reproducer available (yet?).

Environment (please complete the following information):

Output of uname -a or ver

Linux W4DEUMSY9003463 5.4.72-microsoft-standard-WSL2 #1 SMP Wed Oct 28 23:40:43 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Ubuntu 20.04.2 LTS

Output of java -version

OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode)

Quarkus version or git rev

2.0.1.Final

(also seen in 2.0.0)

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.8.1 or in this case better to say Eclipse 2021-06.

Additional context

Seems to come from a shutdown hook?

Btw, Eclipse is running in the WSL2 Ubuntu dist (xfce, accessed via xrdp), not on Windows host.

@famod famod added the kind/bug Something isn't working label Jul 9, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented Jul 9, 2021

/cc @geoand

@famod
Copy link
Member Author

famod commented Jul 9, 2021

/cc @stuartwdouglas

@famod famod changed the title Sporadic EOFException when running tests in Eclipse with jaoco extension Sporadic EOFException when running tests in Eclipse with jacoco extension Jul 9, 2021
@famod
Copy link
Member Author

famod commented Aug 24, 2021

@stuartwdouglas This is probably a race between between the shutdown hook of quarkus-jacoco and the one from jacoco itself:
https://github.com/jacoco/jacoco/blob/v0.8.7/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java#L55
which dumps the file (by default):
https://github.com/jacoco/jacoco/blob/v0.8.7/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/Agent.java#L145

I suppose this might not catch that jacoc shudown hook thread in all cases: https://github.com/quarkusio/quarkus/blob/main/test-framework/jacoco/runtime/src/main/java/io/quarkus/jacoco/runtime/ReportCreator.java#L57

I was thinking about trying to deduce from a OverlappingFileLockException whether jacoco is still writing the file, see also: https://github.com/jacoco/jacoco/blob/v0.8.7/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/output/FileOutput.java#L70

WDYT?

PS, OTOH, do we need the report at all when running from an IDE?

@stuartwdouglas
Copy link
Member

I don't know why that code is not working, but that is likely the cause.

I was thinking the solution would be to disable dump on exit, and instead use JMX to dump the file, but I don't know when I will get time to investigate this approach.

If possible it would be nice to disable this for IDE based test runs, but AFAIK there is no easy way to detect this.

@famod
Copy link
Member Author

famod commented Aug 24, 2021

If possible it would be nice to disable this for IDE based test runs, but AFAIK there is no easy way to detect this.

Well, IDK about other IDEs, but in Eclipse you have that special runner: org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
But I suppose we want to detect all IDEs?

@stuartwdouglas
Copy link
Member

I guess maven and gradle have their own runners as well. We could look for the maven/gradle ones and if they are not present then disable jacoco.

@famod
Copy link
Member Author

famod commented Sep 12, 2021

For mvn, we could check the trace for org.apache.maven.surefire.

But for gradle? These are the first stack frames for a test in devtools/gradle (don't have another example ATM):

	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:99)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:79)
	at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:75)
	at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
	at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
	at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
	at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
	at com.sun.proxy.$Proxy2.stop(Unknown Source)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
	at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
	at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
	at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
	at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

org.gradle.api.internal.tasks.testing maybe? I don't like the internal bit though...

/cc @glefloch

@glefloch
Copy link
Member

Yes, looking at the stack while running a test from gradle, the first test trace I can see is org.gradle.api.internal.tasks.testing and org.gradle.api.internal.tasks.testing.junitplatform.

@famod
Copy link
Member Author

famod commented Sep 14, 2021

@glefloch do you think it's stable enough to use it to detect a non-IDE run? I'm not familiar with how IDEs run Gradle tests.

@glefloch
Copy link
Member

Yes I think we can.

@clainchoupi
Copy link

Hi guys,
I have the same behavior when I try to generate the Jacoco report with a Gitlab Pipeline. Some times it succed to generate the jacoco.xml file, but most of the time it won't, while it works every time when I "mvn verify" in VSCode

My pipeline config looks like that :

test:
  stage: test
  script:
    - ./mvnw verify
  artifacts:
   when: always
   paths:
     - target/jacoco-report/jacoco.xml
# Issue en cours sur Jacoco avec Quarkus qui empeche de générer le report 
# https://issueexplorer.com/issue/quarkusio/quarkus/18571
# Coverage step commentée en attendant (fonctionne dans l'IDE)
coverage:
  stage: coverage
  image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
  script:
    - python /opt/cover2cover.py target/jacoco-reports/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml
  needs: ["test"]
  artifacts:
    reports:
      cobertura: target/site/cobertura.xml  

@famod
Copy link
Member Author

famod commented Nov 8, 2021

So the above report means that this is not only an IDE problem.
(Btw, in my project I disabled report generation altogether as Jenkins or the IDEs themselves are doing it for us).

I had another look amd that OverlappingFileLockException approach won't work reliably because there is no guarantee who comes first (the jacoco agent or the quarkus ReportCreator), so the creator might run too early and miss coverage.
But maybe File.length() could help here...

stuartwdouglas added a commit to stuartwdouglas/quarkus that referenced this issue Nov 9, 2021
Jacoco will create a zero length file early, we need to wait until it
has actually been written.

Fixes quarkusio#18571
@quarkus-bot quarkus-bot bot added this to the 2.5 - main milestone Nov 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/testing kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants