mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-28 14:10:37 +00:00
* fix(docker): bundle Lark broker runtime helpers * docs(lark): document standalone broker import dependencies
96 lines
3.7 KiB
Python
96 lines
3.7 KiB
Python
"""Exercise the broker image's Python file layout without an installed harness."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
@pytest.fixture
|
|
def image_broker(tmp_path: Path) -> Path:
|
|
dockerfile = REPO_ROOT / "docker/lark-cli-broker/Dockerfile"
|
|
runtime_stage = dockerfile.read_text(encoding="utf-8").replace("\\\n", " ").rsplit("\nFROM ", 1)[1]
|
|
image_root = tmp_path / "image"
|
|
for instruction in runtime_stage.splitlines():
|
|
words = shlex.split(instruction, comments=True)
|
|
if not words or words[0] != "COPY" or words[1].startswith("--from="):
|
|
continue
|
|
for source in words[1:-1]:
|
|
if not source.endswith(".py"):
|
|
continue
|
|
destination = image_root / words[-1].lstrip("/")
|
|
if words[-1].endswith("/"):
|
|
destination /= Path(source).name
|
|
destination.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copyfile(REPO_ROOT / source, destination)
|
|
return image_root / "opt/broker/lark_broker.py"
|
|
|
|
|
|
def run_isolated(broker: Path, code: str, *args: str) -> subprocess.CompletedProcess[str]:
|
|
bootstrap = "import runpy, sys\nfrom pathlib import Path\nbroker = Path(sys.argv.pop(1))\nsys.path.insert(0, str(broker.parent))\n"
|
|
# -I ignores inherited PYTHONPATH and -S skips installed editable packages.
|
|
# Only the image's script directory is added back, matching its entrypoint.
|
|
return subprocess.run(
|
|
[sys.executable, "-I", "-S", "-c", bootstrap + textwrap.dedent(code), str(broker), *args],
|
|
cwd=broker.parent,
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=30,
|
|
check=False,
|
|
)
|
|
|
|
|
|
def test_image_installs_shim_without_harness(image_broker: Path, tmp_path: Path) -> None:
|
|
runtime = tmp_path / "runtime"
|
|
completed = run_isolated(image_broker, 'runpy.run_path(str(broker), run_name="__main__")', "install-shim", str(runtime))
|
|
|
|
assert completed.returncode == 0, completed.stderr
|
|
launcher = runtime / "bin/lark-cli"
|
|
shim = runtime / "bin/lark-cli-shim.py"
|
|
assert launcher.read_text(encoding="utf-8").startswith("#!/bin/sh\n")
|
|
assert str(shim) in launcher.read_text(encoding="utf-8")
|
|
assert shim.read_text(encoding="utf-8").startswith("#!/usr/bin/env python3\n")
|
|
assert json.loads((runtime / ".deerflow-lark-cli-runtime.json").read_text(encoding="utf-8"))["kind"] == "shim"
|
|
|
|
|
|
def test_image_serves_health_without_harness(image_broker: Path) -> None:
|
|
completed = run_isolated(
|
|
image_broker,
|
|
"""
|
|
import json
|
|
import threading
|
|
from http.client import HTTPConnection
|
|
|
|
module = runpy.run_path(str(broker))
|
|
config = module["BrokerConfig"](lark_cli_path=sys.executable, config_dir="config", data_dir="data", port=0)
|
|
with module["serve"](config) as server:
|
|
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
thread.start()
|
|
try:
|
|
connection = HTTPConnection(*server.server_address[:2], timeout=5)
|
|
try:
|
|
connection.request("GET", "/v1/health")
|
|
response = connection.getresponse()
|
|
assert response.status == 200
|
|
assert json.loads(response.read()) == {"ok": True}
|
|
finally:
|
|
connection.close()
|
|
finally:
|
|
server.shutdown()
|
|
thread.join(timeout=5)
|
|
assert not thread.is_alive()
|
|
""",
|
|
)
|
|
|
|
assert completed.returncode == 0, completed.stderr
|