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());
+ }
+}