forked from wangbo/easyai
74 lines
3.9 KiB
Python
74 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise the actual installer with real Compose parsing and failing Docker transports."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
|
|
root = Path(__file__).resolve().parent.parent
|
|
real_docker = shutil.which('docker')
|
|
with tempfile.TemporaryDirectory(prefix='easyai-install-failures-') as temporary:
|
|
base = Path(temporary)
|
|
for phase in ('storage', 'manifest', 'pull', 'health'):
|
|
project = base / phase
|
|
project.mkdir()
|
|
for name in ('scripts', 'system-update'):
|
|
shutil.copytree(root / name, project / name, ignore=shutil.ignore_patterns('__pycache__'))
|
|
for name in ('start.sh', 'docker-compose.yml', 'easyai-proxy.conf.sample'):
|
|
shutil.copy2(root / name, project / name)
|
|
for sample in root.glob('.env*.sample'):
|
|
shutil.copy2(sample, project / sample.name)
|
|
sample = project / '.env.sample'
|
|
sample.write_text(sample.read_text().replace('UPDATE_MANIFEST_SOURCE=remote', 'UPDATE_MANIFEST_SOURCE=local'))
|
|
binaries = project / 'bin'
|
|
binaries.mkdir()
|
|
commands = project / 'commands.jsonl'
|
|
docker = binaries / 'docker'
|
|
docker.write_text('''#!/usr/bin/env python3
|
|
import json,os,subprocess,sys
|
|
args=sys.argv[1:]
|
|
with open(os.environ['TEST_COMMANDS'],'a') as log: log.write(json.dumps(args)+'\\n')
|
|
if args[:1]==['--config']: args=args[2:]
|
|
if args[:2]==['compose','config'] or args[:2]==['compose','version']:
|
|
sys.exit(subprocess.call([os.environ['REAL_DOCKER'],*args]))
|
|
if args[:2]==['manifest','inspect']:
|
|
if os.environ['TEST_PHASE']=='manifest': print('manifest unknown',file=sys.stderr);sys.exit(1)
|
|
print(json.dumps({'Descriptor':{'platform':{'os':'linux','architecture':'amd64'}}}));sys.exit(0)
|
|
if args[:2]==['compose','pull']: sys.exit(18 if os.environ['TEST_PHASE']=='pull' else 0)
|
|
if args[:3]==['compose','ps','-q']: print('test-'+args[-1]);sys.exit(0)
|
|
if args[:1]==['inspect']:
|
|
if '--format' in args: print('true|unhealthy');sys.exit(0)
|
|
sys.exit(1)
|
|
if args[:2]==['container','inspect']:
|
|
if os.environ['TEST_PHASE']=='storage' and args[-1]=='easyai-server':
|
|
print(json.dumps([{'Config':{'Labels':{'com.docker.compose.project':'unrelated-project'}},'Mounts':[]}]))
|
|
sys.exit(0)
|
|
sys.exit(1)
|
|
sys.exit(0)
|
|
''')
|
|
docker.chmod(0o755)
|
|
for name, code in [('sudo', '#!/bin/sh\nexec "$@"\n'), ('curl', '#!/bin/sh\nexit 0\n')]:
|
|
path = binaries / name
|
|
path.write_text(code)
|
|
path.chmod(0o755)
|
|
env = {k: v for k, v in os.environ.items() if not k.startswith(('UPDATE_', 'DEPLOY_', 'COMPOSE_'))}
|
|
env.update({'PATH': str(binaries) + os.pathsep + env['PATH'], 'REAL_DOCKER': real_docker,
|
|
'TEST_COMMANDS': str(commands), 'TEST_PHASE': phase, 'CI': 'true',
|
|
'DEPLOY_ACCESS': 'ip', 'DEPLOY_IP': '127.0.0.1', 'DEPLOY_NON_INTERACTIVE': '1',
|
|
'DEPLOY_HEALTH_TIMEOUT_SECONDS': '1'})
|
|
result = subprocess.run(['bash', 'start.sh'], cwd=project, env=env, capture_output=True, text=True, errors='replace', timeout=120)
|
|
assert result.returncode != 0, (phase, result.stdout, result.stderr)
|
|
assert '应用启动成功' not in result.stdout and '部署完成' not in result.stdout, result.stdout
|
|
calls = [json.loads(line) for line in commands.read_text().splitlines()]
|
|
if phase in ('storage', 'manifest'):
|
|
assert not any(call[:2] in (['compose', 'pull'], ['compose', 'up']) for call in calls)
|
|
if phase == 'pull':
|
|
assert ['compose', 'pull'] in calls, (result.stdout, result.stderr, calls)
|
|
assert not any(call[:2] == ['compose', 'up'] for call in calls)
|
|
if phase == 'health':
|
|
assert ['compose', 'up', '-d'] in calls
|
|
assert '部署未完成' in result.stdout + result.stderr
|
|
print(phase + ': installer failed without reporting success or continuing to the next stage')
|