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

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


The following commit(s) were added to refs/heads/master by this push:
     new d3856f4b10cf test(metadata): cover getColumnsToIndex when the table 
schema is absent (#19859)
d3856f4b10cf is described below

commit d3856f4b10cfcdb25f0e8b5b84e625db3dc14feb
Author: Ranga Reddy <[email protected]>
AuthorDate: Fri Sep 18 12:37:39 2026 +0530

    test(metadata): cover getColumnsToIndex when the table schema is absent 
(#19859)
    
    * test(metadata): cover getColumnsToIndex when the table schema is absent
    
    Closes #17410.
    
    HUDI-9194 asked whether getColumnsToIndexWithoutRequiredMetaFields needs a 
test
    case. Its branches are almost all covered already through the public
    getColumnsToIndex wrapper: the explicit column list, meta columns inside 
that
    list, unsupported types, nested fields, the max-columns cap, and meta fields
    disabled. One branch was not reachable from any existing case, because every
    one of them supplies a schema: the path taken when the table schema is 
absent.
    
    Added a case for it, pinning three outcomes that differ in ways worth 
fixing in
    place:
    
    - No explicit column list: the inner call returns nothing, so the caller is
      left with just the always-indexed meta columns. Col stats initialises 
rather
      than failing.
    - An explicit column list: it throws IllegalArgumentException naming the
      missing schema, since the configured names cannot be resolved to field
      schemas without one, and indexing nothing would look like the config had
      been honoured.
    - The same list while the table is initialising: the names are recorded 
without
      schemas, so col stats can be enabled before the first commit has produced 
a
      schema.
    
    Test-only; no production code touched.
    
    * test(metadata): pin that the initializing branch never resolves the schema
    
    Supply the table schema as a Lazy that fails the test if it is ever forced,
    rather than an eagerly computed empty Option. The initializing branch 
returns
    before touching tableSchemaLazyOpt, and an eager value cannot tell "never
    resolved" from "resolved and absent".
    
    This matters on the real path: ColumnStatsIndexer passes isTableInitializing
    together with Lazy.lazily(tryResolveSchemaForTable) whenever an explicit 
column
    list is set, including on tables that already have data, so resolving in 
this
    branch would cost a schema read there.
    
    Verified by hoisting the checkArgument above the initializing return, which
    turns the test red on the supplier.
    
    * test(metadata): trim the test javadoc to what it verifies
---
 .../hudi/metadata/TestHoodieTableMetadataUtil.java | 46 ++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/metadata/TestHoodieTableMetadataUtil.java
 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/metadata/TestHoodieTableMetadataUtil.java
index 769af07c7388..6b34762d97fc 100644
--- 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/metadata/TestHoodieTableMetadataUtil.java
+++ 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/metadata/TestHoodieTableMetadataUtil.java
@@ -96,6 +96,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
@@ -605,6 +606,51 @@ public class TestHoodieTableMetadataUtil extends 
HoodieCommonTestHarness {
         Lazy.eagerly(Option.of(schema)), true, V1).keySet()));
   }
 
+  /**
+   * The schema-absent branch of {@code 
getColumnsToIndexWithoutRequiredMetaFields}, which
+   * {@link #testGetColumnsToIndex()} never reaches because every case there 
supplies a schema. With no
+   * explicit column list it yields only the always-indexed meta columns; with 
one it throws, since those
+   * names cannot be resolved without a schema. While initializing it returns 
them unresolved instead.
+   */
+  @Test
+  public void testGetColumnsToIndexWhenTableSchemaIsAbsent() {
+    HoodieTableConfig tableConfig = metaClient.getTableConfig();
+
+    HoodieMetadataConfig noColumnList = HoodieMetadataConfig.newBuilder()
+        .enable(true).withMetadataIndexColumnStats(true)
+        .build();
+    assertListEquality(new 
ArrayList<>(Arrays.asList(HoodieTableMetadataUtil.META_COLS_TO_ALWAYS_INDEX)),
+        new ArrayList<>(HoodieTableMetadataUtil.getColumnsToIndex(tableConfig, 
noColumnList,
+            Lazy.eagerly(Option.empty()), false, V1).keySet()));
+
+    HoodieMetadataConfig withColumnList = HoodieMetadataConfig.newBuilder()
+        .enable(true).withMetadataIndexColumnStats(true)
+        .withColumnStatsIndexForColumns("col_1,col_2")
+        .build();
+    Throwable thrown = assertThrows(IllegalArgumentException.class,
+        () -> HoodieTableMetadataUtil.getColumnsToIndex(tableConfig, 
withColumnList,
+            Lazy.eagerly(Option.empty()), false, V1),
+        "an explicit column list cannot be resolved without a table schema");
+    assertTrue(String.valueOf(thrown.getMessage()).contains("Table schema not 
found"),
+        () -> "the failure should name the missing schema, but was: " + 
thrown.getMessage());
+
+    // Table initialisation is the exception: the configured names are 
recorded without schemas, so col
+    // stats can be enabled before the first commit has produced one. The meta 
columns are added by the
+    // caller either way.
+    //
+    // The schema is supplied as a lazy that fails if it is ever forced, 
because this branch must return
+    // without resolving it at all. ColumnStatsIndexer passes 
isTableInitializing=true together with a
+    // Lazy.lazily(tryResolveSchemaForTable) whenever an explicit column list 
is set, including on tables
+    // that already have data, so resolving here would cost a schema read on 
that path. An eagerly-computed
+    // empty Option cannot tell "never resolved" from "resolved and absent"; 
this can.
+    List<String> expectedWhileInitialising = new 
ArrayList<>(Arrays.asList(HoodieTableMetadataUtil.META_COLS_TO_ALWAYS_INDEX));
+    expectedWhileInitialising.addAll(Arrays.asList("col_1", "col_2"));
+    assertListEquality(expectedWhileInitialising,
+        new ArrayList<>(HoodieTableMetadataUtil.getColumnsToIndex(tableConfig, 
withColumnList,
+            Lazy.lazily(() -> fail("the initializing branch must not resolve 
the table schema")),
+            true, V1).keySet()));
+  }
+
   private void assertListEquality(List<String> expected, List<String> actual) {
     Collections.sort(expected);
     Collections.sort(actual);

Reply via email to