This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/dev/pr-12895-14a27ac26a0a71b56722f86cdf8ec2779094ceaf in repository https://gitbox.apache.org/repos/asf/seatunnel.git
commit b65fe82b040c203ce669db83431916108f3e866e Author: zhiweiniu <[email protected]> AuthorDate: Sat Oct 24 02:15:43 2026 +0000 [Fix][E2E] Skip suites when all selected containers are disabled (#12895) --- .../apache/seatunnel/e2e/common/TestSuiteBase.java | 2 + .../common/junit/ContainerSelectionCondition.java | 80 ++++++++++++++ .../junit/ContainerSelectionConditionTest.java | 123 +++++++++++++++++++++ 3 files changed, 205 insertions(+) diff --git a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/TestSuiteBase.java b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/TestSuiteBase.java index a82bd4e763..f32f46d3a8 100644 --- a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/TestSuiteBase.java +++ b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/TestSuiteBase.java @@ -20,6 +20,7 @@ package org.apache.seatunnel.e2e.common; import org.apache.seatunnel.e2e.common.container.ContainerTcpProxy; import org.apache.seatunnel.e2e.common.container.TestContainer; import org.apache.seatunnel.e2e.common.container.TestContainersFactory; +import org.apache.seatunnel.e2e.common.junit.ContainerSelectionCondition; import org.apache.seatunnel.e2e.common.junit.ContainerTestingExtension; import org.apache.seatunnel.e2e.common.junit.TestCaseInvocationContextProvider; import org.apache.seatunnel.e2e.common.junit.TestContainers; @@ -41,6 +42,7 @@ import java.util.Arrays; import java.util.List; @ExtendWith({ + ContainerSelectionCondition.class, ContainerTestingExtension.class, TestLoggerExtension.class, TestCaseInvocationContextProvider.class, diff --git a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionCondition.java b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionCondition.java new file mode 100644 index 0000000000..b4429523a8 --- /dev/null +++ b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionCondition.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.seatunnel.e2e.common.junit; + +import org.apache.seatunnel.e2e.common.container.TestContainer; +import org.apache.seatunnel.e2e.common.util.ContainerUtil; + +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionContext; + +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Method; +import java.util.List; + +/** + * Skips a suite or test method when every container selected by {@code RUN_ENGINES} is excluded by + * {@link DisabledOnContainer}. + * + * <p>JUnit requires a {@code TestTemplateInvocationContextProvider} to provide a non-empty stream. + * Without this condition, a suite disabled for the only engine selected for a pull request produces + * an empty stream and fails with {@code PreconditionViolationException} instead of being skipped. + */ +@Slf4j +public class ContainerSelectionCondition implements ExecutionCondition { + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + List<TestContainer> discoveredContainers = ContainerUtil.discoverTestContainers(); + if (shouldDisable( + discoveredContainers, + context.getRequiredTestClass(), + context.getTestMethod().orElse(null))) { + String reason = + String.format( + "All test containers selected by RUN_ENGINES are disabled for %s.", + context.getDisplayName()); + log.info(reason); + return ConditionEvaluationResult.disabled(reason); + } + return ConditionEvaluationResult.enabled( + "At least one applicable test container is available."); + } + + /** + * Decides whether the class or method must be skipped. + * + * <p>An empty discovered list keeps the suite enabled so that a real container discovery + * failure stays visible instead of being silently skipped. + */ + static boolean shouldDisable( + List<TestContainer> discoveredContainers, Class<?> testClass, Method testMethod) { + if (discoveredContainers.isEmpty()) { + return false; + } + List<TestContainer> applicableContainers = + AnnotationUtil.filterDisabledContainers(discoveredContainers, testClass); + if (testMethod != null) { + applicableContainers = + AnnotationUtil.filterDisabledContainers(applicableContainers, testMethod); + } + return applicableContainers.isEmpty(); + } +} diff --git a/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionConditionTest.java b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionConditionTest.java new file mode 100644 index 0000000000..146fe9c685 --- /dev/null +++ b/seatunnel-e2e/seatunnel-e2e-common/src/test/java/org/apache/seatunnel/e2e/common/junit/ContainerSelectionConditionTest.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.seatunnel.e2e.common.junit; + +import org.apache.seatunnel.e2e.common.container.EngineType; +import org.apache.seatunnel.e2e.common.container.TestContainer; +import org.apache.seatunnel.e2e.common.container.TestContainerId; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.apache.seatunnel.e2e.common.container.TestContainerId.FLINK_1_18; +import static org.apache.seatunnel.e2e.common.container.TestContainerId.SEATUNNEL; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class ContainerSelectionConditionTest { + + private static final List<TestContainer> ZETA_ONLY = + Collections.singletonList(container(SEATUNNEL)); + + private static final List<TestContainer> ZETA_AND_FLINK = + Arrays.asList(container(SEATUNNEL), container(FLINK_1_18)); + + @Test + void shouldDisableSuiteWhenAllSelectedEnginesAreDisabled() { + assertTrue( + ContainerSelectionCondition.shouldDisable( + ZETA_ONLY, AllEnginesDisabledSuite.class, null)); + } + + @Test + void shouldDisableSuiteWhenAllSelectedContainersAreDisabledByIdentifier() { + assertTrue( + ContainerSelectionCondition.shouldDisable( + ZETA_ONLY, ZetaContainerDisabledSuite.class, null)); + } + + @Test + void shouldKeepSuiteWhenAnotherSelectedEngineRemains() { + assertFalse( + ContainerSelectionCondition.shouldDisable( + ZETA_AND_FLINK, ZetaEngineDisabledSuite.class, null)); + } + + @Test + void shouldKeepSuiteWhenNoContainerWasDiscovered() { + assertFalse( + ContainerSelectionCondition.shouldDisable( + Collections.emptyList(), AllEnginesDisabledSuite.class, null)); + } + + @Test + void shouldDisableMethodWhenAllSelectedEnginesAreDisabled() throws Exception { + Method method = MethodLevelSuite.class.getDeclaredMethod("zetaOnly"); + + assertTrue( + ContainerSelectionCondition.shouldDisable( + ZETA_ONLY, MethodLevelSuite.class, method)); + } + + @Test + void shouldKeepMethodWhenAnotherSelectedEngineRemains() throws Exception { + Method method = MethodLevelSuite.class.getDeclaredMethod("notZeta"); + + assertFalse( + ContainerSelectionCondition.shouldDisable( + ZETA_AND_FLINK, MethodLevelSuite.class, method)); + } + + private static TestContainer container(TestContainerId identifier) { + TestContainer container = mock(TestContainer.class); + when(container.identifier()).thenReturn(identifier); + return container; + } + + @DisabledOnContainer( + value = {}, + type = {EngineType.SEATUNNEL, EngineType.FLINK}) + private static class AllEnginesDisabledSuite {} + + @DisabledOnContainer(value = SEATUNNEL) + private static class ZetaContainerDisabledSuite {} + + @DisabledOnContainer( + value = {}, + type = EngineType.SEATUNNEL) + private static class ZetaEngineDisabledSuite {} + + private static class MethodLevelSuite { + + @DisabledOnContainer( + value = {}, + type = EngineType.SEATUNNEL) + void zetaOnly() {} + + @DisabledOnContainer( + value = {}, + type = EngineType.FLINK) + void notZeta() {} + } +}
