forked from wangbo/easyai
127 lines
6.4 KiB
Python
127 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Real Git/config adoption regression; container mutation is not used here."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import time
|
|
|
|
source = Path(__file__).resolve().parent.parent
|
|
started = time.monotonic()
|
|
|
|
|
|
def run(args, root, env=None):
|
|
return subprocess.run(args, cwd=root, env=env, capture_output=True, text=True, timeout=30)
|
|
|
|
|
|
with tempfile.TemporaryDirectory(prefix='easyai-legacy-update-') as directory:
|
|
base = Path(directory)
|
|
root = base / 'easyai'
|
|
root.mkdir()
|
|
(root / 'docker-compose.yml').write_text('services:\n easyai-server:\n image: server:old\n environment:\n - EXISTING=keep\n watchtower:\n image: watcher:old\n environment:\n - WATCHTOWER_HTTP_API_TOKEN=${LEGACY_TOKEN}\n')
|
|
(root / '.gitignore').write_text('.env\ndata/\n')
|
|
(root / '.env').write_text('VERSION=old\nCONFIG_JWT_SECRET=keep-this-private-key\n')
|
|
for args in [['git','init','-q'], ['git','config','user.name','Update test'], ['git','config','user.email','test@example.invalid'], ['git','add','.'], ['git','commit','-qm','test: 旧部署基准']]:
|
|
assert run(args, root).returncode == 0
|
|
remote = base / 'remote.git'
|
|
seed = base / 'seed'
|
|
assert run(['git','clone','-q','--bare',str(root),str(remote)], base).returncode == 0
|
|
assert run(['git','remote','add','origin',str(remote)], root).returncode == 0
|
|
assert run(['git','fetch','-q'],root).returncode == 0
|
|
branch = run(['git','branch','--show-current'], root).stdout.strip()
|
|
assert run(['git','branch','--set-upstream-to','origin/'+branch],root).returncode == 0
|
|
assert run(['git','clone','-q',str(remote),str(seed)],base).returncode == 0
|
|
(seed / 'docker-compose.yml').write_text('''services:
|
|
easyai-server:
|
|
image: server:new
|
|
environment:
|
|
- EXISTING=keep
|
|
- MODEL_CONVERSION_WORKER_TOKEN=${MODEL_CONVERSION_WORKER_TOKEN}
|
|
watchtower:
|
|
image: watcher:new
|
|
environment:
|
|
- WATCHTOWER_HTTP_API_TOKEN=${WATCHTOWER_API_KEY}
|
|
easyai-updater:
|
|
image: updater:new
|
|
environment:
|
|
- UPDATE_MANIFEST_FILE=/etc/manifest.json
|
|
volumes:
|
|
- ./data/update-state:/state
|
|
- ./system-update/release-manifest.json:/etc/manifest.json:ro
|
|
networks:
|
|
easyai:
|
|
ipv4_address: 172.21.0.31
|
|
model-conversion-worker:
|
|
image: worker:new
|
|
volumes:
|
|
- accepted-data:/fixture
|
|
networks:
|
|
easyai: {}
|
|
volumes:
|
|
accepted-data: {}
|
|
''')
|
|
(seed / 'scripts').mkdir()
|
|
(seed / 'scripts/init-security-env.sh').write_text('# modern security initializer\n')
|
|
(seed / 'demo.example.conf').write_text('# upstream example\n')
|
|
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']]:
|
|
assert run(args,seed).returncode == 0
|
|
with (root / 'docker-compose.yml').open('a') as stream:
|
|
stream.write(''' easyai-updater:
|
|
image: updater:new
|
|
environment:
|
|
- UPDATE_MANIFEST_FILE=/state/custom.json
|
|
volumes:
|
|
- ./data/update-state:/state
|
|
networks:
|
|
- easyai
|
|
''')
|
|
(root / 'scripts').mkdir()
|
|
(root / 'scripts/init-security-env.sh').write_text('# local legacy initializer\n')
|
|
(root / 'demo.example.conf').write_text('# custom nginx source; active copy elsewhere\n')
|
|
original = (root / 'docker-compose.yml').read_bytes().replace(b' environment:\n - WATCHTOWER_HTTP_API_TOKEN=${LEGACY_TOKEN}\n', b'')
|
|
(root / 'docker-compose.yml').write_bytes(original)
|
|
bins = base / 'bin'
|
|
bins.mkdir()
|
|
docker = bins / 'docker'
|
|
docker.write_text('#!/bin/sh\nexit 0\n')
|
|
docker.chmod(0o755)
|
|
env = {**os.environ, 'PATH': str(bins)+os.pathsep+os.environ['PATH']}
|
|
legacy = run(['git','pull','--ff-only'],root)
|
|
assert legacy.returncode != 0 and 'would be overwritten' in legacy.stderr
|
|
assert original == (root / 'docker-compose.yml').read_bytes()
|
|
(root / 'business.js').write_text('local business code\n')
|
|
assert run(['git','add','business.js'],root).returncode == 0
|
|
rejected = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
|
assert rejected.returncode != 0
|
|
assert original == (root / 'docker-compose.yml').read_bytes()
|
|
assert run(['git','reset','-q','HEAD','--','business.js'],root).returncode == 0
|
|
accepted = run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
|
assert accepted.returncode == 0, accepted.stdout+accepted.stderr
|
|
assert run(['git','pull','--ff-only'],root).returncode == 0
|
|
assert run(['git','diff','--name-only'],root).stdout == ''
|
|
override=json.loads((root/'data/deployment-config/legacy-compose.json').read_text())
|
|
assert override == {'services': {'easyai-updater': {'environment': {'UPDATE_MANIFEST_FILE': '/state/custom.json'}}}}, override
|
|
assert 'COMPOSE_FILE=docker-compose.yml:data/deployment-config/legacy-compose.json' in (root/'.env').read_text()
|
|
assert 'CONFIG_JWT_SECRET=keep-this-private-key' 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_bytes()==original
|
|
assert (backups[0]/'demo.example.conf').read_text().startswith('# custom nginx')
|
|
assert (backups[0]/'.env').stat().st_mode & 0o077 == 0
|
|
assert (backups[0]).stat().st_mode & 0o077 == 0
|
|
resolved=run(['docker','compose','--env-file','.env','config','--format','json'],root)
|
|
assert resolved.returncode==0,resolved.stderr
|
|
config=json.loads(resolved.stdout)
|
|
assert config['services']['easyai-updater']['networks']['easyai']['ipv4_address']=='172.21.0.31'
|
|
assert config['services']['easyai-updater']['environment']['UPDATE_MANIFEST_FILE']=='/state/custom.json'
|
|
assert 'model-conversion-worker' in config['services']
|
|
assert 'accepted-data' in config['volumes']
|
|
assert 'WATCHTOWER_HTTP_API_TOKEN' in config['services']['watchtower']['environment']
|
|
repeat=run(['python3',str(source/'scripts/prepare-update-repository.py'),str(root)],root,env)
|
|
assert repeat.returncode==0
|
|
assert len(list((root/'data/deployment-backups').glob('legacy-update-*')))==1
|
|
print('legacy Git conflict: reproduced; code guard, private backups, local override, new Worker and updater address passed')
|
|
print(json.dumps({'passed':True,'durationSeconds':round(time.monotonic()-started,3)}))
|