From b25cd72fc30c673bdc187c9f2400435c790ec53e Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 20 Jul 2026 23:40:42 +0000 Subject: [PATCH] test(backend): cover poll_ca_cert timeout paths for diff-coverage gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests for the three uncovered paths introduced by the poll_ca_cert extraction: the timeout + sleep branches in backend/util, and the TimeoutError → GatewayError and TimeoutError → die() conversions in the macOS and Firecracker callers. --- tests/unit/test_backend_util.py | 29 +++++++++++++++++++++++++ tests/unit/test_firecracker_infra_vm.py | 10 +++++++++ tests/unit/test_macos_infra.py | 8 +++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/unit/test_backend_util.py diff --git a/tests/unit/test_backend_util.py b/tests/unit/test_backend_util.py new file mode 100644 index 0000000..4978158 --- /dev/null +++ b/tests/unit/test_backend_util.py @@ -0,0 +1,29 @@ +"""Unit: shared cross-backend helpers in backend/util.py.""" + +from __future__ import annotations + +import unittest +from unittest.mock import patch + +from bot_bottle.backend import util as backend_util + + +class TestPollCaCert(unittest.TestCase): + def test_returns_pem_on_first_success(self) -> None: + result = backend_util.poll_ca_cert(lambda: "PEM", timeout=1.0) + self.assertEqual("PEM", result) + + def test_raises_timeout_error_when_cert_never_appears(self) -> None: + with self.assertRaises(TimeoutError): + backend_util.poll_ca_cert(lambda: None, timeout=0.0) + + def test_polls_until_cert_appears(self) -> None: + responses = iter([None, None, "-----BEGIN CERTIFICATE-----\n"]) + with patch("bot_bottle.backend.util.time.sleep") as mock_sleep: + result = backend_util.poll_ca_cert(lambda: next(responses), timeout=5.0) + self.assertTrue(result.startswith("-----BEGIN CERTIFICATE-----")) + self.assertEqual(2, mock_sleep.call_count) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/unit/test_firecracker_infra_vm.py b/tests/unit/test_firecracker_infra_vm.py index 705e8d7..8cafd8c 100644 --- a/tests/unit/test_firecracker_infra_vm.py +++ b/tests/unit/test_firecracker_infra_vm.py @@ -71,6 +71,16 @@ class TestSshGatewayTransport(unittest.TestCase): t.exec(["mkdir", "-p", "/git-gate"]) +class TestGatewayCaPem(unittest.TestCase): + def test_dies_when_cert_never_appears(self) -> None: + from subprocess import CompletedProcess + infra = infra_vm.InfraVm(vm=None, guest_ip="10.0.0.1", private_key=Path("/k")) + with patch.object(infra_vm.subprocess, "run", + return_value=CompletedProcess([], 1, stdout="", stderr="")), \ + self.assertRaises(SystemExit): + infra.gateway_ca_pem(timeout=0) + + class TestRegistryVolume(unittest.TestCase): def test_reuses_existing_volume(self): import tempfile diff --git a/tests/unit/test_macos_infra.py b/tests/unit/test_macos_infra.py index 012f531..a026143 100644 --- a/tests/unit/test_macos_infra.py +++ b/tests/unit/test_macos_infra.py @@ -153,6 +153,14 @@ class TestCaCertPem(unittest.TestCase): argv = mod.run_container_argv.call_args.args[0] self.assertEqual(["container", "exec", "bot-bottle-mac-infra", "cat"], argv[:4]) + def test_raises_gateway_error_when_cert_never_appears(self) -> None: + from bot_bottle.backend.macos_container.gateway import GatewayError + svc = MacosInfraService(repo_root=Path("/r")) + with patch(f"{_INFRA}.container_mod") as mod: + mod.run_container_argv.return_value = _fail() + with self.assertRaises(GatewayError): + svc.ca_cert_pem(timeout=0) + class TestProbeControlPlane(unittest.TestCase): def test_returns_url_when_running(self) -> None: