138 lines
6.1 KiB
Python
138 lines
6.1 KiB
Python
"""仅在 Docker 本地测试容器中执行的真实 HTTP 冒烟检查。"""
|
|
import os
|
|
import sys
|
|
import time
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
import django
|
|
import requests
|
|
from bs4 import BeautifulSoup
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
|
|
if os.environ.get("DJANGO_SETTINGS_MODULE") != "wagtailcms.settings.docker_local":
|
|
raise SystemExit("拒绝执行:此脚本只允许用于 docker_local 隔离环境。")
|
|
|
|
django.setup()
|
|
|
|
from wagtail.models import Page
|
|
from apps.core.models import ContactPage, SiteSettings
|
|
from apps.forms.models import Lead
|
|
|
|
BACKEND = "http://localhost:8000"
|
|
FRONTEND = "http://frontend:3000"
|
|
COMPANY = "Docker 联调测试公司"
|
|
|
|
|
|
def require(condition, message):
|
|
if not condition:
|
|
raise AssertionError(message)
|
|
|
|
|
|
def csrf(response):
|
|
response.raise_for_status()
|
|
field = BeautifulSoup(response.text, "html.parser").find("input", {"name": "csrfmiddlewaretoken"})
|
|
require(field is not None, "响应没有 CSRF 表单令牌")
|
|
return field["value"]
|
|
|
|
|
|
def main():
|
|
session = requests.Session()
|
|
login_url = f"{BACKEND}/admin/login/"
|
|
token = csrf(session.get(login_url, timeout=30))
|
|
response = session.post(login_url, data={
|
|
"username": os.environ["DJANGO_SUPERUSER_USERNAME"],
|
|
"password": os.environ["DJANGO_SUPERUSER_PASSWORD"],
|
|
"csrfmiddlewaretoken": token,
|
|
}, headers={"Referer": login_url}, timeout=30)
|
|
response.raise_for_status()
|
|
require("sessionid" in session.cookies, "后台登录失败;已有管理员密码不会自动重置")
|
|
|
|
setup_url = f"{BACKEND}/admin/company-setup/"
|
|
payload = {
|
|
"company_name": COMPANY,
|
|
"contact_phone": "010-12345678",
|
|
"contact_email": "leads@example.test",
|
|
"address": "仅用于 Docker 本地联调",
|
|
"icp_number": "",
|
|
"create_demo": "on",
|
|
}
|
|
for attempt in range(2):
|
|
token = csrf(session.get(setup_url, timeout=30))
|
|
response = session.post(setup_url, data={**payload, "csrfmiddlewaretoken": token},
|
|
headers={"Referer": setup_url}, timeout=120)
|
|
response.raise_for_status()
|
|
require("企业资料已保存" in response.text, "开站向导保存失败")
|
|
require(SiteSettings.objects.filter(company_name=COMPANY).exists(), "企业资料未持久化")
|
|
if attempt == 0:
|
|
count = Page.objects.count()
|
|
page_state = list(Page.objects.order_by("pk").values_list(
|
|
"pk", "title", "live", "has_unpublished_changes", "latest_revision_id",
|
|
))
|
|
else:
|
|
require(Page.objects.count() == count, "重复开站产生重复页面")
|
|
require(list(Page.objects.order_by("pk").values_list(
|
|
"pk", "title", "live", "has_unpublished_changes", "latest_revision_id",
|
|
)) == page_state, "重复开站改变已有页面状态")
|
|
print("PASS: HTTP 登录、CSRF 开站表单及重复执行")
|
|
|
|
response = requests.post(f"{FRONTEND}/api/revalidate", json={"tags": ["wagtail-pages"]}, timeout=30)
|
|
require(response.status_code == 401, "缓存刷新接口未拒绝匿名请求")
|
|
response = requests.post(f"{FRONTEND}/api/revalidate", json={"tags": ["wagtail-pages", "site-settings"]},
|
|
headers={"Authorization": f"Bearer {os.environ['REVALIDATE_SECRET']}"}, timeout=30)
|
|
require(response.status_code == 200, "授权缓存刷新失败")
|
|
print("PASS: 前端缓存刷新鉴权和内部网络连接")
|
|
|
|
for path, text in [
|
|
("/", COMPANY), ("/products", "企业内容平台"),
|
|
("/products/content-platform", "企业内容平台"),
|
|
("/solutions/digital-workplace", "企业数字化协同"),
|
|
("/cases/demo-content-project", "虚构"),
|
|
("/blog/website-content-checklist", "上线内容清单"),
|
|
("/about", COMPANY), ("/contact", "需求描述"),
|
|
]:
|
|
for attempt in range(24):
|
|
response = requests.get(f"{FRONTEND}{path}", timeout=30)
|
|
if response.status_code == 200 and text in response.text:
|
|
break
|
|
time.sleep(5)
|
|
require(response.status_code == 200 and text in response.text, f"前端页面未显示真实内容:{path}")
|
|
print(f"PASS: 前端 {path}")
|
|
|
|
contact = ContactPage.objects.get(slug="contact")
|
|
form = next(block.value["form"] for block in contact.body if block.block_type == "form")
|
|
form.notification_email = "leads@example.test"
|
|
form.save(update_fields=["notification_email"])
|
|
marker = f"docker-smoke-{uuid.uuid4().hex}"
|
|
cors = requests.options(f"{BACKEND}/api/v1/custom/leads/", headers={
|
|
"Origin": "http://localhost:13000", "Access-Control-Request-Method": "POST",
|
|
"Access-Control-Request-Headers": "content-type",
|
|
}, timeout=30)
|
|
require(cors.headers.get("Access-Control-Allow-Origin") == "http://localhost:13000", "浏览器跨域预检未通过")
|
|
response = requests.post(f"{BACKEND}/api/v1/custom/leads/", json={
|
|
"form_id": form.pk, "data": {"name": "Docker 测试", "company": COMPANY,
|
|
"phone": "010-12345678", "email": "visitor@example.test", "message": marker},
|
|
"source_url": "http://localhost:13000/contact", "website": "",
|
|
}, headers={"Origin": "http://localhost:13000"}, timeout=30)
|
|
require(response.status_code == 201 and response.json().get("success"), "咨询提交失败")
|
|
require(Lead.objects.filter(form=form, data__message=marker).exists(), "咨询未入库")
|
|
found = False
|
|
for attempt in range(15):
|
|
messages = requests.get("http://mailpit:8025/api/v1/messages", timeout=10).json().get("messages", [])
|
|
for message in messages:
|
|
detail = requests.get(f"http://mailpit:8025/api/v1/message/{message['ID']}", timeout=10).json()
|
|
if marker in detail.get("Text", ""):
|
|
found = True
|
|
break
|
|
if found:
|
|
break
|
|
time.sleep(2)
|
|
require(found, "通知邮件未被 Mailpit 捕获")
|
|
print("PASS: 跨域预检、真实表单 API、PostgreSQL 线索入库及 SMTP 邮件捕获")
|
|
print("ALL LOCAL HTTP SMOKE CHECKS PASSED")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|