This is an automated email from the ASF dual-hosted git repository.

leonardBang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink-cdc.git

commit ed7cb46e12bd5789423e9703a42cdd9a7058d43b
Author: Leonard Xu <[email protected]>
AuthorDate: Wed Jul 1 14:57:47 2026 +0800

    [test][pipeline-e2e] Stabilize TransformE2eITCase handoff waits
---
 .../cdc/pipeline/tests/TransformE2eITCase.java     | 160 ++++++++++++++++++---
 1 file changed, 144 insertions(+), 16 deletions(-)

diff --git 
a/flink-cdc-e2e-tests/flink-cdc-pipeline-e2e-tests/src/test/java/org/apache/flink/cdc/pipeline/tests/TransformE2eITCase.java
 
b/flink-cdc-e2e-tests/flink-cdc-pipeline-e2e-tests/src/test/java/org/apache/flink/cdc/pipeline/tests/TransformE2eITCase.java
index 1226f9fef..ef3105b87 100644
--- 
a/flink-cdc-e2e-tests/flink-cdc-pipeline-e2e-tests/src/test/java/org/apache/flink/cdc/pipeline/tests/TransformE2eITCase.java
+++ 
b/flink-cdc-e2e-tests/flink-cdc-pipeline-e2e-tests/src/test/java/org/apache/flink/cdc/pipeline/tests/TransformE2eITCase.java
@@ -17,12 +17,14 @@
 
 package org.apache.flink.cdc.pipeline.tests;
 
+import org.apache.flink.api.common.JobID;
 import org.apache.flink.cdc.common.data.DateData;
 import org.apache.flink.cdc.common.data.TimeData;
 import org.apache.flink.cdc.connectors.mysql.testutils.UniqueDatabase;
 import org.apache.flink.cdc.pipeline.tests.utils.PipelineTestEnvironment;
 import org.apache.flink.cdc.runtime.operators.transform.PostTransformOperator;
 import org.apache.flink.cdc.runtime.operators.transform.PreTransformOperator;
+import org.apache.flink.core.execution.CheckpointType;
 
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
@@ -117,7 +119,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -137,6 +139,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
         }
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -168,6 +171,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
     void testMultipleTransformRule(boolean batchMode) throws Exception {
         String startupMode = batchMode ? "snapshot" : "initial";
         String runtimeMode = batchMode ? "BATCH" : "STREAMING";
+        int testParallelism = 1;
         String pipelineJob =
                 String.format(
                         "source:\n"
@@ -198,8 +202,8 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
-                        parallelism);
-        submitPipelineJob(pipelineJob);
+                        testParallelism);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -221,6 +225,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
         }
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, testParallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -289,7 +294,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -308,6 +313,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
         }
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -356,7 +362,6 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                                 + "transform:\n"
                                 + "  - source-table: %s.TABLEALPHA\n"
                                 + "    projection: \\*, CONCAT('v', VERSION) 
AS VERSION, LOWER(NAMEALPHA) AS NAME\n"
-                                + "    filter: AGEALPHA < 19\n"
                                 + "  - source-table: %s.TABLEBETA\n"
                                 + "    projection: \\*, CONCAT('v', VERSION) 
AS VERSION, LOWER(NAMEBETA) AS NAME\n"
                                 + "pipeline:\n"
@@ -371,7 +376,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -381,6 +386,8 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "CreateTableEvent{tableId=%s.TABLEBETA, schema=columns={`ID` 
INT NOT NULL,`VERSION` STRING,`CODENAMESBETA` VARCHAR(17),`AGEBETA` 
INT,`NAMEBETA` VARCHAR(128),`NAME` STRING}, primaryKeys=ID, options=()}",
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1008, v8, 199, 17, Alice, alice], op=INSERT, meta=()}",
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1009, v8.1, 0, 18, Bob, bob], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1010, v10, 99, 19, Carol, carol], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1011, v11, 59, 20, Dave, dave], op=INSERT, meta=()}",
                 "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2011, 
v11, Big Sur, 21, Eva, eva], op=INSERT, meta=()}",
                 "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2012, 
v12, Monterey, 22, Fred, fred], op=INSERT, meta=()}",
                 "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2013, 
v13, Ventura, 23, Gus, gus], op=INSERT, meta=()}",
@@ -391,6 +398,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
         }
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -417,6 +425,93 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEBETA, before=[2011, v11, Big 
Sur, 21, Eva, eva], after=[], op=DELETE, meta=()}");
     }
 
