| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- """Q1-B 8755短生命周期真实HTTP复验工具。"""
- from __future__ import annotations
- import json
- import os
- import sys
- import threading
- from pathlib import Path
- from urllib.parse import urlparse
- import requests
- from sqlalchemy import func, select
- from werkzeug.serving import make_server
- BACKEND_ROOT = Path(__file__).resolve().parents[2]
- if str(BACKEND_ROOT) not in sys.path:
- sys.path.insert(0, str(BACKEND_ROOT))
- def _assert_test_database() -> None:
- database_url = os.environ.get("DMS_DATABASE_URL", "")
- database_name = urlparse(database_url).path.lstrip("/")
- if not database_name.endswith("_test"):
- raise RuntimeError("Q1-B真实HTTP复验只允许连接以_test结尾的测试库")
- def main() -> None:
- _assert_test_database()
- password = os.environ["DMS_TEST_USER_PASSWORD"]
- from app import app
- from dms.extensions import db
- from dms.models import AuditLog
- server = make_server("127.0.0.1", 8755, app, threaded=True)
- server_thread = threading.Thread(
- target=server.serve_forever,
- name="q1b-http-verify",
- daemon=True,
- )
- server_thread.start()
- base_url = "http://127.0.0.1:8755/api/v1"
- origin = "http://127.0.0.1:9346"
- try:
- tokens: dict[str, str] = {}
- for username in ("admin", "user"):
- response = requests.post(
- f"{base_url}/auth/login",
- json={
- "username": username,
- "password": password,
- "keepSignedIn": False,
- },
- timeout=5,
- )
- response.raise_for_status()
- tokens[username] = response.json()["data"]["accessToken"]
- with app.app_context():
- audit_before = db.session.scalar(
- select(func.count()).select_from(AuditLog)
- )
- role_results = {}
- stable_data = None
- for username, token in tokens.items():
- response = requests.get(
- f"{base_url}/config/ui-dictionaries",
- headers={
- "Authorization": f"Bearer {token}",
- "Origin": origin,
- },
- timeout=5,
- )
- response.raise_for_status()
- body = response.json()
- assert body["requestId"] == response.headers["X-Request-Id"]
- assert response.headers["Access-Control-Allow-Origin"] == origin
- exposed = {
- value.strip().lower()
- for value in response.headers[
- "Access-Control-Expose-Headers"
- ].split(",")
- }
- assert "x-request-id" in exposed
- assert set(body["data"]["dictionaries"]) == {
- "roleCodes",
- "allowedModules",
- "documentTypes",
- "documentStatuses",
- "securityLevels",
- "visibilityTypes",
- "attachmentTypes",
- "subjectTypes",
- "allowedActions",
- "categoryTypes",
- "enabledStatuses",
- "auditResults",
- "auditActions",
- "auditTargets",
- }
- if stable_data is None:
- stable_data = body["data"]
- else:
- assert body["data"] == stable_data
- role_results[username] = {
- "status": response.status_code,
- "requestIdMatches": True,
- }
- repeated = requests.get(
- f"{base_url}/config/ui-dictionaries",
- headers={
- "Authorization": f"Bearer {tokens['admin']}",
- "Origin": origin,
- },
- timeout=5,
- )
- repeated.raise_for_status()
- assert repeated.json()["data"] == stable_data
- unauthenticated = requests.get(
- f"{base_url}/config/ui-dictionaries",
- headers={"Origin": origin},
- timeout=5,
- )
- assert unauthenticated.status_code == 401
- unauthenticated_body = unauthenticated.json()
- assert (
- unauthenticated_body["requestId"]
- == unauthenticated.headers["X-Request-Id"]
- )
- labels = {
- item["code"]: item["label"]
- for item in stable_data["dictionaries"]["securityLevels"]
- }
- assert labels["INTERNAL"] == "内部"
- assert repeated.encoding.lower() == "utf-8"
- with app.app_context():
- audit_after = db.session.scalar(
- select(func.count()).select_from(AuditLog)
- )
- assert audit_after == audit_before
- print(
- json.dumps(
- {
- "port": 8755,
- "database": "dms_test",
- "roles": role_results,
- "unauthenticatedStatus": unauthenticated.status_code,
- "dictionaryCount": len(stable_data["dictionaries"]),
- "utf8Chinese": True,
- "continuousResponsesStable": True,
- "auditCountBefore": audit_before,
- "auditCountAfter": audit_after,
- "requestIdMatches": True,
- "corsOrigin": origin,
- "exposeHeaders": repeated.headers[
- "Access-Control-Expose-Headers"
- ],
- },
- ensure_ascii=False,
- )
- )
- finally:
- server.shutdown()
- server.server_close()
- server_thread.join(timeout=5)
- if __name__ == "__main__":
- main()
|