From 0303b128afed319632add24040527a6e3b500d57 Mon Sep 17 00:00:00 2001 From: Frosty <112929809+FrostyHec@users.noreply.github.com> Date: Thu, 19 Mar 2026 23:44:47 +0800 Subject: [PATCH 1/4] feat(client): add support for skipping required checks in HugeClientBuilder --- .../apache/hugegraph/driver/HugeClient.java | 5 ++ .../hugegraph/driver/HugeClientBuilder.java | 29 ++++++++--- .../apache/hugegraph/structure/auth/User.java | 6 ++- .../hugegraph/unit/HugeClientBuilderTest.java | 51 +++++++++++++++++++ 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java index 091e38fc2..4b2ba57a0 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java @@ -122,6 +122,11 @@ public static HugeClientBuilder builder(String url, String graphSpace, String gr return new HugeClientBuilder(url, graphSpace, graph); } + public static HugeClientBuilder builder(String url, String graphSpace, String graph, + boolean skipRequiredChecks) { + return new HugeClientBuilder(url, graphSpace, graph, skipRequiredChecks); + } + public static HugeClientBuilder builder(String url, String graph) { return new HugeClientBuilder(url, HugeClientBuilder.DEFAULT_GRAPHSPACE, graph); } diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java index 9b9c03b9e..8438e8aeb 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java @@ -50,13 +50,26 @@ public class HugeClientBuilder { /** Set them null by default to keep compatibility with 'timeout' */ private Integer connectTimeout; private Integer readTimeout; + private final boolean skipRequiredChecks; public HugeClientBuilder(String url, String graphSpace, String graph) { - E.checkArgument(url != null && !url.isEmpty(), - "Expect a string value as the url parameter argument, but got: %s", url); - E.checkArgument(graph != null && !graph.isEmpty(), - "Expect a string value as the graph name parameter argument, but got: %s", - graph); + this(url, graphSpace, graph, false); + } + + public HugeClientBuilder(String url, String graphSpace, String graph, + boolean skipRequiredChecks) { + this.skipRequiredChecks = skipRequiredChecks; + + if (!skipRequiredChecks) { + E.checkArgument(url != null && !url.isEmpty(), + "Expect a string value as the url parameter " + + "argument, but got: %s", url); + E.checkArgument(graph != null && !graph.isEmpty(), + "Expect a string value as the graph name " + + "parameter argument, but got: %s", + graph); + } + this.url = url; this.graphSpace = graphSpace; this.graph = graph; @@ -76,8 +89,10 @@ public HugeClientBuilder(String url, String graphSpace, String graph) { } public HugeClient build() { - E.checkArgument(this.url != null, "The url parameter can't be null"); - E.checkArgument(this.graph != null, "The graph parameter can't be null"); + if (!this.skipRequiredChecks) { + E.checkArgument(this.url != null, "The url parameter can't be null"); + E.checkArgument(this.graph != null, "The graph parameter can't be null"); + } return new HugeClient(this); } diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java b/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java index 3f7ba4c6e..2ee579c9c 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java @@ -155,9 +155,11 @@ public static class UserRole { // Mapping of: graphSpace -> graph -> permission -> resourceType -> resources @JsonProperty("roles") - private Map>>>> roles; + private Map>>>> roles; - public Map>>>> roles() { + public Map>>>> roles() { return Collections.unmodifiableMap(this.roles); } diff --git a/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java new file mode 100644 index 000000000..3d9c2df6a --- /dev/null +++ b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java @@ -0,0 +1,51 @@ +package org.apache.hugegraph.unit; + +import org.apache.hugegraph.driver.HugeClient; +import org.apache.hugegraph.driver.HugeClientBuilder; +import org.apache.hugegraph.rest.ClientException; +import org.junit.Assert; +import org.junit.Test; + +public class HugeClientBuilderTest { + + @Test + public void testBuilderWithSkipRequiredChecks() { + // Should not throw IllegalArgumentException when skipRequiredChecks is true and graph is null + HugeClientBuilder builder = new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, true); + try { + builder.build(); + } catch (IllegalArgumentException e) { + Assert.fail("Should not throw IllegalArgumentException when skipRequiredChecks is true, but got: " + e.getMessage()); + } catch (Exception e) { + // Expected since there is probably no server running at localhost:8080 + // The fact we reach here means the bypass of graph/url check was successful. + } + } + + @Test(expected = IllegalArgumentException.class) + public void testBuilderWithoutSkipRequiredChecks() { + // Should throw exception when skipRequiredChecks is false and graph is null + HugeClientBuilder builder = new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, false); + builder.build(); + } + + @Test + public void testHugeClientBuilderMethod() { + // Should not throw IllegalArgumentException + HugeClientBuilder builder = HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", null, true); + try { + builder.build(); + } catch (IllegalArgumentException e) { + Assert.fail("Should not throw IllegalArgumentException when skipRequiredChecks is true, but got: " + e.getMessage()); + } catch (Exception e) { + // Expected + } + } + + @Test(expected = IllegalArgumentException.class) + public void testHugeClientBuilderMethodWithoutSkip() { + // Should throw exception + HugeClientBuilder builder = HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", null); + builder.build(); + } +} From aa8044bc32b263d6ebd462bf135f5d724538da3f Mon Sep 17 00:00:00 2001 From: Frosty <112929809+FrostyHec@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:19:44 +0800 Subject: [PATCH 2/4] fix: update User.java formatting and enhance HugeClientBuilderTest with additional checks --- .../apache/hugegraph/structure/auth/User.java | 4 +- .../hugegraph/unit/HugeClientBuilderTest.java | 80 +++++++++++++------ 2 files changed, 57 insertions(+), 27 deletions(-) diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java b/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java index 2ee579c9c..3de439ae7 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/structure/auth/User.java @@ -155,10 +155,10 @@ public static class UserRole { // Mapping of: graphSpace -> graph -> permission -> resourceType -> resources @JsonProperty("roles") - private Map>>>> roles; - public Map>>>> roles() { return Collections.unmodifiableMap(this.roles); } diff --git a/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java index 3d9c2df6a..bd17ca6b3 100644 --- a/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java +++ b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java @@ -1,8 +1,24 @@ +/* + * 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; import org.apache.hugegraph.driver.HugeClient; import org.apache.hugegraph.driver.HugeClientBuilder; -import org.apache.hugegraph.rest.ClientException; import org.junit.Assert; import org.junit.Test; @@ -10,42 +26,56 @@ public class HugeClientBuilderTest { @Test public void testBuilderWithSkipRequiredChecks() { - // Should not throw IllegalArgumentException when skipRequiredChecks is true and graph is null - HugeClientBuilder builder = new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, true); - try { - builder.build(); - } catch (IllegalArgumentException e) { - Assert.fail("Should not throw IllegalArgumentException when skipRequiredChecks is true, but got: " + e.getMessage()); - } catch (Exception e) { - // Expected since there is probably no server running at localhost:8080 - // The fact we reach here means the bypass of graph/url check was successful. - } + // Constructor should NOT throw when skipRequiredChecks=true, even with null graph/url. + // No build() call here to avoid triggering HTTP (no server available in unit tests). + HugeClientBuilder builder = new HugeClientBuilder( + "http://127.0.0.1:8080", "DEFAULT", null, true); + Assert.assertNotNull(builder); + // Also verify null url is accepted when skipRequiredChecks=true + HugeClientBuilder builder2 = new HugeClientBuilder( + null, "DEFAULT", "hugegraph", true); + Assert.assertNotNull(builder2); + } + + @Test(expected = IllegalArgumentException.class) + public void testConstructorCheckWithoutSkip() { + // Constructor should throw when graph is null and skipRequiredChecks=false + new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, false); + } + + @Test(expected = IllegalArgumentException.class) + public void testBuildCheckWithoutSkip_nullGraph() { + // Construct with valid params, null out graph afterwards to test build() check path + HugeClientBuilder builder = new HugeClientBuilder( + "http://127.0.0.1:8080", "DEFAULT", "hugegraph", false); + builder.configGraph(null); + builder.build(); } @Test(expected = IllegalArgumentException.class) - public void testBuilderWithoutSkipRequiredChecks() { - // Should throw exception when skipRequiredChecks is false and graph is null - HugeClientBuilder builder = new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, false); + public void testBuildCheckWithoutSkip_nullUrl() { + // Construct with valid params, null out url afterwards to test build() check path + HugeClientBuilder builder = new HugeClientBuilder( + "http://127.0.0.1:8080", "DEFAULT", "hugegraph", false); + builder.configUrl(null); builder.build(); } @Test public void testHugeClientBuilderMethod() { - // Should not throw IllegalArgumentException - HugeClientBuilder builder = HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", null, true); - try { - builder.build(); - } catch (IllegalArgumentException e) { - Assert.fail("Should not throw IllegalArgumentException when skipRequiredChecks is true, but got: " + e.getMessage()); - } catch (Exception e) { - // Expected - } + // HugeClient.builder factory should NOT throw when skipRequiredChecks=true. + // No build() call here to avoid triggering HTTP (no server available in unit tests). + HugeClientBuilder builder = HugeClient.builder( + "http://127.0.0.1:8080", "DEFAULT", null, true); + Assert.assertNotNull(builder); } @Test(expected = IllegalArgumentException.class) public void testHugeClientBuilderMethodWithoutSkip() { - // Should throw exception - HugeClientBuilder builder = HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", null); + // build() should throw when graph is null and skipRequiredChecks defaults to false + HugeClientBuilder builder = HugeClient.builder( + "http://127.0.0.1:8080", "DEFAULT", "hugegraph"); + builder.configGraph(null); builder.build(); } } From f4a753b2d69de2e121a7d8f2e866042b257d3603 Mon Sep 17 00:00:00 2001 From: imbajin Date: Sun, 19 Apr 2026 00:12:42 +0800 Subject: [PATCH 3/4] refactor(client): replace skipRequiredChecks bool param with chainable graphRequired() method - Move url/graph validation from constructor to build() for true null support - Replace boolean constructor param with fluent .graphRequired(false) chain method - Rename field to graphRequired (default true) for clearer semantics - Clean up HugeClient javadoc: remove redundant class/constructor comments - Simplify tests: remove redundant cases, use direct null params from start --- .serena/project.yml | 125 ++++++++++++------ .../apache/hugegraph/driver/HugeClient.java | 16 +-- .../hugegraph/driver/HugeClientBuilder.java | 34 ++--- .../hugegraph/unit/HugeClientBuilderTest.java | 71 +++++----- 4 files changed, 136 insertions(+), 110 deletions(-) diff --git a/.serena/project.yml b/.serena/project.yml index 7cea692f2..edbab5745 100644 --- a/.serena/project.yml +++ b/.serena/project.yml @@ -1,15 +1,26 @@ + + # list of languages for which language servers are started; choose from: -# al bash clojure cpp csharp csharp_omnisharp -# dart elixir elm erlang fortran go -# haskell java julia kotlin lua markdown -# nix perl php python python_jedi r -# rego ruby ruby_solargraph rust scala swift -# terraform typescript typescript_vts zig +# al bash clojure cpp csharp +# csharp_omnisharp dart elixir elm erlang +# fortran fsharp go groovy haskell +# haxe java julia kotlin lua +# markdown +# matlab nix pascal perl php +# php_phpactor powershell python python_jedi r +# rego ruby ruby_solargraph rust scala +# swift terraform toml typescript typescript_vts +# vue yaml zig +# (This list may be outdated. For the current list, see values of Language enum here: +# https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py +# For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) # Note: # - For C, use cpp # - For JavaScript, use typescript +# - For Free Pascal/Lazarus, use pascal # Special requirements: -# - csharp: Requires the presence of a .sln file in the project folder. +# Some languages require additional setup/installations. +# See here for details: https://oraios.github.io/serena/01-about/020_programming-languages.html#language-servers # When using multiple languages, the first language server that supports a given file will be used for that file. # The first language is the default language and the respective language server will be used as a fallback. # Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored. @@ -20,14 +31,12 @@ languages: # For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings encoding: "utf-8" -# whether to use the project's gitignore file to ignore files -# Added on 2025-04-07 +# whether to use project's .gitignore files to ignore files ignore_all_files_in_gitignore: true -# list of additional paths to ignore -# same syntax as gitignore, so you can use * and ** -# Was previously called `ignored_dirs`, please update your config if you are using that. -# Added (renamed) on 2025-04-07 +# list of additional paths to ignore in this project. +# Same syntax as gitignore, so you can use * and **. +# Note: global ignored_paths from serena_config.yml are also applied additively. ignored_paths: [] # whether the project is in read-only mode @@ -35,45 +44,48 @@ ignored_paths: [] # Added on 2025-04-18 read_only: false -# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details. +# list of tool names to exclude. +# This extends the existing exclusions (e.g. from the global configuration) +# # Below is the complete list of tools for convenience. # To make sure you have the latest list of tools, and to view their descriptions, # execute `uv run scripts/print_tool_overview.py`. # -# * `activate_project`: Activates a project by name. +# * `activate_project`: Activates a project based on the project name or path. # * `check_onboarding_performed`: Checks whether project onboarding was already performed. # * `create_text_file`: Creates/overwrites a file in the project directory. -# * `delete_lines`: Deletes a range of lines within a file. -# * `delete_memory`: Deletes a memory from Serena's project-specific memory store. +# * `delete_memory`: Delete a memory file. Should only happen if a user asks for it explicitly, +# for example by saying that the information retrieved from a memory file is no longer correct +# or no longer relevant for the project. +# * `edit_memory`: Replaces content matching a regular expression in a memory. # * `execute_shell_command`: Executes a shell command. -# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced. -# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type). -# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type). +# * `find_file`: Finds files in the given relative paths +# * `find_referencing_symbols`: Finds symbols that reference the given symbol using the language server backend +# * `find_symbol`: Performs a global (or local) search using the language server backend. # * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. # * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. -# * `initial_instructions`: Gets the initial instructions for the current project. -# Should only be used in settings where the system prompt cannot be set, -# e.g. in clients you have no control over, like Claude Desktop. +# * `initial_instructions`: Provides instructions Serena usage (i.e. the 'Serena Instructions Manual') +# for clients that do not read the initial instructions when the MCP server is connected. # * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. -# * `insert_at_line`: Inserts content at a given line in a file. # * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. # * `list_dir`: Lists files and directories in the given directory (optionally with recursion). -# * `list_memories`: Lists memories in Serena's project-specific memory store. +# * `list_memories`: List available memories. Any memory can be read using the `read_memory` tool. # * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). -# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context). # * `read_file`: Reads a file within the project directory. -# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store. -# * `remove_project`: Removes a project from the Serena configuration. -# * `replace_lines`: Replaces a range of lines within a file with new content. -# * `replace_symbol_body`: Replaces the full definition of a symbol. -# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen. +# * `read_memory`: Read the content of a memory file. This tool should only be used if the information +# is relevant to the current task. You can infer whether the information +# is relevant from the memory file name. +# You should not read the same memory file multiple times in the same conversation. +# * `rename_memory`: Renames or moves a memory. Moving between project and global scope is supported +# (e.g., renaming "global/foo" to "bar" moves it from global to project scope). +# * `rename_symbol`: Renames a symbol throughout the codebase using language server refactoring capabilities. +# For JB, we use a separate tool. +# * `replace_content`: Replaces content in a file (optionally using regular expressions). +# * `replace_symbol_body`: Replaces the full definition of a symbol using the language server backend. +# * `safe_delete_symbol`: # * `search_for_pattern`: Performs a search for a pattern in the project. -# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase. -# * `switch_modes`: Activates modes by providing a list of their names -# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information. -# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task. -# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed. -# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store. +# * `write_memory`: Write some information (utf-8-encoded) about this project that can be useful for future tasks to a memory in md format. +# The memory name should be meaningful. excluded_tools: [] # initial prompt for the project. It will always be given to the LLM upon activating the project @@ -82,7 +94,8 @@ initial_prompt: "" # the name by which the project can be referenced within Serena project_name: "toolchain" -# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default) +# list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). +# This extends the existing inclusions (e.g. from the global configuration). included_optional_tools: [] # list of mode names to that are always to be included in the set of active modes @@ -103,3 +116,39 @@ default_modes: [] # fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. # This cannot be combined with non-empty excluded_tools or included_optional_tools. fixed_tools: [] + +# time budget (seconds) per tool call for the retrieval of additional symbol information +# such as docstrings or parameter information. +# This overrides the corresponding setting in the global configuration; see the documentation there. +# If null or missing, use the setting from the global configuration. +symbol_info_budget: + +# The language backend to use for this project. +# If not set, the global setting from serena_config.yml is used. +# Valid values: LSP, JetBrains +# Note: the backend is fixed at startup. If a project with a different backend +# is activated post-init, an error will be returned. +language_backend: + +# line ending convention to use when writing source files. +# Possible values: unset (use global setting), "lf", "crlf", or "native" (platform default) +# This does not affect Serena's own files (e.g. memories and configuration files), which always use native line endings. +line_ending: + +# list of regex patterns which, when matched, mark a memory entry as read‑only. +# Extends the list from the global configuration, merging the two lists. +read_only_memory_patterns: [] + +# list of regex patterns for memories to completely ignore. +# Matching memories will not appear in list_memories or activate_project output +# and cannot be accessed via read_memory or write_memory. +# To access ignored memory files, use the read_file tool on the raw file path. +# Extends the list from the global configuration, merging the two lists. +# Example: ["_archive/.*", "_episodes/.*"] +ignored_memory_patterns: [] + +# advanced configuration option allowing to configure language server-specific options. +# Maps the language key to the options. +# Have a look at the docstring of the constructors of the LS implementations within solidlsp (e.g., for C# or PHP) to see which options are available. +# No documentation on options means no options are available. +ls_specific_settings: {} diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java index 4b2ba57a0..c681a76a9 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClient.java @@ -32,9 +32,8 @@ import com.google.common.base.Strings; /** - * The HugeClient class is the main entry point for interacting with a HugeGraph server. - * It provides methods for managing graphs, schemas, jobs, tasks, and other resources. - * It also implements the Closeable interface, so it can be used in a try-with-resources statement. + * Main entry point for HugeGraph server operations. + * Use {@link #builder(String, String, String)} to create an instance. */ public class HugeClient implements Closeable { @@ -72,11 +71,6 @@ public class HugeClient implements Closeable { private WhiteIpListManager whiteIpListManager; private VermeerManager vermeerManager; - /** - * Constructs a new HugeClient using the provided builder. - * - * @param builder the HugeClientBuilder to use for configuration - */ public HugeClient(HugeClientBuilder builder) { this.borrowedClient = false; this.graphSpaceName = builder.graphSpace(); @@ -111,7 +105,6 @@ public HugeClient(HugeClientBuilder builder) { } } - // QUESTION: add gs to method param? public HugeClient(HugeClient client, String graphSpace, String graph) { this.borrowedClient = true; this.client = client.client; @@ -122,11 +115,6 @@ public static HugeClientBuilder builder(String url, String graphSpace, String gr return new HugeClientBuilder(url, graphSpace, graph); } - public static HugeClientBuilder builder(String url, String graphSpace, String graph, - boolean skipRequiredChecks) { - return new HugeClientBuilder(url, graphSpace, graph, skipRequiredChecks); - } - public static HugeClientBuilder builder(String url, String graph) { return new HugeClientBuilder(url, HugeClientBuilder.DEFAULT_GRAPHSPACE, graph); } diff --git a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java index 8438e8aeb..2b5d547b3 100644 --- a/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java +++ b/hugegraph-client/src/main/java/org/apache/hugegraph/driver/HugeClientBuilder.java @@ -50,26 +50,9 @@ public class HugeClientBuilder { /** Set them null by default to keep compatibility with 'timeout' */ private Integer connectTimeout; private Integer readTimeout; - private final boolean skipRequiredChecks; + private boolean graphRequired = true; public HugeClientBuilder(String url, String graphSpace, String graph) { - this(url, graphSpace, graph, false); - } - - public HugeClientBuilder(String url, String graphSpace, String graph, - boolean skipRequiredChecks) { - this.skipRequiredChecks = skipRequiredChecks; - - if (!skipRequiredChecks) { - E.checkArgument(url != null && !url.isEmpty(), - "Expect a string value as the url parameter " + - "argument, but got: %s", url); - E.checkArgument(graph != null && !graph.isEmpty(), - "Expect a string value as the graph name " + - "parameter argument, but got: %s", - graph); - } - this.url = url; this.graphSpace = graphSpace; this.graph = graph; @@ -89,13 +72,22 @@ public HugeClientBuilder(String url, String graphSpace, String graph, } public HugeClient build() { - if (!this.skipRequiredChecks) { - E.checkArgument(this.url != null, "The url parameter can't be null"); - E.checkArgument(this.graph != null, "The graph parameter can't be null"); + if (this.graphRequired) { + E.checkArgument(this.url != null && !this.url.isEmpty(), + "Expect a string value as the url parameter argument, but got: %s", + this.url); + E.checkArgument(this.graph != null && !this.graph.isEmpty(), + "Expect a string value as the graph name parameter argument, but got: %s", + this.graph); } return new HugeClient(this); } + public HugeClientBuilder graphRequired(boolean graphRequired) { + this.graphRequired = graphRequired; + return this; + } + public HugeClientBuilder configGraphSpace(String graphSpace) { this.graphSpace = graphSpace; return this; diff --git a/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java index bd17ca6b3..c1379218a 100644 --- a/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java +++ b/hugegraph-client/src/test/java/org/apache/hugegraph/unit/HugeClientBuilderTest.java @@ -25,57 +25,54 @@ public class HugeClientBuilderTest { @Test - public void testBuilderWithSkipRequiredChecks() { - // Constructor should NOT throw when skipRequiredChecks=true, even with null graph/url. - // No build() call here to avoid triggering HTTP (no server available in unit tests). - HugeClientBuilder builder = new HugeClientBuilder( - "http://127.0.0.1:8080", "DEFAULT", null, true); + public void testConstructorAcceptsNullUrlAndGraph() { + HugeClientBuilder builder = new HugeClientBuilder(null, "DEFAULT", null); Assert.assertNotNull(builder); - // Also verify null url is accepted when skipRequiredChecks=true - HugeClientBuilder builder2 = new HugeClientBuilder( - null, "DEFAULT", "hugegraph", true); - Assert.assertNotNull(builder2); + } + + @Test + public void testGraphRequiredFalseSkipsBuildValidation() { + // graphRequired(false) must skip IllegalArgumentException — only connection-level + // failure is expected since no server is available in unit tests + try { + HugeClient.builder(null, "DEFAULT", null).graphRequired(false).build(); + Assert.fail("Expected connection-level exception"); + } catch (IllegalArgumentException e) { + Assert.fail("Should not throw IllegalArgumentException — validation must be skipped"); + } catch (Exception e) { + // Expected: validation was skipped, failed at HTTP connection as intended + } } @Test(expected = IllegalArgumentException.class) - public void testConstructorCheckWithoutSkip() { - // Constructor should throw when graph is null and skipRequiredChecks=false - new HugeClientBuilder("http://127.0.0.1:8080", "DEFAULT", null, false); + public void testBuildFailsWithNullUrl() { + HugeClient.builder(null, "DEFAULT", "hugegraph").build(); } @Test(expected = IllegalArgumentException.class) - public void testBuildCheckWithoutSkip_nullGraph() { - // Construct with valid params, null out graph afterwards to test build() check path - HugeClientBuilder builder = new HugeClientBuilder( - "http://127.0.0.1:8080", "DEFAULT", "hugegraph", false); - builder.configGraph(null); - builder.build(); + public void testBuildFailsWithNullGraph() { + HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", null).build(); } @Test(expected = IllegalArgumentException.class) - public void testBuildCheckWithoutSkip_nullUrl() { - // Construct with valid params, null out url afterwards to test build() check path - HugeClientBuilder builder = new HugeClientBuilder( - "http://127.0.0.1:8080", "DEFAULT", "hugegraph", false); - builder.configUrl(null); - builder.build(); + public void testBuildFailsWithEmptyUrl() { + HugeClient.builder("", "DEFAULT", "hugegraph").build(); } - @Test - public void testHugeClientBuilderMethod() { - // HugeClient.builder factory should NOT throw when skipRequiredChecks=true. - // No build() call here to avoid triggering HTTP (no server available in unit tests). - HugeClientBuilder builder = HugeClient.builder( - "http://127.0.0.1:8080", "DEFAULT", null, true); - Assert.assertNotNull(builder); + @Test(expected = IllegalArgumentException.class) + public void testBuildFailsWithEmptyGraph() { + HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", "").build(); + } + + @Test(expected = IllegalArgumentException.class) + public void testBuildFailsAfterConfigGraphNull() { + HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", "hugegraph") + .configGraph(null).build(); } @Test(expected = IllegalArgumentException.class) - public void testHugeClientBuilderMethodWithoutSkip() { - // build() should throw when graph is null and skipRequiredChecks defaults to false - HugeClientBuilder builder = HugeClient.builder( - "http://127.0.0.1:8080", "DEFAULT", "hugegraph"); - builder.configGraph(null); - builder.build(); + public void testBuildFailsAfterConfigUrlNull() { + HugeClient.builder("http://127.0.0.1:8080", "DEFAULT", "hugegraph") + .configUrl(null).build(); } } From fa4146aacaee5d541127f07b42b65182237fbfcb Mon Sep 17 00:00:00 2001 From: imbajin Date: Sun, 19 Apr 2026 02:45:33 +0800 Subject: [PATCH 4/4] fix(client): update HugeClientHttpsTest assertions to match new error messages --- .../org/apache/hugegraph/functional/HugeClientHttpsTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hugegraph-client/src/test/java/org/apache/hugegraph/functional/HugeClientHttpsTest.java b/hugegraph-client/src/test/java/org/apache/hugegraph/functional/HugeClientHttpsTest.java index 25b11fc1e..3ad104816 100644 --- a/hugegraph-client/src/test/java/org/apache/hugegraph/functional/HugeClientHttpsTest.java +++ b/hugegraph-client/src/test/java/org/apache/hugegraph/functional/HugeClientHttpsTest.java @@ -139,7 +139,7 @@ public void testHttpsClientBuilderWithConnectionPoolNoParam() { .configSSL("", "") .build(); }, e -> { - Assert.assertContains("The url parameter can't be null", + Assert.assertContains("Expect a string value as the url parameter argument", e.getMessage()); }); } @@ -153,7 +153,7 @@ public void testHttpsClientBuilderWithConnectionPoolNoGraphParam() { .configSSL("", "") .build(); }, e -> { - Assert.assertContains("The graph parameter can't be null", + Assert.assertContains("Expect a string value as the graph name parameter argument", e.getMessage()); }); }