-
Notifications
You must be signed in to change notification settings - Fork 137
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
base: main
Are you sure you want to change the base?
Conversation
...t/java/org/projectnessie/tools/compatibility/internal/TestNessieCompatibilityExtensions.java
Outdated
Show resolved
Hide resolved
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestEngine.java
Outdated
Show resolved
Hide resolved
...env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestDescriptorTree.java
Outdated
Show resolved
Hide resolved
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.
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> |
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 believe MultiEnvTestFilter
needs to be updated to check whether all multi-env ID segments are recognised... Currently it checks that any match.
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 don't mind doing this, but I'm unsure if it is necessary. This would couple the cartesian product logic to the filter. The MultiEnvTestEngine
is responsible for expanding the environments. Perhaps other types of expansion would be desirable in the future? From the filter's perspective, it seems reasonable to include a test as long as we see at least one correct segment type. This shouldn't happen in practice, so either way is fine with me.
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.
At the time, I was not correct above about the expansion logic, but now that it is fixed it should hold.
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestEngine.java
Outdated
Show resolved
Hide resolved
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestEngine.java
Outdated
Show resolved
Hide resolved
...-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvExtensionRegistry.java
Outdated
Show resolved
Hide resolved
...ulti-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestExtension.java
Outdated
Show resolved
Hide resolved
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestFilter.java
Outdated
Show resolved
Hide resolved
# Conflicts: # compatibility/common/src/test/java/org/projectnessie/tools/compatibility/internal/TestNessieCompatibilityExtensions.java
# Conflicts: # testing/multi-env-test-engine/src/test/java/org/projectnessie/junit/engine/TestMultiEnvTestEngine.java
Note: I am developing on a Mac and could not validate |
this.delegate = delegate; | ||
this.environment = environment; | ||
this.environmentNames = environmentNames; |
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.
why rename? The String
is opaque in this context, does not convey anything about names, IMHO.
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.
On review, I meant environmentIds
not names, updated accordingly. The goal was to give a bit of clarity into what the value holds. If we want to treat it as opaque, I can rename to suffix
instead.
More generally, I've found that there is some ambiguity in naming. This is a multiple environment test engine, what is an environment? Take the example OlderNessieServersExtension (S1, S2) and OlderNessieClientsExtension (C1) which will run:
- S1, C1
- S2, C1
There are a number of concepts that need names:
- Each multienv extension (e.g. OlderNessieServersExtension)
- Each segement type (e.g. nessie-server-version)
- Each "environment id" within an extension (e.g. S1 and S2 individually)
- Each unique combination of environment ids on a test execution (e.g. [S1, C1])
If we go from the name here, it seems #4 is meant to be "environment"
Possible names to make this work:
- Dimension
- Dimension type
- Dimension element
- Environment
e.g.
public interface MultiEnvTestExtension extends Extension {
String dimensionType();
List<String> allDimensionElements(ConfigurationParameters configuration);
default int dimensionPriority() {
return 0;
}
}
Thoughts?
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.
This particular class is meant to make multi-env testa distinguishable in tools that do not understand Junit5 UniqueId
(i.e. those that deal with test class/method names only). environmentIds
works in this case, but I still think the rename is unnecessary in this case as the old environment
works just as well :)
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.
1. Dimention
- SGTM (but let's wait a bit with renaming :) )
2. Dimention type
- I prefer segment (current) as it related to JUnit5 ID segments.
3. Dimention elements
- Maybe Category
? (in the statistical sense)
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.
Keeping environment
as # 4 is fine with me. I don't think "category" should be used for elements, "category" is synonymous with dimension type / segment type. Also, I don't think we should use "segment" alone because a UniqueId segment is the pair of segment type + segment value.
It looks like we should choose
- One of (dimension | segment | category) for # 2
- Whether or not to use "type" as a suffix for # 2. I'd avoid "segment" alone, but could see "category" or "category type" working fine.
- One of (value | element | ID) for # 3
My vote at the moment is "dimension", "type", and "value":
public @interface MultiEnvDimensionType {}
public interface MultiEnvTestExtension extends Extension {
List<String> allDimensionValues(ConfigurationParameters configuration);
int segmentPriority()
}
For now, I've reverted these back to environment
and will see what the rename would look like in practice.
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.
Proposed naming: colan-dremio@e4625b7
There are some subtle advantages here. For example in this block, it can be ambiguous about whether currentSegmentTypes/Values
is referring to MultiEnv segments or all JUnit segments (engine, class, nested-class, method too). I had considered currentMultiEnvSegmentTypes/Values
to clarify this. Now that it is currentDimensionTypes/Values
, the ambiguity is also resolved.
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestFilter.java
Outdated
Show resolved
Hide resolved
...lti-env-test-engine/src/test/java/org/projectnessie/junit/engine/TestMultiEnvTestEngine.java
Outdated
Show resolved
Hide resolved
...v-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvJupiterConfiguration.java
Outdated
Show resolved
Hide resolved
List<TestDescriptor> newLeafNodes = new ArrayList<>(); | ||
for (TestDescriptor parentNode : latestLeafNodes) { | ||
for (String environmentId : | ||
multiEnvTestExtension.allEnvironmentIds(configurationParameters)) { |
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.
TBH, I find this method of constructing a Cartesian product of environments a bit obscure. Why not simply have nested loops in one method (without calling out to this helper class)?
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've moved the tree construction logic directly into the engine implementation as part of fixing the updated cartesian test. The main annoyance is that the tree of nodes (represented by recursive child references) sits independently of the UniqueIds of those nodes. My new implementation still maintains a cache of known nodes to keep lookup simple, but should be simpler overall.
...g/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestFilter.java
Show resolved
Hide resolved
# Conflicts: # testing/multi-env-test-engine/src/main/java/org/projectnessie/junit/engine/MultiEnvTestDescriptorTree.java
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.
Only a partial review this time, but I think we're getting close to the end :)
...t/java/org/projectnessie/tools/compatibility/internal/TestNessieCompatibilityExtensions.java
Outdated
Show resolved
Hide resolved
@@ -22,13 +22,13 @@ | |||
/** | |||
* Interface for JUnit5 test extensions that require running the same suite of tests in multiple | |||
* executions environments. For example, running the same tests for multiple versions of a Nessie | |||
* Client. | |||
* Client.<br> |
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.
Maybe just <p>
? cf.
nessie/api/client/src/main/java/org/projectnessie/client/builder/StreamingUtil.java
Line 32 in 81b34b6
* <p>Use the functions that return {@link Stream}s in the builders that implement {@link |
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.
Done
.filter(MultiEnvTestExtension.class::isAssignableFrom) | ||
.flatMap(registry::stream); | ||
return r; | ||
return findMultiEnvTestExtensionsOn(testClass).flatMap(registry::stream); |
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.
Maybe use it in registerExtensions
too?
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.
Done
@@ -51,19 +51,6 @@ public Stream<MultiEnvTestExtension> stream() { | |||
} | |||
|
|||
public Stream<? extends MultiEnvTestExtension> stream(Class<?> testClass) { |
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.
stream()
(no args) is unused now.
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.
Weird, my IDE seems to be confused about this one. Removed.
} | ||
|
||
/** Immutable key of segment types for the intermediate cartesian product tree. */ | ||
private static class SegmentTypes { |
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.
Why not @Value.Immutable
? It would be possible to add default helper methods for .root()
and .append(String child)
even if SegmentTypes
were an interface
.
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.
Done
putTestIntoParent( | ||
testDescriptor, nodeAtCurrentPosition, environmentNames, discoveryRequest); |
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 think it might still be preferable to use the old resolveSelectors(...)
method... How does the new code behave when (e.g. IDE) selects only one test method for execution? For example, run the whole test suite, but then select only one test in one particular environment for debugging in IntelliJ.
In this PR in my env. that will run the test method in all environments, before the PR, only in one env (as it should).
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.
Added this back. It had some interesting side effects where resolution would discover children that do not apply. With some post-filtering, it looks like this works better.
Added tests to cover these scenarios.
…esn't select too many things
Currently,
MultiEnvTestEngine
only supports a singleMultiEnvTestExtension
at a time. This adds support for multipleMultiEnvTestExtension
s. 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
andOlderNessieServersExtension
. Withnessie.versions
property set to1,2
, the following test environments would run: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.Future work: Does not yet support complex
@Nested
tests. Two tests are added but@Disabled
for future development, seeonlyNestedTest
andcartesianNestedTest
.