Files
bluebird/scripts/smoke.py
T

110 lines
4.8 KiB
Python

"""Verify the native release in an isolated directory on the workspace filesystem."""
import http.cookiejar
import json
import os
from pathlib import Path
import secrets
import shutil
import socket
import sqlite3
import subprocess
import tarfile
import tempfile
import time
import urllib.request
project = Path(__file__).resolve().parent.parent
stage = Path(tempfile.mkdtemp(prefix=".bluebird-smoke-", dir=project))
server = None
try:
with tarfile.open(project / "build/bluebird-linux-amd64.tar.gz") as archive:
archive.extractall(stage, filter="data")
with socket.socket() as sock:
sock.bind(("127.0.0.1", 0))
port = sock.getsockname()[1]
base = f"http://127.0.0.1:{port}"
config = stage / "config.toml"
source = (config.read_text().replace("127.0.0.1:8080", f"127.0.0.1:{port}")
.replace("http://localhost:8080", base)
.replace("min_free_bytes = 1073741824", "min_free_bytes = 0")
.replace("encryption = false", "encryption = true"))
config.write_text(source)
binary = str(stage / "bluebird")
password = secrets.token_urlsafe(24)
env = os.environ.copy()
env["BLUEBIRD_ADMIN_PASSWORD"] = password
subprocess.run([binary, "init", "--config", str(config)], env=env, check=True,
capture_output=True, timeout=15)
server = subprocess.Popen([binary, "serve", "--config", str(config)],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
opener = urllib.request.build_opener(
urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
def call(method, path, body=None, raw=False):
headers = {}
if body is not None:
if not raw:
body = json.dumps(body).encode()
headers = {"Origin": base, "Content-Type":
"application/octet-stream" if raw else "application/json"}
request = urllib.request.Request(base + "/api/v1" + path, data=body,
headers=headers, method=method)
with opener.open(request, timeout=10) as response:
return json.loads(response.read())
for _ in range(50):
try:
assert call("GET", "/health")["ready"]
break
except (OSError, AssertionError):
time.sleep(.1)
else:
raise AssertionError("Release server did not start")
with opener.open(base + "/", timeout=10) as response:
assert b'<div id="app">' in response.read()
call("GET", "/policy")
payload = b"bluebird-release-smoke\n" * 4096
parcel = call("POST", "/uploads", {
"files": [{"name": "first.dat", "size": len(payload)},
{"name": "same.dat", "size": len(payload)}],
"days": 7, "downloads": 2, "renew": True, "password": ""})
for file in parcel["files"]:
call("PUT", f"/uploads/{parcel['id']}/files/{file['id']}", payload, True)
share = call("POST", f"/uploads/{parcel['id']}/publish", {})
call("POST", "/pickup/resolve", {"code": share["code"]})
request = urllib.request.Request(
base + f"/api/v1/pickup/files/{parcel['files'][0]['id']}/download")
with opener.open(request, timeout=10) as response:
assert response.read() == payload
call("POST", "/admin/login", {"username": "admin", "password": password})
stats = call("GET", "/admin/stats")
assert stats["objects"] == 1 and stats["files"] == 2
server.terminate()
server.wait(timeout=10)
server = None
subprocess.run([binary, "check", "--config", str(config)], check=True,
capture_output=True, timeout=15)
backup = stage / "backup.tar.gz"
subprocess.run([binary, "backup", "--config", str(config), "--output", str(backup)],
check=True, capture_output=True, timeout=15)
restored = stage / "restore.toml"
restored.write_text(source.replace('data_dir = "var"', 'data_dir = "restored-var"'))
subprocess.run([binary, "restore", "--config", str(restored), "--input", str(backup)],
check=True, capture_output=True, timeout=15)
subprocess.run([binary, "check", "--config", str(restored)], check=True,
capture_output=True, timeout=15)
with sqlite3.connect(stage / "restored-var/db/bluebird.db") as db:
assert db.execute("SELECT state,code_hash FROM parcels").fetchone() == ("restored", None)
assert db.execute("SELECT count(*) FROM grants").fetchone()[0] == 0
assert db.execute("SELECT count(*) FROM objects").fetchone()[0] == 1
print("发布包验证通过:初始化、内嵌前端、匿名去重、加密下载、管理、检查、备份恢复。")
finally:
if server is not None:
server.terminate()
try:
server.wait(timeout=10)
except subprocess.TimeoutExpired:
server.kill()
server.wait()
shutil.rmtree(stage)