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 Cartesian products of environments in MultiEnvTestEngine #7816

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

colan-dremio
Copy link

Currently, MultiEnvTestEngine only supports a single MultiEnvTestExtension at a time. This adds support for multiple MultiEnvTestExtensions. It will perform a Cartesian product of the registered environment IDs.

For example, it would become possible to test multiple Nessie client versions with multiple Nessie server versions through a combination of OlderNessieClientsExtension and OlderNessieServersExtension. With nessie.versions property set to 1,2, the following test environments would run:

  • [client:1][server:1]
  • [client:1][server:2]
  • [client:2][server:1]
  • [client:2][server:2]

This is also enables downstream projects to use their own implementations of MultiEnvTestExtension. For example, a downstream project could test multiple Nessie versions against multiple types of object storage.

@colan-dremio colan-dremio marked this pull request as draft December 6, 2023 20:04
* <p>Actual test environments are expected to be managed by JUnit 5 extensions, implementing the
* {@link MultiEnvTestExtension} interface.
*/
public class MultiEnvTestEngine implements TestEngine {

private static final Logger LOGGER = LoggerFactory.getLogger(MultiEnvTestEngine.class);
private static final boolean FAIL_ON_MISSING_ENVIRONMENTS =
!Boolean.getBoolean("org.projectnessie.junit.engine.ignore-empty-environments");
private static final MultiEnvExtensionRegistry FILTER_REGISTRY = new MultiEnvExtensionRegistry();
Copy link
Author

Choose a reason for hiding this comment

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

@dimas-b you mentioned that this was not a constant. Did you just want the casing changed to filterRegistry, or were you concerned by the addition of a second currentRegistry below?

I found that two registries were needed, one for the test environment creation and one that keeps track of all known MultiEnvTestExtensions to use for test filtering.

Copy link
Member

Choose a reason for hiding this comment

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

I'd prefer to keep the old lower case name... or perhaps globalRegistry if you want to make it easier to distinguish from currentRegistry.

Copy link
Author

Choose a reason for hiding this comment

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

It was not needed. But I found a couple interesting things:

  • The registry needs to be cleared between each test. I found tests like bothOnJunitJupiter would fail if run alone, but would pass when the whole TestMultiEnvTestEngine class was run. Clearing the registries between tests exposes this issue.
  • The filter needs its own registry in case multi-env tests are selected on other engines (also see bothOnJunitJupiter)

JupiterConfiguration nodeConfiguration =
new CachingJupiterConfiguration(
new MultiEnvJupiterConfiguration(
configurationParameters, "TODO")); // TODO
Copy link
Author

Choose a reason for hiding this comment

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

I still need to look at test naming here.

Copy link
Member

@dimas-b dimas-b left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution @colan-dremio !

This is just a preliminary quick review from my side :)

* </ul>
* will result in the following IDs:
* <ul>
* <li>[engine:nessie-multi-env][segmentA:1][segmentB:1][segmentC:1]</li>
Copy link
Member

Choose a reason for hiding this comment

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

I believe MultiEnvTestFilter needs to be updated to check whether all multi-env ID segments are recognised... Currently it checks that any match.

descriptor -> {
if (descriptor instanceof ClassBasedTestDescriptor) {
Class<?> testClass = ((ClassBasedTestDescriptor) descriptor).getTestClass();
registry.registerExtensions(testClass);
FILTER_REGISTRY.registerExtensions(testClass);
currentRegistry.registerExtensions(testClass);
Copy link
Member

Choose a reason for hiding this comment

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

Why exactly do we need two registries?

currentRegistry is used only during discovery, but MultiEnvTestFilter should use the same extensions for filtering, which is why the registry was static before. See comments in MultiEnvTestFilter for more details about the rationale.

Copy link
Author

Choose a reason for hiding this comment

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

(replied in #7816 (comment) instead accidentally)


public void clear() {
registry = MutableExtensionRegistry.createRegistryWithDefaultExtensions(
new DefaultJupiterConfiguration(new EmptyConfigurationParameters()));
Copy link
Member

Choose a reason for hiding this comment

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

Let's call this from the constructor to avoid duplicating (re-)initialization logic.

* UniqueID. Higher numbers will appear earlier in the JUnit UniqueId. For extensions with the
* same order value, the segmentType will be sorted alphabetically.
*/
default int getOrder() {
Copy link
Member

Choose a reason for hiding this comment

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

How about priority() or weight()?

  1. the get prefix does not align with the allEnvironmentIds() method.
  2. "order" sounds a bit too strong. This value affects the placement of the extension's segment in the test UniqueId values... it does not affect execution order of tests or extensions at all (cf. the JUnit5 @Order annotation).

MultiEnvExtensionRegistry registry = registry();

// Keep separate registry from MultiEnvTestEngine in case we are running on another engine and still need to filter.
registry.registerExtensions(testClass);
if (id.getEngineId().map("junit-jupiter"::equals).orElse(false)) {
if (registry.stream(testClass).findAny().isPresent()) {
Copy link
Member

Choose a reason for hiding this comment

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

WDYT about moving segmentType() to an annotation on MultiEnvTestExtension? Then a registry instance will not be required here at all. The stream method could probably be refactored to offer a static part for discovering annotations.

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.

None yet

2 participants