Files
cms-SiteForge/scripts/verify_sqlite_pg_transfer.py
T

69 lines
3.4 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""REAL PostgreSQL data migration CI smoke with a disposable isolated target.
This script deliberately never runs on ambiguous production-looking DB names.
Set SITEFORGE_ALLOW_PG_DATA_SMOKE=1 and database suffix _ci/_test.
"""
# Allow direct `python scripts/name.py` from a fresh source checkout.
import sys as _sys
from pathlib import Path as _Path
_sys.path.insert(0, str(_Path(__file__).resolve().parents[1]))
import os
import subprocess
import sys
import tempfile
import uuid
from pathlib import Path
from urllib.parse import unquote,urlsplit
from app import db
from app.sqlite_pg_transfer import migrate
from app.pg_disaster_recovery import RecoveryError
url = os.environ.get('SITEFORGE_DATABASE_URL','')
name = unquote(urlsplit(url).path.lstrip('/'))
if not db.POSTGRES or os.environ.get('SITEFORGE_ALLOW_PG_DATA_SMOKE')!='1' or not name.endswith(('_ci','_test')):
raise SystemExit('Requires explicit CI-only PG smoke flag and _ci/_test database')
with tempfile.TemporaryDirectory(prefix='sf-v818-ci-') as temp:
source=Path(temp)/'siteforge.sqlite3'
env=os.environ.copy(); env.pop('SITEFORGE_DATABASE_URL',None)
env['SITEFORGE_DATA_DIR']=temp
env['SITEFORGE_DB_FILE']=str(source)
marker='migration-smoke-'+uuid.uuid4().hex[:10]
code=r'''from app import (db,enterprise,factory_api,migration_audit,reusables,release_api,
cms_pipeline,v8_workflows,v8_templates,wp_migration_v81,wp_migration_v82,
wp_migration_v83,connectors_v84,connectors_v85,studio_v86,site_design_v87,multilingual)
import os
assert not db.POSTGRES
assert not os.path.exists(db.DB_FILE)
db.init()
for x in (enterprise,factory_api,migration_audit,reusables,release_api,
cms_pipeline,v8_workflows,v8_templates,wp_migration_v81,wp_migration_v82,
wp_migration_v83,connectors_v84,connectors_v85,studio_v86,site_design_v87,multilingual):x.setup()
s=os.environ['V818_MARKER']
with db.connect() as c:
c.execute('INSERT INTO sites(id,name,created_at,updated_at) VALUES (?,?,?,?)',(s,'Migration Sample',db.now(),db.now()))
for i in range(3):
c.execute('INSERT INTO entries(id,site_id,type,title,route,slug,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?)',
(s+'e'+str(i),s,'product','Migrated Car '+str(i),'/products/'+str(i)+'/','p'+str(i),db.now(),db.now()))
c.execute('INSERT INTO redirects(id,site_id,old_path,new_path) VALUES (?,?,?,?)',(s+'r',s,'/old/','/products/0/'))
'''
env['V818_MARKER']=marker
subprocess.run([sys.executable,'-c',code],check=True,env=env)
try:
result=migrate(source,confirmed_offline=True)
assert result['verified'] and result['details']['entries']['rows']==3
assert result['details']['redirects']['rows']==1
assert db.one('SELECT COUNT(*) AS n FROM entries WHERE site_id=?',(marker,))['n']==3
assert db.one('SELECT COUNT(*) AS n FROM redirects WHERE site_id=?',(marker,))['n']==1
# Re-running must fail: no duplicate rows, no silent upsert.
try:migrate(source,confirmed_offline=True)
except RecoveryError as exc:
assert 'not empty' in str(exc)
else:raise AssertionError('Migration unexpectedly allowed nonempty target')
print(f'PASS: actual PostgreSQL transfer {result["tables"]} tables, {result["records"]} records; rerun blocked')
finally:
with db.connect() as c:
c.execute('DELETE FROM sites WHERE id=?',(marker,))