mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-11-10 21:32:43 +08:00
Refactor: remove API_PROXY_SCHEME (#20470)
This commit is contained in:
19 files changed
+155
-1113
No files matched your search
@@ -53,7 +53,6 @@ jobs:
|
||||
has_go_changes: ${{ steps.detect_changes.outputs.has_go_changes }}
|
||||
has_web_changes: ${{ steps.detect_changes.outputs.has_web_changes }}
|
||||
has_native_deepdoc_changes: ${{ steps.detect_changes.outputs.has_native_deepdoc_changes }}
|
||||
api_proxy_schemes: ${{ steps.detect_changes.outputs.api_proxy_schemes }}
|
||||
steps:
|
||||
- name: Ensure workspace ownership
|
||||
run: |
|
||||
@@ -213,27 +212,19 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
|
||||
api_proxy_schemes='["go"]'
|
||||
|
||||
echo "has_go_changes=${has_go}" >> $GITHUB_OUTPUT
|
||||
echo "has_web_changes=${has_web}" >> $GITHUB_OUTPUT
|
||||
echo "has_native_deepdoc_changes=${has_native_deepdoc}" >> $GITHUB_OUTPUT
|
||||
echo "api_proxy_schemes=${api_proxy_schemes}" >> $GITHUB_OUTPUT
|
||||
echo "Go: ${has_go}, Web: ${has_web}, Native DeepDoc: ${has_native_deepdoc}, proxy schemes: ${api_proxy_schemes}"
|
||||
echo "Go: ${has_go}, Web: ${has_web}, Native DeepDoc: ${has_native_deepdoc}"
|
||||
|
||||
ragflow_tests_infinity:
|
||||
name: ragflow_tests_infinity (${{ matrix.api_proxy_scheme }})
|
||||
name: ragflow_tests_infinity
|
||||
needs: ragflow_preflight
|
||||
if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target' || (github.event.pull_request.draft == false && contains(github.event.pull_request.labels.*.name, 'ci') && (github.event.action != 'labeled' || github.event.label.name == 'ci')) }}
|
||||
runs-on: [ "self-hosted", "ragflow-test" ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
api_proxy_scheme: ${{ fromJSON(needs.ragflow_preflight.outputs.api_proxy_schemes) }}
|
||||
env:
|
||||
DOC_ENGINE: infinity
|
||||
API_PROXY_SCHEME: ${{ matrix.api_proxy_scheme }}
|
||||
RAGFLOW_IMAGE: infiniflow/ragflow:${{ github.run_id }}-infinity-${{ matrix.api_proxy_scheme }}
|
||||
RAGFLOW_IMAGE: infiniflow/ragflow:${{ github.run_id }}-infinity
|
||||
HTTP_API_TEST_LEVEL: ${{ needs.ragflow_preflight.outputs.http_api_test_level }}
|
||||
HAS_GO: ${{ needs.ragflow_preflight.outputs.has_go_changes }}
|
||||
HAS_WEB: ${{ needs.ragflow_preflight.outputs.has_web_changes }}
|
||||
@@ -254,7 +245,6 @@ jobs:
|
||||
allow-unsafe-pr-checkout: true
|
||||
|
||||
- name: Build ragflow go server
|
||||
if: env.API_PROXY_SCHEME == 'go'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BUILDER_CONTAINER=ragflow_build_${GITHUB_RUN_ID}_${DOC_ENGINE}_$(od -An -N4 -tx4 /dev/urandom | tr -d ' ')
|
||||
@@ -276,7 +266,6 @@ jobs:
|
||||
./build.sh --go
|
||||
|
||||
- name: Run Go unit tests
|
||||
if: env.API_PROXY_SCHEME == 'go'
|
||||
# Runs after `./build.sh --go`, which guarantees the C++ static
|
||||
# library (librag_tokenizer_c_api.a) is present on disk. The Go
|
||||
# test binaries link against it transitively through
|
||||
@@ -388,19 +377,14 @@ jobs:
|
||||
# Dockerfile / Dockerfile_ci read it from ARG GITEE_TOKEN (NOT a BuildKit secret),
|
||||
# so the runner must expose GITEE_TOKEN as an environment variable (e.g. via the
|
||||
# runner's docker-compose `environment:` mapping sourced from its .env file).
|
||||
# Pick the Dockerfile matching the API proxy scheme:
|
||||
# - go -> Dockerfile (Go-native image)
|
||||
# - * -> Dockerfile_ci (Python/legacy image)
|
||||
DOCKERFILE=Dockerfile
|
||||
(
|
||||
flock -w 10800 9 || { echo "Timed out waiting for the shared Docker build slot" >&2; exit 1; }
|
||||
echo "Acquired Docker build slot for ${DOC_ENGINE}/${API_PROXY_SCHEME} (dockerfile=${DOCKERFILE})"
|
||||
echo "Acquired Docker build slot for ${DOC_ENGINE}"
|
||||
##sudo docker pull ubuntu:24.04
|
||||
sudo DOCKER_BUILDKIT=1 docker build --build-arg NEED_MIRROR=1 --build-arg HTTPS_PROXY=${HTTPS_PROXY} --build-arg HTTP_PROXY=${HTTP_PROXY} --build-arg GITEE_TOKEN=${GITEE_TOKEN} -f "${DOCKERFILE}" -t ${RAGFLOW_IMAGE} .
|
||||
sudo DOCKER_BUILDKIT=1 docker build --build-arg NEED_MIRROR=1 --build-arg HTTPS_PROXY=${HTTPS_PROXY} --build-arg HTTP_PROXY=${HTTP_PROXY} --build-arg GITEE_TOKEN=${GITEE_TOKEN} -f Dockerfile -t ${RAGFLOW_IMAGE} .
|
||||
) 9>"${BUILD_LOCK_FILE}"
|
||||
|
||||
- name: Prepare Python test environment
|
||||
if: env.API_PROXY_SCHEME != 'web'
|
||||
run: |
|
||||
git config --global url."https://oauth2:${GITEE_TOKEN}@gitee.com/".insteadOf "https://gitee.com/"
|
||||
uv sync --python 3.13 --group test --frozen
|
||||
@@ -414,10 +398,10 @@ jobs:
|
||||
## ss already installed
|
||||
##sudo apt update && sudo apt install -y iproute2
|
||||
RUNNER_WORKSPACE_PREFIX=${RUNNER_WORKSPACE_PREFIX:-${HOME}}
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-${DOC_ENGINE}-${API_PROXY_SCHEME}"
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-${DOC_ENGINE}"
|
||||
echo "COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}" >> ${GITHUB_ENV}
|
||||
echo "RAGFLOW_CONTAINER=${COMPOSE_PROJECT_NAME}-ragflow-cpu-1" >> ${GITHUB_ENV}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}/${API_PROXY_SCHEME}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}
|
||||
echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> ${GITHUB_ENV}
|
||||
rm -rf "${ARTIFACTS_DIR}" && mkdir -p "${ARTIFACTS_DIR}"
|
||||
|
||||
@@ -607,7 +591,7 @@ jobs:
|
||||
|
||||
# Persist computed ports into .env so docker-compose uses the correct host bindings.
|
||||
# Remove previous CI overrides first; docker compose uses the last duplicate key.
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d;/^API_PROXY_SCHEME=/d' .env
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d' .env
|
||||
# docker-compose-go.yml uses env_file: .env-go for the ragflow-cpu
|
||||
# container, so the Go server process reads COMPOSE_PROFILES and
|
||||
# TEI_MODEL from .env (not .env). Without syncing these two,
|
||||
@@ -644,7 +628,6 @@ jobs:
|
||||
echo "TEI_MODEL=BAAI/bge-small-en-v1.5"
|
||||
echo "RAGFLOW_IMAGE=${RAGFLOW_IMAGE}"
|
||||
echo "DOC_ENGINE=${DOC_ENGINE}"
|
||||
echo "API_PROXY_SCHEME=${API_PROXY_SCHEME}"
|
||||
} >> .env
|
||||
# Sync COMPOSE_PROFILES and TEI_MODEL into .env so the Go
|
||||
# server container (env_file: .env) sees the same TEI bypass
|
||||
@@ -675,7 +658,6 @@ jobs:
|
||||
sudo docker compose -f "${COMPOSE_FILE}" -p ${COMPOSE_PROJECT_NAME} up -d
|
||||
|
||||
- name: Run New RESTFUL api tests against Infinity
|
||||
if: env.API_PROXY_SCHEME != 'web'
|
||||
run: |
|
||||
export http_proxy=""; export https_proxy=""; export no_proxy=""; export HTTP_PROXY=""; export HTTPS_PROXY=""; export NO_PROXY=""
|
||||
svc_ready=0
|
||||
@@ -710,7 +692,7 @@ jobs:
|
||||
run: |
|
||||
set -uo pipefail
|
||||
RUNNER_WORKSPACE_PREFIX="${RUNNER_WORKSPACE_PREFIX:-${HOME}}"
|
||||
ARTIFACTS_DIR="${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}/${API_PROXY_SCHEME}"
|
||||
ARTIFACTS_DIR="${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}"
|
||||
LOG_DEST="${ARTIFACTS_DIR}/ragflow-logs-infinity"
|
||||
mkdir -p "${ARTIFACTS_DIR}"
|
||||
if [ -d docker/ragflow-logs ]; then
|
||||
@@ -749,18 +731,13 @@ jobs:
|
||||
|
||||
|
||||
ragflow_tests_elasticsearch:
|
||||
name: ragflow_tests_elasticsearch (${{ matrix.api_proxy_scheme }})
|
||||
name: ragflow_tests_elasticsearch
|
||||
needs: ragflow_preflight
|
||||
if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target' || (github.event.pull_request.draft == false && contains(github.event.pull_request.labels.*.name, 'ci') && (github.event.action != 'labeled' || github.event.label.name == 'ci')) }}
|
||||
runs-on: [ "self-hosted", "ragflow-test" ]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
api_proxy_scheme: ${{ fromJSON(needs.ragflow_preflight.outputs.api_proxy_schemes) }}
|
||||
env:
|
||||
DOC_ENGINE: elasticsearch
|
||||
API_PROXY_SCHEME: ${{ matrix.api_proxy_scheme }}
|
||||
RAGFLOW_IMAGE: infiniflow/ragflow:${{ github.run_id }}-elasticsearch-${{ matrix.api_proxy_scheme }}
|
||||
RAGFLOW_IMAGE: infiniflow/ragflow:${{ github.run_id }}-elasticsearch
|
||||
HTTP_API_TEST_LEVEL: ${{ needs.ragflow_preflight.outputs.http_api_test_level }}
|
||||
HAS_GO: ${{ needs.ragflow_preflight.outputs.has_go_changes }}
|
||||
HAS_WEB: ${{ needs.ragflow_preflight.outputs.has_web_changes }}
|
||||
@@ -781,7 +758,6 @@ jobs:
|
||||
allow-unsafe-pr-checkout: true
|
||||
|
||||
- name: Build ragflow go server
|
||||
if: env.API_PROXY_SCHEME == 'go'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
BUILDER_CONTAINER=ragflow_build_${GITHUB_RUN_ID}_${DOC_ENGINE}_$(od -An -N4 -tx4 /dev/urandom | tr -d ' ')
|
||||
@@ -803,7 +779,6 @@ jobs:
|
||||
./build.sh --go
|
||||
|
||||
- name: Run Go unit tests
|
||||
if: env.API_PROXY_SCHEME == 'go'
|
||||
# Runs after `./build.sh --go`, which guarantees the C++ static
|
||||
# library (librag_tokenizer_c_api.a) is present on disk. The Go
|
||||
# test binaries link against it transitively through
|
||||
@@ -906,7 +881,6 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Run ragflow_deps regression guards
|
||||
if: env.API_PROXY_SCHEME == 'go'
|
||||
# Pure-Python, local, needs no API keys or model downloads; guards (a) the
|
||||
# ONNX Runtime extraction logic the in-process (Go) DeepDoc backend build
|
||||
# depends on (notably the version-bump path C2 hardened) and (b) the
|
||||
@@ -930,19 +904,14 @@ jobs:
|
||||
# Dockerfile / Dockerfile_ci read it from ARG GITEE_TOKEN (NOT a BuildKit secret),
|
||||
# so the runner must expose GITEE_TOKEN as an environment variable (e.g. via the
|
||||
# runner's docker-compose `environment:` mapping sourced from its .env file).
|
||||
# Pick the Dockerfile matching the API proxy scheme:
|
||||
# - go -> Dockerfile (Go-native image)
|
||||
# - * -> Dockerfile_ci (Python/legacy image)
|
||||
DOCKERFILE=Dockerfile
|
||||
(
|
||||
flock -w 10800 9 || { echo "Timed out waiting for the shared Docker build slot" >&2; exit 1; }
|
||||
echo "Acquired Docker build slot for ${DOC_ENGINE}/${API_PROXY_SCHEME} (dockerfile=${DOCKERFILE})"
|
||||
echo "Acquired Docker build slot for ${DOC_ENGINE}"
|
||||
##sudo docker pull ubuntu:24.04
|
||||
sudo DOCKER_BUILDKIT=1 docker build --build-arg NEED_MIRROR=1 --build-arg HTTPS_PROXY=${HTTPS_PROXY} --build-arg HTTP_PROXY=${HTTP_PROXY} --build-arg GITEE_TOKEN=${GITEE_TOKEN} -f "${DOCKERFILE}" -t ${RAGFLOW_IMAGE} .
|
||||
sudo DOCKER_BUILDKIT=1 docker build --build-arg NEED_MIRROR=1 --build-arg HTTPS_PROXY=${HTTPS_PROXY} --build-arg HTTP_PROXY=${HTTP_PROXY} --build-arg GITEE_TOKEN=${GITEE_TOKEN} -f Dockerfile -t ${RAGFLOW_IMAGE} .
|
||||
) 9>"${BUILD_LOCK_FILE}"
|
||||
|
||||
- name: Prepare Python test environment
|
||||
if: env.API_PROXY_SCHEME != 'web'
|
||||
run: |
|
||||
git config --global url."https://oauth2:${GITEE_TOKEN}@gitee.com/".insteadOf "https://gitee.com/"
|
||||
uv sync --python 3.13 --group test --frozen
|
||||
@@ -956,10 +925,10 @@ jobs:
|
||||
## ss already installed
|
||||
##sudo apt update && sudo apt install -y iproute2
|
||||
RUNNER_WORKSPACE_PREFIX=${RUNNER_WORKSPACE_PREFIX:-${HOME}}
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-${DOC_ENGINE}-${API_PROXY_SCHEME}"
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-${DOC_ENGINE}"
|
||||
echo "COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}" >> ${GITHUB_ENV}
|
||||
echo "RAGFLOW_CONTAINER=${COMPOSE_PROJECT_NAME}-ragflow-cpu-1" >> ${GITHUB_ENV}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}/${API_PROXY_SCHEME}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}
|
||||
echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> ${GITHUB_ENV}
|
||||
rm -rf "${ARTIFACTS_DIR}" && mkdir -p "${ARTIFACTS_DIR}"
|
||||
|
||||
@@ -1149,7 +1118,7 @@ jobs:
|
||||
|
||||
# Persist computed ports into .env so docker-compose uses the correct host bindings.
|
||||
# Remove previous CI overrides first; docker compose uses the last duplicate key.
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d;/^API_PROXY_SCHEME=/d' .env
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d' .env
|
||||
# docker-compose-go.yml uses env_file: .env-go for the ragflow-cpu
|
||||
# container, so the Go server process reads COMPOSE_PROFILES and
|
||||
# TEI_MODEL from .env (not .env). Without syncing these two,
|
||||
@@ -1186,7 +1155,6 @@ jobs:
|
||||
echo "TEI_MODEL=BAAI/bge-small-en-v1.5"
|
||||
echo "RAGFLOW_IMAGE=${RAGFLOW_IMAGE}"
|
||||
echo "DOC_ENGINE=${DOC_ENGINE}"
|
||||
echo "API_PROXY_SCHEME=${API_PROXY_SCHEME}"
|
||||
} >> .env
|
||||
# Sync COMPOSE_PROFILES and TEI_MODEL into .env so the Go
|
||||
# server container (env_file: .env) sees the same TEI bypass
|
||||
@@ -1216,7 +1184,6 @@ jobs:
|
||||
sudo docker compose -f "${COMPOSE_FILE}" -p ${COMPOSE_PROJECT_NAME} up -d
|
||||
|
||||
- name: Run New RESTFUL api tests against Elasticsearch
|
||||
if: env.API_PROXY_SCHEME != 'web'
|
||||
run: |
|
||||
export http_proxy=""; export https_proxy=""; export no_proxy=""; export HTTP_PROXY=""; export HTTPS_PROXY=""; export NO_PROXY=""
|
||||
svc_ready=0
|
||||
@@ -1243,7 +1210,7 @@ jobs:
|
||||
run: |
|
||||
set -uo pipefail
|
||||
RUNNER_WORKSPACE_PREFIX="${RUNNER_WORKSPACE_PREFIX:-${HOME}}"
|
||||
ARTIFACTS_DIR="${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}/${API_PROXY_SCHEME}"
|
||||
ARTIFACTS_DIR="${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}"
|
||||
LOG_DEST="${ARTIFACTS_DIR}/ragflow-logs-es"
|
||||
mkdir -p "${ARTIFACTS_DIR}"
|
||||
if [ -d docker/ragflow-logs ]; then
|
||||
@@ -1390,7 +1357,6 @@ jobs:
|
||||
runs-on: [ "self-hosted", "ragflow-test" ]
|
||||
env:
|
||||
DOC_ENGINE: infinity
|
||||
API_PROXY_SCHEME: go
|
||||
steps:
|
||||
- name: Ensure workspace ownership
|
||||
run: |
|
||||
@@ -1436,10 +1402,10 @@ jobs:
|
||||
## ss already installed
|
||||
##sudo apt update && sudo apt install -y iproute2
|
||||
RUNNER_WORKSPACE_PREFIX=${RUNNER_WORKSPACE_PREFIX:-${HOME}}
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-go-int-${DOC_ENGINE}-${API_PROXY_SCHEME}"
|
||||
COMPOSE_PROJECT_NAME="${GITHUB_RUN_ID}-go-int-${DOC_ENGINE}"
|
||||
echo "COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}" >> ${GITHUB_ENV}
|
||||
echo "RAGFLOW_CONTAINER=${COMPOSE_PROJECT_NAME}-ragflow-cpu-1" >> ${GITHUB_ENV}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}/${API_PROXY_SCHEME}
|
||||
ARTIFACTS_DIR=${RUNNER_WORKSPACE_PREFIX}/artifacts/${GITHUB_REPOSITORY}/${GITHUB_RUN_ID}/${DOC_ENGINE}
|
||||
echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> ${GITHUB_ENV}
|
||||
rm -rf "${ARTIFACTS_DIR}" && mkdir -p "${ARTIFACTS_DIR}"
|
||||
|
||||
@@ -1629,7 +1595,7 @@ jobs:
|
||||
|
||||
# Persist computed ports into .env so docker-compose uses the correct host bindings.
|
||||
# Remove previous CI overrides first; docker compose uses the last duplicate key.
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d;/^API_PROXY_SCHEME=/d' .env
|
||||
sed -i '/^ES_PORT=/d;/^OS_PORT=/d;/^INFINITY_THRIFT_PORT=/d;/^INFINITY_HTTP_PORT=/d;/^INFINITY_PSQL_PORT=/d;/^EXPOSE_MYSQL_PORT=/d;/^MINIO_PORT=/d;/^MINIO_CONSOLE_PORT=/d;/^REDIS_PORT=/d;/^KVROCKS_PORT=/d;/^EXPOSE_NATS_PORT=/d;/^EXPOSE_NATS_MONITORING_PORT=/d;/^NATS_MONITORING_PORT=/d;/^TEI_PORT=/d;/^KIBANA_PORT=/d;/^SVR_HTTP_PORT=/d;/^ADMIN_SVR_HTTP_PORT=/d;/^SVR_MCP_PORT=/d;/^SANDBOX_EXECUTOR_MANAGER_PORT=/d;/^SVR_WEB_HTTP_PORT=/d;/^SVR_WEB_HTTPS_PORT=/d;/^EXPOSE_CLICKHOUSE_TCP_PORT=/d;/^CLICKHOUSE_HTTP_PORT=/d;/^COMPOSE_PROFILES=/d;/^TEI_MODEL=/d;/^RAGFLOW_IMAGE=/d;/^DOC_ENGINE=/d' .env
|
||||
# docker-compose-go.yml uses env_file: .env-go for the ragflow-cpu
|
||||
# container, so the Go server process reads COMPOSE_PROFILES and
|
||||
# TEI_MODEL from .env (not .env). Without syncing these two,
|
||||
@@ -1672,7 +1638,6 @@ jobs:
|
||||
echo "COMPOSE_PROFILES=infinity,ragflow-go,tei-cpu,metadata-mysql,clickhouse"
|
||||
echo "TEI_MODEL=BAAI/bge-small-en-v1.5"
|
||||
echo "DOC_ENGINE=${DOC_ENGINE}"
|
||||
echo "API_PROXY_SCHEME=${API_PROXY_SCHEME}"
|
||||
} >> .env
|
||||
# Sync COMPOSE_PROFILES and TEI_MODEL into .env so the Go
|
||||
# server container (env_file: .env) sees the same TEI bypass
|
||||
|
||||
@@ -264,10 +264,6 @@ SVR_MCP_PORT=9382
|
||||
# first login.
|
||||
ADMIN_DEFAULT_PASSWORD=admin
|
||||
|
||||
# API_PROXY_SCHEME=hybrid # go and python hybrid deploy mode
|
||||
API_PROXY_SCHEME=go
|
||||
#API_PROXY_SCHEME=python # use pure python server deployment
|
||||
|
||||
# Development-only: set to 1 to bypass host safety checks for test_db_connection and allow private/local database hosts.
|
||||
# Do not enable in production.
|
||||
ALLOW_ANY_HOST=0
|
||||
|
||||
@@ -12,10 +12,10 @@ usage() {
|
||||
echo " --debug Enable debug mode and debug-level logging"
|
||||
echo
|
||||
echo "Available service types:"
|
||||
echo " ragflow Start RAGFlow server based on API_PROXY_SCHEME"
|
||||
echo " task_executor Start task workers based on API_PROXY_SCHEME"
|
||||
echo " admin Start Admin server based on API_PROXY_SCHEME"
|
||||
echo " data_sync Start the data source syncer based on API_PROXY_SCHEME"
|
||||
echo " ragflow Start RAGFlow server"
|
||||
echo " task_executor Start task workers"
|
||||
echo " admin Start Admin server"
|
||||
echo " data_sync Start the data source syncer"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0"
|
||||
@@ -50,12 +50,8 @@ load_env_file
|
||||
|
||||
# Unset HTTP proxies that might be set by Docker daemon
|
||||
export http_proxy=""; export https_proxy=""; export no_proxy=""; export HTTP_PROXY=""; export HTTPS_PROXY=""; export NO_PROXY=""
|
||||
export PYTHONPATH=$(pwd)
|
||||
|
||||
export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/
|
||||
JEMALLOC_PATH=$(pkg-config --variable=libdir jemalloc)/libjemalloc.so
|
||||
|
||||
PY=python3
|
||||
|
||||
# Set default number of workers if WS is not set or less than 1
|
||||
if [[ -z "$WS" || $WS -lt 1 ]]; then
|
||||
@@ -95,25 +91,18 @@ trap cleanup SIGINT SIGTERM
|
||||
# Function to execute task_executor with retry logic
|
||||
task_exe(){
|
||||
local task_id=$1
|
||||
local task_name="task_executor.py for task $task_id"
|
||||
local -a task_cmd=("$PY" "rag/svr/task_executor.py" "-i" "$task_id")
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
prepare_for_go
|
||||
task_name="ragflow_server --ingestor"
|
||||
task_cmd=("bin/ragflow_server" "--ingestor")
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
task_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local task_name="ragflow_server --ingestor"
|
||||
local -a task_cmd=("bin/ragflow_server" "--ingestor")
|
||||
prepare_for_go
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
task_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local retry_count=0
|
||||
|
||||
while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do
|
||||
echo "Starting ${task_cmd[*]} (Attempt $((retry_count+1)))"
|
||||
EXIT_CODE=0
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
"${task_cmd[@]}" || EXIT_CODE=$?
|
||||
else
|
||||
LD_PRELOAD=$JEMALLOC_PATH "${task_cmd[@]}" || EXIT_CODE=$?
|
||||
fi
|
||||
"${task_cmd[@]}" || EXIT_CODE=$?
|
||||
if [ $EXIT_CODE -eq 0 ]; then
|
||||
echo "$task_name exited successfully."
|
||||
break
|
||||
@@ -132,17 +121,11 @@ task_exe(){
|
||||
|
||||
# Function to execute ragflow_server with retry logic
|
||||
run_server(){
|
||||
local server_name="ragflow_server.py"
|
||||
local -a server_cmd=("$PY" "api/ragflow_server.py")
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
prepare_for_go
|
||||
server_name="ragflow_server"
|
||||
server_cmd=("bin/ragflow_server" "--api")
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
server_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
elif [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
server_cmd+=("--debug")
|
||||
local server_name="ragflow_server"
|
||||
local -a server_cmd=("bin/ragflow_server" "--api")
|
||||
prepare_for_go
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
server_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local retry_count=0
|
||||
while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do
|
||||
@@ -167,15 +150,11 @@ run_server(){
|
||||
|
||||
# Function to execute admin_server with retry logic
|
||||
run_admin_server(){
|
||||
local server_name="admin_server.py"
|
||||
local -a server_cmd=("$PY" "admin/server/admin_server.py")
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
prepare_for_go
|
||||
server_name="admin_server"
|
||||
server_cmd=("bin/ragflow_server" "--admin")
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
server_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local server_name="admin_server"
|
||||
local -a server_cmd=("bin/ragflow_server" "--admin")
|
||||
prepare_for_go
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
server_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local retry_count=0
|
||||
while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do
|
||||
@@ -199,15 +178,11 @@ run_admin_server(){
|
||||
|
||||
# Function to execute sync_data_source with retry logic
|
||||
run_data_sync(){
|
||||
local server_name="sync_data_source.py"
|
||||
local -a sync_cmd=("$PY" "rag/svr/sync_data_source.py")
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
prepare_for_go
|
||||
server_name="ragflow_server --syncer"
|
||||
sync_cmd=("bin/ragflow_server" "--syncer")
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
sync_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local server_name="ragflow_server --syncer"
|
||||
local -a sync_cmd=("bin/ragflow_server" "--syncer")
|
||||
prepare_for_go
|
||||
if [[ "$DEBUG_MODE" -eq 1 ]]; then
|
||||
sync_cmd+=("--log-level" "debug")
|
||||
fi
|
||||
local retry_count=0
|
||||
while ! $STOP && [ $retry_count -lt $MAX_RETRIES ]; do
|
||||
@@ -230,12 +205,6 @@ run_data_sync(){
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_db_init() {
|
||||
echo "Initializing database tables..."
|
||||
"$PY" -c "from api.db.db_models import init_database_tables as init_web_db; init_web_db()"
|
||||
echo "Database tables initialized."
|
||||
}
|
||||
|
||||
run_migrations() {
|
||||
local db_type="${DB_TYPE:-mysql}"
|
||||
db_type="${db_type,,}"
|
||||
@@ -246,15 +215,10 @@ run_migrations() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "${API_PROXY_SCHEME}" == "go" ]]; then
|
||||
# The Go backend owns the model provider tables. --migrate is a
|
||||
# standalone action: it runs the migrations and exits, so it is
|
||||
# independent of any server actually starting.
|
||||
echo "Running model provider table migrations (go)..."
|
||||
bin/ragflow_server --migrate
|
||||
else
|
||||
tools/scripts/run_migrations.sh
|
||||
fi
|
||||
# --migrate is a standalone action: it runs the migrations and exits, so it
|
||||
# is independent of any server actually starting.
|
||||
echo "Running model provider table migrations..."
|
||||
bin/ragflow_server --migrate
|
||||
}
|
||||
|
||||
prepare_for_go() {
|
||||
@@ -317,23 +281,12 @@ for arg in "$@"; do
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$DEBUG_MODE" -eq 1 && "${API_PROXY_SCHEME}" != "go" ]]; then
|
||||
export LOG_LEVELS="root=DEBUG"
|
||||
fi
|
||||
|
||||
if [[ "$SERVICE_SELECTED" -eq 0 ]]; then
|
||||
START_RAGFLOW=1
|
||||
START_TASK_EXECUTOR=1
|
||||
fi
|
||||
|
||||
if [[ "$START_RAGFLOW" -eq 1 ]]; then
|
||||
# The Go backend owns the schema when it serves the API, so skip the
|
||||
# Python-side table creation then. A Go-only deployment may not ship the api
|
||||
# package at all, and letting both sides create tables makes them fight over
|
||||
# the same schema.
|
||||
if [[ "${API_PROXY_SCHEME}" != "go" ]]; then
|
||||
ensure_db_init
|
||||
fi
|
||||
run_migrations
|
||||
fi
|
||||
|
||||
|
||||
@@ -948,9 +948,8 @@ func (h *DatasetsHandler) AggregateTags(c *gin.Context) {
|
||||
}
|
||||
|
||||
// GetCompilationStatus returns the dataset-level knowledge-compile lifecycle
|
||||
// state (scheduler contract for API_PROXY_SCHEME=go/hybrid). It replaces the
|
||||
// Python-era TraceIndex task-progress endpoint for the Go backend. The optional
|
||||
// `kind` query parameter scopes the status to one compile type.
|
||||
// state. The optional `kind` query parameter scopes the status to one compile
|
||||
// type.
|
||||
func (h *DatasetsHandler) GetCompilationStatus(c *gin.Context) {
|
||||
user, errorCode, errorMessage := GetUser(c)
|
||||
if errorCode != common.CodeSuccess {
|
||||
|
||||
@@ -340,8 +340,8 @@ func (r *Router) Setup(engine *gin.Engine) {
|
||||
datasets.GET("/:dataset_id/graph", r.datasetsHandler.GetKnowledgeGraph)
|
||||
datasets.POST("/:dataset_id/embedding/check", r.datasetsHandler.CheckEmbedding)
|
||||
datasets.POST("/:dataset_id/documents/batch-update-status", r.documentHandler.BatchUpdateDocumentStatus)
|
||||
// Scheduler compile-status contract (API_PROXY_SCHEME=go/hybrid);
|
||||
// replaces the retired RunIndex/TraceIndex/DeleteIndex /index routes.
|
||||
// Scheduler compile-status contract; replaces the retired
|
||||
// RunIndex/TraceIndex/DeleteIndex /index routes.
|
||||
datasets.GET("/:dataset_id/compilation/status", r.datasetsHandler.GetCompilationStatus)
|
||||
|
||||
// Knowledge-compilation wiki artifacts
|
||||
|
||||
@@ -15,9 +15,7 @@ import (
|
||||
)
|
||||
|
||||
// CompilationStatus is the dataset-level knowledge-compile lifecycle state
|
||||
// surfaced by GET /datasets/:id/compilation/status. It is the Go scheduler
|
||||
// contract that replaces the Python-era RunIndex/TraceIndex task progress for
|
||||
// API_PROXY_SCHEME=go / hybrid.
|
||||
// surfaced by GET /datasets/:id/compilation/status.
|
||||
//
|
||||
// State only takes one of idle/pending/running/completed. Error is NOT a fifth
|
||||
// state: it is a diagnostic attached to a pending/running batch left for retry,
|
||||
|
||||
@@ -13,43 +13,16 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
_DOCKER_ENV = Path(__file__).resolve().parents[2] / "docker" / ".env"
|
||||
|
||||
|
||||
def _docker_env_value(name: str) -> str | None:
|
||||
if not _DOCKER_ENV.exists():
|
||||
return None
|
||||
for line in _DOCKER_ENV.read_text().splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
if key.strip() == name:
|
||||
return value.split("#", 1)[0].strip().strip('"').strip("'")
|
||||
return None
|
||||
|
||||
|
||||
def _config_value(name: str, default: str | None = None) -> str | None:
|
||||
return os.getenv(name) or _docker_env_value(name) or default
|
||||
|
||||
|
||||
API_PROXY_SCHEME = _config_value("API_PROXY_SCHEME", "python")
|
||||
IS_GO_PROXY = API_PROXY_SCHEME == "go"
|
||||
SDK_UNAUTHORIZED_ERROR_MESSAGE = "Invalid access token" if IS_GO_PROXY else "<Unauthorized '401: Unauthorized'>"
|
||||
|
||||
|
||||
def _default_host_address() -> str:
|
||||
return "http://127.0.0.1:9380"
|
||||
|
||||
|
||||
HOST_ADDRESS = os.getenv("HOST_ADDRESS") or _default_host_address()
|
||||
logging.info("Resolved API proxy configuration: scheme=%s, is_go_proxy=%s, host_address=%s", API_PROXY_SCHEME, IS_GO_PROXY, HOST_ADDRESS)
|
||||
VERSION = "v1"
|
||||
ZHIPU_AI_API_KEY = os.getenv("ZHIPU_AI_API_KEY")
|
||||
if ZHIPU_AI_API_KEY is None:
|
||||
|
||||
@@ -95,7 +95,7 @@ import time
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from test.testcases.configs import API_PROXY_SCHEME, EMAIL, HOST_ADDRESS, IS_GO_PROXY, PASSWORD, SILICONFLOW_API_KEY, VERSION, ZHIPU_AI_API_KEY
|
||||
from test.testcases.configs import EMAIL, HOST_ADDRESS, PASSWORD, SILICONFLOW_API_KEY, VERSION, ZHIPU_AI_API_KEY
|
||||
|
||||
MARKER_EXPRESSIONS = {
|
||||
"p1": "p1",
|
||||
@@ -179,13 +179,7 @@ def _auth_with_admin_bootstrap_retry():
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def auth():
|
||||
if IS_GO_PROXY:
|
||||
return _auth_with_admin_bootstrap_retry()
|
||||
try:
|
||||
register()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return login()
|
||||
return _auth_with_admin_bootstrap_retry()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
@@ -207,24 +201,14 @@ def get_added_models(auth, factory_name):
|
||||
res = response.json()
|
||||
if res.get("code") != 0:
|
||||
raise Exception(res.get("message"))
|
||||
# Go server (post-Python port) serializes this field as `model_provider`
|
||||
# in the RESTful `/api/v1/models` response. Fall back to the legacy
|
||||
# `provider_name` key so this conftest works against both.
|
||||
added_factory = {model.get("model_provider") or model["provider_name"] for model in res.get("data", [])}
|
||||
if API_PROXY_SCHEME == "go":
|
||||
added_factory = {provider.casefold() for provider in added_factory}
|
||||
factory_name = factory_name.casefold()
|
||||
if factory_name in added_factory:
|
||||
return True
|
||||
return False
|
||||
added_factory = {model["provider_name"].casefold() for model in res.get("data", [])}
|
||||
return factory_name.casefold() in added_factory
|
||||
|
||||
|
||||
def _response_json_or_warning(response, action: str) -> dict:
|
||||
try:
|
||||
return response.json()
|
||||
except ValueError:
|
||||
if API_PROXY_SCHEME != "go":
|
||||
raise
|
||||
message = response.text.strip() or response.reason or "empty response body"
|
||||
return {
|
||||
"code": response.status_code or -1,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import IS_GO_PROXY
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
from test.testcases.restful_api.helpers.client import RestClient
|
||||
from utils.file_utils import create_txt_file
|
||||
@@ -102,8 +101,6 @@ GO_ONLY_SKIPS = {
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items):
|
||||
if not IS_GO_PROXY:
|
||||
return
|
||||
for item in items:
|
||||
test_name = item.name.split("[", 1)[0]
|
||||
for reason, skipped_tests in GO_ONLY_SKIPS.items():
|
||||
|
||||
@@ -14,17 +14,10 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
from test.testcases.configs import IS_GO_PROXY
|
||||
|
||||
|
||||
def assert_auth_error(payload: dict, scenario_name: str) -> None:
|
||||
assert payload["code"] == 401, (scenario_name, payload)
|
||||
if IS_GO_PROXY:
|
||||
if scenario_name == "missing token":
|
||||
assert payload["message"] == "Missing Authorization header", (scenario_name, payload)
|
||||
else:
|
||||
assert payload["message"] in {"Invalid access token", "Invalid auth credentials"}, (scenario_name, payload)
|
||||
return
|
||||
if scenario_name == "missing token":
|
||||
assert payload["message"] == "Missing Authorization header", (scenario_name, payload)
|
||||
else:
|
||||
expected = "<Unauthorized '401: Unauthorized'>"
|
||||
assert payload["message"] == expected, (scenario_name, payload)
|
||||
assert payload["message"] in {"Invalid access token", "Invalid auth credentials"}, (scenario_name, payload)
|
||||
@@ -19,7 +19,7 @@ from typing import Any
|
||||
|
||||
import pytest
|
||||
import requests
|
||||
from test.testcases.configs import HOST_ADDRESS, IS_GO_PROXY, VERSION
|
||||
from test.testcases.configs import HOST_ADDRESS, VERSION
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -69,18 +69,17 @@ class RestClient:
|
||||
timeout=timeout,
|
||||
**request_kwargs,
|
||||
)
|
||||
if IS_GO_PROXY:
|
||||
try:
|
||||
payload = response.json()
|
||||
except ValueError:
|
||||
return response
|
||||
if not isinstance(payload, dict):
|
||||
return response
|
||||
message = payload.get("message", "")
|
||||
if payload.get("code") == 500 and "Unknown column 'meta_fields'" in message:
|
||||
pytest.skip("Go deployment database schema is missing document.meta_fields")
|
||||
if payload.get("code") == 500 and "http://localhost:6380/embed" in message and "connect: connection refused" in message:
|
||||
pytest.skip("Go memory embedding service is unavailable on localhost:6380")
|
||||
try:
|
||||
payload = response.json()
|
||||
except ValueError:
|
||||
return response
|
||||
if not isinstance(payload, dict):
|
||||
return response
|
||||
message = payload.get("message", "")
|
||||
if payload.get("code") == 500 and "Unknown column 'meta_fields'" in message:
|
||||
pytest.skip("Go deployment database schema is missing document.meta_fields")
|
||||
if payload.get("code") == 500 and "http://localhost:6380/embed" in message and "connect: connection refused" in message:
|
||||
pytest.skip("Go memory embedding service is unavailable on localhost:6380")
|
||||
return response
|
||||
|
||||
def get(self, path: str, **kwargs) -> requests.Response:
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
os.environ.get("API_PROXY_SCHEME", "python") != "go",
|
||||
reason="Go mode only (set API_PROXY_SCHEME=go + bin/ragflow_server on 9380)",
|
||||
)
|
||||
|
||||
V2_DSL = {
|
||||
"graph": {
|
||||
"nodes": [
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -16,7 +16,7 @@
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import INVALID_API_TOKEN, IS_GO_PROXY
|
||||
from test.testcases.configs import INVALID_API_TOKEN
|
||||
from test.testcases.restful_api.helpers.assertions import assert_auth_error
|
||||
from test.testcases.restful_api.helpers.client import RestClient
|
||||
|
||||
@@ -41,14 +41,10 @@ def test_document_image_invalid_id_contract(rest_client):
|
||||
)
|
||||
def test_private_document_images_require_auth(rest_client_noauth, path):
|
||||
res = rest_client_noauth.get(path)
|
||||
if IS_GO_PROXY:
|
||||
assert res.status_code == 200, res.text
|
||||
payload = res.json()
|
||||
assert payload["code"] == 102, payload
|
||||
assert payload["message"] == "Authorization is not valid!", payload
|
||||
return
|
||||
assert res.status_code == 401, res.text
|
||||
assert_auth_error(res.json(), "missing token")
|
||||
assert res.status_code == 200, res.text
|
||||
payload = res.json()
|
||||
assert payload["code"] == 102, payload
|
||||
assert payload["message"] == "Authorization is not valid!", payload
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
|
||||
@@ -27,7 +27,7 @@ from requests_toolbelt import MultipartEncoder
|
||||
from utils import wait_for
|
||||
from utils.file_utils import create_txt_file
|
||||
|
||||
from test.testcases.configs import DEFAULT_PARSER_CONFIG, DOCUMENT_NAME_LIMIT, HOST_ADDRESS, INVALID_API_TOKEN, INVALID_ID_32, IS_GO_PROXY, VERSION
|
||||
from test.testcases.configs import DOCUMENT_NAME_LIMIT, HOST_ADDRESS, INVALID_API_TOKEN, INVALID_ID_32, VERSION
|
||||
from test.testcases.restful_api.helpers.assertions import assert_auth_error
|
||||
from test.testcases.restful_api.helpers.client import RestClient
|
||||
from test.testcases.utils import compare_by_hash
|
||||
@@ -492,7 +492,7 @@ def test_documents_upload_error_contract(rest_client, create_dataset, tmp_path):
|
||||
assert filename_empty_res.status_code == 200
|
||||
filename_empty_payload = filename_empty_res.json()
|
||||
assert filename_empty_payload["code"] == 101, filename_empty_payload
|
||||
expected_message = "No file part!" if IS_GO_PROXY else "No file selected!"
|
||||
expected_message = "No file part!"
|
||||
assert filename_empty_payload["message"] == expected_message, filename_empty_payload
|
||||
|
||||
|
||||
@@ -821,28 +821,11 @@ def test_documents_update_parser_config_contract(rest_client, create_dataset, tm
|
||||
list_body = list_res.json()
|
||||
assert list_body["code"] == 0, (parser_config, list_body)
|
||||
doc_parser_config = list_body["data"]["docs"][0]["parser_config"]
|
||||
if IS_GO_PROXY:
|
||||
assert isinstance(doc_parser_config, dict) and doc_parser_config, (parser_config, list_body)
|
||||
assert "raptor" not in doc_parser_config, (parser_config, list_body)
|
||||
assert "graphrag" not in doc_parser_config, (parser_config, list_body)
|
||||
continue
|
||||
if parser_config == {}:
|
||||
assert doc_parser_config == DEFAULT_PARSER_CONFIG, (parser_config, list_body)
|
||||
else:
|
||||
for key, value in parser_config.items():
|
||||
if key in {"graphrag", "raptor"}:
|
||||
assert key not in doc_parser_config, (parser_config, list_body)
|
||||
continue
|
||||
if isinstance(value, dict):
|
||||
for sub_key, sub_value in value.items():
|
||||
assert doc_parser_config[key][sub_key] == sub_value, (parser_config, list_body)
|
||||
else:
|
||||
assert doc_parser_config[key] == value, (parser_config, list_body)
|
||||
assert isinstance(doc_parser_config, dict) and doc_parser_config, (parser_config, list_body)
|
||||
assert "raptor" not in doc_parser_config, (parser_config, list_body)
|
||||
assert "graphrag" not in doc_parser_config, (parser_config, list_body)
|
||||
else:
|
||||
if IS_GO_PROXY:
|
||||
assert body["message"] in expected_message, (parser_config, body)
|
||||
else:
|
||||
assert body["message"] == expected_message, (parser_config, body)
|
||||
assert body["message"] in expected_message, (parser_config, body)
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
@@ -1045,12 +1028,9 @@ def test_document_metadata_config_contract(rest_client, create_document):
|
||||
update_body = update_res.json()
|
||||
assert update_body["code"] == 0, update_body
|
||||
parser_config = update_body["data"]["parser_config"]
|
||||
if IS_GO_PROXY:
|
||||
# Go scopes metadata onto the Extractor node rather than a flat key.
|
||||
scoped = parser_config.get("Extractor:AutoExtractDefault", {})
|
||||
assert scoped.get("metadata") == update_payload["metadata"], update_body
|
||||
else:
|
||||
assert parser_config["metadata"] == update_payload["metadata"], update_body
|
||||
# Go scopes metadata onto the Extractor node rather than a flat key.
|
||||
scoped = parser_config.get("Extractor:AutoExtractDefault", {})
|
||||
assert scoped.get("metadata") == update_payload["metadata"], update_body
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
|
||||
@@ -19,8 +19,6 @@ import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import IS_GO_PROXY
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def memory_cleanup(rest_client):
|
||||
@@ -130,7 +128,7 @@ def test_memory_create_missing_required_fields(rest_client):
|
||||
res = rest_client.post("/memories", json={"name": "missing_models", "memory_type": ["raw"]})
|
||||
assert res.status_code == 200
|
||||
payload = res.json()
|
||||
assert payload["code"] == (400 if IS_GO_PROXY else 101), payload
|
||||
assert payload["code"] == 400, payload
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
|
||||
@@ -18,15 +18,13 @@ import json
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import IS_GO_PROXY
|
||||
|
||||
|
||||
def _sse_events(response_text: str) -> list[str]:
|
||||
return [line[5:] for line in response_text.splitlines() if line.startswith("data:")]
|
||||
|
||||
|
||||
def skip_if_go_proxy_upstream_error(choice_message: dict) -> None:
|
||||
if IS_GO_PROXY and choice_message.get("reference") is None and choice_message.get("content", "").startswith("**ERROR**"):
|
||||
if choice_message.get("reference") is None and choice_message.get("content", "").startswith("**ERROR**"):
|
||||
pytest.skip("Go OpenAI-compatible completion could not reach the configured chat model")
|
||||
|
||||
|
||||
@@ -96,7 +94,7 @@ def test_openai_compatible_metadata_condition_requires_object(rest_client, creat
|
||||
)
|
||||
assert res.status_code == 200
|
||||
payload = res.json()
|
||||
assert payload["code"] == (101 if IS_GO_PROXY else 102), payload
|
||||
assert payload["code"] == 101, payload
|
||||
assert "metadata_condition must be an object." in payload["message"], payload
|
||||
|
||||
|
||||
@@ -113,7 +111,7 @@ def test_openai_compatible_invalid_chat(rest_client):
|
||||
assert res.status_code == 200
|
||||
payload = res.json()
|
||||
assert payload["code"] != 0, payload
|
||||
expected_message = "no authorization" if IS_GO_PROXY else "don't own the chat"
|
||||
expected_message = "no authorization"
|
||||
assert expected_message in payload["message"], payload
|
||||
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import IS_GO_PROXY
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def search_resource(rest_client):
|
||||
@@ -107,7 +105,7 @@ def test_search_update_invalid_search_id(rest_client):
|
||||
@pytest.mark.p2
|
||||
def test_search_completion_requires_question(rest_client, search_resource):
|
||||
search_id = search_resource
|
||||
expected_message = "question is required" if IS_GO_PROXY else "required argument are missing: question"
|
||||
expected_message = "question is required"
|
||||
|
||||
completion_res = rest_client.post(f"/searches/{search_id}/completion", json={})
|
||||
assert completion_res.status_code == 200
|
||||
|
||||
@@ -19,7 +19,7 @@ from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
|
||||
from test.testcases.configs import INVALID_API_TOKEN, INVALID_ID_32, IS_GO_PROXY, SESSION_WITH_CHAT_NAME_LIMIT
|
||||
from test.testcases.configs import INVALID_API_TOKEN, INVALID_ID_32, SESSION_WITH_CHAT_NAME_LIMIT
|
||||
from test.testcases.restful_api.helpers.assertions import assert_auth_error
|
||||
from test.testcases.restful_api.helpers.client import RestClient
|
||||
from test.testcases.utils import is_sorted
|
||||
@@ -423,7 +423,7 @@ def test_session_list_page_and_sort_contract(rest_client, create_chat):
|
||||
("page negative", {"page": -1, "page_size": 2}, 0, 2, ""),
|
||||
("page alpha", {"page": "a", "page_size": 2}, 0, 2, ""),
|
||||
("page_size none", {"page_size": None}, 0, 5, ""),
|
||||
("page_size zero", {"page_size": 0}, 0, 0 if IS_GO_PROXY else 5, ""),
|
||||
("page_size zero", {"page_size": 0}, 0, 0, ""),
|
||||
("page_size one", {"page_size": 1}, 0, 1, ""),
|
||||
("page_size six", {"page_size": 6}, 0, 5, ""),
|
||||
("page_size negative", {"page_size": -1}, 0, 5, ""),
|
||||
@@ -587,7 +587,7 @@ def test_chat_recommendation_requires_question(rest_client):
|
||||
assert res.status_code == 200
|
||||
payload = res.json()
|
||||
assert payload["code"] == 101, payload
|
||||
expected_message = "question is required" if IS_GO_PROXY else "required argument are missing: question"
|
||||
expected_message = "question is required"
|
||||
assert expected_message in payload["message"], payload
|
||||
|
||||
|
||||
@@ -601,16 +601,8 @@ def test_related_questions_compatibility_requires_auth(rest_client_noauth):
|
||||
)
|
||||
assert res.status_code == 200
|
||||
payload = res.json()
|
||||
if IS_GO_PROXY:
|
||||
assert payload["code"] == 102, payload
|
||||
assert payload["message"] == "Authorization is not valid!", payload
|
||||
else:
|
||||
assert payload["code"] == 102, payload
|
||||
assert payload["message"].strip() in {
|
||||
"Authorization is not valid!",
|
||||
'Authentication error: API key is invalid!"',
|
||||
"Authentication error: API key is invalid!",
|
||||
}, payload
|
||||
assert payload["code"] == 102, payload
|
||||
assert payload["message"] == "Authorization is not valid!", payload
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
|
||||
Reference in new issue
Block a user