diff --git a/test_all_apis.sh b/test_all_apis.sh new file mode 100755 index 0000000..10ab50c --- /dev/null +++ b/test_all_apis.sh @@ -0,0 +1,209 @@ +#!/bin/bash + +# ========================================== +# 完整 API 测试脚本 +# 测试所有 32 个后端 API 端点 +# ========================================== + +set -e + +BASE_URL="${API_BASE_URL:-http://localhost:8080}" +API_URL="$BASE_URL/api/v1" + +echo "==========================================" +echo " RustJR 完整 API 测试" +echo " 测试目标: $BASE_URL" +echo "==========================================" + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# 计数器 +TOTAL=0 +PASSED=0 +FAILED=0 + +# 测试函数 +test_api() { + local method=$1 + local endpoint=$2 + local data=$3 + local description=$4 + + TOTAL=$((TOTAL + 1)) + + echo -n "[$TOTAL] $description... " + + if [ "$method" == "GET" ]; then + response=$(curl -s -o /dev/null -w "%{http_code}" "$API_URL$endpoint" 2>/dev/null || echo "000") + else + response=$(curl -s -o /dev/null -w "%{http_code}" -X $method -H "Content-Type: application/json" -d "$data" "$API_URL$endpoint" 2>/dev/null || echo "000") + fi + + if [ "$response" == "200" ] || [ "$response" == "201" ]; then + echo -e "${GREEN}✓ PASS${NC} (HTTP $response)" + PASSED=$((PASSED + 1)) + elif [ "$response" == "404" ] || [ "$response" == "400" ]; then + echo -e "${YELLOW}⚠ WARN${NC} (HTTP $response - 可能数据不存在)" + PASSED=$((PASSED + 1)) + elif [ "$response" == "000" ]; then + echo -e "${RED}✗ FAIL${NC} (连接失败)" + FAILED=$((FAILED + 1)) + else + echo -e "${RED}✗ FAIL${NC} (HTTP $response)" + FAILED=$((FAILED + 1)) + fi +} + +# 健康检查 +echo "" +echo "==================== 健康检查 ====================" +test_api "GET" "" "" "健康检查 (基础路径)" + +HEALTH_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL/health" 2>/dev/null || echo "000") +if [ "$HEALTH_STATUS" == "200" ]; then + echo -e "${GREEN}✓ 服务运行正常${NC}" +else + echo -e "${RED}✗ 服务未运行,请先启动后端服务: cargo run${NC}" + exit 1 +fi + +# ==================== Account API (11个端点) ==================== +echo "" +echo "==================== Account API (11个端点) ====================" + +TIMESTAMP=$(date +%s) + +# 1. 创建实体账户 +test_api "POST" "/physical-accounts" "{\"account_no\":\"ACC_TEST_$TIMESTAMP\",\"account_name\":\"测试账户\",\"bank_code\":\"ICBC\",\"consistency_mode\":\"eventual\",\"outbound_control\":\"online_bank\"}" "创建实体账户" + +# 2. 获取实体账户列表 +test_api "GET" "/physical-accounts?page=1&page_size=10" "" "获取实体账户列表" + +# 3. 获取实体账户详情 +test_api "GET" "/physical-accounts/1" "" "获取实体账户详情" + +# 4. 冻结实体账户 +test_api "POST" "/physical-accounts/1/freeze" "{\"amount\":\"100.00\"}" "冻结实体账户" + +# 5. 解冻实体账户 +test_api "POST" "/physical-accounts/1/unfreeze" "{\"amount\":\"50.00\"}" "解冻实体账户" + +# 6. 创建虚拟子账户 +test_api "POST" "/sub-accounts" "{\"physical_account_id\":1,\"account_code\":\"SUB_$TIMESTAMP\",\"account_type\":\"settlement\"}" "创建虚拟子账户" + +# 7. 获取子账户详情 +test_api "GET" "/sub-accounts/1" "" "获取子账户详情" + +# 8. 获取子账户余额 +test_api "GET" "/sub-accounts/1/balance" "" "获取子账户余额" + +# 9. 冻结子账户 +test_api "POST" "/sub-accounts/1/freeze" "{\"amount\":\"10.00\"}" "冻结子账户" + +# 10. 解冻子账户 +test_api "POST" "/sub-accounts/1/unfreeze" "{\"amount\":\"5.00\"}" "解冻子账户" + +# 11. 关闭子账户 (跳过,会影响后续测试) +echo "[跳过] 关闭子账户 (会影响后续测试)" + +# ==================== Transaction API (5个端点) ==================== +echo "" +echo "==================== Transaction API (5个端点) ====================" + +# 12. 发起转账 +test_api "POST" "/transactions/transfer" "{\"from_account_id\":1,\"to_account_id\":1,\"amount\":\"100.00\",\"remark\":\"测试转账\"}" "发起转账" + +# 13. 发起充值 +test_api "POST" "/transactions/deposit" "{\"account_id\":1,\"amount\":\"1000.00\",\"source_key\":\"DEP_$TIMESTAMP\"}" "发起充值" + +# 14. 发起提现 +test_api "POST" "/transactions/withdraw" "{\"account_id\":1,\"amount\":\"50.00\"}" "发起提现" + +# 15. 获取交易详情 +test_api "GET" "/transactions/1" "" "获取交易详情" + +# 16. 获取交易列表 +test_api "GET" "/transactions?page=1&page_size=10" "" "获取交易列表" + +# ==================== Ledger API (3个端点) ==================== +echo "" +echo "==================== Ledger API (3个端点) ====================" + +# 17. 获取会计科目列表 +test_api "GET" "/ledger/subjects" "" "获取会计科目列表" + +# 18. 获取分录详情 +test_api "GET" "/ledger/entries/1" "" "获取分录详情" + +# 19. 获取账户分录列表 +test_api "GET" "/ledger/accounts/1/entries?account_type=physical" "" "获取账户分录列表" + +# ==================== Reconciliation API (8个端点) ==================== +echo "" +echo "==================== Reconciliation API (8个端点) ====================" + +# 20. 执行对账 +test_api "POST" "/reconciliation/run" "{\"physical_account_id\":1,\"recon_date\":\"2024-01-01\"}" "执行对账" + +# 21. 获取对账批次详情 +test_api "GET" "/reconciliation/batches/1" "" "获取对账批次详情" + +# 22. 获取对账明细 +test_api "GET" "/reconciliation/batches/1/items" "" "获取对账明细" + +# 23. 三账校验 +test_api "GET" "/reconciliation/three-account/1" "" "三账校验" + +# 24. 创建手工补录 +test_api "POST" "/reconciliation/adjustments" "{\"adjustment_type\":\"add\",\"account_id\":1,\"amount\":\"100.00\",\"reason\":\"测试补录\"}" "创建手工补录" + +# 25. 审批补录 +test_api "POST" "/reconciliation/adjustments/1/approve" "{\"approver\":\"admin\"}" "审批补录" + +# 26. 拒绝补录 +test_api "POST" "/reconciliation/adjustments/2/reject" "{\"approver\":\"admin\",\"reason\":\"测试拒绝\"}" "拒绝补录" + +# 27. 获取待审批补录 +test_api "GET" "/reconciliation/adjustments/pending" "" "获取待审批补录" + +# ==================== Points API (5个端点) ==================== +echo "" +echo "==================== Points API (5个端点) ====================" + +# 28. 获取积分账户 +test_api "GET" "/points/accounts/1" "" "获取积分账户" + +# 29. 获取积分 +test_api "POST" "/points/earn" "{\"points_account_id\":1,\"amount\":\"100.00\"}" "获取积分" + +# 30. 消费积分 +test_api "POST" "/points/spend" "{\"points_account_id\":1,\"amount\":\"50.00\"}" "消费积分" + +# 31. 转移积分 +test_api "POST" "/points/transfer" "{\"from_account_id\":1,\"to_account_id\":2,\"amount\":\"10.00\"}" "转移积分" + +# 32. 获取积分交易列表 +test_api "GET" "/points/transactions?page=1&page_size=10" "" "获取积分交易列表" + +# ==================== 测试结果汇总 ==================== +echo "" +echo "==========================================" +echo " 测试结果汇总" +echo "==========================================" +echo "总计测试: $TOTAL" +echo -e "通过: ${GREEN}$PASSED${NC}" +echo -e "失败: ${RED}$FAILED${NC}" +echo "" + +if [ $FAILED -eq 0 ]; then + echo -e "${GREEN}✓ 所有测试通过!${NC}" + exit 0 +else + echo -e "${YELLOW}⚠ 部分测试失败,请检查后端服务和数据库状态${NC}" + exit 1 +fi + diff --git a/tests/api_integration_tests.rs b/tests/api_integration_tests.rs new file mode 100644 index 0000000..bdf982f --- /dev/null +++ b/tests/api_integration_tests.rs @@ -0,0 +1,727 @@ +//! API 集成测试 +//! 测试所有 32 个后端 API 端点 + +use axum::http::StatusCode; +use serde_json::{json, Value}; + +/// 测试辅助模块 +mod test_helpers { + use super::*; + + /// 测试基础 URL + pub const BASE_URL: &str = "http://localhost:8080"; + + /// 创建测试客户端 + pub fn create_client() -> reqwest::Client { + reqwest::Client::new() + } + + /// 断言响应成功 + pub fn assert_success(status: StatusCode) { + assert!(status.is_success(), "Expected success status, got: {}", status); + } +} + +// ==================== Account API 测试 (11个端点) ==================== + +#[cfg(test)] +mod account_api_tests { + use super::test_helpers::*; + use reqwest::Client; + use serde_json::json; + + /// 测试创建实体账户 + /// POST /api/v1/physical-accounts + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_create_physical_account() { + let client = create_client(); + let url = format!("{}/api/v1/physical-accounts", BASE_URL); + + let body = json!({ + "account_no": format!("ACC_TEST_{}", chrono::Utc::now().timestamp()), + "account_name": "测试账户", + "bank_code": "ICBC", + "bank_name": "中国工商银行", + "consistency_mode": "eventual", + "outbound_control": "online_bank" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + assert!(res.status().is_success(), "创建账户失败: {}", res.status()); + + let json: serde_json::Value = res.json().await.unwrap(); + assert!(json["data"]["id"].is_number(), "返回数据应包含 id"); + println!("✅ 创建实体账户成功: {:?}", json); + } + + /// 测试获取实体账户列表 + /// GET /api/v1/physical-accounts + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_list_physical_accounts() { + let client = create_client(); + let url = format!("{}/api/v1/physical-accounts?page=1&page_size=10", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + assert!(res.status().is_success(), "获取账户列表失败"); + + let json: serde_json::Value = res.json().await.unwrap(); + assert!(json["data"]["data"].is_array(), "返回数据应为数组"); + println!("✅ 获取账户列表成功, 总数: {}", json["data"]["total"]); + } + + /// 测试获取实体账户详情 + /// GET /api/v1/physical-accounts/:id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_physical_account() { + let client = create_client(); + let url = format!("{}/api/v1/physical-accounts/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + // 可能账户不存在,接受 404 + if res.status().is_success() { + let json: serde_json::Value = res.json().await.unwrap(); + println!("✅ 获取账户详情成功: {:?}", json["data"]["account_no"]); + } else { + println!("⚠️ 账户不存在 (预期行为)"); + } + } + + /// 测试冻结实体账户资金 + /// POST /api/v1/physical-accounts/:id/freeze + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_freeze_physical_account() { + let client = create_client(); + let url = format!("{}/api/v1/physical-accounts/1/freeze", BASE_URL); + + let body = json!({ + "amount": "100.00" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("冻结账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试解冻实体账户资金 + /// POST /api/v1/physical-accounts/:id/unfreeze + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_unfreeze_physical_account() { + let client = create_client(); + let url = format!("{}/api/v1/physical-accounts/1/unfreeze", BASE_URL); + + let body = json!({ + "amount": "50.00" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("解冻账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试创建虚拟子账户 + /// POST /api/v1/sub-accounts + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_create_sub_account() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts", BASE_URL); + + let body = json!({ + "physical_account_id": 1, + "account_code": format!("SUB_TEST_{}", chrono::Utc::now().timestamp()), + "account_type": "settlement" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("创建子账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取子账户详情 + /// GET /api/v1/sub-accounts/:id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_sub_account() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取子账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取子账户余额 + /// GET /api/v1/sub-accounts/:id/balance + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_sub_account_balance() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts/1/balance", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取子账户余额结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试冻结子账户资金 + /// POST /api/v1/sub-accounts/:id/freeze + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_freeze_sub_account() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts/1/freeze", BASE_URL); + + let body = json!({ + "amount": "10.00" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("冻结子账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试解冻子账户资金 + /// POST /api/v1/sub-accounts/:id/unfreeze + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_unfreeze_sub_account() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts/1/unfreeze", BASE_URL); + + let body = json!({ + "amount": "5.00" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("解冻子账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试关闭子账户 + /// POST /api/v1/sub-accounts/:id/close + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_close_sub_account() { + let client = create_client(); + let url = format!("{}/api/v1/sub-accounts/1/close", BASE_URL); + + let res = client.post(&url) + .send() + .await + .expect("请求失败"); + + println!("关闭子账户结果: {} - {:?}", res.status(), res.text().await); + } +} + +// ==================== Transaction API 测试 (5个端点) ==================== + +#[cfg(test)] +mod transaction_api_tests { + use super::test_helpers::*; + use serde_json::json; + + /// 测试发起转账 + /// POST /api/v1/transactions/transfer + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_transfer() { + let client = create_client(); + let url = format!("{}/api/v1/transactions/transfer", BASE_URL); + + let body = json!({ + "from_account_id": 1, + "to_account_id": 2, + "amount": "100.00", + "remark": "测试转账" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("转账结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试发起充值 + /// POST /api/v1/transactions/deposit + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_deposit() { + let client = create_client(); + let url = format!("{}/api/v1/transactions/deposit", BASE_URL); + + let body = json!({ + "account_id": 1, + "amount": "1000.00", + "source_key": format!("DEP_{}", chrono::Utc::now().timestamp()), + "remark": "测试充值" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("充值结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试发起提现 + /// POST /api/v1/transactions/withdraw + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_withdraw() { + let client = create_client(); + let url = format!("{}/api/v1/transactions/withdraw", BASE_URL); + + let body = json!({ + "account_id": 1, + "amount": "50.00", + "remark": "测试提现" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("提现结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取交易详情 + /// GET /api/v1/transactions/:id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_transaction() { + let client = create_client(); + let url = format!("{}/api/v1/transactions/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取交易详情结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取交易列表 + /// GET /api/v1/transactions + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_list_transactions() { + let client = create_client(); + let url = format!("{}/api/v1/transactions?page=1&page_size=10", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + assert!(res.status().is_success(), "获取交易列表失败"); + println!("获取交易列表成功"); + } +} + +// ==================== Ledger API 测试 (3个端点) ==================== + +#[cfg(test)] +mod ledger_api_tests { + use super::test_helpers::*; + + /// 测试获取会计科目列表 + /// GET /api/v1/ledger/subjects + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_list_subjects() { + let client = create_client(); + let url = format!("{}/api/v1/ledger/subjects", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取会计科目结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取分录详情 + /// GET /api/v1/ledger/entries/:id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_entry() { + let client = create_client(); + let url = format!("{}/api/v1/ledger/entries/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取分录详情结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取账户分录列表 + /// GET /api/v1/ledger/accounts/:id/entries + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_account_entries() { + let client = create_client(); + let url = format!("{}/api/v1/ledger/accounts/1/entries?account_type=physical", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取账户分录结果: {} - {:?}", res.status(), res.text().await); + } +} + +// ==================== Reconciliation API 测试 (8个端点) ==================== + +#[cfg(test)] +mod reconciliation_api_tests { + use super::test_helpers::*; + use serde_json::json; + + /// 测试执行对账 + /// POST /api/v1/reconciliation/run + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_run_reconciliation() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/run", BASE_URL); + + let body = json!({ + "physical_account_id": 1, + "recon_date": "2024-01-01" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("执行对账结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取对账批次详情 + /// GET /api/v1/reconciliation/batches/:id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_batch() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/batches/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取对账批次结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取对账明细 + /// GET /api/v1/reconciliation/batches/:id/items + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_batch_items() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/batches/1/items", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取对账明细结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试三账校验 + /// GET /api/v1/reconciliation/three-account/:account_id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_verify_three_accounts() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/three-account/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + if res.status().is_success() { + let json: serde_json::Value = res.json().await.unwrap(); + println!("✅ 三账校验成功: is_balanced={}", json["data"]["is_balanced"]); + } else { + println!("三账校验失败: {}", res.status()); + } + } + + /// 测试创建手工补录 + /// POST /api/v1/reconciliation/adjustments + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_create_adjustment() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/adjustments", BASE_URL); + + let body = json!({ + "adjustment_type": "add", + "account_id": 1, + "amount": "100.00", + "reason": "测试补录" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("创建补录结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试审批补录 + /// POST /api/v1/reconciliation/adjustments/:id/approve + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_approve_adjustment() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/adjustments/1/approve", BASE_URL); + + let body = json!({ + "approver": "admin" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("审批补录结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试拒绝补录 + /// POST /api/v1/reconciliation/adjustments/:id/reject + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_reject_adjustment() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/adjustments/1/reject", BASE_URL); + + let body = json!({ + "approver": "admin", + "reason": "测试拒绝" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("拒绝补录结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取待审批补录列表 + /// GET /api/v1/reconciliation/adjustments/pending + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_list_pending_adjustments() { + let client = create_client(); + let url = format!("{}/api/v1/reconciliation/adjustments/pending", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取待审批补录结果: {} - {:?}", res.status(), res.text().await); + } +} + +// ==================== Points API 测试 (5个端点) ==================== + +#[cfg(test)] +mod points_api_tests { + use super::test_helpers::*; + use serde_json::json; + + /// 测试获取积分账户 + /// GET /api/v1/points/accounts/:sub_account_id + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_get_points_accounts() { + let client = create_client(); + let url = format!("{}/api/v1/points/accounts/1", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取积分账户结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取积分 + /// POST /api/v1/points/earn + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_earn_points() { + let client = create_client(); + let url = format!("{}/api/v1/points/earn", BASE_URL); + + let body = json!({ + "points_account_id": 1, + "amount": "100.00", + "remark": "测试获取积分" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("获取积分结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试消费积分 + /// POST /api/v1/points/spend + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_spend_points() { + let client = create_client(); + let url = format!("{}/api/v1/points/spend", BASE_URL); + + let body = json!({ + "points_account_id": 1, + "amount": "50.00", + "remark": "测试消费积分" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("消费积分结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试转移积分 + /// POST /api/v1/points/transfer + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_transfer_points() { + let client = create_client(); + let url = format!("{}/api/v1/points/transfer", BASE_URL); + + let body = json!({ + "from_account_id": 1, + "to_account_id": 2, + "amount": "10.00", + "remark": "测试转移积分" + }); + + let res = client.post(&url) + .json(&body) + .send() + .await + .expect("请求失败"); + + println!("转移积分结果: {} - {:?}", res.status(), res.text().await); + } + + /// 测试获取积分交易列表 + /// GET /api/v1/points/transactions + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_list_points_transactions() { + let client = create_client(); + let url = format!("{}/api/v1/points/transactions?page=1&page_size=10", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + println!("获取积分交易列表结果: {} - {:?}", res.status(), res.text().await); + } +} + +// ==================== 健康检查测试 ==================== + +#[cfg(test)] +mod health_tests { + use super::test_helpers::*; + + /// 测试健康检查端点 + /// GET /health + #[tokio::test] + #[ignore = "需要运行后端服务"] + async fn test_health_check() { + let client = create_client(); + let url = format!("{}/health", BASE_URL); + + let res = client.get(&url) + .send() + .await + .expect("请求失败"); + + assert!(res.status().is_success(), "健康检查失败"); + println!("✅ 健康检查通过"); + } +} +