mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
97 lines
5.0 KiB
Python
97 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Smoke-test the root Go Compose model with disposable data and random ports.
|
|
|
|
Build first: docker build -t anonymous-github-go:deployment-test .
|
|
Run: python3 backend/scripts/test-deployment.py [image]
|
|
"""
|
|
import base64
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import secrets
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import urllib.request
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
IMAGE = sys.argv[1] if len(sys.argv) > 1 else 'anonymous-github-go:deployment-test'
|
|
PROJECT = 'go-deployment-test-' + secrets.token_hex(6)
|
|
ENV = {key: os.environ[key] for key in ('PATH', 'HOME', 'DOCKER_HOST', 'DOCKER_CONTEXT', 'DOCKER_CONFIG') if key in os.environ}
|
|
ENV.update(DB_USERNAME='smoke', DB_PASSWORD=secrets.token_hex(20), EXPOSED_PORT='5000')
|
|
|
|
|
|
def run(*args, capture=True):
|
|
return subprocess.run(args, cwd=ROOT, env=ENV, check=True, text=True,
|
|
stdout=subprocess.PIPE if capture else None).stdout
|
|
|
|
|
|
with tempfile.TemporaryDirectory(prefix=PROJECT) as directory:
|
|
envfile = Path(directory) / 'app.env'
|
|
envfile.write_text('\n'.join([
|
|
'SESSION_SECRET=' + secrets.token_hex(32),
|
|
'CREDENTIAL_KEYS=' + json.dumps({'smoke': base64.b64encode(secrets.token_bytes(32)).decode()}),
|
|
'CREDENTIAL_ACTIVE_KEY_ID=smoke', 'GITHUB_OAUTH_ENABLED=false',
|
|
'GITHUB_APP_ENABLED=false', 'COOKIE_SECURE=false',
|
|
'SHARED_CACHE_ENABLED=true', 'SHARED_CACHE_FREE_BYTES=0',
|
|
'DB_USERNAME=' + ENV['DB_USERNAME'], 'DB_PASSWORD=' + ENV['DB_PASSWORD'],
|
|
]) + '\n')
|
|
envfile.chmod(0o600)
|
|
ENV['APP_ENV_FILE'] = str(envfile)
|
|
base = ['docker', 'compose', '--env-file', '/dev/null']
|
|
model = json.loads(run(*base, '-f', 'docker-compose.yml', 'config', '--format', 'json'))
|
|
assert set(model['services']) == {'anonymous_github', 'mongodb', 'redis', 'mongodb-backup'}
|
|
for files, expected in [(['docker-compose.yml', 'docker-compose.github-app.yml'], 4),
|
|
(['docker-compose.node.yml', 'docker-compose.node.github-app.yml'], 5)]:
|
|
flags = [arg for file in files for arg in ('-f', file)]
|
|
other = json.loads(run(*base, *flags, 'config', '--no-env-resolution', '--format', 'json'))
|
|
assert len(other['services']) == expected
|
|
app = model['services']['anonymous_github']
|
|
assert app['read_only'] and app['init']
|
|
assert app['healthcheck']['test'] == ['CMD', '/usr/local/bin/anonymous-server', 'healthcheck']
|
|
assert app['pids_limit'] == 128 and app['cap_drop'] == ['ALL']
|
|
assert 'streamer' not in app['depends_on']
|
|
# Replace all persisted data and host bindings before starting any container.
|
|
del model['services']['mongodb-backup']
|
|
app.pop('build', None)
|
|
app['image'] = IMAGE
|
|
app['ports'] = [{'target': 5000, 'published': '0', 'host_ip': '127.0.0.1', 'protocol': 'tcp'}]
|
|
app['volumes'] = [{'type': 'volume', 'source': 'test_repositories', 'target': '/app/repositories'}]
|
|
mongo = model['services']['mongodb']
|
|
mongo['image'] = 'mongo:7'
|
|
mongo.pop('ports', None)
|
|
mongo['volumes'] = [{'type': 'volume', 'source': 'test_mongo', 'target': '/data/db'}]
|
|
model['services']['redis'].pop('ports', None)
|
|
model['volumes'] = {'test_repositories': {}, 'test_mongo': {}}
|
|
model['networks'] = {'default': {}}
|
|
model['name'] = PROJECT
|
|
for service in model['services'].values():
|
|
service['restart'] = 'no'
|
|
assert all(v['type'] == 'volume' for v in service.get('volumes', []))
|
|
config = Path(directory) / 'compose.json'
|
|
config.write_text(json.dumps(model))
|
|
config.chmod(0o600)
|
|
compose = base + ['-p', PROJECT, '-f', str(config)]
|
|
try:
|
|
run(*compose, 'up', '-d', '--no-build', '--wait', '--wait-timeout', '120', capture=False)
|
|
cid = run(*compose, 'ps', '-q', 'anonymous_github').strip()
|
|
info = json.loads(run('docker', 'inspect', cid))[0]
|
|
assert info['Config']['User'] == '10001:10001'
|
|
assert info['HostConfig']['ReadonlyRootfs']
|
|
run(*compose, 'exec', '-T', 'anonymous_github', 'sh', '-ec',
|
|
'test "$(id -u)" = 10001; touch /tmp/smoke /app/repositories/smoke; '
|
|
'test ! -w /app/public; test ! -e /usr/local/bin/node; '
|
|
'rm /tmp/smoke /app/repositories/smoke')
|
|
address = run(*compose, 'port', 'anonymous_github', '5000').strip()
|
|
for path in ('/healthcheck', '/', '/llms.txt', '/maintenance-openapi.json'):
|
|
with urllib.request.urlopen('http://' + address + path, timeout=10) as response:
|
|
assert response.status == 200
|
|
assert response.read(), path
|
|
run(*compose, 'stop', 'anonymous_github', capture=False)
|
|
state = json.loads(run('docker', 'inspect', cid))[0]['State']
|
|
assert state['ExitCode'] == 0 and not state['OOMKilled'], state
|
|
print('PASS: Go default, Node rollback models, isolated startup, non-root writes, static routes, graceful shutdown')
|
|
finally:
|
|
# Only this randomly named test project owns these disposable volumes.
|
|
run(*compose, 'down', '--volumes', '--timeout', '45', capture=False)
|