Files
cms-SiteForge/scripts/http_v833_tradepro.py
T

79 lines
4.4 KiB
Python
Raw Normal View History

"""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()