diff --git a/AGENTS.md b/AGENTS.md index cb3142655b..733bd0ec42 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,6 +51,30 @@ Use this file as the local operating guide for the current codebase. Prefer the - Remove commented-out Go code instead of leaving recovery notes in place. - Keep package comments and doc comments aligned with the current runtime path, not with migration history. +## Go Test Tiers +Go tests are classified by build tag so the default `go test ./...` run stays self-contained. Tag a test file with `//go:build ` placed before the `package` clause. + +| Tier | Build tag | Runs by default? | Needs | +|---|---|---|---| +| Unit | (none) | Yes (`go test ./...`) | Native CGO static libs (wired by `build.sh --test`); no external services — uses in-memory SQLite, miniredis, or `httptest` stubs. | +| Integration | `integration` | No (`-tags integration`) | A real service: MySQL/MinIO/Elasticsearch/Infinity/LLM. Single component, reasonably fast. | +| E2E | `e2e` | No (`-tags e2e`) | Full cross-component pipeline (ingest → index → retrieve) against real services; heavy/slow. | +| Manual | `manual` | No (`-tags manual`) | Very slow/expensive (deepdoc render/parity/snapshot/bench). **Local opt-in ONLY — never run in CI.** | +| Native (orthogonal) | `cgo` / `!cgo` | `cgo` auto-satisfies under CGO_ENABLED=1 | Native static libs (`office_oxide`/`pdfium`/`pdf_oxide`). Combine with tiers, e.g. `//go:build cgo && integration`. | + +Run tiers locally via `build.sh`: +```bash +bash build.sh --test # unit tier (no tags) +bash build.sh --test-integration ./... # integration tier +bash build.sh --test-e2e # e2e tier +bash build.sh --test-manual # manual tier (very slow) +bash build.sh --test-all # integration + e2e (never includes manual) +``` +Rules: +- New tests that touch a real external service MUST carry `integration`/`e2e`/`manual` — do not rely on `t.Skip` + env vars to soft-isolate them in the default unit run. Keep an env guard as a harmless secondary safety net if desired. +- `manual` is never wired into CI or any automated pipeline. +- `unit` (no tag) must stay free of external-service dependencies so `go test ./...` passes without MySQL/MinIO/ES/Infinity/LLM. The native CGO static libraries (`office_oxide`/`pdfium`/`pdf_oxide`) are still required at build time and are wired automatically by `build.sh --test`; that is expected, not an external service. + ## Working Rules - Before editing, inspect the nearest code path that actually owns the behavior. - Keep changes small and local unless the task is explicitly a broader refactor. diff --git a/build.sh b/build.sh index a07b1fbc55..bddfad206b 100755 --- a/build.sh +++ b/build.sh @@ -432,6 +432,24 @@ run_go_tests() { go test -count=1 "$@" } +# Run Go tests gated behind a build tag (or space-separated tag list), e.g. +# `./build.sh --test-integration -run TestFoo ./internal/engine/...`. +# See "Go Test Tiers" in AGENTS.md for the tier definitions. +run_go_tests_tagged() { + local tags="$1"; shift + print_section "Running Go tests (tags: ${tags})" + + cd "$PROJECT_ROOT" + setup_cgo_env + + if [ "$#" -eq 0 ]; then + set -- ./... + fi + GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 \ + CGO_CFLAGS="$CGO_CFLAGS" CGO_LDFLAGS="$CGO_LDFLAGS" \ + go test -tags "${tags}" -count=1 "$@" +} + # Clean build artifacts clean() { print_section "Cleaning build artifacts" @@ -487,9 +505,18 @@ OPTIONS: --cpp, -c Build only C++ static library --cpp-test Build C++ test executable (requires --cpp first) --go, -g Build only Go server (requires C++ library to be built) - --test, -t Run Go unit tests (sets up CGO env for office_oxide). - Any extra args are forwarded to `go test`, e.g. + --test, -t Run Go unit tests (no build tag). Sets up the CGO env and + native static libs (office_oxide/pdfium/pdf_oxide) needed to + build (same contract as the Go tier table in AGENTS.md). + Extra args are forwarded to `go test`, e.g. `$0 --test -run TestFoo ./internal/admin/...` + --test-integration Run Go tests tagged 'integration' (need real services, + e.g. MySQL/MinIO/ES/Infinity/LLM). e.g. + `$0 --test-integration ./internal/engine/...` + --test-e2e Run Go tests tagged 'e2e' (full-pipeline, heavy). + --test-manual Run Go tests tagged 'manual' (very slow; local opt-in + ONLY, never run in CI). + --test-all Run 'integration' + 'e2e' tests (excludes 'manual'). --clean, -C Clean all build artifacts --run, -r Build and run the server --strip, -s Strip debug symbols from Go binaries (-ldflags="-s -w") @@ -501,8 +528,12 @@ EXAMPLES: $0 --cpp # Build only C++ library $0 --go # Build only Go server $0 --cpp-test # Build C++ test executable - $0 --test # Run all Go tests + $0 --test # Run all Go tests (unit tier, no build tag) $0 --test -run TestFoo ./internal/admin/... # Targeted Go tests + $0 --test-integration ./internal/engine/... # integration tier + $0 --test-e2e # e2e tier + $0 --test-manual # manual tier (very slow) + $0 --test-all # integration + e2e (no manual) $0 --run # Build and run $0 --clean # Clean build artifacts @@ -551,6 +582,38 @@ main() { run_go_tests "${args[@]:1}" fi ;; + --test-integration) + check_go_deps + if [ "${args[1]:-}" = "--" ]; then + run_go_tests_tagged integration "${args[@]:2}" + else + run_go_tests_tagged integration "${args[@]:1}" + fi + ;; + --test-e2e) + check_go_deps + if [ "${args[1]:-}" = "--" ]; then + run_go_tests_tagged e2e "${args[@]:2}" + else + run_go_tests_tagged e2e "${args[@]:1}" + fi + ;; + --test-manual) + check_go_deps + if [ "${args[1]:-}" = "--" ]; then + run_go_tests_tagged manual "${args[@]:2}" + else + run_go_tests_tagged manual "${args[@]:1}" + fi + ;; + --test-all) + check_go_deps + if [ "${args[1]:-}" = "--" ]; then + run_go_tests_tagged "integration e2e" "${args[@]:2}" + else + run_go_tests_tagged "integration e2e" "${args[@]:1}" + fi + ;; --clean|-C) clean ;; diff --git a/internal/agent/component/stagehand_runtime_integration_test.go b/internal/agent/component/stagehand_runtime_integration_test.go index 73a44b878f..50d8b72a3e 100644 --- a/internal/agent/component/stagehand_runtime_integration_test.go +++ b/internal/agent/component/stagehand_runtime_integration_test.go @@ -38,6 +38,9 @@ // export OPENAI_MODEL=... // rtk go test ./internal/agent/component/ -count=1 \ // -run TestStagehandRuntime_Extract -v -timeout 3m + +//go:build integration + package component import ( diff --git a/internal/engine/elasticsearch/kg_test.go b/internal/engine/elasticsearch/kg_test.go index 9e4941cc5c..8c17686922 100644 --- a/internal/engine/elasticsearch/kg_test.go +++ b/internal/engine/elasticsearch/kg_test.go @@ -14,6 +14,8 @@ // limitations under the License. // +//go:build integration + package elasticsearch import ( diff --git a/internal/ingestion/pipeline/pipeline_knowledge_compiler_test.go b/internal/ingestion/pipeline/pipeline_knowledge_compiler_test.go index 57483a1c5d..2c7fd5d797 100644 --- a/internal/ingestion/pipeline/pipeline_knowledge_compiler_test.go +++ b/internal/ingestion/pipeline/pipeline_knowledge_compiler_test.go @@ -24,6 +24,10 @@ import ( // init hook fires and the component name referenced by the template is // resolvable in the default runtime factory. "ragflow/internal/agent/runtime" + // Blank-import the parent component package so its init registers the + // File/Parser/TokenChunker components this test's template references. + _ "ragflow/internal/ingestion/component" + _ "ragflow/internal/ingestion/component/chunker" _ "ragflow/internal/ingestion/component/knowledge_compiler" ) diff --git a/internal/ingestion/pipeline/template_integration_test.go b/internal/ingestion/pipeline/template_integration_test.go index dee9f7ab22..1a5be500e3 100644 --- a/internal/ingestion/pipeline/template_integration_test.go +++ b/internal/ingestion/pipeline/template_integration_test.go @@ -19,6 +19,8 @@ // Tokenizer and title weighting runs - the q__vec first element is // 0.1*len(name) + 0.9*len(content), and embedding_token_consumption includes // the one title encode (len(name)) plus the per-chunk content encodes. +//go:build integration + package pipeline import ( diff --git a/internal/ingestion/service/real_consumer_pipeline_test.go b/internal/ingestion/service/real_consumer_pipeline_test.go index 23d81f4527..8848e5f249 100644 --- a/internal/ingestion/service/real_consumer_pipeline_test.go +++ b/internal/ingestion/service/real_consumer_pipeline_test.go @@ -1,4 +1,4 @@ -//go:build integration +//go:build e2e package service diff --git a/internal/ingestion/task/pipeline_e2e_test.go b/internal/ingestion/task/pipeline_e2e_test.go index d01be5ccfc..ac9cc690d8 100644 --- a/internal/ingestion/task/pipeline_e2e_test.go +++ b/internal/ingestion/task/pipeline_e2e_test.go @@ -14,6 +14,8 @@ // limitations under the License. // +//go:build e2e + package task import ( diff --git a/internal/ingestion/task/real_consumer_test.go b/internal/ingestion/task/real_consumer_test.go index 3be0c70ac7..baed6516e4 100644 --- a/internal/ingestion/task/real_consumer_test.go +++ b/internal/ingestion/task/real_consumer_test.go @@ -1,5 +1,3 @@ -//go:build integration - // // Copyright 2026 The InfiniFlow Authors. All Rights Reserved. // @@ -14,7 +12,8 @@ // 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. -// + +//go:build e2e package task diff --git a/internal/storage/minio_test.go b/internal/storage/minio_test.go index 35365c446a..faa54a0506 100644 --- a/internal/storage/minio_test.go +++ b/internal/storage/minio_test.go @@ -14,6 +14,8 @@ // limitations under the License. // +//go:build integration + package storage import (