Files
PlantAI-rag-new/tests/docgen/run_e2e_curl.sh
jerryandClaude Fable 5 5888e1d5c1 test(docgen): 测试治理资产——131 条验收用例 + 三轮留痕 + E2E/回归套件
- tests/docgen/:DC-UNIT/API/CONF/E2E/UI/REGRESSION/PERF 分组用例与可复跑脚本,报告逐条留痕(R1-R3 全记录)
- 意图 30 条前后端同表双跑(pytest + node)
- Playwright headless:docgen-ui/docgen-regression spec + b3 benchpanel 第 5 TAB 断言更新

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-03 21:13:47 +08:00

163 lines
8.4 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# run_e2e_curl.sh —— DC-E2E-CURL-01~09(端到端 curl 序列,每步断言)
#
# 前置(必须由 TL 完成,本脚本不做任何启动动作):
# 1. TL 已启动 dev BFF 与 vstore 实例(vstore 必须开启加密落盘);
# 2. 通过环境变量告知地址:
# DOCGEN_E2E_VSTORE 默认 http://127.0.0.1:8094
# DOCGEN_E2E_BFF 默认 http://127.0.0.1:8090
# DOCGEN_E2E_VAULT vstore 加密库目录绝对路径(用于保密断言),必填
# DOCGEN_E2E_SENTINEL 入库样例的明文标志串(用于 grep 无命中断言),必填
# 3. 若未提供必填变量:本脚本打印 PENDING 并以 77 退出(SKIP,不视为 FAIL)。
#
# 纪律:
# - 只在 TL 指定的端口与目录上操作;样例用占位明文;
# - 断言幂等(不依赖 vault 既有数据的命中次序;删除只删本次入库记录);
# - 失败立即退出非零;每步输出对应用例编号,便于回填 test_case_report.md。
#
# R1 执行口径(2026-09-03):BFF=8090、vstore=8094(TL 授权端口)。
set -u
cd "$(dirname "$0")/../.." || exit 2 # 仓库根
VSTORE="${DOCGEN_E2E_VSTORE:-http://127.0.0.1:8094}"
BFF="${DOCGEN_E2E_BFF:-http://127.0.0.1:8090}"
VAULT="${DOCGEN_E2E_VAULT:-}"
SENTINEL="${DOCGEN_E2E_SENTINEL:-}"
say() { echo "== $1 =="; }
ok() { echo " [PASS] $1"; }
die() { echo " [FAIL] $1"; echo "===== E2E 汇总:本步断言失败(exit 1) ====="; exit 1; }
if [ -z "$VAULT" ] || [ -z "$SENTINEL" ]; then
echo "[PENDING] 需 TL 提供 DOCGEN_E2E_VAULT(vstore 加密库目录)与 DOCGEN_E2E_SENTINEL(样例明文标志串),本脚本 SKIP"
exit 77
fi
command -v curl >/dev/null || { echo "curl 缺失"; exit 2; }
PY=/home/xzq/5090/teamWorkspace/zh/plantai-rag-new-venv/bin/python
# ---------- DC-E2E-CURL-01 健康检查 ----------
say "DC-E2E-CURL-01 /api/vstore/health"
HEALTH=$(curl -fsS "$VSTORE/api/vstore/health") || die "vstore health 请求失败"
echo "$HEALTH" | grep -q '"ok":true' && ok "health ok" || die "health 非 ok:$HEALTH"
# ---------- DC-E2E-CURL-02 入库 → 保密断言(黄金断言) ----------
say "DC-E2E-CURL-02 入库 + ls 仅 .enc + 明文 grep 无命中"
SAMPLE=/tmp/docgen_e2e_sample.docx
"$PY" - <<'PYEOF' || die "样例 docx 生成失败"
import os
from docx import Document
d = Document()
d.add_heading("占位测试标题", level=1)
d.add_paragraph("样例明文标志串:%s。" % os.environ["DOCGEN_E2E_SENTINEL"])
d.save("/tmp/docgen_e2e_sample.docx")
PYEOF
INGEST_OUT=$(curl -fsS -X POST "$VSTORE/api/vstore/ingest" \
-F "file=@$SAMPLE;filename=样例通知.docx" \
-F "name=样例通知R1" -F "category=通知" -F "as_template=true")
echo "$INGEST_OUT" | grep -q '"ok":true' && ok "ingest ok" || die "ingest 失败:$INGEST_OUT"
NEW_DOC_ID=$(echo "$INGEST_OUT" | sed -n 's/.*"document_id":"\([^"]*\)".*/\1/p')
[ -n "$NEW_DOC_ID" ] && ok "取到 document_id=$NEW_DOC_ID" || die "ingest 响应缺 document_id"
# 保密断言 A:ls vault 只见 .enc
LS_OUT=$(ls -1 "$VAULT")
echo "$LS_OUT" | grep -q '\.enc$' || die "vault 目录无 .enc 文件:$LS_OUT"
BAD=$(echo "$LS_OUT" | grep -v -E '(\.enc$)' || true)
[ -z "$BAD" ] && ok "ls vault 仅见 .enc" || die "vault 出现异常文件:$BAD"
# 保密断言 B:明文 grep 无命中
if grep -rq "$SENTINEL" "$VAULT" 2>/dev/null; then die "vault 内 grep 命中明文标志串(明文落盘!)"; fi
ok "明文 grep 无命中($SENTINEL)"
# ---------- DC-E2E-CURL-03 检索 ----------
say "DC-E2E-CURL-03 检索"
SEARCH_MODE=$(curl -fsS "$VSTORE/api/vstore/search?q=$SENTINEL&top_k=3&as_template=true" \
| sed -n 's/.*"mode":"\([^"]*\)".*/\1/p')
case "$SEARCH_MODE" in
vector|keyword|latest) ok "search mode=$SEARCH_MODE(三档降级内)" ;;
*) die "检索 mode 异常:$SEARCH_MODE" ;;
esac
# ---------- DC-E2E-CURL-04 取明文(仅生成时取用路径) ----------
say "DC-E2E-CURL-04 取文档明文"
curl -fsS "$VSTORE/api/vstore/documents/$NEW_DOC_ID" >/tmp/docgen_doc.json \
&& ok "GET documents/{id} 200" || die "GET documents/{id} 失败"
grep -q "$SENTINEL" /tmp/docgen_doc.json \
&& ok "响应含明文全文(占位样例标志串)" || die "documents 响应未含明文全文"
grep -q '"outline"' /tmp/docgen_doc.json && ok "响应含 outline 字段" || die "documents 响应缺 outline"
rm -f /tmp/docgen_doc.json
# ---------- DC-E2E-CURL-05 BFF 入库 ----------
say "DC-E2E-CURL-05 BFF 入库"
BFF_UP=$(curl -fsS -X POST "$BFF/api/docgen/library" \
-F "file=@$SAMPLE;filename=样例通知BFF.docx" \
-F "name=样例通知BFFR1" -F "category=通知")
echo "$BFF_UP" | grep -q '"ok":true' && ok "BFF 入库 ok" || die "BFF 入库失败:$BFF_UP"
BFF_LIB_ID=$(echo "$BFF_UP" | sed -n 's/.*"library_id":"\([^"]*\)".*/\1/p' | head -1)
[ -n "$BFF_LIB_ID" ] && ok "BFF 库记录 id=$BFF_LIB_ID" || die "BFF 入库响应缺 library_id"
# 复验保密断言
if grep -rq "$SENTINEL" "$VAULT" 2>/dev/null; then die "BFF 入库后 vault 出现明文(保密断言失败)"; fi
ok "BFF 入库后 vault 仍无明文"
# ---------- DC-E2E-CURL-06 BFF 生成 ----------
say "DC-E2E-CURL-06 BFF 生成"
GEN=$(curl -fsS -X POST "$BFF/api/docgen/generate" \
-H 'Content-Type: application/json' \
-d '{"description":"帮我写一份年度工作总结","session_id":"e2e-sess-1","library_ids":[]}')
echo "$GEN" | grep -q '"status":"done"' && ok "生成 done" || die "生成未 done:$GEN"
ART_ID=$(echo "$GEN" | sed -n 's/.*"artifact":{[^}]*"id":"\([^"]*\)".*/\1/p')
[ -n "$ART_ID" ] && ok "取到 artifact id=$ART_ID" || die "未取到 artifact id"
# ---------- DC-E2E-CURL-07 编辑/保存/导出 ----------
say "DC-E2E-CURL-07 编辑/保存/导出"
curl -fsS -X PATCH "$BFF/api/docgen/artifacts/$ART_ID/content" \
-H 'Content-Type: application/json' -d '{"markdown":"# 新标题\n\n新正文段落。"}' \
| grep -q '"ok":true' && ok "PATCH content ok" || die "PATCH content 失败"
curl -fsS -X POST "$BFF/api/docgen/artifacts/$ART_ID/edit" \
-H 'Content-Type: application/json' -d '{"instruction":"润色一下第一段"}' \
| grep -q '"ok":true' && ok "edit ok" || die "edit 失败"
curl -fsS -X POST "$BFF/api/docgen/artifacts/$ART_ID/export" \
-H 'Content-Type: application/json' -d '{"format":"pdf"}' \
| grep -q '"ok":true' && ok "export pdf ok" || die "export 失败"
# ---------- DC-E2E-CURL-08 下载断言 + 可打开断言 ----------
say "DC-E2E-CURL-08 下载 attachment + 文件可打开"
cd /tmp || exit 2
curl -fsS -D /tmp/docgen_dl_headers.txt -o /tmp/docgen_e2e_out.pdf \
"$BFF/api/docgen/artifacts/$ART_ID/download?format=pdf" || die "download 失败"
grep -qi 'Content-Disposition:.*attachment' /tmp/docgen_dl_headers.txt \
&& ok "Content-Disposition attachment" || die "缺 attachment 头:$(cat /tmp/docgen_dl_headers.txt)"
grep -qi "filename\*=UTF-8''" /tmp/docgen_dl_headers.txt \
&& ok "RFC 5987 filename* 编码" || echo " [WARN] 未检出 filename*=UTF-8''(记录实测列)"
"$PY" - <<'PYEOF' && ok "PDF 可打开且页数>0" || die "下载的 PDF 打不开"
import fitz
with fitz.open("/tmp/docgen_e2e_out.pdf") as doc:
assert doc.page_count > 0
PYEOF
curl -fsS -X POST "$BFF/api/docgen/artifacts/$ART_ID/export" \
-H 'Content-Type: application/json' -d '{"format":"docx"}' \
| grep -q '"ok":true' || die "export docx 失败"
curl -fsS -o /tmp/docgen_e2e_out.docx \
"$BFF/api/docgen/artifacts/$ART_ID/download?format=docx" || die "docx download 失败"
"$PY" - <<'PYEOF' && ok "DOCX 可打开且段落>0" || die "下载的 DOCX 打不开"
import docx
d = docx.Document("/tmp/docgen_e2e_out.docx")
assert len(d.paragraphs) > 0
PYEOF
# ---------- DC-E2E-CURL-09 删除与收尾保密复验 ----------
say "DC-E2E-CURL-09 删除与收尾"
if [ -n "$BFF_LIB_ID" ]; then
DL_STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE "$BFF/api/docgen/library/$BFF_LIB_ID")
[ "$DL_STATUS" = "204" ] && ok "DELETE 库记录 204" || die "DELETE 库记录 HTTP $DL_STATUS"
# vstore 端删除复验:BFF 库记录 id 即 vstore document_id,对应 .enc 应消失
if [ ! -f "$VAULT/$BFF_LIB_ID.enc" ]; then
ok "对应密文 .enc 已删除"
else
echo " [WARN] vault 端 $BFF_LIB_ID.enc 仍存在(记录实测列)"
fi
fi
if grep -rq "$SENTINEL" "$VAULT" 2>/dev/null; then die "收尾后 vault 仍有明文(保密断言失败)"; fi
ok "收尾后 vault 无明文"
rm -f "$SAMPLE" /tmp/docgen_e2e_out.pdf /tmp/docgen_e2e_out.docx /tmp/docgen_dl_headers.txt
echo "===== E2E 汇总:全部断言步骤通过(FAIL=0) ====="