ci(docker): require the full integration suite
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
"""Tests for the socket-shared Docker host address helper."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from scripts.docker_host_address import default_ipv4_gateway
|
||||
|
||||
|
||||
class TestDefaultIpv4Gateway(unittest.TestCase):
|
||||
def test_decodes_linux_little_endian_gateway(self) -> None:
|
||||
routes = (
|
||||
"Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n"
|
||||
"eth0 00000000 010011AC 0003 0 0 0 00000000 0 0 0\n"
|
||||
)
|
||||
self.assertEqual("172.17.0.1", default_ipv4_gateway(routes))
|
||||
|
||||
def test_rejects_table_without_default_gateway(self) -> None:
|
||||
routes = (
|
||||
"Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT\n"
|
||||
"eth0 000011AC 00000000 0001 0 0 0 00FFFFFF 0 0 0\n"
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "no active"):
|
||||
default_ipv4_gateway(routes)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -67,6 +67,14 @@ class TestDockerInfraService(unittest.TestCase):
|
||||
self.assertTrue(any(GATEWAY_NAME in a for a in rms))
|
||||
self.assertTrue(any(ORCHESTRATOR_NAME in a for a in rms))
|
||||
|
||||
def test_named_mounts_propagate_to_both_planes(self) -> None:
|
||||
svc = DockerInfraService(
|
||||
root_mount_source="registry-volume",
|
||||
gateway_ca_mount_source="ca-volume",
|
||||
)
|
||||
self.assertEqual("registry-volume", svc.orchestrator()._root_mount_source)
|
||||
self.assertEqual("ca-volume", svc.gateway()._ca_mount_source)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -47,6 +47,20 @@ class TestDockerOrchestrator(unittest.TestCase):
|
||||
def test_url_is_host_loopback(self) -> None:
|
||||
self.assertEqual("http://127.0.0.1:8099", self.orch.url())
|
||||
|
||||
def test_socket_shared_client_uses_explicit_host_and_open_bind(self) -> None:
|
||||
orch = DockerOrchestrator(
|
||||
port=8099, client_host="172.17.0.1", root_mount_source="state-volume"
|
||||
)
|
||||
with patch(_TOKEN, return_value="k"), \
|
||||
patch(_URLOPEN, side_effect=[urllib.error.URLError("down"), _health(200)]), \
|
||||
patch(_RUN, return_value=_proc()) as run, patch(_SLEEP):
|
||||
orch.ensure_running()
|
||||
self.assertEqual("http://172.17.0.1:8099", orch.url())
|
||||
argv = next(c.args[0] for c in run.call_args_list
|
||||
if c.args[0][:2] == ["docker", "run"])
|
||||
self.assertEqual("0.0.0.0:8099:8099", argv[argv.index("--publish") + 1])
|
||||
self.assertIn("state-volume:/bot-bottle-root", argv)
|
||||
|
||||
def test_gateway_url_is_the_container_dns_name(self) -> None:
|
||||
# The gateway reaches the orchestrator by name on the control network.
|
||||
self.assertEqual(f"http://{ORCHESTRATOR_NAME}:8099", self.orch.gateway_url())
|
||||
@@ -110,6 +124,8 @@ class TestDockerOrchestrator(unittest.TestCase):
|
||||
# The lean control plane: no mitmproxy CA mount, no gateway daemons.
|
||||
self.assertFalse([a for a in argv if a.endswith(":/home/mitmproxy/.mitmproxy")])
|
||||
self.assertNotIn("BOT_BOTTLE_GATEWAY_DAEMONS", " ".join(argv))
|
||||
self.assertNotIn("/bot-bottle-src", " ".join(argv))
|
||||
self.assertNotIn("PYTHONPATH", " ".join(argv))
|
||||
# Orchestrator entrypoint args (image ENTRYPOINT is `-m bot_bottle.orchestrator`).
|
||||
self.assertIn("--broker", argv)
|
||||
self.assertIn("stub", argv)
|
||||
|
||||
@@ -142,6 +142,22 @@ class TestDockerGateway(unittest.TestCase):
|
||||
# Data plane resolves policy against the orchestrator control plane.
|
||||
self.assertIn(f"BOT_BOTTLE_ORCHESTRATOR_URL={_ORCH_URL}", runs[0])
|
||||
|
||||
def test_named_ca_volume_supports_socket_shared_runner(self) -> None:
|
||||
sc = DockerGateway(
|
||||
"bot-bottle-gateway:latest", ca_mount_source="ci-ca-volume"
|
||||
)
|
||||
|
||||
def fake(argv: list[str], **_kw: object) -> Mock:
|
||||
return _proc(stdout="") if argv[:2] == ["docker", "ps"] else _proc()
|
||||
|
||||
with patch(_RUN_DOCKER, side_effect=fake) as run:
|
||||
sc.connect_to_orchestrator(_ORCH_URL, _TOKEN)
|
||||
argv = next(c.args[0] for c in run.call_args_list
|
||||
if c.args[0][:2] == ["docker", "run"])
|
||||
self.assertIn(
|
||||
"ci-ca-volume:/home/mitmproxy/.mitmproxy", argv
|
||||
)
|
||||
|
||||
def test_connect_injects_the_pre_minted_gateway_token(self) -> None:
|
||||
# The gateway presents the token the orchestrator handed it — it never
|
||||
# mints (holds no signing key). The value rides the env (bare `--env
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
"""Unit tests for CI's unittest execution-count gate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from scripts.unittest_gate import assurance_errors
|
||||
|
||||
|
||||
class TestAssuranceErrors(unittest.TestCase):
|
||||
def test_accepts_suite_that_meets_minimum_without_skips(self) -> None:
|
||||
self.assertEqual(
|
||||
[],
|
||||
assurance_errors(
|
||||
tests_run=22, skipped=0, minimum_executed=22, fail_on_skip=True
|
||||
),
|
||||
)
|
||||
|
||||
def test_rejects_green_suite_below_execution_minimum(self) -> None:
|
||||
errors = assurance_errors(
|
||||
tests_run=22, skipped=18, minimum_executed=22, fail_on_skip=False
|
||||
)
|
||||
self.assertEqual(1, len(errors))
|
||||
self.assertIn("executed 4", errors[0])
|
||||
|
||||
def test_rejects_any_skip_when_required(self) -> None:
|
||||
errors = assurance_errors(
|
||||
tests_run=23, skipped=1, minimum_executed=22, fail_on_skip=True
|
||||
)
|
||||
self.assertEqual(["1 test(s) skipped in a no-skip suite"], errors)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user