DUNGEONS-34: implement Webka local streaming app
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
62
scripts/smoke.py
Normal file
62
scripts/smoke.py
Normal file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exercise the actual Rust/static HTTP service; keep all service work foreground."""
|
||||
import http.cookiejar
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import socket
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
with socket.socket() as sock:
|
||||
sock.bind(('127.0.0.1', 0))
|
||||
port = sock.getsockname()[1]
|
||||
origin = f'http://127.0.0.1:{port}'
|
||||
with tempfile.TemporaryDirectory(prefix='webka-smoke-') as data:
|
||||
env = dict(os.environ, WEBKA_DATA=data, WEBKA_BIND=f'127.0.0.1:{port}', WEBKA_ORIGIN=origin, WEBKA_MDNS='0')
|
||||
proc = subprocess.Popen([str(root / 'backend/target/debug/webka')], cwd=root, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
try:
|
||||
for _ in range(100):
|
||||
try:
|
||||
with urllib.request.urlopen(origin + '/api/bootstrap', timeout=1) as response:
|
||||
assert json.load(response)['needs_setup'] is True
|
||||
break
|
||||
except (urllib.error.URLError, ConnectionError):
|
||||
if proc.poll() is not None:
|
||||
raise RuntimeError(proc.stderr.read().decode())
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
raise RuntimeError('Service did not become ready')
|
||||
for route in ['/', '/login', '/host', '/watch', '/settings/accounts', '/settings/general']:
|
||||
with urllib.request.urlopen(origin + route) as response:
|
||||
assert response.status == 200, route
|
||||
assert 'text/html' in response.headers['Content-Type'], route
|
||||
assert response.headers['X-Content-Type-Options'] == 'nosniff'
|
||||
cookies = http.cookiejar.CookieJar()
|
||||
client = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookies))
|
||||
def request(path, body=None):
|
||||
return client.open(urllib.request.Request(origin + path, data=json.dumps(body).encode() if body is not None else None, headers={'Origin': origin, 'Content-Type': 'application/json'}))
|
||||
password = 'smoke-test-password-123'
|
||||
with request('/api/bootstrap', {'username': 'owner', 'password': password, 'setup_token': Path(data, 'setup-token').read_text()}) as response:
|
||||
assert response.status == 201
|
||||
with request('/api/login', {'username': 'owner', 'password': password}) as response:
|
||||
assert response.status == 200
|
||||
with request('/api/session') as response:
|
||||
assert json.load(response)['role'] == 'admin'
|
||||
with request('/api/status') as response:
|
||||
status = json.load(response)
|
||||
assert status['local_url'] == origin + '/watch' and status['live'] is False
|
||||
with request('/api/logout', {}) as response:
|
||||
assert response.status == 204
|
||||
print('PASS: all six static routes, first-run setup, login, cookie/session, local share URL, logout, security headers.')
|
||||
finally:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.communicate(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
proc.communicate()
|
||||
Reference in New Issue
Block a user