"""Regression tests for release safety and CMS review persistence.""" import json from fastapi.testclient import TestClient from fastapi import HTTPException import pytest from app import db, cms_pipeline, release_api from app.main import app def test_pending_and_failed_build_cannot_be_deployed(monkeypatch,tmp_path): monkeypatch.setattr(db,'DATA',tmp_path) monkeypatch.setattr(db,'DB_FILE',tmp_path/'pending.sqlite3') db.init() with db.connect() as c: c.execute('INSERT INTO sites(id,name,created_at,updated_at) VALUES (?,?,?,?)',('sitepending','Sample',db.now(),db.now())) for state in ['queued','running','failed','unknown']: c.execute('INSERT INTO builds(id,site_id,created_at,status,zip_path) VALUES (?,?,?,?,?)', (state,'sitepending',db.now(),state,str(tmp_path/'missing.zip'))) for state in ['queued','running','failed','unknown']: with pytest.raises(HTTPException) as exc: release_api.approved('sitepending',state) assert exc.value.status_code==409 def test_cms_warnings_saved_and_reviewed(monkeypatch,tmp_path): monkeypatch.setattr(db,'DATA',tmp_path) monkeypatch.setattr(db,'DB_FILE',tmp_path/'review.sqlite3') monkeypatch.setenv('SITEFORGE_ADMIN_PASSWORD','test-admin-password-for-cms-reviews') monkeypatch.setenv('SITEFORGE_SESSION_SECRET','test-session-secret-for-cms-reviews-long') with TestClient(app) as c: assert c.post('/api/auth/login',json={'password':'test-admin-password-for-cms-reviews'}).status_code==200 c.headers['X-SiteForge-CSRF']=c.get('/api/auth/me').json()['csrf'] res=c.post('/api/sites',json={'name':'CMS Review Test','mode':'migration'}) assert res.status_code==201,res.text sid=res.json()['id'] blob={'items':[{'id':3,'type':'page','title':{'rendered':'About'},'link':'https://old.example/about/', 'content':{'rendered':'
old
'},'acf':{'related':[1,2]}}]} res=c.post(f'/api/migrations/sites/{sid}/import',data={'platform':'wordpress-rest','conflict':'skip'}, files={'file':('export.json',json.dumps(blob).encode(),'application/json')}) assert res.status_code==200,res.text assert res.json()['pending_review_count']==1 get=c.get(f'/api/migrations/sites/{sid}/reviews') assert get.status_code==200 and get.json()['pending']==1 issue=get.json()['items'][0]['id'] reject=c.post(f'/api/migrations/sites/{sid}/reviews/{issue}/resolve',json={'resolution':'ok'}) assert reject.status_code==400 ok=c.post(f'/api/migrations/sites/{sid}/reviews/{issue}/resolve',json={'resolution':'已逐项检查关联产品及图片,确认无需迁移旧关联。'}) assert ok.status_code==200,ok.text assert ok.json()['pending']==0 assert c.get(f'/api/migrations/sites/{sid}/reviews').json()['items']==[] assert c.get(f'/api/migrations/sites/{sid}/reviews?state=resolved').json()['items'][0]['resolution'] def test_signatures_are_bound_to_http_path(monkeypatch,tmp_path): from app import deploy_agent import zipfile,io,time from fastapi.testclient import TestClient monkeypatch.setattr(deploy_agent,'ROOT',tmp_path) secret='release-secret-very-long-at-least-thirtytwo-bytes' monkeypatch.setenv('SITEFORGE_DEPLOY_SECRET',secret) buf=io.BytesIO() with zipfile.ZipFile(buf,'w') as z:z.writestr('index.html','