#!/usr/bin/env python3 """ 测试 POST /indexer/build-docs 接口:构造请求数据、调用接口、打印完整响应。 用法: 1. 先启动 Indexer 服务: ./scripts/start_indexer.sh (或 uvicorn api.indexer_app:app --port 6004) 2. 执行: python scripts/test_build_docs_api.py 也可指定地址: INDEXER_URL=http://localhost:6004 python scripts/test_build_docs_api.py """ import json import os import sys from datetime import datetime, timezone # 项目根目录 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, ROOT) # 默认使用 requests 调真实服务;若未安装则回退到 TestClient try: import requests HAS_REQUESTS = True except ImportError: HAS_REQUESTS = False def build_sample_request(): """构造一条完整的 build-docs 请求体(对应 shoplazza_product_spu / sku / option 表结构)。""" now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") return { "tenant_id": "162", "items": [ { "spu": { "id": 10001, "tenant_id": "162", "title": "测试T恤 纯棉短袖", "brief": "舒适纯棉,多色可选", "description": "这是一款适合日常穿着的纯棉T恤,透气吸汗。", "vendor": "测试品牌", "category": "服装/上衣/T恤", "category_id": 100, "category_level": 2, "category_path": "服装/上衣/T恤", "fake_sales": 1280, "image_src": "https://example.com/img/tshirt.jpg", "tags": "T恤,纯棉,短袖,夏季", "create_time": now, "update_time": now, }, "skus": [ { "id": 20001, "spu_id": 10001, "price": 99.0, "compare_at_price": 129.0, "sku": "SKU-TSHIRT-001", "inventory_quantity": 50, "option1": "黑色", "option2": "M", "option3": None, }, { "id": 20002, "spu_id": 10001, "price": 99.0, "compare_at_price": 129.0, "sku": "SKU-TSHIRT-002", "inventory_quantity": 30, "option1": "白色", "option2": "L", "option3": None, }, ], "options": [ {"id": 1, "position": 1, "name": "颜色"}, {"id": 2, "position": 2, "name": "尺码"}, ], } ], } def call_via_http(base_url: str, body: dict): """通过 HTTP 调用 build-docs。""" url = f"{base_url.rstrip('/')}/indexer/build-docs" r = requests.post(url, json=body, timeout=30) return r.status_code, r.text, r.json() if r.headers.get("content-type", "").startswith("application/json") else None def call_via_test_client(body: dict): """通过 FastAPI TestClient 调用(不依赖已启动服务,但需 DB/ES 已配置)。""" from fastapi.testclient import TestClient import api.indexer_app as indexer_app with TestClient(indexer_app.app) as client: r = client.post("/indexer/build-docs", json=body) return r.status_code, r.text, r.json() if r.headers.get("content-type", "").startswith("application/json") else None def main(): body = build_sample_request() print("=" * 60) print("【请求】POST /indexer/build-docs") print("=" * 60) print(json.dumps(body, ensure_ascii=False, indent=2)) base_url = os.getenv("INDEXER_URL", "http://localhost:6004") use_http = HAS_REQUESTS and (os.getenv("USE_TEST_CLIENT", "").lower() not in ("1", "true", "yes")) if use_http: try: status, raw, data = call_via_http(base_url, body) except requests.RequestException as e: print("\n[错误] 无法连接 Indexer 服务:", e) print("请先启动: ./scripts/start_indexer.sh 或 uvicorn api.indexer_app:app --port 6004") if HAS_REQUESTS: print("或使用进程内测试: USE_TEST_CLIENT=1 python scripts/test_build_docs_api.py") sys.exit(1) else: if not use_http and not HAS_REQUESTS: print("\n[提示] 未安装 requests,使用 TestClient 调用(需配置 DB/ES)。") else: print("\n[提示] 使用 TestClient 调用(USE_TEST_CLIENT=1)。") try: status, raw, data = call_via_test_client(body) except Exception as e: print("\n[错误] TestClient 调用失败:", e) print("请确保已 source activate.sh 且 DB/ES 环境变量正确,或先启动 Indexer 再用 HTTP 调用。") sys.exit(1) print("\n" + "=" * 60) print("【响应】HTTP status =", status) print("=" * 60) if data is not None: print(json.dumps(data, ensure_ascii=False, indent=2, default=str)) if data.get("docs"): doc = data["docs"][0] print("\n" + "=" * 60) print("【返回 doc 顶层字段】共 {} 个".format(len(doc))) print("=" * 60) for k in sorted(doc.keys()): print(" ", k) else: print(raw) if status != 200: sys.exit(1) if __name__ == "__main__": main()