How to ensure IJobChangeListener completion? #1301
-
RCPTT is a platform for testing Eclipse-based UI applications. One of its features is an option to wait for completion of any background tasks before proceeding to the next test step. This imitates user behavior, where after an interaction user waits for all relevant changes to happen on screen and then either proceeds to the next test step or verifies the application state. A part of this feature waits for background jobs to complete. A few years back, this feature has started to produce inconsistent results. It turns out, we relied on IJobChangeListeners to detect job completion. This is incorrect, as job listeners are themselves a background operation, that should block a next test step from starting. Relying on one listener to wait for completion of all listeners is futile. I investigated the matter recently and has tried a few things to restore the feature. Job.join() itself relies on listeners and exits before listeners complete. I was forced to use private methods via reflection to wait for listeners completion. Is there any API to join a job including its listeners? How are Job framework clients supposed to know that side effects from running the job would no longer happen?
|
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 31 replies
-
I'm not really involved in that topic, so pardon, if this is stupid: Would it help to replace the JobManager instance reflectively with another instance that can track job progress, just during the test execution? My rationale is basically that you might "design" the JobManager as you need it, if you have to use reflection anyway. |
Beta Was this translation helpful? Give feedback.
-
Sadly there is no such API. I myself struggled a lot with this already and actually "all jobs finished" is nothing you can really ever be wait for because jobs might be scheduled any time. So from what you described, I would register one global Job listener, and then record any Jobs that are started between two steps and join / wait on them because that are the jobs that have been triggered by the current step. Depending on your usecase you probably can use:
|
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Any additional API that would add a listener for listening on listener updates may be used by other clients and so will be not sufficient for the purpose of listening on listeners. The potential (theoretical) solution I see is to provide the possibility to set a different job manager implementation for tests, or possibility to supply a "delegate" job manager for tests (to not implement everything and to ensure the actual implementation one wants to test is not changed by the test). |
Beta Was this translation helpful? Give feedback.
-
Sorry, using official API is not a misuse by definition. Typically "continuation work" is not don in the job because the listener and the job are from different modules / projects so one can't simply "enable the button" in the same job that has nothing to do with the button because it simply doesn't know anything about button at all.
Snippet above is not a best practice because calling syncExec() from a job should be avoided in all cases. The reason is that syncExec() is acquiring a lock and the job itself might have already have one or multiple locks taken => straight forward road to deadlocks.
This is what the listeners API is for. There is no "family" API yet as a "family" is a very generic concept (can be null, String or whatever). JobGroup has already join(). |
Beta Was this translation helpful? Give feedback.
@laeubi thank you for the snippet!
I agree with @laeubi here: it seems to me that adding a method to wait for listeners is a bad idea and only meant to compensate for bad practices in the user code.
I can of course understand that RCPTT needs that because it should work even with (sorry for being blunt) poorly programmed client code, but I don't think providing such a method as part of the API is a good idea because it encourages bad practices.
My naive approach would be to: