初始化蓝鸟文件快递柜源码与部署文档
This commit is contained in:
commit
5643d22242
70 files changed
+18669
No files matched your search
@@ -0,0 +1,109 @@
|
||||
"""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)
|
||||
Reference in new issue
Block a user