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

FrankChen021 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 26556ffc062 test: Make `EmbeddedKafkaSupervisorTest` wait for Broker 
queryability  (#20620)
26556ffc062 is described below

commit 26556ffc0629fa62ec89c52e0e9afe09e7b93d71
Author: Andreas Maechler <[email protected]>
AuthorDate: Fri Oct 16 23:08:28 2026 -0600

    test: Make `EmbeddedKafkaSupervisorTest` wait for Broker queryability  
(#20620)
    
    * Fix flaky 
EmbeddedKafkaSupervisorTest.testSupervisorIngestsOnlySelectedPartitions
    
    waitForSelectedRows only waited for the indexer's ingest/events/processed
    metric, so the SQL assertions could run before the Broker had the datasource
    in its schema and fail with "Object 'datasource_xxx' not found".
    
    Wait for ingest/handoff/count instead, then for the segments to be queryable
    through the Broker with waitForAllSegmentsToBeQueryable. Handoff follows
    publish, which commits the partition 1 offset before the supervisor spec is
    replaced, so the replacement supervisor resumes from it.
    
    Submit both specs through submitSupervisor so the shared teardown suspends
    the supervisor and cancels its tasks even when the test fails.
    
    * Wait for Broker queryability in the other EmbeddedKafkaSupervisorTest SQL 
checks
    
    test_runKafkaSupervisor checked the row count after an indexer-only
    ingest/events/processed wait, and header filtering queried right after
    handoff without checking the Broker.
    
    Add EmbeddedClusterApis.waitForSegmentsToBeQueryable, which takes the
    segment count so it also covers unpublished realtime segments, and make
    waitForAllSegmentsToBeQueryable delegate to it. test_runKafkaSupervisor
    waits for its 10 segments with it. Header filtering and the
    selected-partitions test share a waitForHandedOffRows helper.
---
 .../simulate/EmbeddedKafkaSupervisorTest.java      | 32 ++++++++++------------
 .../testing/embedded/EmbeddedClusterApis.java      | 12 +++++++-
 2 files changed, 25 insertions(+), 19 deletions(-)

diff --git 
a/extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/simulate/EmbeddedKafkaSupervisorTest.java
 
b/extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/simulate/EmbeddedKafkaSupervisorTest.java
index f407b13fa98..762de1e983d 100644
--- 
a/extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/simulate/EmbeddedKafkaSupervisorTest.java
+++ 
b/extensions-core/kafka-indexing-service/src/test/java/org/apache/druid/indexing/kafka/simulate/EmbeddedKafkaSupervisorTest.java
@@ -121,11 +121,11 @@ public class EmbeddedKafkaSupervisorTest extends 
EmbeddedClusterTestBase
     final KafkaSupervisorSpec spec = newKafkaSupervisor()
         .withIoConfig(io -> 
io.withPartitionIds(Set.of(1)).withTaskCount(2).withStopTaskCount(1))
         .build(dataSource, topic);
-    cluster.callApi().postSupervisor(spec);
+    submitSupervisor(spec);
 
     // One record per partition, but only partition 1 is selected.
     kafkaServer.produceRecordsToTopic(partitionRecords(topic, 4));
-    waitForSelectedRows(dataSource, 1);
+    waitForHandedOffRows(1);
 
     Assertions.assertEquals("1", cluster.runSql("SELECT COUNT(*) FROM %s", 
dataSource));
     Assertions.assertEquals("0", cluster.runSql("SELECT COUNT(*) FROM %s WHERE 
item != 'p1'", dataSource));
@@ -134,12 +134,11 @@ public class EmbeddedKafkaSupervisorTest extends 
EmbeddedClusterTestBase
     final KafkaSupervisorSpec expanded = newKafkaSupervisor()
         .withIoConfig(io -> io.withPartitionIds(Set.of(1, 
3)).withTaskCount(2).withStopTaskCount(1))
         .build(dataSource, topic);
-    cluster.callApi().postSupervisor(expanded);
-    waitForSelectedRows(dataSource, 2);
+    submitSupervisor(expanded);
+    waitForHandedOffRows(2);
 
     Assertions.assertEquals("2", cluster.runSql("SELECT COUNT(*) FROM %s", 
dataSource));
     Assertions.assertEquals("0", cluster.runSql("SELECT COUNT(*) FROM %s WHERE 
item = 'p2'", dataSource));
-    cluster.callApi().postSupervisor(expanded.createSuspendedSpec());
   }
 
   private static List<ProducerRecord<byte[], byte[]>> partitionRecords(String 
topic, int partitions)
@@ -156,12 +155,17 @@ public class EmbeddedKafkaSupervisorTest extends 
EmbeddedClusterTestBase
     return records;
   }
 
-  private void waitForSelectedRows(String source, int count)
+  /**
+   * Waits for {@code count} segments, one per row with maxRowsPerSegment = 1, 
to be handed off and queryable through
+   * the Broker. Handoff follows publish, so the task's offsets are committed 
by the time this returns.
+   */
+  private void waitForHandedOffRows(int count)
   {
     indexer.latchableEmitter().waitForEventAggregate(
-        event -> 
event.hasMetricName("ingest/events/processed").hasDimension(DruidMetrics.DATASOURCE,
 source),
+        event -> 
event.hasMetricName("ingest/handoff/count").hasDimension(DruidMetrics.DATASOURCE,
 dataSource),
         agg -> agg.hasSumAtLeast(count)
     );
+    cluster.callApi().waitForAllSegmentsToBeQueryable(dataSource, coordinator, 
30_000L);
   }
 
   @Test
@@ -202,13 +206,9 @@ public class EmbeddedKafkaSupervisorTest extends 
EmbeddedClusterTestBase
       Assertions.assertEquals(TaskState.RUNNING, task.getStatusCode());
     }
 
-    // Wait until all produced records have been ingested before verifying the 
row count,
+    // Wait until the Broker can query all produced records before verifying 
the row count,
     // otherwise the query below can race ingestion and observe fewer than the 
expected rows
-    indexer.latchableEmitter().waitForEventAggregate(
-        event -> event.hasMetricName("ingest/events/processed")
-                      .hasDimension(DruidMetrics.DATASOURCE, dataSource),
-        agg -> agg.hasSumAtLeast(expectedSegments)
-    );
+    cluster.callApi().waitForSegmentsToBeQueryable(dataSource, 
expectedSegments, 30_000L);
 
     // Verify the count of rows ingested into the datasource so far
     Assertions.assertEquals(
@@ -270,11 +270,7 @@ public class EmbeddedKafkaSupervisorTest extends 
EmbeddedClusterTestBase
     // Wait for segment handoff without suspending the supervisor; its short 
task duration publishes the segments.
     // Suspending while ingestion is in progress can replace the supervisor 
while the task's checkpoint request is in
     // flight, which fails the task before it publishes anything.
-    indexer.latchableEmitter().waitForEventAggregate(
-        event -> event.hasMetricName("ingest/handoff/count")
-                      .hasDimension(DruidMetrics.DATASOURCE, dataSource),
-        agg -> agg.hasSumAtLeast(expectedRecords)
-    );
+    waitForHandedOffRows(expectedRecords);
 
     // Verify only filtered records were ingested
     Assertions.assertEquals(String.valueOf(expectedRecords), 
cluster.runSql("SELECT COUNT(*) FROM %s", dataSource));
diff --git 
a/services/src/test/java/org/apache/druid/testing/embedded/EmbeddedClusterApis.java
 
b/services/src/test/java/org/apache/druid/testing/embedded/EmbeddedClusterApis.java
index a4fb736ee64..b25c6567ad9 100644
--- 
a/services/src/test/java/org/apache/druid/testing/embedded/EmbeddedClusterApis.java
+++ 
b/services/src/test/java/org/apache/druid/testing/embedded/EmbeddedClusterApis.java
@@ -372,7 +372,6 @@ public class EmbeddedClusterApis implements EmbeddedResource
       long timeoutMillis
   )
   {
-    final String escapedDataSource = StringUtils.escapeSql(dataSource);
     final int numSegments = (int) coordinator
         .bindings()
         .segmentsMetadataStorage()
@@ -381,6 +380,17 @@ public class EmbeddedClusterApis implements 
EmbeddedResource
         .filter(segment -> !segment.isTombstone())
         .count();
 
+    waitForSegmentsToBeQueryable(dataSource, numSegments, timeoutMillis);
+  }
+
+  /**
+   * Like {@link #waitForAllSegmentsToBeQueryable}, but waits for a given 
number of segments, which may include
+   * unpublished realtime segments that are not in the metadata store yet.
+   */
+  public void waitForSegmentsToBeQueryable(String dataSource, int numSegments, 
long timeoutMillis)
+  {
+    final String escapedDataSource = StringUtils.escapeSql(dataSource);
+
     waitForResult(
         () -> runSql(
             "SELECT COUNT(*) FROM sys.segments WHERE datasource='%s' AND 
is_available = 1",


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to