103 lines
4.4 KiB
Python
103 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise a release binary using disposable data only, on either Linux architecture."""
|
|
|
|
import contextlib
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import secrets
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import urllib.error
|
|
import urllib.parse
|
|
import urllib.request
|
|
|
|
|
|
binary = str(Path(sys.argv[1]).resolve())
|
|
version = Path('VERSION').read_text().strip()
|
|
assert subprocess.check_output([binary, '--version'], text=True).strip() == f'RawMark {version}'
|
|
|
|
|
|
with tempfile.TemporaryDirectory(prefix='rawmark-release-') as directory:
|
|
data = Path(directory) / 'data'
|
|
with socket.socket() as listener:
|
|
listener.bind(('127.0.0.1', 0))
|
|
port = listener.getsockname()[1]
|
|
origin = f'http://127.0.0.1:{port}'
|
|
environment = {**os.environ, 'RAWMARK_DATA': str(data),
|
|
'RAWMARK_VAULT': str(data / 'vault'), 'RAWMARK_ADDR': f'127.0.0.1:{port}'}
|
|
|
|
def request(path, *, method='GET', body=None, token=None, status=200):
|
|
headers = {'Accept-Language': 'en'}
|
|
if token:
|
|
headers['Authorization'] = 'Bearer ' + token
|
|
if body is not None:
|
|
headers['Content-Type'] = 'application/json'
|
|
body = json.dumps(body).encode()
|
|
req = urllib.request.Request(origin + '/api/v1/' + path, data=body, headers=headers, method=method)
|
|
try:
|
|
response = urllib.request.urlopen(req, timeout=5)
|
|
except urllib.error.HTTPError as error:
|
|
response = error
|
|
with response:
|
|
assert response.status == status, (path, response.status, response.read())
|
|
result = json.load(response)
|
|
assert (result['code'] == 0) == (status < 400), result
|
|
return result['data']
|
|
|
|
@contextlib.contextmanager
|
|
def running():
|
|
with (Path(directory) / 'server.log').open('w+') as log:
|
|
process = subprocess.Popen([binary], env=environment, stdout=log, stderr=log)
|
|
try:
|
|
for _ in range(100):
|
|
if process.poll() is not None:
|
|
raise RuntimeError(f'Release binary exited with {process.returncode}')
|
|
try:
|
|
request('health')
|
|
break
|
|
except urllib.error.URLError:
|
|
time.sleep(0.1)
|
|
else:
|
|
raise TimeoutError('Release binary did not become healthy')
|
|
yield
|
|
except BaseException:
|
|
log.flush()
|
|
log.seek(0)
|
|
print(log.read(), file=sys.stderr)
|
|
raise
|
|
finally:
|
|
if process.poll() is None:
|
|
process.terminate()
|
|
process.wait(timeout=20)
|
|
|
|
with running():
|
|
assert request('auth/state')['setUp'] is False
|
|
request('tree', status=401)
|
|
token = request('auth/setup', method='POST', body={'password': secrets.token_urlsafe(24)})['token']
|
|
assert token.startswith('rms_')
|
|
entries = request('tree', token=token)['entries']
|
|
assert len([entry for entry in entries if not entry['dir'] and entry['path'].endswith('.md')]) == 7
|
|
for note in Path('deploy/data/vault').rglob('*.md'):
|
|
assert (data / 'vault' / note.relative_to('deploy/data/vault')).read_bytes() == note.read_bytes()
|
|
path = urllib.parse.quote('Getting Started/Welcome to RawMark.md')
|
|
original = (data / 'vault/Getting Started/Welcome to RawMark.md').read_bytes()
|
|
req = urllib.request.Request(origin + '/api/v1/files/' + path, data=original + b'\nRelease smoke test.\n',
|
|
headers={'Authorization': 'Bearer ' + token}, method='PUT')
|
|
with urllib.request.urlopen(req, timeout=5) as response:
|
|
assert json.load(response)['code'] == 0
|
|
|
|
before = {str(p.relative_to(data / 'vault')): hashlib.sha256(p.read_bytes()).hexdigest()
|
|
for p in (data / 'vault').rglob('*') if p.is_file()}
|
|
with running():
|
|
assert request('auth/state')['setUp'] is True
|
|
request('auth/me', token=token)
|
|
after = {str(p.relative_to(data / 'vault')): hashlib.sha256(p.read_bytes()).hexdigest()
|
|
for p in (data / 'vault').rglob('*') if p.is_file()}
|
|
assert before == after, 'Restart modified existing notes'
|
|
print(f'RawMark {version}: initialization, authentication, examples, editing and restart passed')
|