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

jmclean pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new a06411cbd1 [#10226] Require namespace validation in FunctionEntity 
builder (#10230)
a06411cbd1 is described below

commit a06411cbd1b338cf03909c25af2dc3f10c121123
Author: YuF-9468 <[email protected]>
AuthorDate: Fri Mar 6 12:52:24 2026 +0800

    [#10226] Require namespace validation in FunctionEntity builder (#10230)
    
    ## Summary
    Fixes #10226.
    
    `FunctionEntity.Builder.build()` validates required fields through
    `fields()`, but `namespace` was missing from that map, allowing invalid
    entities to be built with null namespace. This PR marks namespace as
    required and includes it in validation.
    
    ## Changes
    - Added `NAMESPACE` as a required `Field` in `FunctionEntity`.
    - Added `namespace` to `FunctionEntity#fields()` so `build()` validation
    enforces it.
    - Added `TestFunctionEntity` with:
      - a regression test that `build()` throws when namespace is missing;
      - a positive test that build succeeds when namespace is provided.
    
    ## Validation
    - Added/updated unit tests for the changed behavior.
    
    Co-authored-by: YuF-9468 <[email protected]>
---
 .../org/apache/gravitino/meta/FunctionEntity.java  |  3 +
 .../apache/gravitino/meta/TestFunctionEntity.java  | 84 ++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/core/src/main/java/org/apache/gravitino/meta/FunctionEntity.java 
b/core/src/main/java/org/apache/gravitino/meta/FunctionEntity.java
index 041702b17a..3b9f4230ea 100644
--- a/core/src/main/java/org/apache/gravitino/meta/FunctionEntity.java
+++ b/core/src/main/java/org/apache/gravitino/meta/FunctionEntity.java
@@ -41,6 +41,8 @@ public class FunctionEntity implements Entity, Auditable, 
HasIdentifier, Functio
       Field.required("id", Long.class, "The unique id of the function 
entity.");
   public static final Field NAME =
       Field.required("name", String.class, "The name of the function entity.");
+  public static final Field NAMESPACE =
+      Field.required("namespace", Namespace.class, "The namespace of the 
function entity.");
   public static final Field COMMENT =
       Field.optional("comment", String.class, "The comment or description of 
the function entity.");
   public static final Field FUNCTION_TYPE =
@@ -68,6 +70,7 @@ public class FunctionEntity implements Entity, Auditable, 
HasIdentifier, Functio
     Map<Field, Object> fields = Maps.newHashMap();
     fields.put(ID, id);
     fields.put(NAME, name);
+    fields.put(NAMESPACE, namespace);
     fields.put(COMMENT, comment);
     fields.put(FUNCTION_TYPE, functionType);
     fields.put(DETERMINISTIC, deterministic);
diff --git 
a/core/src/test/java/org/apache/gravitino/meta/TestFunctionEntity.java 
b/core/src/test/java/org/apache/gravitino/meta/TestFunctionEntity.java
new file mode 100644
index 0000000000..c2fd2fb9cf
--- /dev/null
+++ b/core/src/test/java/org/apache/gravitino/meta/TestFunctionEntity.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.meta;
+
+import java.time.Instant;
+import org.apache.gravitino.Namespace;
+import org.apache.gravitino.function.FunctionDefinition;
+import org.apache.gravitino.function.FunctionDefinitions;
+import org.apache.gravitino.function.FunctionImpl;
+import org.apache.gravitino.function.FunctionImpls;
+import org.apache.gravitino.function.FunctionParam;
+import org.apache.gravitino.function.FunctionParams;
+import org.apache.gravitino.function.FunctionType;
+import org.apache.gravitino.rel.types.Types;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class TestFunctionEntity {
+
+  @Test
+  public void testBuildShouldFailWhenNamespaceIsMissing() {
+    FunctionParam param = FunctionParams.of("param1", Types.IntegerType.get());
+    FunctionImpl impl = FunctionImpls.ofSql(FunctionImpl.RuntimeType.SPARK, 
"SELECT param1 + 1");
+    FunctionDefinition definition =
+        FunctionDefinitions.of(
+            new FunctionParam[] {param}, Types.IntegerType.get(), new 
FunctionImpl[] {impl});
+    AuditInfo auditInfo =
+        
AuditInfo.builder().withCreator("tester").withCreateTime(Instant.now()).build();
+
+    Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () ->
+            FunctionEntity.builder()
+                .withId(1L)
+                .withName("f")
+                .withComment("test")
+                .withFunctionType(FunctionType.SCALAR)
+                .withDeterministic(true)
+                .withDefinitions(new FunctionDefinition[] {definition})
+                .withAuditInfo(auditInfo)
+                .build());
+  }
+
+  @Test
+  public void testBuildShouldSucceedWhenNamespaceIsPresent() {
+    FunctionParam param = FunctionParams.of("param1", Types.IntegerType.get());
+    FunctionImpl impl = FunctionImpls.ofSql(FunctionImpl.RuntimeType.SPARK, 
"SELECT param1 + 1");
+    FunctionDefinition definition =
+        FunctionDefinitions.of(
+            new FunctionParam[] {param}, Types.IntegerType.get(), new 
FunctionImpl[] {impl});
+    AuditInfo auditInfo =
+        
AuditInfo.builder().withCreator("tester").withCreateTime(Instant.now()).build();
+
+    FunctionEntity entity =
+        FunctionEntity.builder()
+            .withId(1L)
+            .withName("f")
+            .withNamespace(Namespace.of("m1", "c1", "s1"))
+            .withComment("test")
+            .withFunctionType(FunctionType.SCALAR)
+            .withDeterministic(true)
+            .withDefinitions(new FunctionDefinition[] {definition})
+            .withAuditInfo(auditInfo)
+            .build();
+
+    Assertions.assertEquals(Namespace.of("m1", "c1", "s1"), 
entity.namespace());
+  }
+}

Reply via email to