Files
gitea-dynamic-runner/tests/test_opensandbox_worker.py
T
panxiao81 5348ca9891
test / python (pull_request) Successful in 10s
test / shell (pull_request) Successful in 14s
将 OpenSandbox 调度改为持久事件循环
2026-09-18 19:25:09 +00:00

102 lines
3.3 KiB
Python

import asyncio
import pytest
from gitea_dynamic_runner.models import RunnerRequest
from gitea_dynamic_runner.opensandbox_worker import (
OpenSandboxScheduler,
RegistrationTokens,
sandbox_request,
)
def request(backend: str = "vm") -> RunnerRequest:
return RunnerRequest(
job_id=42,
run_id=7,
backend=backend,
repository="panxiao81/example",
job_name="publish image",
labels=("self-hosted", backend),
)
def test_sandbox_request_uses_pool_identity_and_one_time_token_url():
document = sandbox_request(
request(), "gitea-vm-abcd", "http://scheduler/token/nonce"
)
assert document["pool"] == "ci-vm"
assert document["entrypoint"] == ["/usr/local/libexec/gitea-opensandbox-runner"]
assert document["env"]["GITEA_RUNNER_LABELS"] == "self-hosted:host,vm:host"
assert document["env"]["GITEA_RUNNER_REGISTRATION_TOKEN_URL"].endswith("/nonce")
assert document["env"]["CI_SPIFFE_ID"] == (
"spiffe://ddupan.top/ci/panxiao81/example/publish-image-3e72cdc4a97e"
)
assert document["metadata"]["ci.ddupan.top/runner"] == "true"
async def test_registration_token_is_single_use(monkeypatch):
monkeypatch.setattr(
"gitea_dynamic_runner.opensandbox_worker.TOKEN_BASE_URL",
"http://scheduler/token",
)
tokens = RegistrationTokens(b"secret\n")
nonce, url = await tokens.issue()
assert url == f"http://scheduler/token/{nonce}"
assert await tokens.consume(nonce) == b"secret"
assert await tokens.consume(nonce) is None
class FakeOpenSandbox:
def __init__(self):
self.created = None
self.deleted = []
async def create(self, **document):
self.created = document
return {"id": "sandbox-1"}
async def get(self, sandbox_id):
return {"status": {"state": "Terminated"}}
async def delete(self, sandbox_id):
self.deleted.append(sandbox_id)
async def test_scheduler_creates_monitors_and_deletes(monkeypatch):
monkeypatch.setattr(
"gitea_dynamic_runner.opensandbox_worker.TOKEN_BASE_URL",
"http://scheduler/token",
)
client = FakeOpenSandbox()
scheduler = OpenSandboxScheduler(client, RegistrationTokens(b"secret"))
assert await scheduler.create(request()) == "sandbox-1"
await scheduler.active[42]
assert client.created["pool"] == "ci-vm"
assert client.deleted == ["sandbox-1"]
async def test_scheduler_rejects_duplicate_active_job():
client = FakeOpenSandbox()
scheduler = OpenSandboxScheduler(client, RegistrationTokens(b"secret"))
scheduler.active[42] = asyncio.Future()
with pytest.raises(ValueError, match="already"):
await scheduler.create(request())
async def test_scheduler_deletes_sandbox_for_completed_runner():
class RunningOpenSandbox(FakeOpenSandbox):
async def get(self, sandbox_id):
return {"status": {"state": "Running"}}
client = RunningOpenSandbox()
scheduler = OpenSandboxScheduler(client, RegistrationTokens(b"secret"))
await scheduler.create(request())
runner_name = next(iter(scheduler.runners))
assert await scheduler.complete(runner_name) is True
assert client.deleted == ["sandbox-1"]
assert scheduler.active == {}
assert scheduler.runners == {}
assert await scheduler.complete(runner_name) is False