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() {}
+    }
+}

Reply via email to