230 lines
8.2 KiB
Python
230 lines
8.2 KiB
Python
"""
|
|
dnfs 黑盒用户模拟测试 — 创建笔记 → 查询 → 更新 → 删除(含内容审核)。
|
|
|
|
用户旅程:
|
|
已登录用户携带 Bearer Token:
|
|
1. 创建根节点笔记(内容经 ai_review 审核)
|
|
2. 创建子节点笔记
|
|
3. 查询节点列表
|
|
4. 更新笔记标题和内容
|
|
5. 删除叶子节点(无子节点)
|
|
6. 删除非空节点(应拒绝)
|
|
7. 无 Token 操作(应拒绝)
|
|
8. 创建时缺少必填参数(应报错)
|
|
|
|
前提: gateway 已启动,有已注册用户和有效 Token。
|
|
"""
|
|
|
|
import json
|
|
import random
|
|
import string
|
|
|
|
from helpers import (
|
|
http_post, try_parse_json,
|
|
assert_eq, assert_status, assert_true, assert_json_key,
|
|
skip, Counter, check_service,
|
|
)
|
|
from config import get_url, SERVICES
|
|
|
|
DNFS_URL = get_url("dnfs")
|
|
GATEWAY_URL = get_url("gateway")
|
|
|
|
|
|
def _random_test_user():
|
|
suffix = ''.join(random.choices(string.ascii_lowercase, k=6))
|
|
return f"dtest_{suffix}@test.local"
|
|
|
|
|
|
def _register_and_login(gw_url: str, counter: Counter):
|
|
"""通过 gateway 注册并登录,返回 (token, email)。失败返回 (None, None)。"""
|
|
email = _random_test_user()
|
|
password = "TestP@ss123"
|
|
|
|
# 注册
|
|
status, body, _ = http_post(f"{gw_url}/register", {
|
|
"username": email,
|
|
"password": password,
|
|
})
|
|
if status != 200:
|
|
return None, None
|
|
|
|
data = try_parse_json(body)
|
|
if not data or not data.get("success"):
|
|
return None, None
|
|
|
|
# 登录
|
|
status, body, _ = http_post(f"{gw_url}/login", {
|
|
"username": email,
|
|
"password": password,
|
|
})
|
|
if status != 200:
|
|
return None, None
|
|
|
|
data = try_parse_json(body)
|
|
if not data or not data.get("success"):
|
|
return None, None
|
|
|
|
token = (data.get("data") or {}).get("token", "")
|
|
return token, email
|
|
|
|
|
|
def run(url: str = None):
|
|
"""dnfs 用户模拟测试入口。返回 (passed, failed, skipped)。"""
|
|
du = url or DNFS_URL
|
|
c = Counter()
|
|
|
|
print(f"\n--- dnfs 笔记管理流程 ---\n")
|
|
|
|
# ------------------------------------------------------------------
|
|
# 0. 检查服务可用性
|
|
# ------------------------------------------------------------------
|
|
if not check_service(du)[0]:
|
|
skip("全部测试", "dnfs 服务不可达", c)
|
|
return c.passed, c.failed, c.skipped
|
|
|
|
# ------------------------------------------------------------------
|
|
# 准备: 注册用户并获取 Token
|
|
# ------------------------------------------------------------------
|
|
gw_available = check_service(GATEWAY_URL)[0]
|
|
if not gw_available:
|
|
skip("全部测试", "gateway 服务不可达,无法获取 Token", c)
|
|
return c.passed, c.failed, c.skipped
|
|
|
|
token, email = _register_and_login(GATEWAY_URL, c)
|
|
if not token:
|
|
skip("全部测试", "无法完成注册/登录获取 Token", c)
|
|
return c.passed, c.failed, c.skipped
|
|
|
|
auth_headers = {"Authorization": f"Bearer {token}"}
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 1: 无 Token 创建笔记 — 应拒绝
|
|
# ------------------------------------------------------------------
|
|
status, body, _ = http_post(f"{du}/add_note", {
|
|
"pid": 0,
|
|
"title": "test",
|
|
"content": "test content",
|
|
})
|
|
assert_eq(status, 401, "创建笔记-无Token-拒绝 (401)", c)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 2: 创建笔记 — 缺少参数
|
|
# ------------------------------------------------------------------
|
|
status, body, _ = http_post(f"{du}/add_note", {
|
|
"pid": 0,
|
|
}, headers=auth_headers)
|
|
assert_eq(status, 400, "创建笔记-缺少title/content (400)", c)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 3: 创建根节点笔记
|
|
# ------------------------------------------------------------------
|
|
note_title = f"测试笔记_{random.randint(1000, 9999)}"
|
|
note_content = "这是一段正常的测试内容,用于验证笔记创建功能。"
|
|
status, body, _ = http_post(f"{du}/add_note", {
|
|
"pid": 0,
|
|
"title": note_title,
|
|
"content": note_content,
|
|
}, headers=auth_headers)
|
|
# 期望 200(审核通过则成功)
|
|
data = try_parse_json(body)
|
|
assert_true(
|
|
status == 200 and data is not None and data.get("success") is True,
|
|
"创建笔记-根节点", c,
|
|
f"status={status} body={body[:150]}",
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 4: 查询根节点下的笔记列表
|
|
# ------------------------------------------------------------------
|
|
status, body, _ = http_post(f"{du}/get_notes", {"pid": 0})
|
|
assert_eq(status, 200, "查询笔记-根节点 (200)", c)
|
|
notes = try_parse_json(body)
|
|
assert_true(
|
|
isinstance(notes, list),
|
|
"查询笔记-返回列表", c,
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 5: 创建子节点笔记
|
|
# ------------------------------------------------------------------
|
|
# 先获取刚创建的笔记 ID
|
|
child_note_id = None
|
|
if notes and len(notes) > 0:
|
|
# 找到我们刚创建的笔记
|
|
for note in notes:
|
|
if note.get("title") == note_title:
|
|
child_note_id = note.get("id")
|
|
break
|
|
|
|
if child_note_id:
|
|
child_title = f"子笔记_{random.randint(1000, 9999)}"
|
|
child_content = "这是子节点的测试内容。"
|
|
status, body, _ = http_post(f"{du}/add_note", {
|
|
"pid": child_note_id,
|
|
"title": child_title,
|
|
"content": child_content,
|
|
}, headers=auth_headers)
|
|
data = try_parse_json(body)
|
|
assert_true(
|
|
status == 200 and data is not None,
|
|
"创建笔记-子节点", c,
|
|
f"status={status} body={body[:150]}",
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 6: 删除非空节点 — 应拒绝(有子节点)
|
|
# ------------------------------------------------------------------
|
|
if child_note_id:
|
|
status, body, _ = http_post(f"{du}/delete_note", {
|
|
"id": child_note_id,
|
|
}, headers=auth_headers)
|
|
data = try_parse_json(body)
|
|
assert_true(
|
|
status in (400, 403) or (data and not data.get("success")),
|
|
"删除笔记-非空节点-拒绝", c,
|
|
f"status={status} body={body[:150]}",
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 7: 更新笔记内容
|
|
# ------------------------------------------------------------------
|
|
if child_note_id:
|
|
updated_title = f"更新_{random.randint(1000, 9999)}"
|
|
updated_content = "更新后的测试内容,依然正常无害。"
|
|
status, body, _ = http_post(f"{du}/update_note", {
|
|
"id": child_note_id,
|
|
"pid": 0,
|
|
"title": updated_title,
|
|
"content": updated_content,
|
|
}, headers=auth_headers)
|
|
data = try_parse_json(body)
|
|
assert_true(
|
|
status == 200 and data is not None and data.get("success") is True,
|
|
"更新笔记-内容", c,
|
|
f"status={status} body={body[:150]}",
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 8: 更新笔记 — 缺少参数
|
|
# ------------------------------------------------------------------
|
|
status, body, _ = http_post(f"{du}/update_note", {
|
|
"id": child_note_id,
|
|
}, headers=auth_headers)
|
|
assert_eq(status, 400, "更新笔记-缺少参数 (400)", c)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 场景 9: 删除笔记 — 缺少 id 参数
|
|
# ------------------------------------------------------------------
|
|
status, body, _ = http_post(f"{du}/delete_note", {}, headers=auth_headers)
|
|
assert_eq(status, 400, "删除笔记-缺少id (400)", c)
|
|
|
|
# ------------------------------------------------------------------
|
|
# 汇总
|
|
# ------------------------------------------------------------------
|
|
print(f"\n dnfs 测试完成: {c.summary()}")
|
|
return c.passed, c.failed, c.skipped
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|