Files
easyai/scripts/test-repository-image-restore.py
T
easyai02 e3d760c5ab
Test deployment public URL (Linux) / test-linux (push) Canceled after 0s
fix(deploy): 通过更新脚本恢复受控仓库镜像定义
2026-10-05 11:35:47 +08:00

96 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""Exercise reviewed image-pin adoption with real Git and Compose parsing only."""
import json
import os
from pathlib import Path
import subprocess
import tempfile
import time
source = Path(__file__).resolve().parent.parent
prepare = Path(os.environ.get('EASYAI_PREPARE_UPDATE_SCRIPT', source / 'scripts/prepare-update-repository.py'))
started = time.monotonic()
pin = 'repository-web@sha256:' + 'a' * 64
def run(args, root, env=None):
return subprocess.run(args, cwd=root, env=env, capture_output=True, text=True, timeout=30)
def checked(args, root, env=None):
result = run(args, root, env)
assert result.returncode == 0, result.stdout + result.stderr
return result.stdout
for restore in ('', 'easyai-web', 'redis', 'ws-gateway'):
with tempfile.TemporaryDirectory(prefix='easyai-image-restore-') as directory:
base = Path(directory)
root = base / 'easyai'
root.mkdir()
compose = '''services:
easyai-web:
image: repository-web:${VERSION}
environment:
- EXISTING=keep
easyai-server:
image: repository-server:${VERSION}
environment:
- LOCAL_SETTING=original
redis:
image: redis:7
'''
(root / 'docker-compose.yml').write_text(compose)
(root / '.gitignore').write_text('.env\ndata/\n')
env_original = b'VERSION=latest\nCONFIG_JWT_SECRET=test-private-value\n'
(root / '.env').write_bytes(env_original)
for args in (['git', 'init', '-q', '-b', 'main'], ['git', 'config', 'user.name', 'Update test'], ['git', 'config', 'user.email', 'test@example.invalid'], ['git', 'add', '.'], ['git', 'commit', '-qm', 'test: 旧部署基准']):
checked(args, root)
remote = base / 'remote.git'
seed = base / 'seed'
checked(['git', 'clone', '-q', '--bare', str(root), str(remote)], base)
checked(['git', 'remote', 'add', 'origin', str(remote)], root)
checked(['git', 'fetch', '-q'], root)
checked(['git', 'branch', '--set-upstream-to', 'origin/main'], root)
checked(['git', 'clone', '-q', str(remote), str(seed)], base)
(seed / 'docker-compose.yml').write_text(compose.replace(' - EXISTING=keep', ' - EXISTING=keep\n - NEW_SETTING=from-repository'))
for args in (['git', 'config', 'user.name', 'Update test'], ['git', 'config', 'user.email', 'test@example.invalid'], ['git', 'add', '.'], ['git', 'commit', '-qm', 'test: 新部署配置'], ['git', 'push', '-q']):
checked(args, seed)
original = compose.replace('repository-web:${VERSION}', pin).replace('LOCAL_SETTING=original', 'LOCAL_SETTING=custom').replace('redis:7', 'redis:6.2')
(root / 'docker-compose.yml').write_text(original)
env = {**os.environ, 'UPDATE_RESTORE_REPOSITORY_IMAGES': restore, 'UPDATE_SERVICES': 'easyai-server easyai-web'}
result = run(['python3', str(prepare), str(root)], root, env)
if restore in ('redis', 'ws-gateway'):
assert result.returncode != 0, result.stdout
assert (root / 'docker-compose.yml').read_text() == original
assert (root / '.env').read_bytes() == env_original
assert not (root / 'data').exists()
continue
assert result.returncode == 0, result.stdout + result.stderr
checked(['git', 'pull', '--ff-only'], root)
config = json.loads(checked(['docker', 'compose', '--env-file', '.env', 'config', '--format', 'json'], root))
services = config['services']
assert services['easyai-web']['image'] == ('repository-web:latest' if restore else pin), services['easyai-web']['image']
assert services['easyai-web']['environment']['NEW_SETTING'] == 'from-repository'
assert services['easyai-server']['environment']['LOCAL_SETTING'] == 'custom'
assert services['redis']['image'] == 'redis:6.2'
assert 'CONFIG_JWT_SECRET=test-private-value' in (root / '.env').read_text()
backups = list((root / 'data/deployment-backups').glob('legacy-update-*'))
assert len(backups) == 1
assert (backups[0] / 'docker-compose.yml').read_text() == original
assert (backups[0] / '.env').read_bytes() == env_original
assert (backups[0] / '.env').stat().st_mode & 0o077 == 0
metadata = json.loads((backups[0] / 'migration.json').read_text())
if restore:
assert metadata['restoredRepositoryImages'] == ['easyai-web']
# A second adoption preserves the result and creates no extra backup.
checked(['python3', str(prepare), str(root)], root, env)
assert len(list((root / 'data/deployment-backups').glob('legacy-update-*'))) == 1
for mode, adopt in (('image', '1'), ('full', '0')):
env = {**os.environ, 'UPDATE_MODE': mode, 'UPDATE_ADOPT_LEGACY_CONFIG': adopt, 'UPDATE_RESTORE_REPOSITORY_IMAGES': 'easyai-web'}
result = run(['bash', str(source / 'update.sh')], source, env)
assert result.returncode != 0 and '尚未修改配置或容器' in result.stderr
print(json.dumps({'passed': True, 'cases': 6, 'durationSeconds': round(time.monotonic() - started, 3)}))