-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
Make RunNotifier code concurrent #625
Conversation
This is a copy of pull #578 with tests fixed and other cleanups applied. I'm not yet happy with the state of the tests. We need better tests to verify that existing listener notifications are not called concurrently, but annotated implementations are called concurrently. I'm not familiar with Maven, so I cannot verify if those changes are correct. Ideally, we should use the jcip-annotations jar at compile time, but users should not be required to have it at run-time. I'm also not sure whether we should use jcip-annotations vs. our own annotation. |
I'm planning to handle this pull request and the other with a light touch until @kcooney and @Tibor17 have iterated to their satisfaction. Please feel free to explicitly invoke me (with a ping to [email protected], if needed) if I should wake up sooner. Thanks! |
Conflicts: build.xml src/main/java/org/junit/runner/notification/RunNotifier.java src/main/java/org/junit/runner/notification/SynchronizedRunListener.java src/test/java/org/junit/tests/AllTests.java
Conflicts: src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java src/test/java/org/junit/tests/AllTests.java
…_remove-jcip-deps Conflicts: src/test/java/org/junit/runner/notification/SynchronizedRunListenerTest.java
Update Javadoc Delete AddRemoveListenerTest (functionality covered by RunNotifierTest)
@dsaff @Tibor17 I modified this pull request to match the proposal to have a new RunNotifier.ThreadSafe annotation and did a rewrite of the Javadoc. Please take another look David, don't pull this via the git-hub UI; there are a lot of commits, and we don't want them all on the main branch. I'll do a non-fast-forward merge once everyone is comfortable with the final result. Thanks for all the work! |
Set<MethodSignature> synchronizedRunListenerMethods= getAllDeclaredMethods( | ||
SynchronizedRunListener.class); | ||
|
||
assertTrue(synchronizedRunListenerMethods.containsAll(runListenerMethods)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clever. Thanks.
@Tibor17, @kcooney, I've just gone through and made comments about the only places where I think we need to further make changes. There's not many. @Tibor17, I gather that you feel that @kcooney has made more changes to your initial pull than strictly necessary. In some cases, I agree with @kcooney: the additional javadoc is quite helpful for implementors navigating the new thread-aware landscape we're setting before them. @kcooney appears to have already backed out the major unrelated changes that I saw on a previous commit. If in any place, I felt that the change was actually a negative move, I have indicated so. In any place where it appears to be a stylistic or naming preference issue, the simpler solution is to go with what we have now in this pull, rather than cherry-picking rollbacks. |
@kcooney |
@Tibor17, I did go through the remarks in that comment. I think we could go another couple of weeks debating each individual point--at this point, I'd like to see this get in, and then if you really feel that any of them have been missed that are truly bugs or missing features, I'll happily look at new pull requests fixing them. Like I said, in some cases, you did things in one way, and @kcooney did them in a different way that is equally valid, and I don't think reverting these one by one is productive. |
Thanks for the great feedback. I am traveling and had a poor WiFi |
This and next week i am busy with interviews, but i will try to connect to github if there's some spare time. |
I am still working on some of the requested changes, but I wanted to respond with some questions and comments
I reverted the unrelated changes except for the trivial change to NOTICE.txt
I don't see that documented anywhere. I personally like the f-prefixes. If we change the style for fields, I think we should go back and fix all code under org/junit; a mix of styles for fields would be confusing.
I think RunNotifierTest is a more logical place for these tests. The only changes were removing tests that used listeners that didn't obey the general contract of equals. I don't think we should be testing that, because the behavior can be undefined.
See my question to David above.
SynchronizedRunListener is a package-scope class, so there's no harm to making methods public. I like making the conceptually-public API of a class public; it makes it easier to see the API
I think where I have it is reasonable.
If you can write a test using the public API of RunNotifer that fails with my version of equals but passes with yours, I will consider using your version. Until then, it's much better to have equals() implementations be symmetric, reflexive and transitive.
The prior RunNotifier synchronization would never call two RunListeners concurrently. So if I add two listeners that call common non-thread-safe code, everything will work fine with the old code and my code. With simple synchronization that won't be the case. I'll update the JavaDoc of SynchronizedRunListener to make this clear
I strongly disagree. Documenting the thread-safety guarantees should be part of this pull.
As you have pointed out before, I do tend to be verbose :-) Please feel free to comment on JavaDoc that isn't necessary.
Disagree. These are unit tests of SynchronizedRunListener. Both unit tests and integration tests can be useful. If there is a specific test that should be moved, please comment on the test file.
Why not? SynchronizedRunListener is thread safe, after all. It also allows us to have two examples of thread-safe listeners in the code base. |
Okay, made a bunch of changes. Please take another look |
} | ||
|
||
/** | ||
* Internal use only | ||
*/ | ||
public void removeListener(RunListener listener) { | ||
fListeners.remove(listener); | ||
if (listener == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just move this check to wrapIfNotThreadSafe?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could do that, but then the NullPointerException wouldn't have a message. If that's fine with you, I can make the change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, missed the extra exception info. Never mind, carry on.
Looks to me to be iterating toward completion. A couple more (smaller) comments. |
@dsaff PTAL |
I prefer |
@Tibor17 I don't understand the issue. If the user implements a thread-safe listener without locks, then they should just annotate the listener class with The end-user isn't calling |
The method I have another problem with the static monitor in SynchronizedRunListener. It's a common lock across multiple JunitCore instances/RunNotifiers. Since you wanted prevent from overlapping listeners across multiple threads, the static lock is even worse than the ment treatment. |
@Tibor17 Done. |
@dsaff |
All right, I think we're good to go. Thank you very much to both of you for iterating to a great finishing point. I'll work with @kcooney to merge it in cleanly. |
Merged! Thanks, all. |
Allows multiple threads to concurrently send notifications to RunListeners. Existing RunListener implementations will continue to have their method calls synchronized. RunListener implementations annotated with net.jcip.annotations.ThreadSafe will have their method calls run in parallel if tests are run in parallel.