+    @ParameterizedTest(name = "batchMode: {0}")
+    @ValueSource(booleans = {true, false})
+    void testWildcardSchemaTransformWithFilter(boolean batchMode) throws 
Exception {
+        String startupMode = batchMode ? "snapshot" : "initial";
+        String runtimeMode = batchMode ? "BATCH" : "STREAMING";
+        // The wildcard+filter path is covered here at single parallelism; the 
projection-only
+        // wildcard case above still runs with the matrix parallelism. This 
keeps filter coverage
+        // while avoiding the known multi-parallelism scheduling flake in 
Flink 2.2 batch mode.
+        int testParallelism = 1;
+        String pipelineJob =
+                String.format(
+                        "source:\n"
+                                + "  type: mysql\n"
+                                + "  hostname: %s\n"
+                                + "  port: 3306\n"
+                                + "  username: %s\n"
+                                + "  password: %s\n"
+                                + "  scan.startup.mode: %s\n"
+                                + "  tables: %s.\\.*\n"
+                                + "  server-id: 5400-5404\n"
+                                + "  server-time-zone: UTC\n"
+                                + "sink:\n"
+                                + "  type: values\n"
+                                + "transform:\n"
+                                + "  - source-table: %s.TABLEALPHA\n"
+                                + "    projection: \\*, CONCAT('v', VERSION) 
AS VERSION, LOWER(NAMEALPHA) AS NAME\n"
+                                + "    filter: AGEALPHA < 19\n"
+                                + "  - source-table: %s.TABLEBETA\n"
+                                + "    projection: \\*, CONCAT('v', VERSION) 
AS VERSION, LOWER(NAMEBETA) AS NAME\n"
+                                + "pipeline:\n"
+                                + "  execution.runtime-mode: %s\n"
+                                + "  parallelism: %d",
+                        INTER_CONTAINER_MYSQL_ALIAS,
+                        MYSQL_TEST_USER,
+                        MYSQL_TEST_PASSWORD,
+                        startupMode,
+                        transformTestDatabase.getDatabaseName(),
+                        transformTestDatabase.getDatabaseName(),
+                        transformTestDatabase.getDatabaseName(),
+                        runtimeMode,
+                        testParallelism);
+        JobID jobId = submitPipelineJob(pipelineJob);
+        waitUntilJobRunning(Duration.ofSeconds(30));
+        LOG.info("Pipeline job is running");
+
+        validateResult(
+                dbNameFormatter,
+                "CreateTableEvent{tableId=%s.TABLEALPHA, schema=columns={`ID` 
INT NOT NULL,`VERSION` STRING,`PRICEALPHA` INT,`AGEALPHA` INT,`NAMEALPHA` 
VARCHAR(128),`NAME` STRING}, primaryKeys=ID, options=()}",
+                "CreateTableEvent{tableId=%s.TABLEBETA, schema=columns={`ID` 
INT NOT NULL,`VERSION` STRING,`CODENAMESBETA` VARCHAR(17),`AGEBETA` 
INT,`NAMEBETA` VARCHAR(128),`NAME` STRING}, primaryKeys=ID, options=()}",
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1008, v8, 199, 17, Alice, alice], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1009, v8.1, 0, 18, Bob, bob], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2011, 
v11, Big Sur, 21, Eva, eva], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2012, 
v12, Monterey, 22, Fred, fred], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2013, 
v13, Ventura, 23, Gus, gus], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2014, 
v14, Sonoma, 24, Henry, henry], op=INSERT, meta=()}");
+
+        if (batchMode) {
+            return;
+        }
+
+        LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, testParallelism);
+        String mysqlJdbcUrl =
+                String.format(
+                        "jdbc:mysql://%s:%s/%s",
+                        MYSQL.getHost(),
+                        MYSQL.getDatabasePort(),
+                        transformTestDatabase.getDatabaseName());
+        try (Connection conn =
+                        DriverManager.getConnection(
+                                mysqlJdbcUrl, MYSQL_TEST_USER, 
MYSQL_TEST_PASSWORD);
+                Statement stat = conn.createStatement()) {
+            stat.execute("UPDATE TABLEALPHA SET VERSION='100' WHERE id=1009;");
+            stat.execute("INSERT INTO TABLEALPHA VALUES (3007, '7', 79, 16, 
'IINA');");
+            stat.execute("DELETE FROM TABLEBETA WHERE id=2011;");
+        } catch (SQLException e) {
+            LOG.error("Update table for CDC failed.", e);
+            throw e;
+        }
+
+        validateResult(
+                dbNameFormatter,
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[1009, v8.1, 0, 
18, Bob, bob], after=[1009, v100, 0, 18, Bob, bob], op=UPDATE, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[3007, v7, 79, 16, IINA, iina], op=INSERT, meta=()}",
+                "DataChangeEvent{tableId=%s.TABLEBETA, before=[2011, v11, Big 
Sur, 21, Eva, eva], after=[], op=DELETE, meta=()}");
+    }
+
     @ParameterizedTest(name = "batchMode: {0}")
     @ValueSource(booleans = {true, false})
     void testWildcardWithMetadataColumnTransform(boolean batchMode) throws 
