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

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7620b94
Support cartesian products of environments in MultiEnvTestEngine
colan-dremio Dec 5, 2023
554dfab
Update tests to assert on entire UniqueIds
colan-dremio Dec 6, 2023
e0a8dd3
Merge remote-tracking branch 'upstream/main' into cartesian-multienv
colan-dremio Dec 6, 2023
db22c92
Merge remote-tracking branch 'upstream/main' into cartesian-multienv
colan-dremio Dec 8, 2023
428728a
Remove second registry
colan-dremio Dec 8, 2023
e004be1
Support ordering of extensions
colan-dremio Dec 8, 2023
5faf681
Clear registry between tests
colan-dremio Dec 8, 2023
870d25a
Use separate registry in MultiEnvTestFilter
colan-dremio Dec 8, 2023
5cb8b1b
Re-add tooManyExtensions()
colan-dremio Dec 8, 2023
e8131d4
Clear filter registry between tests too
colan-dremio Dec 8, 2023
67bc7f2
Merge remote-tracking branch 'upstream/main' into cartesian-multienv
colan-dremio May 14, 2024
ab0fd2b
Clear registries between Nessie compat tests
colan-dremio Dec 8, 2023
3df881b
Add missing assert
colan-dremio Dec 8, 2023
db1a3a6
spotless apply
colan-dremio May 14, 2024
5104a20
Call clear from registry constructor
colan-dremio May 14, 2024
732fc44
Rename getOrder to segmentPriority
colan-dremio May 14, 2024
379935f
clarify filter logic
colan-dremio May 14, 2024
577685a
Add environment names to test display names
colan-dremio May 15, 2024
b9c229d
update segmentPriority docs
colan-dremio May 15, 2024
f4e11e4
Reorder extensions to better exercise ordering test
colan-dremio May 16, 2024
a1abab1
Expand cartesian product test
colan-dremio May 17, 2024
a8ce700
Do calculation of partial cartesian product up front in the engine
colan-dremio May 21, 2024
d6fef14
environmentNames -> environmentIds
colan-dremio May 21, 2024
95e8590
Remove filter's dependence on registry
colan-dremio May 21, 2024
915fe05
Remove unnecessary field
colan-dremio May 22, 2024
3439176
spotlessApply
colan-dremio May 22, 2024
1d6166e
Merge remote-tracking branch 'upstream/main' into cartesian-multienv
colan-dremio May 22, 2024
fafab6d
environmentIds -> environment
colan-dremio May 22, 2024
67106da
Add support for TestTemplateTestDescriptor
colan-dremio May 22, 2024
c32b55b
paragraph
colan-dremio May 23, 2024
4a8af55
immutables
colan-dremio May 23, 2024
c7799d0
unused method
colan-dremio May 23, 2024
50b3141
UniqueId selection tests
colan-dremio May 24, 2024
eea4d5d
Switch back to DiscoverySelectorResolver, add post filtering so it do…
colan-dremio May 24, 2024
3ff67f4
Add complex nesting tests, some failing
colan-dremio May 23, 2024
40169b4
Re-use nested find in registry
colan-dremio May 24, 2024
b695dee
fixup
colan-dremio May 24, 2024
4a58d99
Merge remote-tracking branch 'upstream/main' into cartesian-multienv
colan-dremio Jun 3, 2024
3febfbf
remove duplicate annotations
colan-dremio Jun 3, 2024
f0219e1
update new extension
colan-dremio Jun 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,20 @@
import org.junit.platform.commons.util.AnnotationUtils;
import org.junit.platform.engine.ConfigurationParameters;
import org.junit.platform.engine.UniqueId;
import org.projectnessie.junit.engine.MultiEnvSegmentType;
import org.projectnessie.junit.engine.MultiEnvTestExtension;

