Files
cms-SiteForge/scripts/http_v833_tradepro.py
浅念 e21dbb6518 upgrade: adopt V8.33.1 — final merge, our patches upstreamed natively
V8.33.0 absorbed our entire platform patch set as native features
(discovery/env_for macro override/blocks.css priority/type-mapping fix/
frontend entries/locale override) and synced trade-pro from our remote;
V8.33.1 adds HESU PIPE industrial-theme home fixes (1.3.1).

Zero patch re-application this round — all verified native. Theme
suites 35/35; full run 428 passed + same 10 known Windows env fails
(FAILED set unchanged). Live: container 8.33.1-dev.1 healthy, hesupipe
192 entries intact, trade-pro build 203 pages 0 errors.

Patch registry retired to archive — future upgrades are plain overlay.

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-26 14:27:17 +08:00

79 lines
4.4 KiB
Python

"""End-to-end HTTP + Worker smoke test on an isolated disposable SQLite database.
Launches an actual uvicorn process, calls authenticated HTTP APIs, runs a real
Worker claim + isolated subprocess build, then downloads and checks the archive.
Never points at production data or remote deployment services.
"""
from __future__ import annotations
import io
import json
import os
import socket
import subprocess
import sys
import tempfile
import time
import zipfile
from pathlib import Path
from urllib.error import URLError
from urllib.request import urlopen
import httpx
ROOT=Path(__file__).resolve().parent.parent
def run():
with tempfile.TemporaryDirectory(prefix='siteforge-e2e-') as folder:
with socket.socket() as sock:
sock.bind(('127.0.0.1',0)); port=sock.getsockname()[1]
base=f'http://127.0.0.1:{port}'
env=os.environ.copy()
env.update(SITEFORGE_ADMIN_PASSWORD='e2e-only-dummy-password-123456',
SITEFORGE_SESSION_SECRET='e2e-only-session-secret-long-value-123456',
SITEFORGE_DATA_DIR=folder,SITEFORGE_DB_FILE=str(Path(folder)/'siteforge.sqlite3'),
SITEFORGE_DATABASE_URL='',SITEFORGE_REDIS_URL='',SITEFORGE_COOKIE_SECURE='false')
proc=subprocess.Popen([sys.executable,'-m','uvicorn','app.main:app','--host','127.0.0.1','--port',str(port)],
cwd=ROOT,env=env,stdout=subprocess.DEVNULL,stderr=subprocess.PIPE)
try:
for n in range(120):
if proc.poll() is not None:raise RuntimeError('Web startup failed: '+proc.stderr.read().decode(errors='replace')[-3000:])
try:
with urlopen(base+'/api/ready',timeout=0.5) as result:
if result.status==200:break
except (OSError,URLError):time.sleep(0.1)
else:raise RuntimeError('Web readiness timeout')
with httpx.Client(base_url=base,timeout=20,follow_redirects=False) as client:
auth=client.post('/api/auth/login',json={'username':'admin','password':env['SITEFORGE_ADMIN_PASSWORD']})
assert auth.status_code==200,auth.text
me=client.get('/api/auth/me')
assert me.status_code==200,me.text
client.headers['X-SiteForge-CSRF']=me.json()['csrf']
site=client.post('/api/sites',json={'name':'V8.33 Trade Pro Worker','theme':'trade-pro'})
assert site.status_code==201,site.text
sid=site.json()['id']
page=client.post(f'/api/sites/{sid}/entries',json={'type':'page','title':'Test about','route':'/about/','body':'E2E smoke content'})
assert page.status_code==201,page.text
job=client.post(f'/api/sites/{sid}/builds',json={'mirror_images':False},headers={'Idempotency-Key':'e2e-build-000001'})
assert job.status_code==202,job.text
completed=subprocess.run([sys.executable,'-c','from app import db,enterprise,worker; db.init(); enterprise.setup(); assert worker.run_once()'],cwd=ROOT,env=env,capture_output=True,text=True,timeout=70)
assert completed.returncode==0,completed.stderr[-2500:]
builds=client.get(f'/api/sites/{sid}/builds')
assert builds.status_code==200,builds.text
done=[x for x in builds.json() if x['status']=='complete']
if not done:
raise AssertionError('No completed static build: '+str(builds.json())[:1200])
archive=client.get(f"/api/sites/{sid}/builds/{done[0]['id']}/download")
assert archive.status_code==200,archive.text[:300]
with zipfile.ZipFile(io.BytesIO(archive.content)) as z:
assert 'index.html' in z.namelist()
assert 'about/index.html' in z.namelist()
assert '<html lang="en"' in z.read('index.html').decode('utf-8')
preview=client.get(f"/preview/{sid}/{done[0]['id']}/about/")
assert preview.status_code==200 and 'E2E smoke content' in preview.text
print('PASS: ready -> login/CSRF -> create site/page -> enqueue -> Worker build -> ZIP -> preview')
finally:
proc.terminate()
try:proc.communicate(timeout=5)
except subprocess.TimeoutExpired:proc.kill();proc.communicate()
if __name__=='__main__':run()