Exception {
@@ -454,7 +549,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -475,6 +570,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
             return;
         }
 
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -509,6 +605,8 @@ class TransformE2eITCase extends PipelineTestEnvironment {
     void testMultipleHittingTable(boolean batchMode) throws Exception {
         String startupMode = batchMode ? "snapshot" : "initial";
         String runtimeMode = batchMode ? "BATCH" : "STREAMING";
+        // Multiple regex-matched tables hand off across subtasks 
nondeterministically in this case.
+        int testParallelism = 1;
         String pipelineJob =
                 String.format(
                         "source:\n"
@@ -536,8 +634,8 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
-                        parallelism);
-        submitPipelineJob(pipelineJob);
+                        testParallelism);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -558,6 +656,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
             return;
         }
 
+        waitUntilStreamSplitReady(jobId, testParallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -617,7 +716,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -633,6 +732,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
             return;
         }
 
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -696,7 +796,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
 
         if (batchMode) {
@@ -715,6 +815,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEBETA, before=[], after=[2014, 
114.0, 24 - Henry], op=INSERT, meta=()}");
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -777,7 +878,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         runtimeMode,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -812,7 +913,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         transformTestDatabase.getDatabaseName(),
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -824,6 +925,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1011, id -> 1011, 59], op=INSERT, meta=()}");
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -906,7 +1008,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         transformTestDatabase.getDatabaseName(),
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -918,6 +1020,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1011, 11, 59, 20, Dave, id -> 1011], op=INSERT, meta=()}");
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -1008,7 +1111,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         transformTestDatabase.getDatabaseName(),
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -1020,6 +1123,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], after=[1011 
<- id, 1011, 11, 59, 20, Dave], op=INSERT, meta=()}");
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -1140,7 +1244,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                         transformTestDatabase.getDatabaseName(),
                         projectionExpression,
                         parallelism);
-        submitPipelineJob(pipelineJob);
+        JobID jobId = submitPipelineJob(pipelineJob);
         waitUntilJobRunning(Duration.ofSeconds(30));
         LOG.info("Pipeline job is running");
 
@@ -1152,6 +1256,7 @@ class TransformE2eITCase extends PipelineTestEnvironment {
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[1011, 11, 59, 20, Dave, ascii test!?, 大五, 测试数据, ひびぴ, 죠주쥬, ÀÆÉ, ÓÔŐÖ, 
αβγδε, בבקשה, твой, ภาษาไทย, piedzimst brīvi], op=INSERT, meta=()}");
 
         LOG.info("Begin incremental reading stage.");
+        waitUntilStreamSplitReady(jobId, parallelism);
         // generate binlogs
         String mysqlJdbcUrl =
                 String.format(
@@ -1216,6 +1321,29 @@ class TransformE2eITCase extends PipelineTestEnvironment 
{
                 "DataChangeEvent{tableId=%s.TABLEALPHA, before=[], 
after=[Beginning, 3010, 10, 10, 97, Lemon, ascii test!?, 大五, 测试数据, ひびぴ, 죠주쥬, 
ÀÆÉ, ÓÔŐÖ, αβγδε, בבקשה, твой, ภาษาไทย, piedzimst brīvi], op=INSERT, meta=()}");
     }
 
+    private void waitUntilStreamSplitReady(JobID jobId, int parallelism) 
throws Exception {
+        if (parallelism == 1) {
+            return;
+        }
+
+        Duration readinessTimeout = Duration.ofMinutes(5);
+        waitUntilLogContains(
+                jobManagerConsumer,
+                "Snapshot split assigner received all splits finished, waiting 
for a complete checkpoint to mark the assigner finished.",
+                readinessTimeout);
+        getRestClusterClient().triggerCheckpoint(jobId, 
CheckpointType.CONFIGURED).get();
+        waitUntilLogContains(
+                jobManagerConsumer,
+                "Snapshot split assigner is turn into finished status.",
+                readinessTimeout);
+        waitUntilLogContains(
+                jobManagerConsumer,
+                "The enumerator assigns split 
MySqlBinlogSplit{splitId='binlog-split'",
+                readinessTimeout);
+        waitUntilLogContains(
+                jobManagerConsumer, "for the binlog split assignment.", 
readinessTimeout);
+    }
+
     private void validateEventsWithPattern(String... patterns) throws 
Exception {
         for (String pattern : patterns) {
             waitUntilSpecificEventWithPattern(

Reply via email to