In my plugin, there are two unit test execution engines, one that executes locally and one that executes via API on a server. My plugin includes distinct Executors for these execution engines and the respective actions that each supports (run, run w/coverage, debug, watch, and profile):
That all works wonderfully, so no issues there. The problem is that once you’ve executed tests, the context menu actions for entries in the test results tool window don’t seem to have context for which specific executor was used to run those tests. The coarse-grained rerun failed tests action is fine because it was created with the original executor, but if you right-click on a test class or method, implementations of ProgramRunner.canRun() are called to filter the available executors, and that’s only passed each executor ID in turn alongside the RunProfile which is (or should be) execution-agnostic. Ideally the context menu would only include the executors for the specific unit test execution engine that yielded those test results. Hopefully that makes sense…
If I had access to the full AnActionEvent that was originally passed to ExecutorAction.update() which is itself what calls ProgramRunner.canRun(), I could filter by that event’s DataContext which includes enough information for reliable filtering, but that’s unavailable to implementations of canRun(), at least directly.
Is there any other way to get this type of action invocation context from an implementation of ProgramRunner.canRun()? Is it available as a thread local or other type of indirect context?
Hey Scott,
I looked into it until someone from the Platform team comes up with an authoritative answer. Full disclosure: I was looking for evidence in the Platform code on how this could be solved. I didn’t test it, the answer is purely based on how it’s used in the Platform code, and, yes, I used an LLM to dig through the sources.
You have multiple executors for two test engines, and when the user right-clicks a test node in the test results tree, the popup is populated through the normal Run Context flow. That eventually filters executors via ProgramRunner.canRun(executorId, profile), but canRun() only gets executorId + RunProfile, not the original AnActionEvent/DataContext. So both engine-specific executors can appear unless the RunProfile itself carries enough information.
There is no public API to get the invoking DataContext/action context, and I did not find a public thread-local/indirect context intended for that directly from ProgramRunner.canRun(). But there seems to be a public API way to solve the overall problem.
Use the configuration-context layer, not ProgramRunner.canRun(), to recover the original test run context and produce an engine-specific rerun configuration (or mark the produced RunProfile with the originating engine). Then canRun() can remain a pure check on executorId + profile.
ConfigurationContext already preserves the original run configuration / execution environment for exactly this kind of case:
ConfigurationContext constructor first looks for RunConfiguration.DATA_KEY
- if absent, it looks for
ExecutionDataKeys.EXECUTION_ENVIRONMENT
- it exposes
getOriginalConfiguration(...)
And its javadoc explicitly says this is for cases like:
“some test framework runtime configuration that had been launched and that had brought a result test tree on which a right-click action was performed.”
So the supported solution is:
- In your
RunConfigurationProducer / context-based rerun production code, inspect:
context.getOriginalConfiguration(...)
- optionally
context.getDataContext().getData(ExecutionDataKeys.EXECUTION_ENVIRONMENT)
- Determine whether the original run came from local vs server engine.
- Create/configure the rerun
RunConfiguration accordingly.
- Let
ProgramRunner.canRun() filter based on data now stored in the RunProfile.
Evidence
Hi, @patrick.scheibe. Thanks for the suggestion.
That’s actually pretty much exactly what I did actually! There are some minor differences, but overall the approach of using ExecutionDataKeys.EXECUTION_ENVIRONMENT and checking PlatformCoreDataKeys.CONTEXT_COMPONENT as being a TestTreeView all holds. I specifically do it from RunConfigurationProducer.isConfigurationFromContext() when everything else matches, and in addition to returning true, I set a “contextual executor” for the run configuration that’s then used for filtering in canRun(). Works like a charm!
Apologies for not following up here, and again, I really appreciate the time you spent coming up with a really useful recommendation.