fix(tests): resolve pyright errors in stale-check test files
lint / lint (push) Successful in 2m15s
test / unit (pull_request) Successful in 1m3s
test / integration (pull_request) Successful in 21s
test / coverage (pull_request) Successful in 1m15s

Remove unused imports, add missing type annotations, fix Die()
constructor calls (int code, not str), replace fake backend
subclass with patch.object approach to avoid reportMissingParameterType
and override-incompatibility errors in strict pyright mode.
This commit is contained in:
2026-07-09 19:17:43 +00:00
parent 1a53e07039
commit 60231d9070
4 changed files with 104 additions and 163 deletions
+74 -106
View File
@@ -6,7 +6,6 @@ calls are mocked at the module boundary."""
from __future__ import annotations
import contextlib
import tempfile
import unittest
from pathlib import Path
@@ -14,7 +13,13 @@ from types import SimpleNamespace
from typing import Any, cast
from unittest.mock import MagicMock, patch
from bot_bottle.image_cache import StaleImageError
def _bottle_cm(bottle: Any) -> MagicMock:
"""Return a mock context manager that yields `bottle`."""
cm = MagicMock()
cm.__enter__ = MagicMock(return_value=bottle)
cm.__exit__ = MagicMock(return_value=False)
return cm
# ---------------------------------------------------------------------------
@@ -25,78 +30,44 @@ class TestBottleBackendLaunchTemplate(unittest.TestCase):
"""Verify the concrete launch() method on BottleBackend calls
_image_stale_checks unless skip_stale=True, then delegates to _launch_impl."""
def _make_backend(self):
from bot_bottle.backend import BottleBackend
def _make_backend(self) -> Any:
from bot_bottle.backend.docker.backend import DockerBottleBackend
return DockerBottleBackend()
class _FakeBottle:
name = "fake"
@contextlib.contextmanager
def _fake_impl(plan):
yield _FakeBottle()
class _FakeBackend(BottleBackend):
name = "fake"
@classmethod
def is_available(cls): return True
def _preflight(self): pass
def _build_guest_env(self, env): return {}
def _resolve_plan(self, spec, **kw): return cast(Any, SimpleNamespace())
@contextlib.contextmanager
def _launch_impl(self, plan):
yield _FakeBottle()
def prepare_cleanup(self): return cast(Any, None)
def cleanup(self, plan): pass
def enumerate_active(self): return []
return _FakeBackend()
def test_stale_checks_called_by_default(self):
def test_stale_checks_called_by_default(self) -> None:
backend = self._make_backend()
called = []
backend._image_stale_checks = lambda plan: called.append(True) # type: ignore[method-assign]
plan = cast(Any, SimpleNamespace())
with backend.launch(plan):
pass
self.assertEqual([True], called)
bottle = MagicMock()
with patch.object(
backend, "_image_stale_checks",
) as stale_mock, patch.object(
backend, "_launch_impl",
return_value=_bottle_cm(bottle),
):
with backend.launch(plan):
pass
stale_mock.assert_called_once_with(plan)
def test_skip_stale_bypasses_stale_checks(self):
def test_skip_stale_bypasses_stale_checks(self) -> None:
backend = self._make_backend()
backend._image_stale_checks = lambda plan: (_ for _ in ()).throw( # type: ignore[method-assign]
AssertionError("should not be called")
)
plan = cast(Any, SimpleNamespace())
with backend.launch(plan, skip_stale=True):
pass
bottle = MagicMock()
with patch.object(
backend, "_image_stale_checks",
) as stale_mock, patch.object(
backend, "_launch_impl",
return_value=_bottle_cm(bottle),
):
with backend.launch(plan, skip_stale=True):
pass
stale_mock.assert_not_called()
def test_noop_default_image_stale_checks(self):
def test_noop_default_image_stale_checks(self) -> None:
from bot_bottle.backend.docker.backend import DockerBottleBackend
from bot_bottle.backend import BottleBackend
class _MinimalBackend(BottleBackend):
name = "minimal"
@classmethod
def is_available(cls): return True
def _preflight(self): pass
def _build_guest_env(self, env): return {}
def _resolve_plan(self, spec, **kw): return cast(Any, SimpleNamespace())
@contextlib.contextmanager
def _launch_impl(self, plan):
yield cast(Any, SimpleNamespace(name="x"))
def prepare_cleanup(self): return cast(Any, None)
def cleanup(self, plan): pass
def enumerate_active(self): return []
backend = _MinimalBackend()
# The default _image_stale_checks must not raise — it's a no-op.
backend._image_stale_checks(cast(Any, SimpleNamespace()))
backend = DockerBottleBackend()
# Call the base-class _image_stale_checks directly to verify it's a no-op.
BottleBackend._image_stale_checks(backend, cast(Any, SimpleNamespace())) # type: ignore[arg-type]
# ---------------------------------------------------------------------------
@@ -104,8 +75,6 @@ class TestBottleBackendLaunchTemplate(unittest.TestCase):
# ---------------------------------------------------------------------------
class TestDockerStaleChecks(unittest.TestCase):
from bot_bottle.backend.docker import launch as _docker_launch_mod
def _plan(self, policy: str = "cached", slug: str = "dev-abc") -> Any:
spec = SimpleNamespace(image_policy=policy)
provision = SimpleNamespace(image="bot-bottle-agent:latest")
@@ -116,7 +85,7 @@ class TestDockerStaleChecks(unittest.TestCase):
agent_provision=provision,
))
def test_fresh_policy_is_noop(self):
def test_fresh_policy_is_noop(self) -> None:
from bot_bottle.backend.docker import launch as mod
with patch.object(mod, "read_committed_image") as rci, \
patch.object(mod, "check_stale") as cs:
@@ -124,7 +93,7 @@ class TestDockerStaleChecks(unittest.TestCase):
rci.assert_not_called()
cs.assert_not_called()
def test_committed_image_present_checks_only_committed(self):
def test_committed_image_present_checks_only_committed(self) -> None:
from bot_bottle.backend.docker import launch as mod
from datetime import datetime, timezone
ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
@@ -136,7 +105,7 @@ class TestDockerStaleChecks(unittest.TestCase):
cs.assert_called_once()
self.assertIn("committed:latest", cs.call_args.args[0])
def test_no_committed_image_checks_agent_and_sidecar(self):
def test_no_committed_image_checks_agent_and_sidecar(self) -> None:
from bot_bottle.backend.docker import launch as mod
from datetime import datetime, timezone
ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
@@ -148,7 +117,7 @@ class TestDockerStaleChecks(unittest.TestCase):
# Should have been called for both agent and sidecar images.
self.assertEqual(2, cs.call_count)
def test_image_not_present_skips_check(self):
def test_image_not_present_skips_check(self) -> None:
from bot_bottle.backend.docker import launch as mod
with patch.object(mod, "read_committed_image", return_value=""), \
patch.object(mod.docker_mod, "image_exists", return_value=False), \
@@ -156,18 +125,7 @@ class TestDockerStaleChecks(unittest.TestCase):
mod.stale_checks(self._plan())
cs.assert_not_called()
def test_backend_image_stale_checks_delegates(self):
from bot_bottle.backend.docker.backend import DockerBottleBackend
from bot_bottle.backend.docker import launch as mod
backend = DockerBottleBackend()
plan = self._plan()
with patch.object(mod, "stale_checks") as sc:
backend._image_stale_checks(plan)
sc.assert_called_once_with(plan)
def test_no_committed_image_only_sidecar_missing_skips_check(self):
# When no committed image, stale_checks checks each image that EXISTS.
# If an image isn't present, check_stale is not called for it.
def test_only_sidecar_missing_checks_only_agent(self) -> None:
from bot_bottle.backend.docker import launch as mod
from datetime import datetime, timezone
ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
@@ -181,10 +139,18 @@ class TestDockerStaleChecks(unittest.TestCase):
patch.object(mod.docker_mod, "image_created_at", return_value=ts), \
patch.object(mod, "check_stale") as cs:
mod.stale_checks(plan)
# Only agent was checked (sidecar not present → skipped).
self.assertEqual(1, cs.call_count)
self.assertIn(plan.image, cs.call_args.args[0])
def test_backend_image_stale_checks_delegates(self) -> None:
from bot_bottle.backend.docker.backend import DockerBottleBackend
from bot_bottle.backend.docker import launch as mod
backend = DockerBottleBackend()
plan = self._plan()
with patch.object(mod, "stale_checks") as sc:
backend._image_stale_checks(plan) # type: ignore[arg-type]
sc.assert_called_once_with(plan)
# ---------------------------------------------------------------------------
# smolmachines backend stale_checks
@@ -198,7 +164,7 @@ class TestSmolmachinesStaleChecks(unittest.TestCase):
agent_image="bot-bottle-claude:latest",
))
def test_fresh_policy_is_noop(self):
def test_fresh_policy_is_noop(self) -> None:
from bot_bottle.backend.smolmachines import launch as mod
with patch.object(mod, "read_committed_image") as rci, \
patch.object(mod, "check_stale_path") as csp:
@@ -206,7 +172,7 @@ class TestSmolmachinesStaleChecks(unittest.TestCase):
rci.assert_not_called()
csp.assert_not_called()
def test_committed_artifact_found_checks_it(self):
def test_committed_artifact_found_checks_it(self) -> None:
from bot_bottle.backend.smolmachines import launch as mod
with tempfile.NamedTemporaryFile(suffix=".smolmachine") as f:
committed_path = f.name
@@ -217,7 +183,7 @@ class TestSmolmachinesStaleChecks(unittest.TestCase):
csp.assert_called_once()
self.assertIn("agent smolmachine", csp.call_args.args[0])
def test_no_committed_agent_artifact_in_cache_is_checked(self):
def test_no_committed_agent_artifact_in_cache_is_checked(self) -> None:
from bot_bottle.backend.smolmachines import launch as mod
digest = "abcdef0123456789"
with tempfile.TemporaryDirectory() as tmp:
@@ -226,28 +192,31 @@ class TestSmolmachinesStaleChecks(unittest.TestCase):
with patch.object(mod, "_SMOLMACHINE_CACHE_DIR", Path(tmp)), \
patch.object(mod, "read_committed_image", return_value=""), \
patch.object(mod.docker_mod, "image_exists", return_value=True), \
patch.object(mod.docker_mod, "image_id",
return_value=f"sha256:{digest}ffffffffffffffff"), \
patch.object(
mod.docker_mod, "image_id",
return_value=f"sha256:{digest}ffffffffffffffff",
), \
patch.object(mod, "check_stale_path") as csp:
mod.stale_checks(self._plan())
# At least the agent artifact check ran.
self.assertGreaterEqual(csp.call_count, 1)
def test_sidecar_artifact_in_cache_is_checked(self):
def test_sidecar_artifact_in_cache_is_checked(self) -> None:
from bot_bottle.backend.smolmachines import launch as mod
digest = "1234567890abcdef"
sidecar_digest = "fedcba9876543210"
with tempfile.TemporaryDirectory() as tmp:
sidecar_artifact = Path(tmp) / f"{sidecar_digest}.smolmachine.smolmachine"
sidecar_artifact = (
Path(tmp) / f"{sidecar_digest}.smolmachine.smolmachine"
)
sidecar_artifact.write_text("")
def image_exists(ref: str) -> bool:
def image_exists(ref: str) -> bool: # pylint: disable=unused-argument
return True
def image_id(ref: str) -> str:
if "sidecar" in ref or ref == mod._bundle.SIDECAR_BUNDLE_IMAGE:
if ref == mod._bundle.SIDECAR_BUNDLE_IMAGE: # type: ignore[attr-defined]
return f"sha256:{sidecar_digest}ffffffff"
return f"sha256:{digest}ffffffff"
return "sha256:0000000000000000ffffffff"
with patch.object(mod, "_SMOLMACHINE_CACHE_DIR", Path(tmp)), \
patch.object(mod, "read_committed_image", return_value=""), \
@@ -255,17 +224,16 @@ class TestSmolmachinesStaleChecks(unittest.TestCase):
patch.object(mod.docker_mod, "image_id", side_effect=image_id), \
patch.object(mod, "check_stale_path") as csp:
mod.stale_checks(self._plan())
# sidecar artifact is present, so check_stale_path should fire for it.
sidecar_calls = [c for c in csp.call_args_list if "sidecar" in c.args[0]]
self.assertTrue(len(sidecar_calls) >= 1)
self.assertGreaterEqual(len(sidecar_calls), 1)
def test_backend_image_stale_checks_delegates(self):
def test_backend_image_stale_checks_delegates(self) -> None:
from bot_bottle.backend.smolmachines.backend import SmolmachinesBottleBackend
from bot_bottle.backend.smolmachines import launch as mod
backend = SmolmachinesBottleBackend()
plan = self._plan()
with patch.object(mod, "stale_checks") as sc:
backend._image_stale_checks(plan)
backend._image_stale_checks(plan) # type: ignore[arg-type]
sc.assert_called_once_with(plan)
@@ -281,7 +249,7 @@ class TestMacosContainerStaleChecks(unittest.TestCase):
image="bot-bottle-agent:latest",
))
def test_fresh_policy_is_noop(self):
def test_fresh_policy_is_noop(self) -> None:
from bot_bottle.backend.macos_container import launch as mod
with patch.object(mod, "read_committed_image") as rci, \
patch.object(mod, "check_stale") as cs:
@@ -289,7 +257,7 @@ class TestMacosContainerStaleChecks(unittest.TestCase):
rci.assert_not_called()
cs.assert_not_called()
def test_committed_image_present_checks_only_committed(self):
def test_committed_image_present_checks_only_committed(self) -> None:
from bot_bottle.backend.macos_container import launch as mod
from datetime import datetime, timezone
ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
@@ -301,7 +269,7 @@ class TestMacosContainerStaleChecks(unittest.TestCase):
cs.assert_called_once()
self.assertIn("committed:latest", cs.call_args.args[0])
def test_no_committed_image_checks_agent_and_sidecar(self):
def test_no_committed_image_checks_agent_and_sidecar(self) -> None:
from bot_bottle.backend.macos_container import launch as mod
from datetime import datetime, timezone
ts = datetime(2025, 1, 1, tzinfo=timezone.utc)
@@ -312,7 +280,7 @@ class TestMacosContainerStaleChecks(unittest.TestCase):
mod.stale_checks(self._plan())
self.assertEqual(2, cs.call_count)
def test_image_not_present_skips_check(self):
def test_image_not_present_skips_check(self) -> None:
from bot_bottle.backend.macos_container import launch as mod
with patch.object(mod, "read_committed_image", return_value=""), \
patch.object(mod.container_mod, "image_exists", return_value=False), \
@@ -320,13 +288,13 @@ class TestMacosContainerStaleChecks(unittest.TestCase):
mod.stale_checks(self._plan())
cs.assert_not_called()
def test_backend_image_stale_checks_delegates(self):
def test_backend_image_stale_checks_delegates(self) -> None:
from bot_bottle.backend.macos_container.backend import MacosContainerBottleBackend
from bot_bottle.backend.macos_container import launch as mod
backend = MacosContainerBottleBackend()
plan = self._plan()
with patch.object(mod, "stale_checks") as sc:
backend._image_stale_checks(plan)
backend._image_stale_checks(plan) # type: ignore[arg-type]
sc.assert_called_once_with(plan)