/**
* Runs the related suite of tests for several Nessie API versions as specified by the {@link
* NessieApiVersions} annotation.
*/
@MultiEnvSegmentType(MultiVersionApiTest.API_VERSION_SEGMENT_TYPE)
public class MultiVersionApiTest implements MultiEnvTestExtension, ExecutionCondition {
public static final String API_VERSION_SEGMENT_TYPE = "nessie-api";

// API version to be used for tests not annotated with `@ForNessieApiVersions`
private static final NessieApiVersion DEFAULT_API_VERSION = NessieApiVersion.V2;

@Override
public String segmentType() {
return API_VERSION_SEGMENT_TYPE;
}

@Override
public List<String> allEnvironmentIds(ConfigurationParameters configuration) {
return Arrays.stream(NessieApiVersion.values()).map(Enum::name).collect(Collectors.toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.junit.platform.engine.ConfigurationParameters;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.UniqueId.Segment;
import org.projectnessie.junit.engine.MultiEnvSegmentType;
import org.projectnessie.junit.engine.MultiEnvTestExtension;
import org.projectnessie.tools.compatibility.api.NessieVersion;
import org.projectnessie.tools.compatibility.api.Version;
Expand All @@ -49,18 +50,14 @@
*
* <p>Implements extension to handle {@link VersionCondition}.
*/
@MultiEnvSegmentType(AbstractMultiVersionExtension.NESSIE_VERSION_SEGMENT_TYPE)
abstract class AbstractMultiVersionExtension
implements BeforeAllCallback, BeforeEachCallback, ExecutionCondition, MultiEnvTestExtension {

private static final String NESSIE_VERSION_SEGMENT_TYPE = "nessie-version";
static final String NESSIE_VERSION_SEGMENT_TYPE = "nessie-version";

private static final ConditionEvaluationResult PASS = enabled(null);

@Override
public String segmentType() {
return NESSIE_VERSION_SEGMENT_TYPE;
}

@Override
public List<String> allEnvironmentIds(ConfigurationParameters configuration) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ void noVersions() {
.hasMessageContaining("TestEngine with ID 'nessie-multi-env' failed to discover tests")
.cause()
.hasMessageContaining(
"MultiEnvTestEngine was enabled, but test extensions did not discover any environment IDs")
.hasMessageContaining("OlderNessieClientsExtension");
"MultiEnvTestEngine was enabled, but test extensions [OlderNessieClientsExtension] did not discover any environment IDs.");
}

@Test
Expand Down Expand Up @@ -210,6 +209,10 @@ void upgrade() {
}

@ExtendWith({OlderNessieClientsExtension.class, SoftAssertionsExtension.class})
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class OldClientsSample {
@InjectSoftAssertions protected SoftAssertions soft;

Expand Down Expand Up @@ -255,6 +258,10 @@ void never() {
}

@ExtendWith({OlderNessieServersExtension.class, SoftAssertionsExtension.class})
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class OldServersSample {
@InjectSoftAssertions protected SoftAssertions soft;

Expand Down Expand Up @@ -305,6 +312,10 @@ void never() {
}

@ExtendWith({OlderNessieServersExtension.class, SoftAssertionsExtension.class})
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class ApiEndpointServerSample {
@InjectSoftAssertions protected SoftAssertions soft;

Expand All @@ -331,6 +342,10 @@ void testSome() throws Exception {
}

@ExtendWith(OlderNessieServersExtension.class)
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class OuterSample {
static final List<Version> outerVersions = new ArrayList<>();
static final List<Version> innerVersions = new ArrayList<>();
Expand All @@ -354,6 +369,10 @@ void inner() {
}

@ExtendWith({NessieUpgradesExtension.class, SoftAssertionsExtension.class})
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class UpgradeSample {
@InjectSoftAssertions protected SoftAssertions soft;

Expand Down Expand Up @@ -400,20 +419,32 @@ void never() {

@ExtendWith(OlderNessieClientsExtension.class)
@ExtendWith(OlderNessieServersExtension.class)
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class TooManyExtensions1 {
@Test
void testSome() {}
}

@ExtendWith(OlderNessieClientsExtension.class)
@ExtendWith(NessieUpgradesExtension.class)
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class TooManyExtensions2 {
@Test
void testSome() {}
}

@ExtendWith(NessieUpgradesExtension.class)
@ExtendWith(OlderNessieServersExtension.class)
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
colan-dremio marked this conversation as resolved.
Show resolved Hide resolved
static class TooManyExtensions3 {
@Test
void testSome() {}
Expand All @@ -422,6 +453,10 @@ void testSome() {}
@ExtendWith(OlderNessieClientsExtension.class)
@ExtendWith(OlderNessieServersExtension.class)
@ExtendWith(NessieUpgradesExtension.class)
@SuppressWarnings({
"JUnitMalformedDeclaration",
"NewClassNamingConvention"
}) // Intentionally not nested, used above
static class TooManyExtensions4 {
@Test
void testSome() {}
Expand Down
1 change: 1 addition & 0 deletions testing/multi-env-test-engine/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies {
api("org.junit.jupiter:junit-jupiter-api")
compileOnly("org.junit.jupiter:junit-jupiter-engine")
implementation("org.junit.platform:junit-platform-launcher")
implementation(libs.guava)

testImplementation("org.junit.platform:junit-platform-testkit")
testCompileOnly("org.junit.jupiter:junit-jupiter-engine")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.junit.engine;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.commons.util.AnnotationUtils;

public final class MultiEnvAnnotationUtils {
private MultiEnvAnnotationUtils() {}

public static <A extends Annotation> Set<A> findNestedRepeatableAnnotationsOn(
Class<?> classToSearch, Class<A> annotationType) {
Set<A> annotations = new HashSet<>();
// Find annotations following the class nesting chain
for (Class<?> cl = classToSearch; cl != null; cl = cl.getDeclaringClass()) {
annotations.addAll(AnnotationUtils.findRepeatableAnnotations(cl, annotationType));
}
return annotations;
}

public static Stream<Class<? extends MultiEnvTestExtension>> findMultiEnvTestExtensionsOn(
Class<?> classToSearch) {
//noinspection unchecked
return findNestedRepeatableAnnotationsOn(classToSearch, ExtendWith.class).stream()
.flatMap(extendWithAnnotation -> Arrays.stream(extendWithAnnotation.value()))
.filter(MultiEnvTestExtension.class::isAssignableFrom)
.map(e -> (Class<? extends MultiEnvTestExtension>) e);
}

public static String segmentTypeOf(Class<? extends MultiEnvTestExtension> extensionClass) {
MultiEnvSegmentType segmentTypeAnnotation =
extensionClass.getAnnotation(MultiEnvSegmentType.class);

if (segmentTypeAnnotation == null) {
throw new IllegalStateException(
String.format(
"%s is missing a MultiEnvSegmentType annotation.", extensionClass.getName()));
}

return segmentTypeAnnotation.value();
}

public static String segmentTypeOf(MultiEnvTestExtension extension) {
return segmentTypeOf(extension.getClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
*/
package org.projectnessie.junit.engine;

import static org.projectnessie.junit.engine.MultiEnvAnnotationUtils.findMultiEnvTestExtensionsOn;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.engine.config.DefaultJupiterConfiguration;
Expand All @@ -34,7 +34,7 @@ public class MultiEnvExtensionRegistry {
private final MutableExtensionRegistry registry;

public MultiEnvExtensionRegistry() {
this.registry =
registry =
MutableExtensionRegistry.createRegistryWithDefaultExtensions(
new DefaultJupiterConfiguration(new EmptyConfigurationParameters()));
}
Expand All @@ -51,19 +51,6 @@ public Stream<MultiEnvTestExtension> stream() {
}

public Stream<? extends MultiEnvTestExtension> stream(Class<?> testClass) {
Copy link
Member

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.

Copy link
Author

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.

Set<ExtendWith> annotations = new HashSet<>();
// Find annotations following the class nesting chain
for (Class<?> cl = testClass; cl != null; cl = cl.getDeclaringClass()) {
annotations.addAll(AnnotationUtils.findRepeatableAnnotations(cl, ExtendWith.class));
}

@SuppressWarnings("unchecked")
Stream<? extends MultiEnvTestExtension> r =
(Stream<? extends MultiEnvTestExtension>)
annotations.stream()
.flatMap(e -> Arrays.stream(e.value()))
.filter(MultiEnvTestExtension.class::isAssignableFrom)
.flatMap(registry::stream);
return r;
return findMultiEnvTestExtensionsOn(testClass).flatMap(registry::stream);
Copy link
Member

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?

Copy link
Author

Choose a reason for hiding this comment

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

Done

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2024 Dremio
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.projectnessie.junit.engine;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MultiEnvSegmentType {
String value();
}
Loading