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 b7b560dfd29 test: poll Broker state instead of schema refresh metrics 
in QueryTestBase (#20319)
b7b560dfd29 is described below

commit b7b560dfd29ac1fbeae75a35c9026bacef549bdf
Author: Frank Chen <[email protected]>
AuthorDate: Thu Sep 24 10:03:56 2026 +0800

    test: poll Broker state instead of schema refresh metrics in QueryTestBase 
(#20319)
    
    * test: poll Broker state instead of schema refresh metrics in QueryTestBase
    
    QueryLaningTest and other QueryTestBase subclasses intermittently timed out 
in
    waitForAllSegmentsToBeAvailable, which waits for an aggregate count of 
Broker
    schema refresh metrics. Add waitForAllSegmentsToBeQueryable, which polls the
    state that SQL queries actually observe: available segments in sys.segments
    and the datasource being present in INFORMATION_SCHEMA.TABLES, and use it in
    QueryTestBase.ingestBasicData().
    
    * Treat empty or non-numeric sys.segments poll results as not yet ready
    
    A NumberFormatException inside the ResultWaiter supplier/matcher would 
abort the
    wait instead of retrying.
    
    * test: escape datasource in Broker polling queries
---
 .../testing/embedded/query/QueryTestBase.java      |  4 +-
 .../testing/embedded/EmbeddedClusterApis.java      | 57 ++++++++++++++++++++++
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git 
a/embedded-tests/src/test/java/org/apache/druid/testing/embedded/query/QueryTestBase.java
 
b/embedded-tests/src/test/java/org/apache/druid/testing/embedded/query/QueryTestBase.java
index e19850276e2..686d7dc253c 100644
--- 
a/embedded-tests/src/test/java/org/apache/druid/testing/embedded/query/QueryTestBase.java
+++ 
b/embedded-tests/src/test/java/org/apache/druid/testing/embedded/query/QueryTestBase.java
@@ -128,7 +128,9 @@ public abstract class QueryTestBase extends 
EmbeddedClusterTestBase
     final IndexTask task = 
MoreResources.Task.BASIC_INDEX.get().dataSource(datasourceName).withId(taskId);
     cluster.callApi().onLeaderOverlord(o -> o.runTask(taskId, task));
     cluster.callApi().waitForTaskToSucceed(taskId, overlord);
-    cluster.callApi().waitForAllSegmentsToBeAvailable(datasourceName, 
coordinator, broker);
+    // Poll the state observed by SQL queries rather than waiting for Broker 
schema refresh metrics,
+    // which has been observed to time out intermittently in CI.
+    cluster.callApi().waitForAllSegmentsToBeQueryable(datasourceName, 
coordinator, 100_000L);
     return datasourceName;
   }
 
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 6ae8750b8d8..8082bced562 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
@@ -332,6 +332,63 @@ public class EmbeddedClusterApis implements 
EmbeddedResource
     );
   }
 
+  /**
+   * Waits for all non-tombstone used segments of the given datasource to be
+   * reported as available in {@code sys.segments} and for the datasource to be
+   * present in the Broker SQL schema, by polling the Broker.
+   * <p>
+   * Unlike {@link #waitForAllSegmentsToBeAvailable}, this method does not 
depend
+   * on schema refresh metrics being emitted by the Broker and verifies the 
state
+   * that SQL queries actually observe.
+   *
+   * @param timeoutMillis maximum time to wait
+   */
+  public void waitForAllSegmentsToBeQueryable(
+      String dataSource,
+      EmbeddedCoordinator coordinator,
+      long timeoutMillis
+  )
+  {
+    final String escapedDataSource = StringUtils.escapeSql(dataSource);
+    final int numSegments = (int) coordinator
+        .bindings()
+        .segmentsMetadataStorage()
+        .retrieveAllUsedSegments(dataSource, Segments.INCLUDING_OVERSHADOWED)
+        .stream()
+        .filter(segment -> !segment.isTombstone())
+        .count();
+
+    waitForResult(
+        () -> runSql(
+            "SELECT COUNT(*) FROM sys.segments WHERE datasource='%s' AND 
is_available = 1",
+            escapedDataSource
+        ),
+        result -> parseCountOrZero(result) >= numSegments
+    ).withTimeoutMillis(timeoutMillis).go();
+
+    waitForResult(
+        () -> runSql(
+            "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA 
= 'druid' AND TABLE_NAME = '%s'",
+            escapedDataSource
+        ),
+        result -> "1".equals(result.trim())
+    ).withTimeoutMillis(timeoutMillis).go();
+  }
+
+  /**
+   * Parses a {@code COUNT(*)} result, treating an empty or non-numeric result
+   * (e.g. while the Broker is still initializing) as zero so that polling 
continues.
+   */
+  private static long parseCountOrZero(String result)
+  {
+    try {
+      return Long.parseLong(result.trim());
+    }
+    catch (NumberFormatException e) {
+      return 0L;
+    }
+  }
+
   /**
    * Waits for all used segments (including overshadowed) of the given 
datasource
    * to be queryable by Brokers when centralized schema is enabled.


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

Reply via email to