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

danny0405 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 6ef0c903540b test(writer): cover legacy populate.meta.fields 
persistence on table version 6 (#19695)
6ef0c903540b is described below

commit 6ef0c903540ba26c92cef36536e8c4681ecf9637
Author: Y Ethan Guo <[email protected]>
AuthorDate: Thu Aug 20 19:07:47 2026 -0700

    test(writer): cover legacy populate.meta.fields persistence on table 
version 6 (#19695)
    
    * test(writer): cover legacy populate.meta.fields persistence on table 
version 6
    
    The existing v6 assertion resolved through the mode property and could not
    fail when the boolean was not persisted. Assert the raw persisted key at
    both persistence sites (table builder and HoodieTableConfig.create), and
    add a Spark datasource end-to-end case writing a table version 6 table for
    every meta fields mode.
    
    Claude-Session: https://claude.ai/code/session_01XZmMF237YSc3Mbfvx8Cz2D
    
    * Parameterize the persistence tests across table versions 6, 9, and 10
    
    Claude-Session: https://claude.ai/code/session_01XZmMF237YSc3Mbfvx8Cz2D
---
 .../hudi/common/table/TestHoodieTableConfig.java   | 35 ++++++++++++++++++
 .../common/table/TestHoodieTableMetaClient.java    | 28 ++++++++------
 .../hudi/functional/TestMetaFieldsModeE2E.java     | 43 ++++++++++++++++++++++
 3 files changed, 95 insertions(+), 11 deletions(-)

diff --git 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableConfig.java
 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableConfig.java
index a6dd7912318a..cdc023602c66 100644
--- 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableConfig.java
+++ 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableConfig.java
@@ -423,6 +423,41 @@ class TestHoodieTableConfig extends 
HoodieCommonTestHarness {
         "the mode must survive on a v6 table -- Uber-style deployments set it 
there via hudi-cli");
   }
 
+  private static Stream<Arguments> tableVersionsAndMetaFieldsModes() {
+    return Stream.of(HoodieTableVersion.SIX, HoodieTableVersion.NINE, 
HoodieTableVersion.TEN)
+        .flatMap(version -> Arrays.stream(MetaFieldsMode.values())
+            .map(mode -> arguments(version, mode)));
+  }
+
+  /**
+   * {@link HoodieTableConfig#create} must derive and persist the legacy 
populate boolean below
+   * table version 10 on its own: callers such as the repair-overwrite-props 
procedure invoke it
+   * directly with user-supplied properties, without going through the table 
builder that also
+   * derives the boolean. From version 10 the mode alone is recorded.
+   */
+  @ParameterizedTest
+  @MethodSource("tableVersionsAndMetaFieldsModes")
+  void testCreatePersistsLegacyBooleanPerTableVersion(HoodieTableVersion 
version, MetaFieldsMode mode)
+      throws IOException {
+    StoragePath versionedMetaPath = new StoragePath(basePath,
+        "v" + version.versionCode() + "-" + mode.name() + "/" + 
HoodieTableMetaClient.METAFOLDER_NAME);
+    Properties props = new Properties();
+    props.setProperty(HoodieTableConfig.NAME.key(), "test-table");
+    props.setProperty(HoodieTableConfig.VERSION.key(), 
String.valueOf(version.versionCode()));
+    props.setProperty(HoodieTableConfig.META_FIELDS_MODE.key(), mode.name());
+    HoodieTableConfig.create(storage, versionedMetaPath, props);
+
+    HoodieTableConfig persisted = new HoodieTableConfig(storage, 
versionedMetaPath);
+    if (version.lesserThan(HoodieTableVersion.TEN)) {
+      assertEquals(Boolean.toString(mode.toLegacyPopulateMetaFields()),
+          
persisted.getProps().getProperty(HoodieTableConfig.POPULATE_META_FIELDS.key()),
+          "create() must persist the derived boolean below v10 for unpatched 
readers, " + mode);
+    } else {
+      
assertFalse(persisted.getProps().containsKey(HoodieTableConfig.POPULATE_META_FIELDS.key()),
+          "create() must record the mode alone from v10, " + mode);
+    }
+  }
+
   @Test
   void testDropInvalidConfigs() {
     // test invalid configs are dropped
diff --git 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableMetaClient.java
 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableMetaClient.java
index 3cc87601cb57..eda38d12c7f9 100644
--- 
a/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableMetaClient.java
+++ 
b/hudi-hadoop-common/src/test/java/org/apache/hudi/common/table/TestHoodieTableMetaClient.java
@@ -44,6 +44,7 @@ import org.junit.jupiter.api.Test;
 import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -229,17 +230,22 @@ class TestHoodieTableMetaClient extends 
HoodieCommonTestHarness {
       
assertFalse(newTable.getProps().containsKey(HoodieTableConfig.POPULATE_META_FIELDS.key()),
           "a table created at v10 records the mode alone for " + mode);
 
-      final String oldPath = tempDir.toAbsolutePath() + Path.SEPARATOR + 
"mfm-v6-" + mode.name();
-      HoodieTableConfig oldTable = HoodieTableMetaClient.newTableBuilder()
-          .setTableType(HoodieTableType.COPY_ON_WRITE.name())
-          .setTableName("mfm-v6-" + mode.name())
-          .setTableVersion(HoodieTableVersion.SIX.versionCode())
-          .setMetaFieldsMode(mode)
-          .initTable(this.metaClient.getStorageConf(), oldPath)
-          .getTableConfig();
-      assertEquals(mode, oldTable.getMetaFieldsMode());
-      assertEquals(mode.toLegacyPopulateMetaFields(), 
oldTable.populateMetaFields(),
-          "a table below v10 must still carry the derived boolean for 
unpatched readers, " + mode);
+      for (HoodieTableVersion oldVersion : 
Arrays.asList(HoodieTableVersion.SIX, HoodieTableVersion.NINE)) {
+        final String oldPath = tempDir.toAbsolutePath() + Path.SEPARATOR
+            + "mfm-v" + oldVersion.versionCode() + "-" + mode.name();
+        HoodieTableConfig oldTable = HoodieTableMetaClient.newTableBuilder()
+            .setTableType(HoodieTableType.COPY_ON_WRITE.name())
+            .setTableName("mfm-v" + oldVersion.versionCode() + "-" + 
mode.name())
+            .setTableVersion(oldVersion.versionCode())
+            .setMetaFieldsMode(mode)
+            .initTable(this.metaClient.getStorageConf(), oldPath)
+            .getTableConfig();
+        assertEquals(mode, oldTable.getMetaFieldsMode());
+        assertEquals(Boolean.toString(mode.toLegacyPopulateMetaFields()),
+            
oldTable.getProps().getProperty(HoodieTableConfig.POPULATE_META_FIELDS.key()),
+            "a table at version " + oldVersion.versionCode()
+                + " must persist the derived boolean for unpatched readers, " 
+ mode);
+      }
     }
   }
 
diff --git 
a/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/functional/TestMetaFieldsModeE2E.java
 
b/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/functional/TestMetaFieldsModeE2E.java
index 58886e72776d..76cfbe687ed2 100644
--- 
a/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/functional/TestMetaFieldsModeE2E.java
+++ 
b/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/functional/TestMetaFieldsModeE2E.java
@@ -27,7 +27,9 @@ import org.apache.hudi.common.model.HoodieRecord;
 import org.apache.hudi.common.model.MetaFieldsMode;
 import org.apache.hudi.common.table.HoodieTableConfig;
 import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.table.HoodieTableVersion;
 import org.apache.hudi.common.table.timeline.HoodieInstant;
+import org.apache.hudi.config.HoodieWriteConfig;
 import org.apache.hudi.testutils.SparkClientFunctionalTestHarness;
 
 import org.apache.spark.api.java.function.VoidFunction2;
@@ -42,7 +44,9 @@ import org.apache.spark.sql.types.StructField;
 import org.apache.spark.sql.types.StructType;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
 
 import java.nio.file.Path;
 import java.util.Arrays;
@@ -52,6 +56,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -281,6 +286,44 @@ class TestMetaFieldsModeE2E extends 
SparkClientFunctionalTestHarness {
         "ALL must persist populate.meta.fields=true for pre-1.3.0 readers");
   }
 
+  private static Stream<Arguments> tableVersionsAndMetaFieldsModes() {
+    return Stream.of(HoodieTableVersion.SIX, HoodieTableVersion.NINE, 
HoodieTableVersion.TEN)
+        .flatMap(version -> Arrays.stream(MetaFieldsMode.values())
+            .map(mode -> Arguments.of(version, mode)));
+  }
+
+  /**
+   * A write at any supported table version must record the mode verbatim, and 
below version 10 also
+   * the derived legacy boolean as a raw property; from version 10 the mode 
alone is recorded. The
+   * boolean is asserted on the raw persisted key rather than through {@code 
populateMetaFields()}
+   * (which resolves through the mode and answers the same either way) because 
an unpatched
+   * pre-1.3.0 reader sees only the raw key. Meta-column population is 
verified for every case.
+   */
+  @ParameterizedTest
+  @MethodSource("tableVersionsAndMetaFieldsModes")
+  void writePersistsModeAndLegacyBooleanPerTableVersion(HoodieTableVersion 
version, MetaFieldsMode mode) {
+    Map<String, String> options = baseOptions();
+    options.put(HoodieWriteConfig.WRITE_TABLE_VERSION.key(), 
String.valueOf(version.versionCode()));
+    options.put(HoodieTableConfig.META_FIELDS_MODE.key(), mode.name());
+    options.put(DataSourceWriteOptions.OPERATION().key(), 
DataSourceWriteOptions.BULK_INSERT_OPERATION_OPT_VAL());
+
+    HoodieTableConfig tc = writeSampleAndGetTableConfig(options, basePath());
+
+    assertEquals(version, tc.getTableVersion());
+    assertEquals(mode, tc.getMetaFieldsMode());
+    assertEquals(mode.name(), tc.getString(HoodieTableConfig.META_FIELDS_MODE),
+        "the mode must be persisted at table version " + 
version.versionCode());
+    if (version.lesserThan(HoodieTableVersion.TEN)) {
+      assertEquals(Boolean.toString(mode.toLegacyPopulateMetaFields()),
+          
tc.getProps().getProperty(HoodieTableConfig.POPULATE_META_FIELDS.key()),
+          "a table below v10 must persist the derived legacy boolean for 
unpatched readers");
+    } else {
+      
assertFalse(tc.getProps().containsKey(HoodieTableConfig.POPULATE_META_FIELDS.key()),
+          "a table at v10 must record the mode alone");
+    }
+    assertMetaColumnPopulation(basePath(), mode);
+  }
+
   @Test
   void unknownModeValueIsRejected() {
     Map<String, String> options = baseOptions();

Reply via email to