#!/usr/bin/env bash # Momentry Core API 全端點測試 — 完整輸入輸出記錄 # 用法: ./tests_api.sh [host] [port] # 預設: http://localhost:3003 HOST="${1:-localhost}" PORT="${2:-3003}" BASE="http://${HOST}:${PORT}" API_KEY="${MOMENTRY_API_KEY:-muser_test_001}" OUTDIR="docs_v1.0/API_V1.0.0/TEST_RESULTS" TIMESTAMP=$(date +%Y%m%d_%H%M%S) OUTFILE="${OUTDIR}/api_test_${TIMESTAMP}.md" LOGDIR="${OUTDIR}/api_responses_${TIMESTAMP}" mkdir -p "$LOGDIR" "$OUTDIR" PASS=0; FAIL=0 log_resp() { echo -n ""; } call_api() { local method="$1" url="$2" desc="$3" section="$4" body="${5:-}" local safe_name safe_name=$(echo "${desc}" | sed 's/[^a-zA-Z0-9_]/_/g' | cut -c1-40) local resp_file="${LOGDIR}/${section}_${safe_name}.json" local http_code http_code=$(curl -s -o "${resp_file}" -w "%{http_code}" \ -X "${method}" \ -H "Content-Type: application/json" \ -H "X-API-Key: ${API_KEY}" \ ${body:+-d "${body}"} \ "${BASE}${url}" 2>/dev/null) local resp_size=$(wc -c < "${resp_file}" 2>/dev/null | tr -d ' ') local resp_preview=$(head -c 200 "${resp_file}" 2>/dev/null | tr '\n' ' ') if [ "${http_code}" -ge 200 ] && [ "${http_code}" -lt 500 ]; then PASS=$((PASS+1)) else FAIL=$((FAIL+1)) fi cat >> "${OUTFILE}" << ENTRY ### ${method} ${url} **說明**: ${desc} **HTTP 狀態**: ${http_code} **回應大小**: ${resp_size} bytes **Request**: \`\`\`bash curl -X ${method} \\ -H "Content-Type: application/json" \\ -H "X-API-Key: YOUR_API_KEY" \\ ${body:+-d '${body}' \\} ${BASE}${url} \`\`\` **Response**: \`\`\`json $(cat "${resp_file}" 2>/dev/null) \`\`\` --- ENTRY printf " %-4s %-50s %s\n" "${http_code}" "${desc}" "${resp_preview:0:80}" } # ==== Test Execution ==== cat > "${OUTFILE}" << HEAD # Momentry Core API 全端點測試報告 (完整 I/O) **測試時間**: $(date '+%Y-%m-%d %H:%M:%S') **伺服器**: ${BASE} **API Key**: ${API_KEY:0:10}... **API 版本**: V4.0 / API V1 **端點總數**: 46 --- HEAD echo "=== Momentry Core API Test ===" echo "Server: ${BASE}" echo "" # 1. Health echo "--- 1. Health ---" SECTION="01_health" call_api GET "/health" "Health check" "$SECTION" call_api GET "/health/detailed" "Health detailed" "$SECTION" # 2. Auth echo "--- 2. Auth ---" SECTION="02_auth" call_api POST "/api/v1/auth/login" "Login" "$SECTION" '{"username":"demo","password":"demo"}' call_api POST "/api/v1/auth/logout" "Logout" "$SECTION" # 3. Files echo "--- 3. Files ---" SECTION="03_files" call_api GET "/api/v1/files" "List files" "$SECTION" call_api GET "/api/v1/files/scan" "Scan files" "$SECTION" call_api POST "/api/v1/files/register" "Register file" "$SECTION" '{"path":"/Users/accusys/test_video/charade_sample.mp4"}' call_api POST "/api/v1/files/unregister" "Unregister file" "$SECTION" '{"file_uuid":"00000000000000000000000000000000"}' DEMO_FILE="417a7e93860d70c87aee6c4c1b715d70" call_api GET "/api/v1/file/${DEMO_FILE}" "File detail" "$SECTION" call_api GET "/api/v1/file/${DEMO_FILE}/probe" "File probe" "$SECTION" call_api GET "/api/v1/file/${DEMO_FILE}/identities" "File identities" "$SECTION" call_api GET "/api/v1/file/${DEMO_FILE}/chunks" "File chunks" "$SECTION" call_api POST "/api/v1/file/${DEMO_FILE}/process" "Trigger processing" "$SECTION" '{"processors":["story"]}' # 4. Identity echo "--- 4. Identity ---" SECTION="04_identity" call_api GET "/api/v1/identities" "List identities" "$SECTION" call_api POST "/api/v1/identity" "Create identity" "$SECTION" '{"face_json_path":"test","identity_name":"Test Identity"}' DEMO_ID="a9a90105-6d6b-46ff-92da-0c3c1a57dff4" call_api GET "/api/v1/identity/${DEMO_ID}" "Identity detail" "$SECTION" call_api GET "/api/v1/identity/${DEMO_ID}/files" "Identity files" "$SECTION" call_api GET "/api/v1/identity/${DEMO_ID}/chunks" "Identity chunks" "$SECTION" call_api POST "/api/v1/identity/${DEMO_ID}/bind" "Bind face" "$SECTION" "{\"file_uuid\":\"${DEMO_FILE}\",\"face_id\":\"face_100\"}" call_api POST "/api/v1/identity/${DEMO_ID}/unbind" "Unbind face" "$SECTION" "{\"file_uuid\":\"${DEMO_FILE}\",\"face_id\":\"face_100\"}" call_api POST "/api/v1/identity/00000000-0000-0000-0000-000000000001/mergeinto" "Merge into" "$SECTION" '{"into_uuid":"00000000-0000-0000-0000-000000000002"}' call_api DELETE "/api/v1/identity/00000000-0000-0000-0000-000000000003" "Delete identity" "$SECTION" # 5. Faces echo "--- 5. Faces ---" SECTION="05_faces" call_api GET "/api/v1/faces/candidates" "Face candidates" "$SECTION" # 6. Search echo "--- 6. Search ---" SECTION="06_search" call_api POST "/api/v1/search" "Vector search" "$SECTION" '{"query":"Cary Grant as mysterious stranger","limit":5}' call_api POST "/api/v1/search/bm25" "BM25 search" "$SECTION" '{"query":"stolen fortune thriller","limit":5}' call_api POST "/api/v1/search/hybrid" "Hybrid search" "$SECTION" '{"query":"Paris apartment scene","limit":5}' call_api POST "/api/v1/search/smart" "Smart search" "$SECTION" '{"uuid":"'${DEMO_FILE}'","query":"Audrey Hepburn","limit":5}' call_api POST "/api/v1/search/universal" "Universal search" "$SECTION" '{"query":"stamp","uuid":"'${DEMO_FILE}'","limit":5}' call_api POST "/api/v1/search/frames" "Frame search" "$SECTION" '{"query":"passport","uuid":"'${DEMO_FILE}'","limit":5}' call_api POST "/api/v1/search/visual" "Visual search" "$SECTION" "{\"uuid\":\"${DEMO_FILE}\",\"criteria\":{}}" call_api POST "/api/v1/search/visual/class" "Visual by class" "$SECTION" "{\"uuid\":\"${DEMO_FILE}\",\"object_class\":\"person\"}" call_api POST "/api/v1/search/visual/density" "Visual by density" "$SECTION" "{\"uuid\":\"${DEMO_FILE}\",\"min_density\":0.5}" call_api POST "/api/v1/search/visual/combination" "Visual combination" "$SECTION" "{\"uuid\":\"${DEMO_FILE}\",\"combination\":[[\"person\",1]]}" call_api POST "/api/v1/search/visual/stats" "Visual stats" "$SECTION" "{\"uuid\":\"${DEMO_FILE}\"}" # 7. Jobs echo "--- 7. Jobs ---" SECTION="07_jobs" call_api GET "/api/v1/jobs" "List jobs" "$SECTION" call_api GET "/api/v1/job/00000000-0000-0000-0000-000000000000" "Job detail" "$SECTION" call_api GET "/api/v1/rule/story/status" "Rule status" "$SECTION" call_api GET "/api/v1/progress/${DEMO_FILE}" "Progress" "$SECTION" # 8. Resources echo "--- 8. Resources ---" SECTION="08_resources" call_api GET "/api/v1/resources" "List resources" "$SECTION" call_api POST "/api/v1/resource/register" "Register resource" "$SECTION" '{"name":"demo_worker","type":"worker","host":"localhost","port":9000}' call_api POST "/api/v1/resource/heartbeat" "Resource heartbeat" "$SECTION" '{"name":"demo_worker"}' # 9. Agents echo "--- 9. Agents ---" SECTION="09_agents" call_api POST "/api/v1/agents/translate" "Translate" "$SECTION" '{"text":"Hello world","target_language":"zh-TW"}' call_api POST "/api/v1/agents/identity/analyze" "Identity analyze" "$SECTION" "{\"file_uuid\":\"${DEMO_FILE}\"}" call_api POST "/api/v1/agents/identity/suggest" "Identity suggest" "$SECTION" "{\"file_uuid\":\"${DEMO_FILE}\"}" call_api GET "/api/v1/agents/identity/status" "Identity agent status" "$SECTION" call_api POST "/api/v1/agents/suggest/merge" "Suggest merge" "$SECTION" "{\"file_uuid\":\"${DEMO_FILE}\"}" call_api POST "/api/v1/agents/5w1h/analyze" "5W1H analyze" "$SECTION" '{"chunk_id":"chunk_1"}' call_api POST "/api/v1/agents/5w1h/batch" "5W1H batch" "$SECTION" '{"chunk_ids":["chunk_1","chunk_2"]}' call_api GET "/api/v1/agents/5w1h/status" "5W1H status" "$SECTION" # 10. Stats & Admin echo "--- 10. Stats & Admin ---" SECTION="10_stats" call_api GET "/api/v1/stats/sftpgo" "SFTPGo status" "$SECTION" call_api GET "/api/v1/stats/inference" "Inference health" "$SECTION" call_api POST "/api/v1/config/cache" "Cache toggle" "$SECTION" '{"enable":true}' # ---- Summary ---- TOTAL=$((PASS + FAIL)) cat >> "${OUTFILE}" << SUMMARY --- ## 測試摘要 | 結果 | 數量 | 佔比 | |------|------|------| | ✅ 通過 (2xx/3xx/4xx) | ${PASS} | $(awk "BEGIN {printf \"%.0f\", ${PASS}/${TOTAL}*100}")% | | ❌ 失敗 (5xx) | ${FAIL} | $(awk "BEGIN {printf \"%.0f\", ${FAIL}/${TOTAL}*100}")% | | **合計** | **${TOTAL}** | **100%** | > 註: 4xx 回應(如 404 Not Found、422 Unprocessable)視為「通過」,因為端點正常回應只是請求參數未能完整比對到資料。5xx 表示伺服器內部錯誤,需修復。 ## 示範數據 | 資源 | UUID | |------|------| | Demo File (Charade) | \`${DEMO_FILE}\` | | Demo Identity (Cary Grant) | \`${DEMO_ID}\` | ## 完整回應檔案 ${LOGDIR}/ SUMMARY echo "" echo "============================================" echo " Test Complete" echo " PASS: ${PASS} FAIL: ${FAIL} TOTAL: ${TOTAL}" echo " Report: ${OUTFILE}" echo " Responses: ${LOGDIR}/" echo "============================================"