This is an automated email from the ASF dual-hosted git repository. imbajin pushed a commit to branch goal-test in repository https://gitbox.apache.org/repos/asf/hugegraph-ai.git
commit 26573b182ed7f5429038239833df7a42b822f427 Author: imbajin <[email protected]> AuthorDate: Sun May 31 01:59:01 2026 +0800 test(client): harden hugegraph contract coverage - add real HugeGraph contract tests for schema, graph, gremlin, and responses - use explicit service fixtures for integration setup - record production fixes with regression evidence --- .../checkpoints/03-client-contract.md | 96 ++++++++++++---------- .workflow/quality-program/coverage/client-g2.json | 1 + .workflow/quality-program/quality-state.json | 26 ++++-- .../quality-program/reports/flaky-risk-ledger.md | 2 +- .../2026-05-31-hugegraph-ai-quality-program.md | 8 +- .../src/tests/api/test_graph.py | 12 +++ .../src/tests/api/test_gremlin.py | 8 ++ .../src/tests/api/test_schema.py | 22 +++++ hugegraph-python-client/src/tests/conftest.py | 14 +++- 9 files changed, 134 insertions(+), 55 deletions(-) diff --git a/.workflow/quality-program/checkpoints/03-client-contract.md b/.workflow/quality-program/checkpoints/03-client-contract.md index a242bdc3..1997bba6 100644 --- a/.workflow/quality-program/checkpoints/03-client-contract.md +++ b/.workflow/quality-program/checkpoints/03-client-contract.md @@ -2,79 +2,91 @@ ## Status -Partially complete; service-bound client contract tests remain blocked. +Complete. -## Blocker +## Service Resolution -Required HugeGraph service is unavailable locally: +Layer B was resumed after starting local Docker/OrbStack and HugeGraph Server `1.7.0`: -- `docker ps --format '{{.Names}} {{.Image}} {{.Ports}}'` failed because the Docker daemon is not reachable at `/Users/imbajin/.orbstack/run/docker.sock`. -- Direct `GET http://127.0.0.1:8080/versions` failed with `ConnectionRefusedError`. +- Image: `hugegraph/hugegraph:1.7.0` +- Container: `hugegraph-quality` +- Health check: `GET http://127.0.0.1:8080/versions` +- Observed version: `{"core":"1.7.0","gremlin":"3.5.1","api":"0.71.0.0"}` -The plan requires Layer B client contract tests to run against a real HugeGraph service and forbids silently skipping selected HugeGraph integration tests. Service-bound schema, graph ID, and Gremlin contract additions remain paused until HugeGraph `1.7.0` is reachable. +The earlier G2 service setup blocker is resolved for this checkpoint. It remains recorded in the flaky-risk ledger as a local environment dependency. -## Completed Non-Service Slice +## Completed Scope +- Added real HugeGraph schema contract coverage for property key, vertex label, edge label, index label, full schema fetch, and typed fetch APIs. +- Added real graph ID behavior coverage for primary-key vertex lookup and custom string ID vertex lookup. +- Added real Gremlin error-surface coverage for invalid traversal execution through production Gremlin client code. - Added malformed/backend error envelope contract tests for `ResponseValidation`. -- Proved the 500 backend envelope regression red first: - - `test_backend_error_envelope_preserves_message` failed because the raised exception was plain `500 Server Error`. -- Applied the minimal production fix: - - Prefer backend `message` over `exception` when extracting error details. - - Raise `Server Exception: {details}` for non-404 HTTP status codes instead of re-raising raw `HTTPError`. -- Tightened legacy client integration setup: - - `ClientUtils()` now honors `HUGEGRAPH_*` env vars when no explicit service object is passed. - - A class-scope autouse fixture gates `hugegraph`-marked tests through `hugegraph_service` before unittest `setUpClass()`. +- Tightened legacy client integration setup so `hugegraph`-marked unittest classes are gated by the shared service fixture before `setUpClass()`. +- Preserved `ClientUtils()` env-driven compatibility for legacy test callers while allowing fixture-injected HugeGraph service config. ## Commands Run ```bash -docker ps --format '{{.Names}} {{.Image}} {{.Ports}}' -uv run python -c "import requests; print(requests.get('http://127.0.0.1:8080/versions', timeout=5).text[:200])" +docker pull hugegraph/hugegraph:1.7.0 +docker run -d --name hugegraph-quality -p 8080:8080 -e PASSWORD=admin hugegraph/hugegraph:1.7.0 +uv run python -c 'import requests; r=requests.get("http://127.0.0.1:8080/versions", timeout=5); print(r.status_code); print(r.text)' uv run pytest hugegraph-python-client/src/tests/api/test_response_validation.py -q uv run pytest hugegraph-python-client/src/tests -m "unit or contract" -q -HUGEGRAPH_REQUIRED=true uv run pytest hugegraph-python-client/src/tests -m "integration and hugegraph" -v --tb=short --maxfail=1 -uv run ruff format --check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/client_utils.py hugegraph-python-client/src/tests/api/test_response_validation.py hugegraph-python-client/src/pyhugegraph/utils/util.py -uv run ruff check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/client_utils.py hugegraph-python-client/src/tests/api/test_response_validation.py hugegraph-python-client/src/pyhugegraph/utils/util.py -uv run pre-commit run trailing-whitespace --files hugegraph-python-client/src/pyhugegraph/utils/util.py -git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff --check +HUGEGRAPH_REQUIRED=true uv run pytest hugegraph-python-client/src/tests -m "integration and hugegraph" -v --tb=short +uv run ruff format --check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/api/test_schema.py hugegraph-python-client/src/tests/api/test_graph.py hugegraph-python-client/src/tests/api/test_gremlin.py +uv run ruff check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/api/test_schema.py hugegraph-python-client/src/tests/api/test_graph.py hugegraph-python-client/src/tests/api/test_gremlin.py +uv run pytest hugegraph-python-client/src/tests -m "unit or contract" --cov=pyhugegraph --cov-report=term --cov-report=json:.workflow/quality-program/coverage/client-g2.json ``` +## Verification Result + +| Layer | Command | Result | +|---|---|---| +| Client unit/contract | `uv run pytest hugegraph-python-client/src/tests -m "unit or contract" -q` | `17 passed, 59 deselected` | +| Client HugeGraph integration | `HUGEGRAPH_REQUIRED=true uv run pytest hugegraph-python-client/src/tests -m "integration and hugegraph" -v --tb=short` | `59 passed, 17 deselected` | +| Targeted G2 service contracts | `HUGEGRAPH_REQUIRED=true uv run pytest ...test_schema... ...test_graph... ...test_gremlin... -q` | `3 passed` | +| Formatting | `uv run ruff format --check ...` | `4 files already formatted` | +| Lint | `uv run ruff check ...` | `All checks passed` | + +## Coverage Delta + +| Artifact | Coverage | +|---|---:| +| `.workflow/quality-program/coverage/client-baseline.json` | `45.0665%` | +| `.workflow/quality-program/coverage/client-g2.json` | `45.1774%` | + +The small coverage increase is expected; G2 primarily improves service-boundary confidence by adding real HugeGraph contract assertions rather than broad line coverage. + ## Files Touched - `.workflow/quality-program/checkpoints/03-client-contract.md` +- `.workflow/quality-program/coverage/client-g2.json` - `.workflow/quality-program/quality-state.json` - `.workflow/quality-program/reports/flaky-risk-ledger.md` - `.workflow/quality-program/reports/production-change-ledger.md` +- `docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md` - `hugegraph-python-client/src/tests/conftest.py` - `hugegraph-python-client/src/tests/client_utils.py` - `hugegraph-python-client/src/tests/api/test_response_validation.py` +- `hugegraph-python-client/src/tests/api/test_schema.py` +- `hugegraph-python-client/src/tests/api/test_graph.py` +- `hugegraph-python-client/src/tests/api/test_gremlin.py` - `hugegraph-python-client/src/pyhugegraph/utils/util.py` ## Production Changes -- `hugegraph-python-client/src/pyhugegraph/utils/util.py` - - Preserves parsed backend error details for 500-class error envelopes. - - Proving test: `uv run pytest hugegraph-python-client/src/tests/api/test_response_validation.py -q` +| File | Change | Proving test | +|---|---|---| +| `hugegraph-python-client/src/pyhugegraph/utils/util.py` | Preserve parsed backend error details for non-404 HTTP errors and prefer server `message` over `exception`. | `uv run pytest hugegraph-python-client/src/tests/api/test_response_validation.py -q` | -## Tests Added or Changed - -- Added `test_backend_error_envelope_preserves_message`. -- Added `test_malformed_error_body_uses_response_text`. -- Added client conftest service gate for `hugegraph`-marked tests. -- Updated `ClientUtils()` to read `HUGEGRAPH_*` env vars for legacy unittest-style integrations. +No additional production-code changes were needed for schema CRUD, graph ID behavior, or Gremlin error-surface coverage. ## Failure Classification -- Service setup failure: HugeGraph Server `1.7.0` is not reachable, and Docker cannot start or inspect containers because the local daemon is unavailable. -- `HUGEGRAPH_REQUIRED=true` integration command now fails at the shared `/versions` readiness fixture before test class setup, not during unrelated cleanup. -- `util.py` keeps its existing CRLF line-ending style; whitespace verification used `cr-at-eol` to avoid a whole-file line-ending rewrite. - -## Resume Condition - -Start a HugeGraph `1.7.0` service reachable at `http://127.0.0.1:8080`, or start the local Docker/OrbStack daemon so the service can be launched with: +- Historical service setup failure: before Docker/OrbStack was started, `HUGEGRAPH_REQUIRED=true` failed at the shared `/versions` readiness fixture and no selected HugeGraph tests were silently skipped. +- Current G2 status: no client contract, server contract, or service setup failures remain in the verified G2 commands. +- `util.py` keeps its existing CRLF line-ending style from the repository; earlier whitespace verification used `cr-at-eol` to avoid a whole-file line-ending rewrite. -```bash -docker run -d --name hugegraph-quality -p 8080:8080 -e PASSWORD=admin hugegraph/hugegraph:1.7.0 -``` +## Next Goal Readiness -Then resume G2 from Step G2.2. +G3 can begin. The local HugeGraph `1.7.0` service is available at `http://127.0.0.1:8080` for LLM HugeGraph boundary tests. diff --git a/.workflow/quality-program/coverage/client-g2.json b/.workflow/quality-program/coverage/client-g2.json new file mode 100644 index 00000000..9cfdbf85 --- /dev/null +++ b/.workflow/quality-program/coverage/client-g2.json @@ -0,0 +1 @@ +{"meta": {"format": 3, "version": "7.10.4", "timestamp": "2026-05-31T01:56:50.083818", "branch_coverage": false, "show_contexts": false}, "files": {"hugegraph-python-client/src/pyhugegraph/__init__.py": {"executed_lines": [1], "summary": {"covered_lines": 0, "num_statements": 0, "percent_covered": 100.0, "percent_covered_display": "100", "missing_lines": 0, "excluded_lines": 0}, "missing_lines": [], "excluded_lines": [], "functions": {"": {"executed_lines": [1], "summary": {"covered_line [...] diff --git a/.workflow/quality-program/quality-state.json b/.workflow/quality-program/quality-state.json index 8414533f..5b85a147 100644 --- a/.workflow/quality-program/quality-state.json +++ b/.workflow/quality-program/quality-state.json @@ -1,12 +1,13 @@ { - "current_goal": "G2", + "current_goal": "G3", "repo_sha_start": "d048bc9fa07042833549dd1def5ff3222c47be70", "base_branch": "main", "open_pr_snapshot_time": "2026-05-30T17:18:30Z", "goals_completed": [ "P0", "G0", - "G1" + "G1", + "G2" ], "files_touched": [ ".workflow/quality-program/README.md", @@ -59,7 +60,9 @@ "docs/quality/hugegraph-integration.md", ".workflow/quality-program/checkpoints/02-service-fixture.md", ".workflow/quality-program/checkpoints/03-client-contract.md", + ".workflow/quality-program/coverage/client-g2.json", ".workflow/quality-program/reports/production-change-ledger.md", + "docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md", "hugegraph-python-client/src/pyhugegraph/utils/util.py" ], "production_changes": [ @@ -74,7 +77,8 @@ "Added file-level unit/contract/integration/hugegraph markers to selected existing tests for Layer A and Layer B selection.", "Added HugeGraph service fixtures and conftest wiring for client and LLM test suites.", "Added response validation contract tests for backend and malformed error envelopes.", - "Updated client integration harness so hugegraph-marked legacy tests use the service fixture gate before unittest setUpClass." + "Updated client integration harness so hugegraph-marked legacy tests use the service fixture gate before unittest setUpClass.", + "Added real HugeGraph schema CRUD, graph ID, and Gremlin error-surface contract tests for G2." ], "commands_run": [ "sed -n '1,220p' AGENTS.md", @@ -118,13 +122,21 @@ "uv run ruff format --check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/client_utils.py hugegraph-python-client/src/tests/api/test_response_validation.py hugegraph-python-client/src/pyhugegraph/utils/util.py", "uv run ruff check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/client_utils.py hugegraph-python-client/src/tests/api/test_response_validation.py hugegraph-python-client/src/pyhugegraph/utils/util.py", "uv run pre-commit run trailing-whitespace --files hugegraph-python-client/src/pyhugegraph/utils/util.py", - "git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff --check" + "git -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff --check", + "docker pull hugegraph/hugegraph:1.7.0", + "docker run -d --name hugegraph-quality -p 8080:8080 -e PASSWORD=admin hugegraph/hugegraph:1.7.0", + "uv run python -c 'import requests; r=requests.get(\"http://127.0.0.1:8080/versions\", timeout=5); print(r.status_code); print(r.text)'", + "HUGEGRAPH_REQUIRED=true uv run pytest hugegraph-python-client/src/tests/api/test_schema.py::test_schema_create_and_fetch_property_vertex_edge_index hugegraph-python-client/src/tests/api/test_graph.py::test_graph_supports_primary_key_and_custom_string_id hugegraph-python-client/src/tests/api/test_gremlin.py::test_gremlin_error_surface_is_explicit -v --tb=short", + "uv run pytest hugegraph-python-client/src/tests -m 'unit or contract' -q", + "HUGEGRAPH_REQUIRED=true uv run pytest hugegraph-python-client/src/tests -m 'integration and hugegraph' -v --tb=short", + "uv run ruff format --check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/api/test_schema.py hugegraph-python-client/src/tests/api/test_graph.py hugegraph-python-client/src/tests/api/test_gremlin.py", + "uv run ruff check hugegraph-python-client/src/tests/conftest.py hugegraph-python-client/src/tests/api/test_schema.py hugegraph-python-client/src/tests/api/test_graph.py hugegraph-python-client/src/tests/api/test_gremlin.py", + "uv run pytest hugegraph-python-client/src/tests -m 'unit or contract' --cov=pyhugegraph --cov-report=term --cov-report=json:.workflow/quality-program/coverage/client-g2.json" ], "known_failures": [ "Root-level LLM collection command fails before collection because existing prompt config requires cwd hugegraph-llm.", "Initial coverage command failed before uv sync because pytest-cov was missing from the active environment.", - "LLM integration and hugegraph collection is empty before G3 adds real-boundary tests; pytest returns exit code 5.", - "G2 service-bound tests blocked: Docker daemon is unavailable and no HugeGraph service is reachable at http://127.0.0.1:8080/versions." + "LLM integration and hugegraph collection is empty before G3 adds real-boundary tests; pytest returns exit code 5." ], "deferred_items": [ "Avoid #350/#277 YAML config migration files unless tests require a narrow compatibility assertion.", @@ -133,5 +145,5 @@ "Avoid #240 vector/property embedding abstraction surface.", "Quarantine client/test fixes overlapping #323/#329/#342 until exact changed files are inspected." ], - "next_recommended_action": "Start Docker/OrbStack and HugeGraph 1.7.0, then resume G2 from Step G2.2" + "next_recommended_action": "Start G3 hugegraph-llm HugeGraph boundary hardening with the local HugeGraph 1.7.0 service" } diff --git a/.workflow/quality-program/reports/flaky-risk-ledger.md b/.workflow/quality-program/reports/flaky-risk-ledger.md index 8bf1e03a..7fa9ebda 100644 --- a/.workflow/quality-program/reports/flaky-risk-ledger.md +++ b/.workflow/quality-program/reports/flaky-risk-ledger.md @@ -6,4 +6,4 @@ | LLM external skip control | Global `SKIP_EXTERNAL_SERVICES=true` prevents selected real HugeGraph boundary tests from opting in | P0 records current issue only | G0/G1 should switch to default-only skip semantics and explicit Layer B fixture behavior | | Client integration selection | Full client suite currently mixes service-bound and local tests | P0 records current issue only | G0/G1 should add markers and fixture-driven selection | | Open PR collisions | Parallel PRs touch config, vertex IDs, Gremlin examples, flow tests, vector/property embedding, and async API | Quarantine list in `00-preflight.md` | Inspect exact files before goals touching those surfaces | -| Local HugeGraph service for G2 | Docker daemon unavailable and no service reachable at `127.0.0.1:8080` | G2 paused before adding unverifiable service-bound tests | Start Docker/OrbStack and HugeGraph `1.7.0`, then resume G2 | +| Local HugeGraph service for G2 | Local Docker/OrbStack availability can block selected Layer B tests | G2 resumed after starting `hugegraph/hugegraph:1.7.0`; full client integration suite passed with `HUGEGRAPH_REQUIRED=true` | Keep using explicit readiness checks and fail selected tests when required service is unavailable | diff --git a/docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md b/docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md index a7bf466e..f27af976 100644 --- a/docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md +++ b/docs/superpowers/plans/2026-05-31-hugegraph-ai-quality-program.md @@ -712,7 +712,7 @@ def client_utils(hugegraph_service): utils.clear_graph_all_data() ``` -- [ ] **Step G2.2: Add schema CRUD contract tests** +- [x] **Step G2.2: Add schema CRUD contract tests** Add tests in `hugegraph-python-client/src/tests/api/test_schema.py` that prove: @@ -736,7 +736,7 @@ def test_schema_create_and_fetch_property_vertex_edge_index(client_utils): If the existing API returns typed objects instead of dicts, assert the public fields exposed by those objects. -- [ ] **Step G2.3: Add graph ID behavior tests** +- [x] **Step G2.3: Add graph ID behavior tests** Add tests in `hugegraph-python-client/src/tests/api/test_graph.py` for: @@ -754,7 +754,7 @@ def test_graph_supports_primary_key_and_custom_string_id(client_utils): If `addVertex` does not accept an `id` property for custom ID labels, write the failing test against the existing public method and fix only the minimal contract gap. -- [ ] **Step G2.4: Add Gremlin envelope and error tests** +- [x] **Step G2.4: Add Gremlin envelope and error tests** Extend `hugegraph-python-client/src/tests/api/test_gremlin.py`: @@ -825,7 +825,7 @@ For each production fix: | G2 | `path` | `summary` | `pytest path::test_name` | `contract gap` | ``` -- [ ] **Step G2.8: Write checkpoint and commit** +- [x] **Step G2.8: Write checkpoint and commit** Create `.workflow/quality-program/checkpoints/03-client-contract.md` and include commands, failures, fixes, and coverage delta. diff --git a/hugegraph-python-client/src/tests/api/test_graph.py b/hugegraph-python-client/src/tests/api/test_graph.py index e980cc30..4c93fe58 100644 --- a/hugegraph-python-client/src/tests/api/test_graph.py +++ b/hugegraph-python-client/src/tests/api/test_graph.py @@ -163,3 +163,15 @@ class TestGraphManager(unittest.TestCase): edge2 = self.graph.addEdge("knows", vertex2.id, vertex1.id, {"date": "2012-01-10"}) edges = self.graph.getEdgesById([edge1.id, edge2.id]) self.assertEqual(len(edges), 2) + + +def test_graph_supports_primary_key_and_custom_string_id(client_utils): + graph = client_utils.graph + graph.addVertex("person", {"name": "quality_marko", "age": 29, "city": "Beijing"}) + person = graph.getVertexByCondition(label="person", properties={"name": "quality_marko"}, limit=1)[0] + assert person.id is not None + + graph.addVertex("book", {"name": "Quality Book", "price": 100}, id="quality-book-1") + book = graph.getVertexById("quality-book-1") + assert book.id == "quality-book-1" + assert book.properties["name"] == "Quality Book" diff --git a/hugegraph-python-client/src/tests/api/test_gremlin.py b/hugegraph-python-client/src/tests/api/test_gremlin.py index 6e53cb3e..3dbd9473 100644 --- a/hugegraph-python-client/src/tests/api/test_gremlin.py +++ b/hugegraph-python-client/src/tests/api/test_gremlin.py @@ -136,3 +136,11 @@ class TestGremlinSetupBehavior(unittest.TestCase): client.gremlin = mock.Mock() with mock.patch.dict(os.environ, {"SKIP_GREMLIN_TESTS": "true"}), self.assertRaises(unittest.SkipTest): TestGremlin.setUpClass() + + +def test_gremlin_error_surface_is_explicit(client_utils): + with pytest.raises(Exception) as exc_info: + client_utils.gremlin.exec("g.V2()") + + message = str(exc_info.value) + assert "g.V2" in message or "No signature" in message or "NotFound" in message diff --git a/hugegraph-python-client/src/tests/api/test_schema.py b/hugegraph-python-client/src/tests/api/test_schema.py index 4dae853b..55e1ecce 100644 --- a/hugegraph-python-client/src/tests/api/test_schema.py +++ b/hugegraph-python-client/src/tests/api/test_schema.py @@ -83,3 +83,25 @@ class TestSchemaManager(unittest.TestCase): def test_get_index_label(self): index_label = self.schema.getIndexLabel("personByCity") self.assertEqual(index_label.name, "personByCity") + + +def test_schema_create_and_fetch_property_vertex_edge_index(client_utils): + schema = client_utils.schema + schema.propertyKey("quality_name").asText().ifNotExist().create() + schema.propertyKey("quality_score").asInt().ifNotExist().create() + schema.vertexLabel("quality_person").properties("quality_name", "quality_score").primaryKeys( + "quality_name" + ).ifNotExist().create() + schema.edgeLabel("quality_knows").sourceLabel("quality_person").targetLabel("quality_person").ifNotExist().create() + schema.indexLabel("quality_person_by_score").onV("quality_person").by("quality_score").range().ifNotExist().create() + + full_schema = schema.getSchema() + + assert "propertykeys" in full_schema + assert "vertexlabels" in full_schema + assert "edgelabels" in full_schema + assert "indexlabels" in full_schema + assert schema.getPropertyKey("quality_name").name == "quality_name" + assert schema.getVertexLabel("quality_person").name == "quality_person" + assert schema.getEdgeLabel("quality_knows").name == "quality_knows" + assert schema.getIndexLabel("quality_person_by_score").name == "quality_person_by_score" diff --git a/hugegraph-python-client/src/tests/conftest.py b/hugegraph-python-client/src/tests/conftest.py index b31142ee..c58cd6b8 100644 --- a/hugegraph-python-client/src/tests/conftest.py +++ b/hugegraph-python-client/src/tests/conftest.py @@ -17,9 +17,21 @@ import pytest +from .client_utils import ClientUtils from .fixtures.hugegraph_service import hugegraph_service -__all__ = ["hugegraph_service"] +__all__ = ["client_utils", "hugegraph_service"] + + [email protected]() +def client_utils(hugegraph_service): + utils = ClientUtils(service=hugegraph_service) + utils.clear_graph_all_data() + utils.init_property_key() + utils.init_vertex_label() + utils.init_edge_label() + yield utils + utils.clear_graph_all_data() @pytest.fixture(scope="class", autouse=True)
