From ae42b68cd0bab3d8b1dd3aaa04d8be70a069b1db Mon Sep 17 00:00:00 2001 From: Himanshu Verma Date: Sat, 17 Oct 2026 20:02:50 +0530 Subject: [PATCH 1/2] fix(ci): append the start-server config lines only once run-api-test.sh now starts the Server twice on the same configuration, first without authentication for CypherAnonymousApiTest and then with it (apache/hugegraph#3366). start-server.sh appended its config lines on every call, so with hstore the second start read usePD as '[true, true]' and failed with "Invalid value for key 'usePD'", which fails the API test step of the hstore job. Append each line only when the file does not already hold it. This also covers the two hbase timeouts and schema.sync_deletion, which were appended the same way. --- .../src/assembly/travis/start-server.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/start-server.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/start-server.sh index b7b70e8cc9..05bf87e9c9 100755 --- a/hugegraph-server/hugegraph-dist/src/assembly/travis/start-server.sh +++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/start-server.sh @@ -42,6 +42,15 @@ function sed_in_place() { esac } +# run-api-test.sh starts the Server twice on the same configuration, and a +# key appended twice is read back as a list, so append each line only once +function append_once() { + local line=$1 + local file=$2 + + grep -qxF "$line" "$file" || echo "$line" >> "$file" +} + case "$BACKEND" in memory) SERIALIZER=text @@ -64,18 +73,18 @@ write_property "$CONF" "serializer" "$SERIALIZER" # Set timeout for hbase if [ "$BACKEND" == "hbase" ]; then - echo "restserver.request_timeout=200" >> $REST_CONF - echo "gremlinserver.timeout=200" >> $REST_CONF + append_once "restserver.request_timeout=200" "$REST_CONF" + append_once "gremlinserver.timeout=200" "$REST_CONF" sed_in_place 's/evaluationTimeout.*/evaluationTimeout: 200000/' "$GREMLIN_CONF" fi # Set usePD=true for hstore if [ "$BACKEND" == "hstore" ]; then - echo "usePD=true" >> $REST_CONF + append_once "usePD=true" "$REST_CONF" fi # Append schema.sync_deletion=true to config file -echo "schema.sync_deletion=true" >> $CONF +append_once "schema.sync_deletion=true" "$CONF" JACOCO_OPTION="" if [ -n "$JACOCO_PORT" ]; then From effa296fa9922c8933f3feb2b5c2d28acde4d29d Mon Sep 17 00:00:00 2001 From: Himanshu Verma Date: Sat, 17 Oct 2026 22:44:06 +0530 Subject: [PATCH 2/2] test(ci): cover a repeated start-server.sh run run-api-test.sh starts the Server twice on one configuration, and the CI planner does not select the hstore or hbase jobs for a change to start-server.sh, so a regression there can merge unnoticed. Add test-start-server.sh, which runs start-server.sh twice for hstore, hbase, rocksdb and memory on a copy of the packaged config, with init-store.sh and start-hugegraph.sh stubbed. It fails when the second start changes the config, or when usePD, the two hbase timeouts or schema.sync_deletion is missing, set twice or set for the wrong backend. Run it in the rocksdb job with the other startup contract tests. --- .github/workflows/server-tests.yml | 1 + .../src/assembly/travis/test-start-server.sh | 95 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100755 hugegraph-server/hugegraph-dist/src/assembly/travis/test-start-server.sh diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index f034a8c44e..c503bacf90 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -77,6 +77,7 @@ jobs: if: inputs.backend == 'rocksdb' run: | "$TRAVIS_DIR/test-wait-storage.sh" + "$TRAVIS_DIR/test-start-server.sh" "$TRAVIS_DIR/test-riscv64-java-runtime.sh" bash "$TRAVIS_DIR/test-tinkerpop-reports.sh" diff --git a/hugegraph-server/hugegraph-dist/src/assembly/travis/test-start-server.sh b/hugegraph-server/hugegraph-dist/src/assembly/travis/test-start-server.sh new file mode 100755 index 0000000000..fa9f1b2858 --- /dev/null +++ b/hugegraph-server/hugegraph-dist/src/assembly/travis/test-start-server.sh @@ -0,0 +1,95 @@ +#!/bin/bash +# +# 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. +# +# Verifies that start-server.sh can run twice on one configuration, as +# run-api-test.sh does: the second start must leave the config unchanged and +# each line the script appends must be there exactly once, since a key set +# twice is read back as a list (usePD as '[true, true]'). + +set -uo pipefail + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +START_SERVER="${1:-${SCRIPT_DIR}/start-server.sh}" +STATIC_DIR=$(cd "${SCRIPT_DIR}/../static" && pwd) +TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/start-server-test.XXXXXX") +FAILURES=0 + +trap 'rm -rf "${TMP_DIR}"' EXIT + +fail() { + echo "FAIL: $1" >&2 + FAILURES=$((FAILURES + 1)) +} + +start_server() { + if ! bash "$START_SERVER" "$server_dir" "$backend" > "${TMP_DIR}/start.log" 2>&1; then + cat "${TMP_DIR}/start.log" >&2 + fail "${backend}: start-server.sh exited non-zero" + return 1 + fi +} + +# The lines that set the key must be exactly key=value, or none if value is empty +assert_key() { + local file=$1 key=$2 value=$3 actual + actual=$(awk -v prefix="${key}=" 'index($0, prefix) == 1' "$file" | paste -sd ' ' -) + [[ "$actual" == "${value:+${key}=${value}}" ]] || + fail "${backend}: ${file##*/} has '${actual}' for ${key}, expected '${value:+${key}=${value}}'" +} + +if [[ ! -f "$START_SERVER" ]]; then + echo "ERROR: start script not found: $START_SERVER" + exit 2 +fi + +for backend in hstore hbase rocksdb memory; do + # A copy of the packaged files, with the backend initialization and the + # Server launch stubbed + server_dir="${TMP_DIR}/${backend}" + mkdir -p "${server_dir}/bin" "${server_dir}/conf/graphs" + cp "${STATIC_DIR}/bin/util.sh" "${server_dir}/bin/" + cp "${STATIC_DIR}/conf/rest-server.properties" "${STATIC_DIR}/conf/gremlin-server.yaml" "${server_dir}/conf/" + cp "${STATIC_DIR}/conf/graphs/hugegraph.properties" "${server_dir}/conf/graphs/" + printf '#!/bin/bash\ncat >/dev/null\n' > "${server_dir}/bin/init-store.sh" + printf '#!/bin/bash\n' > "${server_dir}/bin/start-hugegraph.sh" + chmod +x "${server_dir}/bin/init-store.sh" "${server_dir}/bin/start-hugegraph.sh" + + start_server || continue + cp -R "${server_dir}/conf" "${TMP_DIR}/${backend}-first-start" + start_server || continue + (cd "$TMP_DIR" && diff -ru "${backend}-first-start" "${backend}/conf") >&2 || + fail "${backend}: the second start changed the config as shown above" + + use_pd="" + hbase_timeout="" + case "$backend" in + hstore) use_pd=true ;; + hbase) hbase_timeout=200 ;; + esac + rest_conf="${server_dir}/conf/rest-server.properties" + assert_key "$rest_conf" usePD "$use_pd" + assert_key "$rest_conf" restserver.request_timeout "$hbase_timeout" + assert_key "$rest_conf" gremlinserver.timeout "$hbase_timeout" + assert_key "${server_dir}/conf/graphs/hugegraph.properties" schema.sync_deletion true +done + +if [[ "$FAILURES" -gt 0 ]]; then + echo "FAIL: ${FAILURES} check(s) failed after two starts" >&2 + exit 1 +fi + +echo "PASS: start-server.sh run twice sets each config line once for hstore, hbase, rocksdb and memory"