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

jin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-hugegraph.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e0cffe7c feat(server): add path filter for graphspace (#2898)
2e0cffe7c is described below

commit 2e0cffe7c4a0f82f3fc6bfb7a2f62de9f6b52d9d
Author: Tsukilc <[email protected]>
AuthorDate: Tue Nov 4 19:32:28 2025 +0800

    feat(server): add path filter for graphspace (#2898)
---
 .../apache/hugegraph/api/filter/PathFilter.java    |  92 ++++-
 .../org/apache/hugegraph/unit/UnitTestSuite.java   |   4 +
 .../hugegraph/unit/api/filter/PathFilterTest.java  | 431 +++++++++++++++++++++
 3 files changed, 511 insertions(+), 16 deletions(-)

diff --git 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/PathFilter.java
 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/PathFilter.java
index dda43b3fb..b69ff5959 100644
--- 
a/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/PathFilter.java
+++ 
b/hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/PathFilter.java
@@ -18,11 +18,25 @@
 package org.apache.hugegraph.api.filter;
 
 import java.io.IOException;
+import java.net.URI;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hugegraph.config.HugeConfig;
+import org.apache.hugegraph.config.ServerOptions;
+import org.apache.hugegraph.util.E;
+import org.apache.hugegraph.util.Log;
+import org.slf4j.Logger;
+
+import com.google.common.collect.ImmutableSet;
 
 import jakarta.inject.Singleton;
 import jakarta.ws.rs.container.ContainerRequestContext;
 import jakarta.ws.rs.container.ContainerRequestFilter;
 import jakarta.ws.rs.container.PreMatching;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.PathSegment;
+import jakarta.ws.rs.core.UriInfo;
 import jakarta.ws.rs.ext.Provider;
 
 @Provider
@@ -30,29 +44,75 @@ import jakarta.ws.rs.ext.Provider;
 @PreMatching
 public class PathFilter implements ContainerRequestFilter {
 
+    private static final Logger LOG = Log.logger(PathFilter.class);
+
+    private static final String GRAPH_SPACE = "graphspaces";
+    private static final String ARTHAS_START = "arthas";
+
     public static final String REQUEST_TIME = "request_time";
     public static final String REQUEST_PARAMS_JSON = "request_params_json";
 
+    private static final String DELIMITER = "/";
+    private static final Set<String> WHITE_API_LIST = ImmutableSet.of(
+            "",
+            "apis",
+            "metrics",
+            "versions",
+            "health",
+            "gremlin",
+            "graphs/auth",
+            "graphs/auth/users",
+            "auth/users",
+            "auth/managers",
+            "auth",
+            "hstore",
+            "pd",
+            "kafka",
+            "whiteiplist",
+            "vermeer",
+            "store",
+            "expiredclear",
+            "department",
+            "saas",
+            "trade",
+            "kvstore",
+            "openapi.json"
+    );
+
+    @Context
+    private jakarta.inject.Provider<HugeConfig> configProvider;
+
+    public static boolean isWhiteAPI(String rootPath) {
+
+        return WHITE_API_LIST.contains(rootPath);
+    }
+
     @Override
-    public void filter(ContainerRequestContext context) throws IOException {
+    public void filter(ContainerRequestContext context)
+            throws IOException {
         context.setProperty(REQUEST_TIME, System.currentTimeMillis());
 
-        // TODO: temporarily comment it to fix loader bug, handle it later
-        /*// record the request json
-        String method = context.getMethod();
-        String requestParamsJson = "";
-        if (method.equals(HttpMethod.POST)) {
-            requestParamsJson = IOUtils.toString(context.getEntityStream(),
-                                                 Charsets.toCharset(CHARSET));
-            // replace input stream because we have already read it
-            InputStream in = IOUtils.toInputStream(requestParamsJson, 
Charsets.toCharset(CHARSET));
-            context.setEntityStream(in);
-        } else if (method.equals(HttpMethod.GET)) {
-            MultivaluedMap<String, String> pathParameters = 
context.getUriInfo()
-                                                                   
.getPathParameters();
-            requestParamsJson = pathParameters.toString();
+        List<PathSegment> segments = context.getUriInfo().getPathSegments();
+        E.checkArgument(segments.size() > 0, "Invalid request uri '%s'",
+                        context.getUriInfo().getPath());
+        String rootPath = segments.get(0).getPath();
+
+        if (isWhiteAPI(rootPath) || GRAPH_SPACE.equals(rootPath) ||
+            ARTHAS_START.equals(rootPath)) {
+            return;
         }
 
-        context.setProperty(REQUEST_PARAMS_JSON, requestParamsJson);*/
+        UriInfo uriInfo = context.getUriInfo();
+        String defaultPathSpace =
+                this.configProvider.get().get(ServerOptions.PATH_GRAPH_SPACE);
+        String path = uriInfo.getBaseUri().getPath() +
+                      String.join(DELIMITER, GRAPH_SPACE, defaultPathSpace);
+        for (PathSegment segment : segments) {
+            path = String.join(DELIMITER, path, segment.getPath());
+        }
+        LOG.debug("Redirect request uri from {} to {}",
+                  uriInfo.getRequestUri().getPath(), path);
+        URI requestUri = uriInfo.getRequestUriBuilder().uri(path).build();
+        context.setRequestUri(uriInfo.getBaseUri(), requestUri);
     }
 }
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
index 03d347949..a0cb72aa6 100644
--- 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java
@@ -18,6 +18,7 @@
 package org.apache.hugegraph.unit;
 
 import org.apache.hugegraph.core.RoleElectionStateMachineTest;
+import org.apache.hugegraph.unit.api.filter.PathFilterTest;
 import org.apache.hugegraph.unit.cache.CacheManagerTest;
 import org.apache.hugegraph.unit.cache.CacheTest;
 import org.apache.hugegraph.unit.cache.CachedGraphTransactionTest;
@@ -76,6 +77,9 @@ import org.junit.runners.Suite;
 
 @RunWith(Suite.class)
 @Suite.SuiteClasses({
+        /* api filter */
+        PathFilterTest.class,
+
         /* cache */
         CacheTest.RamCacheTest.class,
         CacheTest.OffheapCacheTest.class,
diff --git 
a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/api/filter/PathFilterTest.java
 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/api/filter/PathFilterTest.java
new file mode 100644
index 000000000..8bfdb8752
--- /dev/null
+++ 
b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/api/filter/PathFilterTest.java
@@ -0,0 +1,431 @@
+/*
+ * 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.hugegraph.unit.api.filter;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.configuration2.Configuration;
+import org.apache.commons.configuration2.PropertiesConfiguration;
+import org.apache.hugegraph.api.filter.PathFilter;
+import org.apache.hugegraph.config.HugeConfig;
+import org.apache.hugegraph.config.ServerOptions;
+import org.apache.hugegraph.testutil.Assert;
+import org.apache.hugegraph.unit.BaseUnitTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import jakarta.inject.Provider;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.core.PathSegment;
+import jakarta.ws.rs.core.UriBuilder;
+import jakarta.ws.rs.core.UriInfo;
+
+/**
+ * Unit tests for PathFilter
+ * Test scenarios:
+ * 1. Whitelist paths are not redirected
+ * 2. Normal paths are correctly prefixed with graphspace
+ * 3. Query parameters are preserved
+ * 4. Special characters and encoding handling
+ * 5. Edge cases (empty path, root path, etc.)
+ */
+public class PathFilterTest extends BaseUnitTest {
+
+    private PathFilter pathFilter;
+    private Provider<HugeConfig> configProvider;
+    private HugeConfig config;
+    private ContainerRequestContext requestContext;
+    private UriInfo uriInfo;
+
+    @Before
+    public void setup() {
+        // Create configuration
+        Configuration conf = new PropertiesConfiguration();
+        conf.setProperty(ServerOptions.PATH_GRAPH_SPACE.name(), "DEFAULT");
+        this.config = new HugeConfig(conf);
+
+        // Create Provider
+        this.configProvider = () -> config;
+
+        // Create PathFilter and inject Provider
+        this.pathFilter = new PathFilter();
+        injectProvider(this.pathFilter, this.configProvider);
+
+        // Mock request context and uriInfo
+        this.requestContext = Mockito.mock(ContainerRequestContext.class);
+        this.uriInfo = Mockito.mock(UriInfo.class);
+        
Mockito.when(this.requestContext.getUriInfo()).thenReturn(this.uriInfo);
+    }
+
+    /**
+     * Inject configProvider using reflection
+     */
+    private void injectProvider(PathFilter filter, Provider<HugeConfig> 
provider) {
+        try {
+            java.lang.reflect.Field field = 
PathFilter.class.getDeclaredField("configProvider");
+            field.setAccessible(true);
+            field.set(filter, provider);
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to inject configProvider", e);
+        }
+    }
+
+    /**
+     * Create PathSegment mock
+     */
+    private PathSegment createPathSegment(String path) {
+        PathSegment segment = Mockito.mock(PathSegment.class);
+        Mockito.when(segment.getPath()).thenReturn(path);
+        return segment;
+    }
+
+    /**
+     * Setup URI information
+     */
+    private void setupUriInfo(String basePath, String requestPath, 
List<String> segments,
+                              String query) {
+        URI baseUri = URI.create("http://localhost:8080"; + basePath);
+        URI requestUri =
+                query != null ? URI.create("http://localhost:8080"; + 
requestPath + "?" + query) :
+                URI.create("http://localhost:8080"; + requestPath);
+
+        Mockito.when(uriInfo.getBaseUri()).thenReturn(baseUri);
+        Mockito.when(uriInfo.getRequestUri()).thenReturn(requestUri);
+
+        List<PathSegment> pathSegments = new ArrayList<>();
+        for (String segment : segments) {
+            pathSegments.add(createPathSegment(segment));
+        }
+        Mockito.when(uriInfo.getPathSegments()).thenReturn(pathSegments);
+        Mockito.when(uriInfo.getPath()).thenReturn(String.join("/", segments));
+
+        // Mock UriBuilder - capture the path passed to uri() method
+        final String[] capturedPath = new String[1];
+        UriBuilder uriBuilder = Mockito.mock(UriBuilder.class);
+        Mockito.when(uriInfo.getRequestUriBuilder()).thenReturn(uriBuilder);
+        
Mockito.when(uriBuilder.uri(Mockito.anyString())).thenAnswer(invocation -> {
+            capturedPath[0] = invocation.getArgument(0);
+            return uriBuilder;
+        });
+        Mockito.when(uriBuilder.build()).thenAnswer(invocation -> {
+            // Build URI based on captured path and preserve query parameters
+            String path = capturedPath[0] != null ? capturedPath[0] : 
requestPath;
+            return URI.create("http://localhost:8080"; + path + (query != null 
? "?" + query : ""));
+        });
+    }
+
+    /**
+     * Test whitelist API - empty path
+     */
+    @Test
+    public void testWhiteListApi_EmptyPath() throws IOException {
+        setupUriInfo("/", "/", List.of(""), null);
+
+        pathFilter.filter(requestContext);
+
+        // Verify whitelist API does not trigger setRequestUri
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+        // Verify request timestamp is set
+        Mockito.verify(requestContext).setProperty(
+                Mockito.eq(PathFilter.REQUEST_TIME), Mockito.anyLong());
+    }
+
+    /**
+     * Test whitelist API - /apis
+     */
+    @Test
+    public void testWhiteListApi_Apis() throws IOException {
+        setupUriInfo("/", "/apis", List.of("apis"), null);
+
+        pathFilter.filter(requestContext);
+
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test whitelist API - /gremlin
+     */
+    @Test
+    public void testWhiteListApi_Gremlin() throws IOException {
+        setupUriInfo("/", "/gremlin", List.of("gremlin"), null);
+
+        pathFilter.filter(requestContext);
+
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test whitelist API - /auth (single segment)
+     */
+    @Test
+    public void testWhiteListApi_Auth() throws IOException {
+        setupUriInfo("/", "/auth", List.of("auth"), null);
+
+        pathFilter.filter(requestContext);
+
+        Mockito.verify(requestContext, Mockito.never())
+               .setRequestUri(Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test whitelist API - /auth/users (multi-segment path)
+     */
+    @Test
+    public void testWhiteListApi_AuthUsers_MultiSegment() throws IOException {
+        // Test complete /auth/users path with all segments
+        setupUriInfo("/", "/auth/users", Arrays.asList("auth", "users"), null);
+
+        pathFilter.filter(requestContext);
+
+        // Should not be redirected (first segment "auth" matches whitelist)
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test graphspaces path is not redirected
+     */
+    @Test
+    public void testGraphSpacePath_NotRedirected() throws IOException {
+        setupUriInfo("/", "/graphspaces/space1/graphs",
+                     Arrays.asList("graphspaces", "space1", "graphs"), null);
+
+        pathFilter.filter(requestContext);
+
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test arthas path is not redirected
+     */
+    @Test
+    public void testArthasPath_NotRedirected() throws IOException {
+        setupUriInfo("/", "/arthas/api", Arrays.asList("arthas", "api"), null);
+
+        pathFilter.filter(requestContext);
+
+        Mockito.verify(requestContext, Mockito.never()).setRequestUri(
+                Mockito.any(URI.class), Mockito.any(URI.class));
+    }
+
+    /**
+     * Test normal path is correctly redirected - single segment
+     */
+    @Test
+    public void testNormalPath_SingleSegment() throws IOException {
+        setupUriInfo("/", "/graphs", List.of("graphs"), null);
+
+        pathFilter.filter(requestContext);
+
+        // Verify redirect is called with correct path
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        Assert.assertTrue("Redirect URI should contain graphspaces/DEFAULT 
prefix",
+                          
capturedUri.getPath().startsWith("/graphspaces/DEFAULT/graphs"));
+        Assert.assertEquals("/graphspaces/DEFAULT/graphs", 
capturedUri.getPath());
+    }
+
+    /**
+     * Test normal path is correctly redirected - multiple segments
+     */
+    @Test
+    public void testNormalPath_MultipleSegments() throws IOException {
+        setupUriInfo("/", "/graphs/hugegraph/vertices",
+                     Arrays.asList("graphs", "hugegraph", "vertices"), null);
+
+        pathFilter.filter(requestContext);
+
+        // Verify redirect is called with correct path
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        Assert.assertEquals("/graphspaces/DEFAULT/graphs/hugegraph/vertices",
+                            capturedUri.getPath());
+    }
+
+    /**
+     * Test query parameters are preserved
+     */
+    @Test
+    public void testQueryParameters_Preserved() throws IOException {
+        String queryString = "limit=10&offset=20&label=person";
+        setupUriInfo("/", "/graphs/hugegraph/vertices",
+                     Arrays.asList("graphs", "hugegraph", "vertices"), 
queryString);
+
+        URI originalRequestUri = uriInfo.getRequestUri();
+        Assert.assertTrue("Original URI should contain query string",
+                          originalRequestUri.toString().contains(queryString));
+
+        pathFilter.filter(requestContext);
+
+        // Use ArgumentCaptor to capture the actual URI passed to setRequestUri
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        // Verify query parameters are indeed preserved
+        Assert.assertNotNull("Query parameters should be preserved", 
capturedUri.getQuery());
+        Assert.assertTrue("Query should contain limit parameter",
+                          capturedUri.getQuery().contains("limit=10"));
+        Assert.assertTrue("Query should contain offset parameter",
+                          capturedUri.getQuery().contains("offset=20"));
+        Assert.assertTrue("Query should contain label parameter",
+                          capturedUri.getQuery().contains("label=person"));
+    }
+
+    /**
+     * Test special characters in path handling
+     */
+    @Test
+    public void testSpecialCharacters_InPath() throws IOException {
+        setupUriInfo("/", "/schema/vertexlabels/person-label",
+                     Arrays.asList("schema", "vertexlabels", "person-label"), 
null);
+
+        pathFilter.filter(requestContext);
+
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        
Assert.assertEquals("/graphspaces/DEFAULT/schema/vertexlabels/person-label",
+                            capturedUri.getPath());
+    }
+
+    /**
+     * Test URL encoded characters handling
+     */
+    @Test
+    public void testUrlEncoded_Characters() throws IOException {
+        // Path contains encoded space %20
+        setupUriInfo("/", "/schema/propertykeys/my%20key",
+                     Arrays.asList("schema", "propertykeys", "my%20key"), 
null);
+
+        pathFilter.filter(requestContext);
+
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        // URI automatically decodes %20 to space
+        Assert.assertEquals("/graphspaces/DEFAULT/schema/propertykeys/my key",
+                            capturedUri.getPath());
+    }
+
+    /**
+     * Test custom graph space configuration
+     */
+    @Test
+    public void testCustomGraphSpace_Configuration() throws IOException {
+        // Modify configuration to custom graph space
+        Configuration customConf = new PropertiesConfiguration();
+        customConf.setProperty(ServerOptions.PATH_GRAPH_SPACE.name(), 
"CUSTOM_SPACE");
+        HugeConfig customConfig = new HugeConfig(customConf);
+
+        Provider<HugeConfig> customProvider = () -> customConfig;
+        injectProvider(this.pathFilter, customProvider);
+
+        setupUriInfo("/", "/graphs/test", Arrays.asList("graphs", "test"), 
null);
+
+        pathFilter.filter(requestContext);
+
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        Assert.assertEquals("/graphspaces/CUSTOM_SPACE/graphs/test", 
capturedUri.getPath());
+    }
+
+    /**
+     * Test deeply nested path
+     */
+    @Test
+    public void testDeeplyNested_Path() throws IOException {
+        setupUriInfo("/", "/graphs/hugegraph/traversers/shortestpath",
+                     Arrays.asList("graphs", "hugegraph", "traversers", 
"shortestpath"), null);
+
+        pathFilter.filter(requestContext);
+
+        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
+        Mockito.verify(requestContext).setRequestUri(Mockito.any(URI.class), 
uriCaptor.capture());
+
+        URI capturedUri = uriCaptor.getValue();
+        
Assert.assertEquals("/graphspaces/DEFAULT/graphs/hugegraph/traversers/shortestpath",
+                            capturedUri.getPath());
+    }
+
+    /**
+     * Test isWhiteAPI static method - single segment whitelist paths
+     * Note: PathFilter.isWhiteAPI() only checks the first segment in actual 
usage
+     */
+    @Test
+    public void testIsWhiteAPI_AllWhiteListPaths() {
+        // Test single-segment whitelist entries (as used in 
PathFilter.filter())
+        Assert.assertTrue(PathFilter.isWhiteAPI(""));
+        Assert.assertTrue(PathFilter.isWhiteAPI("apis"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("metrics"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("versions"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("health"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("gremlin"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("auth"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("hstore"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("pd"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("kafka"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("openapi.json"));
+    }
+
+    /**
+     * Test isWhiteAPI static method - multi-segment strings
+     * Note: This tests the static method directly with multi-segment strings,
+     * but in actual usage, only the first segment is passed to isWhiteAPI()
+     */
+    @Test
+    public void testIsWhiteAPI_MultiSegmentStrings() {
+        // These are how multi-segment entries are stored in the whitelist set
+        Assert.assertTrue(PathFilter.isWhiteAPI("auth/users"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("graphs/auth"));
+        Assert.assertTrue(PathFilter.isWhiteAPI("graphs/auth/users"));
+    }
+
+    /**
+     * Test isWhiteAPI static method - non-whitelist paths
+     */
+    @Test
+    public void testIsWhiteAPI_NonWhiteListPaths() {
+        Assert.assertFalse(PathFilter.isWhiteAPI("graphs"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("schema"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("vertices"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("edges"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("traversers"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("tasks"));
+        Assert.assertFalse(PathFilter.isWhiteAPI("unknown"));
+    }
+}
+

Reply via email to