Skip to content

Commit 97ef460

Browse files
leonardBangclaude
andcommitted
[test][pipeline-e2e] Improve SqlServerE2eITCase startup and stream split stability
SqlServerE2eITCase could proceed before the job was fully visible to the cluster CLI or before the stream split was assigned, making the first incremental assertions race startup. Wait for the submitted job to appear in `flink list`, gate the snapshot-to-stream transition on a completed checkpoint, and split the initial INSERT from later update/delete assertions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 907ffd3 commit 97ef460

1 file changed

Lines changed: 53 additions & 5 deletions

File tree

flink-cdc-e2e-tests/flink-cdc-pipeline-e2e-tests/src/test/java/org/apache/flink/cdc/pipeline/tests/SqlServerE2eITCase.java

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@
1717

1818
package org.apache.flink.cdc.pipeline.tests;
1919

20+
import org.apache.flink.api.common.JobID;
21+
import org.apache.flink.api.common.time.Deadline;
2022
import org.apache.flink.cdc.common.test.utils.TestUtils;
2123
import org.apache.flink.cdc.pipeline.tests.utils.PipelineTestEnvironment;
24+
import org.apache.flink.core.execution.CheckpointType;
2225

2326
import org.assertj.core.api.Assertions;
2427
import org.junit.jupiter.api.AfterEach;
2528
import org.junit.jupiter.api.BeforeEach;
2629
import org.junit.jupiter.api.Test;
2730
import org.slf4j.Logger;
2831
import org.slf4j.LoggerFactory;
32+
import org.testcontainers.containers.Container.ExecResult;
2933
import org.testcontainers.containers.MSSQLServerContainer;
3034
import org.testcontainers.containers.output.Slf4jLogConsumer;
3135
import org.testcontainers.junit.jupiter.Container;
@@ -42,6 +46,8 @@
4246
import java.time.Duration;
4347
import java.util.Arrays;
4448
import java.util.List;
49+
import java.util.concurrent.TimeUnit;
50+
import java.util.concurrent.TimeoutException;
4551
import java.util.regex.Matcher;
4652
import java.util.regex.Pattern;
4753
import java.util.stream.Collectors;
@@ -108,8 +114,8 @@ void testSyncWholeDatabase() throws Exception {
108114
SQL_SERVER_CONTAINER.getPassword(),
109115
parallelism);
110116
Path sqlServerCdcJar = TestUtils.getResource("sqlserver-cdc-pipeline-connector.jar");
111-
submitPipelineJob(pipelineJob, sqlServerCdcJar);
112-
waitUntilJobRunning(Duration.ofSeconds(30));
117+
JobID jobId = submitPipelineJob(pipelineJob, sqlServerCdcJar);
118+
waitUntilJobRunningFromClusterCli(jobId, Duration.ofSeconds(30));
113119
LOG.info("Pipeline job is running");
114120

115121
validateResult(
@@ -126,11 +132,24 @@ void testSyncWholeDatabase() throws Exception {
126132

127133
LOG.info("Begin incremental reading stage.");
128134

135+
waitUntilStreamSplitReady(jobId, parallelism);
136+
129137
try (Connection conn = getSqlServerJdbcConnection();
130138
Statement stat = conn.createStatement()) {
131139
stat.execute("USE inventory;");
132140
stat.execute(
133141
"INSERT INTO dbo.products(id,name,description,weight) VALUES (110,'jacket','water resistent white wind breaker',0.2);");
142+
} catch (SQLException e) {
143+
LOG.error("Insert row for CDC failed.", e);
144+
throw e;
145+
}
146+
147+
waitUntilSpecificEvent(
148+
"DataChangeEvent{tableId=inventory.dbo.products, before=[], after=[110, jacket, water resistent white wind breaker, 0.2], op=INSERT, meta=()}");
149+
150+
try (Connection conn = getSqlServerJdbcConnection();
151+
Statement stat = conn.createStatement()) {
152+
stat.execute("USE inventory;");
134153
stat.execute(
135154
"UPDATE dbo.products SET description='18oz carpenter hammer' WHERE id=106;");
136155
stat.execute("UPDATE dbo.products SET weight=5.1 WHERE id=107;");
@@ -139,9 +158,6 @@ void testSyncWholeDatabase() throws Exception {
139158
LOG.error("Update table for CDC failed.", e);
140159
throw e;
141160
}
142-
143-
waitUntilSpecificEvent(
144-
"DataChangeEvent{tableId=inventory.dbo.products, before=[], after=[110, jacket, water resistent white wind breaker, 0.2], op=INSERT, meta=()}");
145161
waitUntilSpecificEvent(
146162
"DataChangeEvent{tableId=inventory.dbo.products, before=[106, hammer, 16oz carpenter's hammer, 1.0], after=[106, hammer, 18oz carpenter hammer, 1.0], op=UPDATE, meta=()}");
147163
waitUntilSpecificEvent(
@@ -184,4 +200,36 @@ private Connection getSqlServerJdbcConnection() throws SQLException {
184200
SQL_SERVER_CONTAINER.getUsername(),
185201
SQL_SERVER_CONTAINER.getPassword());
186202
}
203+
204+
private void waitUntilStreamSplitReady(JobID jobId, int parallelism) throws Exception {
205+
if (parallelism == 1) {
206+
return;
207+
}
208+
209+
waitUntilSpecificEvent(
210+
jobManagerConsumer,
211+
"Snapshot split assigner received all splits finished, waiting for a complete checkpoint to mark the assigner finished.");
212+
getRestClusterClient().triggerCheckpoint(jobId, CheckpointType.CONFIGURED).get();
213+
waitUntilSpecificEvent(
214+
jobManagerConsumer, "Snapshot split assigner is turn into finished status.");
215+
waitUntilSpecificEvent(
216+
jobManagerConsumer, "Assign split StreamSplit{splitId='stream-split'");
217+
waitUntilSpecificEvent(
218+
taskManagerConsumer,
219+
"Adding split(s) to reader: [StreamSplit{splitId='stream-split'");
220+
}
221+
222+
private void waitUntilJobRunningFromClusterCli(JobID jobId, Duration timeout) throws Exception {
223+
Deadline deadline = Deadline.fromNow(timeout);
224+
String jobIdHex = jobId.toHexString();
225+
while (deadline.hasTimeLeft()) {
226+
ExecResult execResult = jobManager.execInContainer("bash", "-lc", "flink list");
227+
if (execResult.getExitCode() == 0 && execResult.getStdout().contains(jobIdHex)) {
228+
return;
229+
}
230+
TimeUnit.SECONDS.sleep(1);
231+
}
232+
throw new TimeoutException(
233+
String.format("Timed out waiting for job %s to appear in `flink list`.", jobIdHex));
234+
}
187235
}

0 commit comments

Comments
 (0)