Files
base/scripts/api_test.sh
iven 3772afd987 chore: 干净 ERP 基座 — 删除 health/ai/wechat 业务代码
删除内容:
- 前端: health/(67文件), ai/(2文件), Copilot, MediaPicker, 相关API/Store/Hook
- 后端: wechat_handler, wechat_service, wechat_user entity, analytics handler, ai_workflow_seed
- 配置: WechatConfig, AppConfig.wechat, AuthState wechat 字段
- 启动: 微信凭据检查块, ensure_ai_workflows() 调用
- 迁移: 新增 m20260613_000170_drop_wechat_users.rs
- 脚本: api_test_health_alert.py, api_test_mp.py, mpsync.sh/ps1
- E2E: health-data page, flows/ 目录

保留: erp-core/auth/workflow/message/config/plugin + 基座前端 + 通用组件
2026-06-13 00:32:50 +08:00

395 lines
17 KiB
Bash

#!/bin/bash
BASE="http://localhost:3000/api/v1"
RESULTS_FILE="/tmp/hms_test_results.txt"
> "$RESULTS_FILE"
# Login first
LOGIN_RESP=$(curl -s "$BASE/auth/login" -H "Content-Type: application/json" -d '{"username":"admin","password":"Admin@2026"}')
TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])" 2>/dev/null)
REFRESH_TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['refresh_token'])" 2>/dev/null)
if [ -z "$TOKEN" ]; then
echo "LOGIN FAILED - cannot continue"
exit 1
fi
echo "Login successful, TOKEN length: ${#TOKEN}"
# Helper function
test_endpoint() {
local method=$1
local url=$2
local data="$3"
local label=$4
local expected="$5"
local resp_body=""
local http_code=""
if [ "$method" = "GET" ]; then
RESP=$(curl -s -w "\nHTTP_CODE:%{http_code}" "$BASE$url" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" 2>/dev/null)
elif [ "$method" = "DELETE" ]; then
RESP=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X DELETE "$BASE$url" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" 2>/dev/null)
else
RESP=$(curl -s -w "\nHTTP_CODE:%{http_code}" -X "$method" "$BASE$url" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "$data" 2>/dev/null)
fi
http_code=$(echo "$RESP" | grep "HTTP_CODE:" | sed 's/HTTP_CODE://')
resp_body=$(echo "$RESP" | grep -v "HTTP_CODE:")
success=$(echo "$resp_body" | python3 -c "import sys,json; d=json.load(sys.stdin); print('true' if d.get('success') else 'false')" 2>/dev/null || echo "parse_error")
local status="PASS"
if [ -n "$expected" ]; then
if [ "$http_code" != "$expected" ]; then
status="FAIL"
fi
else
if [ "$http_code" -ge 400 ] 2>/dev/null; then
status="FAIL"
fi
fi
echo "$status | $method $url | HTTP $http_code | success=$success | $label" >> "$RESULTS_FILE"
# Return the body for chaining
echo "$resp_body"
}
# ==========================================
# AUTH MODULE (24 endpoints)
# ==========================================
echo "=== AUTH MODULE TESTS ===" >> "$RESULTS_FILE"
# 1. POST /auth/login
echo "PASS | POST /auth/login | HTTP 200 | success=true | Login" >> "$RESULTS_FILE"
# 2. POST /auth/refresh
test_endpoint POST "/auth/refresh" "{\"refresh_token\":\"$REFRESH_TOKEN\"}" "Token refresh"
# Re-login since refresh may invalidate old token
LOGIN_RESP=$(curl -s "$BASE/auth/login" -H "Content-Type: application/json" -d '{"username":"admin","password":"Admin@2026"}')
TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])" 2>/dev/null)
REFRESH_TOKEN=$(echo "$LOGIN_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['refresh_token'])" 2>/dev/null)
# 3. POST /auth/logout - test last to keep token alive
echo "PENDING | POST /auth/logout | - | - | Logout (tested last)" >> "$RESULTS_FILE"
# 4. POST /auth/change-password (wrong password - expect 400 or error)
test_endpoint POST "/auth/change-password" '{"current_password":"wrong_password","new_password":"NewPass123!"}' "Change password wrong current" "400"
# 5. GET /users
USERS_RESP=$(test_endpoint GET "/users?page=1&page_size=10" "" "User list")
# 6. POST /users
RAND=$(date +%s)
CREATE_USER_RESP=$(test_endpoint POST "/users" "{\"username\":\"apitest_${RAND}\",\"password\":\"Test@2026pwd\",\"display_name\":\"API Test User\",\"email\":\"apitest_${RAND}@test.com\"}" "Create user")
USER_ID=$(echo "$CREATE_USER_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
echo " -> Created user: $USER_ID"
# 7. GET /users/{id}
if [ -n "$USER_ID" ]; then
test_endpoint GET "/users/$USER_ID" "" "Get user detail"
fi
# 8. PUT /users/{id}
if [ -n "$USER_ID" ]; then
test_endpoint PUT "/users/$USER_ID" '{"display_name":"API Test User Updated","email":"updated@test.com"}' "Update user"
fi
# 9. DELETE /users/{id}
if [ -n "$USER_ID" ]; then
test_endpoint DELETE "/users/$USER_ID" "" "Delete user (soft)"
fi
# 10. POST /users/{id}/roles - need user id and role id
echo "PENDING | POST /users/{id}/roles | - | - | Assign roles (need user+role)" >> "$RESULTS_FILE"
# 11. POST /users/{id}/reset-password
echo "SKIP | POST /users/{id}/reset-password | - | - | Reset password (skip safety)" >> "$RESULTS_FILE"
# 12. GET /roles
ROLES_RESP=$(test_endpoint GET "/roles?page=1&page_size=10" "" "Role list")
ROLE_ID=$(echo "$ROLES_RESP" | python3 -c "import sys,json; items=json.load(sys.stdin).get('data',{}).get('items',[]); print(items[0]['id'] if items else '')" 2>/dev/null)
echo " -> First role: $ROLE_ID"
# 13. POST /roles
CREATE_ROLE_RESP=$(test_endpoint POST "/roles" "{\"name\":\"API Test Role ${RAND}\",\"code\":\"api_test_${RAND}\",\"description\":\"Test role by API test\"}" "Create role")
NEW_ROLE_ID=$(echo "$CREATE_ROLE_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
echo " -> Created role: $NEW_ROLE_ID"
# 14. GET /roles/permissions => same as GET /permissions (tested later as #20)
# 15. GET /roles/{id}
if [ -n "$NEW_ROLE_ID" ]; then
test_endpoint GET "/roles/$NEW_ROLE_ID" "" "Get role detail"
fi
# 16. PUT /roles/{id}
if [ -n "$NEW_ROLE_ID" ]; then
test_endpoint PUT "/roles/$NEW_ROLE_ID" '{"name":"Updated API Test Role","description":"Updated"}' "Update role"
fi
# 17. DELETE /roles/{id}
if [ -n "$NEW_ROLE_ID" ]; then
test_endpoint DELETE "/roles/$NEW_ROLE_ID" "" "Delete role"
fi
# 18. GET /roles/{id}/permissions
if [ -n "$ROLE_ID" ]; then
test_endpoint GET "/roles/$ROLE_ID/permissions" "" "Get role permissions"
fi
# 19. POST /roles/{id}/permissions
if [ -n "$ROLE_ID" ]; then
test_endpoint POST "/roles/$ROLE_ID/permissions" '{"permission_ids":["user.list","user.create"]}' "Assign permissions to role"
fi
# 20. GET /permissions
test_endpoint GET "/permissions" "" "Permission list"
# 21. GET /organizations
ORGS_RESP=$(test_endpoint GET "/organizations?page=1&page_size=10" "" "Organization list")
# 22. POST /organizations
CREATE_ORG_RESP=$(test_endpoint POST "/organizations" "{\"name\":\"API Test Org ${RAND}\",\"code\":\"TEST_ORG_${RAND}\",\"description\":\"Test org\"}" "Create organization")
ORG_ID=$(echo "$CREATE_ORG_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
echo " -> Created org: $ORG_ID"
# 23. PUT /organizations/{id}
if [ -n "$ORG_ID" ]; then
test_endpoint PUT "/organizations/$ORG_ID" '{"name":"Updated Org","description":"Updated"}' "Update organization"
fi
# 24. DELETE /organizations/{id}
if [ -n "$ORG_ID" ]; then
test_endpoint DELETE "/organizations/$ORG_ID" "" "Delete organization"
fi
# ==========================================
# CONFIG MODULE (19 endpoints)
# ==========================================
echo "" >> "$RESULTS_FILE"
echo "=== CONFIG MODULE TESTS ===" >> "$RESULTS_FILE"
# 1. GET /config/dictionaries
DICTS_RESP=$(test_endpoint GET "/config/dictionaries?page=1&page_size=10" "" "Dictionary list")
# 2. POST /config/dictionaries
CREATE_DICT_RESP=$(test_endpoint POST "/config/dictionaries" "{\"name\":\"API Test Dict ${RAND}\",\"code\":\"api_test_dict_${RAND}\",\"description\":\"Test dictionary\"}" "Create dictionary")
DICT_ID=$(echo "$CREATE_DICT_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 3. PUT /config/dictionaries/{id}
if [ -n "$DICT_ID" ]; then
test_endpoint PUT "/config/dictionaries/$DICT_ID" '{"name":"Updated Dict","description":"Updated"}' "Update dictionary"
fi
# 4. DELETE /config/dictionaries/{id}
if [ -n "$DICT_ID" ]; then
test_endpoint DELETE "/config/dictionaries/$DICT_ID" "" "Delete dictionary"
fi
# 5. GET /config/dictionaries/items
test_endpoint GET "/config/dictionaries/items?page=1&page_size=10" "" "Dictionary items list"
# Create another dict for item tests
CREATE_DICT_RESP2=$(test_endpoint POST "/config/dictionaries" "{\"name\":\"API Test Dict Items ${RAND}\",\"code\":\"api_test_items_${RAND}\"}" "Create dict for item test")
DICT_ID2=$(echo "$CREATE_DICT_RESP2" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 6. POST /config/dictionaries/{dict_id}/items
if [ -n "$DICT_ID2" ]; then
CREATE_ITEM_RESP=$(test_endpoint POST "/config/dictionaries/$DICT_ID2/items" '{"label":"Test Item","value":"test_value","sort_order":1}' "Create dictionary item")
ITEM_ID=$(echo "$CREATE_ITEM_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 7. PUT /config/dictionaries/{dict_id}/items/{item_id}
if [ -n "$ITEM_ID" ]; then
test_endpoint PUT "/config/dictionaries/$DICT_ID2/items/$ITEM_ID" '{"label":"Updated Item","value":"updated_value"}' "Update dictionary item"
# 8. DELETE /config/dictionaries/{dict_id}/items/{item_id}
test_endpoint DELETE "/config/dictionaries/$DICT_ID2/items/$ITEM_ID" "" "Delete dictionary item"
fi
fi
# 9. GET /config/menus
test_endpoint GET "/config/menus" "" "Menu list"
# 10. POST /config/menus
CREATE_MENU_RESP=$(test_endpoint POST "/config/menus" '{"name":"API Test Menu","path":"/test","icon":"test","sort_order":999,"type":"menu"}' "Create menu")
MENU_ID=$(echo "$CREATE_MENU_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 11. PUT /config/menus/{id}
if [ -n "$MENU_ID" ]; then
test_endpoint PUT "/config/menus/$MENU_ID" '{"name":"Updated Menu","path":"/test-updated"}' "Update menu"
fi
# 12. DELETE /config/menus/{id}
if [ -n "$MENU_ID" ]; then
test_endpoint DELETE "/config/menus/$MENU_ID" "" "Delete menu"
fi
# 13. GET /menus/user
test_endpoint GET "/menus/user" "" "User menu tree"
# 14. GET /config/settings/{key}
test_endpoint GET "/config/settings/system.title" "" "Get setting by key"
# 15. PUT /config/settings/{key}
test_endpoint PUT "/config/settings/system.title" '{"value":"HMS Health Platform"}' "Update setting"
# 16. GET /config/numbering-rules
test_endpoint GET "/config/numbering-rules?page=1&page_size=10" "" "Numbering rules list"
# 17. POST /config/numbering-rules
CREATE_NUM_RESP=$(test_endpoint POST "/config/numbering-rules" "{\"name\":\"API Test Rule ${RAND}\",\"code\":\"TEST_NUM_${RAND}\",\"prefix\":\"TST\",\"pattern\":\"{YYYY}{MM}-{SEQ}\",\"seq_length\":4}" "Create numbering rule")
NUM_RULE_ID=$(echo "$CREATE_NUM_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 18. POST /config/numbering-rules/{id}/generate
if [ -n "$NUM_RULE_ID" ]; then
test_endpoint POST "/config/numbering-rules/$NUM_RULE_ID/generate" "{}" "Generate number"
fi
# 19. GET /config/languages
test_endpoint GET "/config/languages" "" "Language list"
# ==========================================
# WORKFLOW MODULE (15 endpoints)
# ==========================================
echo "" >> "$RESULTS_FILE"
echo "=== WORKFLOW MODULE TESTS ===" >> "$RESULTS_FILE"
# 1. GET /workflow/definitions
test_endpoint GET "/workflow/definitions?page=1&page_size=10" "" "Workflow definitions list"
# 2. POST /workflow/definitions
BPMN='<?xml version="1.0" encoding="UTF-8"?><bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn"><bpmn:process id="Process_1" isExecutable="false"><bpmn:startEvent id="StartEvent_1"/><bpmn:endEvent id="EndEvent_1"/><bpmn:sequenceFlow id="Flow_1" sourceRef="StartEvent_1" targetRef="EndEvent_1"/></bpmn:process></bpmn:definitions>'
CREATE_WF_RESP=$(test_endpoint POST "/workflow/definitions" "{\"name\":\"API Test Workflow ${RAND}\",\"description\":\"Test workflow\",\"bpmn_xml\":\"${BPMN}\"}" "Create workflow definition")
WF_DEF_ID=$(echo "$CREATE_WF_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 3. GET /workflow/definitions/{id}
if [ -n "$WF_DEF_ID" ]; then
test_endpoint GET "/workflow/definitions/$WF_DEF_ID" "" "Get workflow definition detail"
# 4. PUT /workflow/definitions/{id}
test_endpoint PUT "/workflow/definitions/$WF_DEF_ID" '{"name":"Updated Workflow","description":"Updated"}' "Update workflow definition"
# 5. POST /workflow/definitions/{id}/publish
test_endpoint POST "/workflow/definitions/$WF_DEF_ID/publish" "{}" "Publish workflow"
fi
# 6. POST /workflow/definitions/{id}/deprecate - create and publish first
# Re-create for deprecate test
WF_DEF2_RESP=$(test_endpoint POST "/workflow/definitions" "{\"name\":\"API Test Workflow Dep ${RAND}\",\"description\":\"For deprecate\",\"bpmn_xml\":\"${BPMN}\"}" "Create workflow for deprecate")
WF_DEF2_ID=$(echo "$WF_DEF2_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
if [ -n "$WF_DEF2_ID" ]; then
test_endpoint POST "/workflow/definitions/$WF_DEF2_ID/publish" "{}" "Publish for deprecate"
test_endpoint POST "/workflow/definitions/$WF_DEF2_ID/deprecate" "{}" "Deprecate workflow"
fi
# 7. POST /workflow/instances
WF_INST_RESP=$(test_endpoint POST "/workflow/instances" "{\"definition_id\":\"${WF_DEF_ID}\",\"variables\":{}}" "Start workflow instance")
WF_INST_ID=$(echo "$WF_INST_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 8. GET /workflow/instances
test_endpoint GET "/workflow/instances?page=1&page_size=10" "" "Workflow instances list"
# 9. GET /workflow/instances/{id}
if [ -n "$WF_INST_ID" ]; then
test_endpoint GET "/workflow/instances/$WF_INST_ID" "" "Get instance detail"
# 10. POST /workflow/instances/{id}/suspend
test_endpoint POST "/workflow/instances/$WF_INST_ID/suspend" "{}" "Suspend instance"
# 11. POST /workflow/instances/{id}/resume
test_endpoint POST "/workflow/instances/$WF_INST_ID/resume" "{}" "Resume instance"
# 12. POST /workflow/instances/{id}/terminate
test_endpoint POST "/workflow/instances/$WF_INST_ID/terminate" "{}" "Terminate instance"
fi
# 13. GET /workflow/tasks/pending
test_endpoint GET "/workflow/tasks/pending?page=1&page_size=10" "" "Pending tasks"
# 14. GET /workflow/tasks/completed
test_endpoint GET "/workflow/tasks/completed?page=1&page_size=10" "" "Completed tasks"
# 15. POST /workflow/tasks/{id}/complete
PENDING_TASK_RESP=$(test_endpoint GET "/workflow/tasks/pending?page=1&page_size=1" "" "Get pending task for complete test")
TASK_ID=$(echo "$PENDING_TASK_RESP" | python3 -c "import sys,json; items=json.load(sys.stdin).get('data',{}).get('items',[]); print(items[0]['id'] if items else '')" 2>/dev/null)
if [ -n "$TASK_ID" ]; then
test_endpoint POST "/workflow/tasks/$TASK_ID/complete" '{"variables":{}}' "Complete task"
else
echo "SKIP | POST /workflow/tasks/{id}/complete | - | - | No pending task available" >> "$RESULTS_FILE"
fi
# ==========================================
# MESSAGE MODULE (10 endpoints)
# ==========================================
echo "" >> "$RESULTS_FILE"
echo "=== MESSAGE MODULE TESTS ===" >> "$RESULTS_FILE"
# 1. GET /messages
test_endpoint GET "/messages?page=1&page_size=10" "" "Message list"
# 2. POST /messages
CREATE_MSG_RESP=$(test_endpoint POST "/messages" '{"title":"API Test Message","content":"Test message content","type":"system","recipient_type":"user"}' "Send message")
MSG_ID=$(echo "$CREATE_MSG_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 3. GET /messages/unread-count
test_endpoint GET "/messages/unread-count" "" "Unread count"
# 4. PUT /messages/{id}/read
if [ -n "$MSG_ID" ]; then
test_endpoint PUT "/messages/$MSG_ID/read" "{}" "Mark message read"
fi
# 5. PUT /messages/read-all
test_endpoint PUT "/messages/read-all" "{}" "Mark all read"
# 6. DELETE /messages/{id}
if [ -n "$MSG_ID" ]; then
test_endpoint DELETE "/messages/$MSG_ID" "" "Delete message"
fi
# 7. GET /message-templates
test_endpoint GET "/message-templates?page=1&page_size=10" "" "Message templates list"
# 8. POST /message-templates
CREATE_TPL_RESP=$(test_endpoint POST "/message-templates" "{\"name\":\"API Test Template ${RAND}\",\"code\":\"test_tpl_${RAND}\",\"content\":\"Hello {{name}}\",\"channel\":\"system\"}" "Create template")
TPL_ID=$(echo "$CREATE_TPL_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('data',{}).get('id',''))" 2>/dev/null)
# 9. PUT /message-templates/{id}
if [ -n "$TPL_ID" ]; then
test_endpoint PUT "/message-templates/$TPL_ID" '{"name":"Updated Template","content":"Hello {{name}}, updated"}' "Update template"
fi
# 10. GET /message-subscriptions
test_endpoint GET "/message-subscriptions?page=1&page_size=10" "" "Subscriptions list"
# ==========================================
# Final: Test logout
# ==========================================
test_endpoint POST "/auth/logout" "{}" "Logout"
# ==========================================
# SUMMARY
# ==========================================
echo "" >> "$RESULTS_FILE"
echo "=== SUMMARY ===" >> "$RESULTS_FILE"
TOTAL=$(grep -c "^PASS\|^FAIL\|^SKIP\|^PENDING" "$RESULTS_FILE")
PASSED=$(grep -c "^PASS" "$RESULTS_FILE")
FAILED=$(grep -c "^FAIL" "$RESULTS_FILE")
SKIPPED=$(grep -c "^SKIP" "$RESULTS_FILE")
PENDING=$(grep -c "^PENDING" "$RESULTS_FILE")
echo "Total: $TOTAL | Passed: $PASSED | Failed: $FAILED | Skipped: $SKIPPED | Pending: $PENDING" >> "$RESULTS_FILE"
echo ""
echo "==============================="
echo "Test completed."
echo "==============================="
cat "$RESULTS_FILE"