This is an automated email from the ASF dual-hosted git repository.
roryqi 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 235b8f876a [MINOR] improvement(server): expose schema separator via
the /configs endpoint (#11322)
235b8f876a is described below
commit 235b8f876a18c4d93b2000e78082cf807c152533
Author: roryqi <[email protected]>
AuthorDate: Tue Jun 2 12:51:43 2026 +0800
[MINOR] improvement(server): expose schema separator via the /configs
endpoint (#11322)
### What changes were proposed in this pull request?
- Expose the `gravitino.schema.separator` server config through
Gravitino's `/configs` endpoint (`ConfigServlet`) by adding it to the
always-exposed `basicConfigEntries`.
- Update `TestConfigServlet` expectations and add a test verifying a
custom separator value is reflected in the response.
### Why are the changes needed?
The schema separator determines how hierarchical (multi-level) schema
names are represented at the API boundary (e.g. `:` in `A:B:C`). Clients
and the web UI need to discover the configured separator to correctly
construct and parse hierarchical schema names. Previously it was only a
server-side config and was not exposed to clients.
### Does this PR introduce _any_ user-facing change?
Yes. The `/configs` endpoint now includes the
`gravitino.schema.separator` key (default `:`).
### How was this patch tested?
Added/updated unit tests in `TestConfigServlet`; `./gradlew :server:test
--tests "org.apache.gravitino.server.web.TestConfigServlet"` passes (8
tests).
---
.../apache/gravitino/server/web/ConfigServlet.java | 3 +-
.../gravitino/server/web/TestConfigServlet.java | 84 +++++++++++-----------
2 files changed, 46 insertions(+), 41 deletions(-)
diff --git
a/server/src/main/java/org/apache/gravitino/server/web/ConfigServlet.java
b/server/src/main/java/org/apache/gravitino/server/web/ConfigServlet.java
index a567a0ddcf..b8bdbfaa1b 100644
--- a/server/src/main/java/org/apache/gravitino/server/web/ConfigServlet.java
+++ b/server/src/main/java/org/apache/gravitino/server/web/ConfigServlet.java
@@ -49,7 +49,8 @@ public class ConfigServlet extends HttpServlet {
OAuthConfig.SCOPE);
private static final ImmutableSet<ConfigEntry<?>> basicConfigEntries =
- ImmutableSet.of(Configs.AUTHENTICATORS, Configs.ENABLE_AUTHORIZATION);
+ ImmutableSet.of(
+ Configs.AUTHENTICATORS, Configs.ENABLE_AUTHORIZATION,
Configs.SCHEMA_SEPARATOR);
private final Map<String, Object> configs = Maps.newHashMap();
diff --git
a/server/src/test/java/org/apache/gravitino/server/web/TestConfigServlet.java
b/server/src/test/java/org/apache/gravitino/server/web/TestConfigServlet.java
index 24f3ac5122..a3ddee599f 100644
---
a/server/src/test/java/org/apache/gravitino/server/web/TestConfigServlet.java
+++
b/server/src/test/java/org/apache/gravitino/server/web/TestConfigServlet.java
@@ -25,9 +25,11 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.gravitino.Configs;
import org.apache.gravitino.auth.AuthenticatorType;
@@ -36,23 +38,28 @@ import org.apache.gravitino.config.ConfigConstants;
import org.apache.gravitino.config.ConfigEntry;
import org.apache.gravitino.server.ServerConfig;
import org.apache.gravitino.server.authentication.OAuthConfig;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
public class TestConfigServlet {
@Test
public void testConfigServlet() throws Exception {
+ Map<String, Object> configs = fetchConfigs(new ServerConfig());
+ Assertions.assertEquals(
+ Lists.newArrayList("simple"),
configs.get(Configs.AUTHENTICATORS.getKey()));
+ Assertions.assertEquals(false,
configs.get(Configs.ENABLE_AUTHORIZATION.getKey()));
+ Assertions.assertEquals(":",
configs.get(Configs.SCHEMA_SEPARATOR.getKey()));
+ }
+
+ @Test
+ public void testConfigServletExposesCustomSchemaSeparator() throws Exception
{
+ // The schema separator must reflect the configured value, not a
hard-coded default.
ServerConfig serverConfig = new ServerConfig();
- ConfigServlet configServlet = new ConfigServlet(serverConfig);
- configServlet.init();
- HttpServletResponse res = mock(HttpServletResponse.class);
- PrintWriter writer = mock(PrintWriter.class);
- when(res.getWriter()).thenReturn(writer);
- configServlet.doGet(null, res);
- verify(writer)
- .write(
-
"{\"gravitino.authorization.enable\":false,\"gravitino.authenticators\":[\"simple\"]}");
- configServlet.destroy();
+ serverConfig.set(Configs.SCHEMA_SEPARATOR, "|");
+ Map<String, Object> configs = fetchConfigs(serverConfig);
+ Assertions.assertEquals("|",
configs.get(Configs.SCHEMA_SEPARATOR.getKey()));
}
@Test
@@ -61,16 +68,9 @@ public class TestConfigServlet {
// absent from the response (no crash) rather than null or empty.
ServerConfig serverConfig = new ServerConfig();
serverConfig.set(Configs.ENABLE_AUTHORIZATION, true);
- ConfigServlet configServlet = new ConfigServlet(serverConfig);
- configServlet.init();
- HttpServletResponse res = mock(HttpServletResponse.class);
- PrintWriter writer = mock(PrintWriter.class);
- when(res.getWriter()).thenReturn(writer);
- configServlet.doGet(null, res);
- verify(writer)
- .write(
-
"{\"gravitino.authorization.enable\":true,\"gravitino.authenticators\":[\"simple\"]}");
- configServlet.destroy();
+ Map<String, Object> configs = fetchConfigs(serverConfig);
+ Assertions.assertEquals(true,
configs.get(Configs.ENABLE_AUTHORIZATION.getKey()));
+
Assertions.assertFalse(configs.containsKey(Configs.SERVICE_ADMINS.getKey()));
}
@Test
@@ -78,16 +78,10 @@ public class TestConfigServlet {
ServerConfig serverConfig = new ServerConfig();
serverConfig.set(Configs.ENABLE_AUTHORIZATION, true);
serverConfig.set(Configs.SERVICE_ADMINS, Lists.newArrayList("admin1",
"admin2"));
- ConfigServlet configServlet = new ConfigServlet(serverConfig);
- configServlet.init();
- HttpServletResponse res = mock(HttpServletResponse.class);
- PrintWriter writer = mock(PrintWriter.class);
- when(res.getWriter()).thenReturn(writer);
- configServlet.doGet(null, res);
- verify(writer)
- .write(
-
"{\"gravitino.authorization.enable\":true,\"gravitino.authenticators\":[\"simple\"],\"gravitino.authorization.serviceAdmins\":[\"admin1\",\"admin2\"]}");
- configServlet.destroy();
+ Map<String, Object> configs = fetchConfigs(serverConfig);
+ Assertions.assertEquals(true,
configs.get(Configs.ENABLE_AUTHORIZATION.getKey()));
+ Assertions.assertEquals(
+ Lists.newArrayList("admin1", "admin2"),
configs.get(Configs.SERVICE_ADMINS.getKey()));
}
@Test
@@ -103,16 +97,8 @@ public class TestConfigServlet {
serverConfig.set(customConfig, "test");
serverConfig.set(Configs.VISIBLE_CONFIGS,
Lists.newArrayList(customConfig.getKey()));
- ConfigServlet configServlet = new ConfigServlet(serverConfig);
- configServlet.init();
- HttpServletResponse res = mock(HttpServletResponse.class);
- PrintWriter writer = mock(PrintWriter.class);
- when(res.getWriter()).thenReturn(writer);
- configServlet.doGet(null, res);
- verify(writer)
- .write(
-
"{\"gravitino.extended.custom.config\":\"test\",\"gravitino.authorization.enable\":false,\"gravitino.authenticators\":[\"simple\"]}");
- configServlet.destroy();
+ Map<String, Object> configs = fetchConfigs(serverConfig);
+ Assertions.assertEquals("test", configs.get(customConfig.getKey()));
}
@Test
@@ -157,4 +143,22 @@ public class TestConfigServlet {
verify(res).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
configServlet.destroy();
}
+
+ /**
+ * Invokes the servlet and parses the JSON it writes back into a map, so
tests can assert on
+ * individual config entries instead of matching a brittle, order-dependent
JSON string.
+ */
+ private Map<String, Object> fetchConfigs(ServerConfig serverConfig) throws
Exception {
+ ConfigServlet configServlet = new ConfigServlet(serverConfig);
+ configServlet.init();
+ HttpServletResponse res = mock(HttpServletResponse.class);
+ PrintWriter writer = mock(PrintWriter.class);
+ when(res.getWriter()).thenReturn(writer);
+ configServlet.doGet(null, res);
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(writer).write(captor.capture());
+ configServlet.destroy();
+ return ObjectMapperProvider.objectMapper()
+ .readValue(captor.getValue(), new TypeReference<Map<String, Object>>()
{});
+ }
}