mirror of
https://github.com/usestrix/strix.git
synced 2026-08-22 02:58:39 +02:00
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
82 lines
2.5 KiB
Python
82 lines
2.5 KiB
Python
"""A bootstrap that dies mid-setup must not leave its transport behind.
|
|
|
|
The bootstrap now runs concurrently with the scan start, so teardown can
|
|
cancel it at any await — including inside ``Client.connect()``, where the
|
|
client exists but no caller will ever see it to close it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import sys
|
|
import types
|
|
from typing import Any
|
|
|
|
import pytest
|
|
|
|
from strix.runtime.caido_bootstrap import bootstrap_caido
|
|
|
|
|
|
class _FakeExecResult:
|
|
stderr = b""
|
|
exit_code = 0
|
|
|
|
def __init__(self, stdout: str) -> None:
|
|
self.stdout = stdout
|
|
|
|
def ok(self) -> bool:
|
|
return True
|
|
|
|
|
|
class _FakeSession:
|
|
async def exec(self, *_args: Any, **_kwargs: Any) -> _FakeExecResult:
|
|
return _FakeExecResult('{"data":{"loginAsGuest":{"token":{"accessToken":"t"}}}}')
|
|
|
|
|
|
class _FakeClient:
|
|
def __init__(self, connect_error: BaseException) -> None:
|
|
self.connect_error = connect_error
|
|
self.closed = False
|
|
|
|
async def connect(self) -> None:
|
|
raise self.connect_error
|
|
|
|
async def aclose(self) -> None:
|
|
self.closed = True
|
|
|
|
|
|
async def _bootstrap_expecting(
|
|
monkeypatch: pytest.MonkeyPatch, error: BaseException
|
|
) -> _FakeClient:
|
|
"""Run a bootstrap whose ``connect()`` fails with ``error``."""
|
|
client = _FakeClient(error)
|
|
# The SDK is imported inside bootstrap_caido (it is slow to import), so the
|
|
# fakes are injected as the modules it imports.
|
|
sdk = types.ModuleType("caido_sdk_client")
|
|
sdk.Client = lambda *_a, **_k: client # type: ignore[attr-defined]
|
|
sdk.TokenAuthOptions = lambda token: token # type: ignore[attr-defined]
|
|
sdk_types = types.ModuleType("caido_sdk_client.types")
|
|
sdk_types.CreateProjectOptions = lambda **_k: None # type: ignore[attr-defined]
|
|
monkeypatch.setitem(sys.modules, "caido_sdk_client", sdk)
|
|
monkeypatch.setitem(sys.modules, "caido_sdk_client.types", sdk_types)
|
|
|
|
with pytest.raises(type(error)):
|
|
await bootstrap_caido(
|
|
_FakeSession(), # type: ignore[arg-type]
|
|
host_url="http://host",
|
|
container_url="http://container",
|
|
)
|
|
return client
|
|
|
|
|
|
async def test_cancellation_during_connect_closes_the_client(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
client = await _bootstrap_expecting(monkeypatch, asyncio.CancelledError())
|
|
assert client.closed
|
|
|
|
|
|
async def test_failed_connect_closes_the_client(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
client = await _bootstrap_expecting(monkeypatch, RuntimeError("no listener"))
|
|
assert client.closed
|