Files
cms-SiteForge/tests/test_p0_71.py
T
浅念 8cea7dee20 chore: baseline V8.10.0-dev.1 with v8_workflows type-mapping fix and trade-pro spec
- SiteForge Enterprise V8.10.0-dev.1 upstream source (210 tests)
- Fix: v8_workflows._mapped_input now reads both 类型/分类 columns so WXR
  imports keep post/product types instead of collapsing to page
- Docs: trade-pro theme port spec (R3) and implementation plan

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-22 16:49:25 +08:00

88 lines
4.2 KiB
Python

"""Deterministic P0 stabilization regression tests (no external services)."""
import json
import time
from pathlib import Path
from bs4 import BeautifulSoup
from fastapi.testclient import TestClient
from app import db, builder
from app.main import app
from app.preview_rewrite import rewrite_preview_html
from app.version import VERSION
from app.worker import heartbeat
from app.worker_health import healthy
def test_preview_rewrites_only_internal_root_links():
old='''<html><head><base href="/"></head><body><a href="/products/">Products</a>
<img src="/assets/example.png"><form action="/contact/"></form>
<video poster="/media/poster.jpg"></video><a href="//cdn.example/image"></a>
<a href="https://outside.example/about/"></a><a href="#part"></a>
<a href="/preview/s1/b1/old/">Old</a></body></html>'''
new=rewrite_preview_html(old,'s1','b1')
soup=BeautifulSoup(new,'html.parser')
assert soup.base['href']=='/preview/s1/b1/'
assert soup.find('a',string='Products')['href']=='/preview/s1/b1/products/'
assert soup.img['src']=='/preview/s1/b1/assets/example.png'
assert soup.form['action']=='/preview/s1/b1/contact/'
assert soup.video['poster']=='/preview/s1/b1/media/poster.jpg'
assert soup.select('a[href="//cdn.example/image"]')
assert soup.select('a[href="https://outside.example/about/"]')
assert soup.select('a[href="#part"]')
assert soup.select('a[href="/preview/s1/b1/old/"]')
assert 'href="/preview/s1/b1/preview/s1/b1/"' not in new
def test_preview_does_not_modify_static_files(monkeypatch,tmp_path):
monkeypatch.setattr(db,'DATA',tmp_path)
monkeypatch.setattr(db,'DB_FILE',tmp_path/'siteforge.sqlite3')
monkeypatch.setenv('SITEFORGE_ADMIN_PASSWORD','test-p0-password-12345')
monkeypatch.setenv('SITEFORGE_SESSION_SECRET','test-p0-long-session-secret-value-123456')
with TestClient(app) as client:
assert client.get('/favicon.ico').status_code==200
health=client.get('/api/health').json()
assert health['version']==VERSION
assert isinstance(health['commit'],str) and health['commit']
assert client.post('/api/auth/login',json={'password':'test-p0-password-12345'}).status_code==200
client.headers['X-SiteForge-CSRF']=client.get('/api/auth/me').json()['csrf']
site=client.post('/api/sites',json={'name':'Preview Test','theme':'industrial'}).json()
sid=site['id']
built=builder.build(sid)['version']
root=tmp_path/'builds'/sid/built/'dist'
# Inject a link into an immutable build for precise comparison.
f=root/'index.html'
content=f.read_text(encoding='utf-8').replace('</body>','<a href="/products/">go to products</a></body>')
f.write_text(content,encoding='utf-8')
res=client.get(f'/preview/{sid}/{built}/')
assert res.status_code==200
s=BeautifulSoup(res.text,'html.parser')
assert s.find('a',string='go to products')['href']==f'/preview/{sid}/{built}/products/'
assert client.get(f'/preview/{sid}/{built}/products/').status_code==200
assert 'href="/products/"' in f.read_text(encoding='utf-8')
# Content types / 404 still preserved.
assert client.get(f'/preview/{sid}/{built}/does-not-exist/').status_code==404
def test_worker_probe_does_not_depend_on_web(monkeypatch,tmp_path):
monkeypatch.setattr(db,'DATA',tmp_path)
assert not healthy(tmp_path/'worker-heartbeat')
heartbeat()
assert healthy(tmp_path/'worker-heartbeat')
assert not healthy(tmp_path/'worker-heartbeat',max_age=0)
import os
old=time.time()-120
os.utime(tmp_path/'worker-heartbeat',(old,old))
assert not healthy(tmp_path/'worker-heartbeat',max_age=45)
def test_worker_compose_reuses_image_and_has_own_healthcheck():
import yaml
root=Path(__file__).resolve().parents[1]
for config in ('compose.yaml','compose.enterprise.yaml'):
comp=yaml.safe_load((root/config).read_text(encoding='utf-8'))
web=comp['services']['siteforge']
worker=comp['services']['worker']
assert web['image']==worker['image']
assert 'build' in web and 'build' not in worker
assert 'app.worker_health' in worker['healthcheck']['test']
assert 'http://127.0.0.1:8787/api/health' not in str(worker['healthcheck'])