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())