Skip to content

[fix][test] Replace fixed sleeps with Awaitility polls in sink tests#86

Merged
david-streamlio merged 2 commits into
apache:masterfrom
david-streamlio:fix/sink-test-sleep-races
Jul 10, 2026
Merged

[fix][test] Replace fixed sleeps with Awaitility polls in sink tests#86
david-streamlio merged 2 commits into
apache:masterfrom
david-streamlio:fix/sink-test-sleep-races

Conversation

@david-streamlio

Copy link
Copy Markdown
Contributor

Fixes #85

Motivation

An audit for timing flakes found the same defect in four more modules. Each writes to a sink that flushes asynchronously, waits a fixed Thread.sleep, then asserts the flush happened. On a slow runner the flush has not run and the assertion fails — the sink is fine, the test raced it.

This shape has already failed two unrelated PRs today:

Findings

Module Test Sleep Then asserts Async mechanism
hdfs3 HdfsSequentialSinkTest.write5000Test 2000 ms verify(..., times(5000)).ack() syncInterval background sync
hdfs3 HdfsSequentialSinkTest, HdfsTextSinkTest 2000 ms verify(..., times(100)).ack() same
mongo MongoSinkTest × 5 sites 1000 ms verify(..., times(n)).ack()/.fail() flushExecutor.scheduleAtFixedRate
influxdb v1 InfluxDBGenericRecordSinkTest 1000 ms verify(influxDB, times(1)).write(...) BatchSink flush executor — the very class whose v2 sibling flaked
hbase HbaseGenericRecordSinkTest 500 ms reads the row back HbaseAbstractSink batch flush

write5000Test is the sharpest: 5000 acks asserted within a hard-coded 2 seconds.

Modifications

Replace each fixed sleep with an Awaitility poll on the same condition. The assertions are unchanged — only the waiting is. awaitility is already on every module's test classpath via the shared java-conventions plugin. The tests also get faster, since a poll returns as soon as the condition holds rather than always sleeping the full duration.

Verifying this change

All four suites pass: ./gradlew :mongo:test :influxdb:test :hdfs3:test :hbase:testBUILD SUCCESSFUL.

More importantly, the race is demonstrated, not asserted. Taking master's MongoSinkTest and shortening its sleep from 1000 ms to 1 ms — simulating a runner slow enough that the flush has not fired — reproduces the CI signature exactly:

MongoSinkTest > testWriteBadMessage FAILED
    Wanted but not invoked: ...
MongoSinkTest > testWriteGoodMessage FAILED
    Wanted but not invoked: ...

The Awaitility version passes with no sleep at all, because it waits on the condition rather than on a guessed duration.

Notes

Five sink tests wrote to a sink that flushes asynchronously, waited a
fixed Thread.sleep, then asserted the flush had happened. When CI is
slow the flush has not run and the assertion fails: the sink is fine,
the test raced it. This is the shape that failed unrelated PRs twice
today, in InfluxDBSinkTest (v2) and PulsarSchemaHistoryTest.

Poll the same conditions with Awaitility instead. The assertions are
unchanged; only the waiting is. The tests also get faster, since a poll
returns as soon as the condition holds.

- mongo: MongoSinkTest, 5 sites
- influxdb: InfluxDBGenericRecordSinkTest (v1) — sibling of the v2 test
  already deflaked
- hdfs3: HdfsSequentialSinkTest, HdfsTextSinkTest — one asserted 5000
  acks within a hard-coded 2 seconds
- hbase: HbaseGenericRecordSinkTest — currently @test(enabled = false),
  so this is a compile-only change there

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR deflakes multiple sink unit tests by replacing fixed Thread.sleep(...) delays with Awaitility-based polling, ensuring assertions wait for asynchronous flush/ack behavior rather than racing it.

Changes:

  • Replace fixed sleeps with Awaitility.await().atMost(...).untilAsserted(...) in MongoDB, InfluxDB v1, and HDFS3 sink tests.
  • Update the HBase sink test (currently disabled) to poll for the row to appear instead of sleeping before reading it back.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
mongo/src/test/java/org/apache/pulsar/io/mongodb/MongoSinkTest.java Replace multiple Thread.sleep(1000) calls with Awaitility polling for ack()/fail() verifications.
influxdb/src/test/java/org/apache/pulsar/io/influxdb/v1/InfluxDBGenericRecordSinkTest.java Replace Thread.sleep(1000) with Awaitility polling for async batch flush verification.
hdfs3/src/test/java/org/apache/pulsar/io/hdfs3/sink/seq/HdfsTextSinkTest.java Replace Thread.sleep(2000) with Awaitility polling for 100/5000 ack assertions.
hdfs3/src/test/java/org/apache/pulsar/io/hdfs3/sink/seq/HdfsSequentialSinkTest.java Replace Thread.sleep(2000) with Awaitility polling for 100/5000 ack assertions.
hbase/src/test/java/org/apache/pulsar/io/hbase/sink/HbaseGenericRecordSinkTest.java Replace Thread.sleep(500) with Awaitility polling until the written row is observable.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 21 to 25
import static org.mockito.Mockito.times;
import java.util.concurrent.TimeUnit;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertNotNull;
import org.apache.pulsar.io.hdfs3.sink.AbstractHdfsSinkTest;
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@david-streamlio david-streamlio merged commit 2ac8d84 into apache:master Jul 10, 2026
3 of 4 checks passed
@david-streamlio david-streamlio deleted the fix/sink-test-sleep-races branch July 10, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Sink tests race their sinks' async flush: fixed Thread.sleep before verify()

2 participants