Files

74 lines
4.1 KiB
Python
Raw Permalink Normal View History

"""Deterministic P3 5,000-product acceptance pilot (isolated, no network).
Run: python scripts/pilot_5000.py --report pilot.json
Optional full build: python scripts/pilot_5000.py --build --report pilot-build.json
No production data are opened or modified. Uses an independent temporary SQLite
volume, 10 x 500 rows; builds the full automotive static site and runs static QA.
A successful test is NOT a commercial content/SEO readiness certificate.
"""
import argparse
import json
import os
import sys
import tempfile
import time
import subprocess
from pathlib import Path
ROOT=Path(__file__).resolve().parent.parent
sys.path.insert(0,str(ROOT))
def run(build=False):
started=time.monotonic()
with tempfile.TemporaryDirectory(prefix='siteforge-5k-pilot-') as work:
os.environ['SITEFORGE_DATA_DIR']=work
os.environ.setdefault('SITEFORGE_ADMIN_PASSWORD','offline-pilot-only-long-password-123456789')
os.environ.setdefault('SITEFORGE_SESSION_SECRET','offline-pilot-only-session-1234567890123456789')
from fastapi.testclient import TestClient
from app.main import app
from app import db,builder,quality,v8_workflows as wf
from app.core import uid
with TestClient(app):
sid=uid();now=db.now()
db.insert('INSERT INTO sites(id,name,theme,created_at,updated_at) VALUES(?,?,?,?,?)',
(sid,'5K Acceptance Pilot','automotive',now,now))
for offset in range(0,5000,500):
data=[{'车型名称':f'Vehicle {i:05d}','品牌':f'Brand {i%20:02d}',
'SEO描述':f'Demo vehicle {i:05d}, pilot only'}
for i in range(offset,offset+500)]
batch=wf.stage(sid,data,kind='vehicle',origin=f'pilot-{offset//500}',
source_keys=[str(i) for i in range(offset,offset+500)])
result=wf.commit(sid,batch['batch_id'])
assert result['created']==500 and not result['errors'],result
import_sec=round(time.monotonic()-started,2)
assert db.one("SELECT COUNT(*) n FROM entries WHERE site_id=? AND type='vehicle'",(sid,))['n']==5000
if not build:
return {'status':'import_passed_build_not_run','source_rows':5000,
'committed':5000,'batches':10,'import_seconds':import_sec,
'note':'Use --build in a sufficiently provisioned CI runner for full static-build QA.'}
report=builder.build(sid,False)
build_sec=round(time.monotonic()-started-import_sec,2)
# Release/SEO QA runs in its own short-lived process in production.
# Do not reuse the large catalogue renderer's heap for the audit.
audit_code=("import json,sys; from app import quality; "
"print(json.dumps(quality.report(sys.argv[1],sys.argv[2])))")
audit=subprocess.run([sys.executable,'-c',audit_code,sid,report['version']],
cwd=str(ROOT),text=True,capture_output=True,timeout=120,check=True,
env=dict(os.environ))
qa=json.loads(audit.stdout)
result={'status':'passed' if qa['errors']==0 and report['pages']>=5000 else 'failed',
'source_rows':5000,'batches':10,'pages':report['pages'],'html_files':qa['files'],
'static_errors':qa['errors'],'static_warnings':qa['warnings'],
'import_seconds':import_sec,'build_seconds':build_sec,
'total_seconds':round(time.monotonic()-started,2),
'disclaimer':'Fixed sample data; not live MySQL, not Docker, not production SEO audit.'}
if result['status']!='passed':raise AssertionError(result)
return result
if __name__=='__main__':
p=argparse.ArgumentParser();p.add_argument('--report');p.add_argument('--build',action='store_true');args=p.parse_args()
result=run(build=args.build)
if args.report:Path(args.report).write_text(json.dumps(result,ensure_ascii=False,indent=2))
print(json.dumps(result,ensure_ascii=False,indent=2))