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

Support parallel test execution in the JUnit5 runner #169

Merged

Conversation

fmeum
Copy link
Member

@fmeum fmeum commented Mar 23, 2023

Before this change, BazelJUnitOutputListener wasn't thread-safe, resulting in exceptions such as the following:

java.util.ConcurrentModificationException
	at java.base/java.util.LinkedList$LLSpliterator.tryAdvance(LinkedList.java:1258)
	at java.base/java.util.stream.Streams$ConcatSpliterator.tryAdvance(Streams.java:720)
	at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647)
	at com.github.bazel_contrib.contrib_rules_jvm.junit5.TestSuiteResult.get(TestSuiteResult.java:95)
	at com.github.bazel_contrib.contrib_rules_jvm.junit5.TestSuiteResult.lambda$get$3(TestSuiteResult.java:92)
        ...

@fmeum
Copy link
Member Author

fmeum commented Mar 23, 2023

@shs96c

Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

I'm surprised that the streams should throw an exception, but if the test passes, I'm going to assume the solution works.

The exception given in the PR description suggests that we could make a copy of the results and nestedSuites collections in TestSuiteResult before iterating over them. Did you consider making TestSuiteResult.get synchronized instead?

@fmeum
Copy link
Member Author

fmeum commented Mar 24, 2023

The exception given in the PR description suggests that we could make a copy of the results and nestedSuites collections in TestSuiteResult before iterating over them. Did you consider making TestSuiteResult.get synchronized instead?

I don't think that would work as making a copy would also require iterating over the lists while addDynamicTest may concurrently modify them.

We could make TestSuiteResult#get and TestSuiteResult#add synchronized instead, which gets the test to pass. It wouldn't be as obviously correct as the approach in this PR, but may be more efficient. What do you prefer?

@shs96c
Copy link
Collaborator

shs96c commented Mar 24, 2023

Working code is what I prefer. We can always reorganise things later if we find that this introduces a bottleneck or reduces the performance of people's tests.

@shs96c
Copy link
Collaborator

shs96c commented Mar 24, 2023

Hmm... thinking about this, would a ReadWriteLock around access to the list of tests give us the best of both worlds?

Before this change, `BazelJUnitOutputListener` wasn't thread-safe,
resulting in exceptions such as the following:

```
java.util.ConcurrentModificationException
	at java.base/java.util.LinkedList$LLSpliterator.tryAdvance(LinkedList.java:1258)
	at java.base/java.util.stream.Streams$ConcatSpliterator.tryAdvance(Streams.java:720)
	at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129)
	at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647)
	at com.github.bazel_contrib.contrib_rules_jvm.junit5.TestSuiteResult.get(TestSuiteResult.java:95)
	at com.github.bazel_contrib.contrib_rules_jvm.junit5.TestSuiteResult.lambda$get$3(TestSuiteResult.java:92)
        ...
```
@fmeum
Copy link
Member Author

fmeum commented Mar 24, 2023

Hmm... thinking about this, would a ReadWriteLock around access to the list of tests give us the best of both worlds?

That's a good idea, did that instead.

@fmeum fmeum requested a review from shs96c March 27, 2023 14:08
Copy link
Collaborator

@shs96c shs96c left a comment

Choose a reason for hiding this comment

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

LGTM. Thank you for the last change

@shs96c shs96c merged commit c6d6a68 into bazel-contrib:main Mar 27, 2023
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.

2 participants