"""Behavioral coverage for the credential-free SCM broker client and I/O.""" from __future__ import annotations import io import json import pytest from testing.tests.test_hermes_scm_broker_support import Response, _load def test_client_default_opener_uses_deadline_bounded_exchange(monkeypatch): client = _load("scm_broker_client") sentinel = object() monkeypatch.setattr( client.deadline_http, "open_bounded", lambda request, *, maximum, timeout: (request, maximum, timeout, sentinel), ) assert client._open("request", 4) == ( "request", client.MAX_RESPONSE_BYTES, 4, sentinel, ) @pytest.mark.parametrize( ("endpoint", "payload", "match"), [ ("/v1/admin", {}, "outside"), ("/v1/metadata", {"path": "x" * (64 * 1024)}, "safe size"), ], ) def test_client_rejects_unknown_or_oversized_operations(endpoint, payload, match): client = _load("scm_broker_client") with pytest.raises(client.PolicyError, match=match): client.request(endpoint, payload, opener=lambda *_a, **_k: None) class _GetCodeResponse(Response): def __init__(self, body: bytes, *, content_type="application/json", code=200): super().__init__(body, content_type=content_type) del self.status self._code = code def getcode(self): return self._code def test_client_accepts_getcode_fallback_and_create_payload(): client = _load("scm_broker_client") seen = [] def opener(request, timeout): seen.append((request, timeout)) return _GetCodeResponse(b"{}") result = client.create_draft( "cassandra", base="main", head="feature/coverage", head_sha="a" * 40, title="WIP: Coverage", body="Review evidence", opener=opener, ) assert result == b"{}" assert json.loads(seen[0][0].data)["repo"] == "cassandra" @pytest.mark.parametrize( ("response", "match"), [ (_GetCodeResponse(b"{}", code=201), "HTTP status"), (_GetCodeResponse(b"{}", content_type="text/plain"), "response type"), ( Response(b"x" * (2 * 1024 * 1024 + 1), content_type="application/json"), "safe size", ), (Response(b"not-json", content_type="application/json"), "Expecting value"), ], ) def test_client_rejects_bad_status_type_size_and_json(response, match): client = _load("scm_broker_client") expected = ( json.JSONDecodeError if match == "Expecting value" else client.PolicyError ) with pytest.raises(expected, match=match): client.request( "/v1/metadata", {"path": "/api/v1/repos/titan/cassandra"}, opener=lambda *_a, **_k: response, ) class _Socket: def __init__(self): self.timeouts = [] def settimeout(self, value): self.timeouts.append(value) class _Stream: def __init__(self, body: bytes, socket_shape: str = "direct"): self.body = io.BytesIO(body) self.socket = _Socket() if socket_shape == "nested": self.fp = type( "FP", (), {"raw": type("Raw", (), {"_sock": self.socket})()} )() elif socket_shape == "direct": self.fp = type("FP", (), {"raw": self.socket})() else: self.fp = None def read(self, size): return self.body.read(size) def test_response_spool_handles_direct_and_absent_socket_shapes(): module = _load("scm_broker_io") for shape in ("direct", "absent"): stream = _Stream(b"safe", shape) spool, length = module.spool_response( stream, 16, (b"forbidden",), memory_limit=8, chunk_size=2, deadline_seconds=5, ) try: assert length == 4 and spool.read() == b"safe" finally: spool.close() @pytest.mark.parametrize("failure", ["deadline", "size", "credential", "read"]) def test_response_spool_closes_and_rejects_each_failure(monkeypatch, failure): module = _load("scm_broker_io") stream = _Stream(b"safe-forbidden-value") kwargs = { "maximum": 128, "forbidden": (b"forbidden",), "memory_limit": 8, "chunk_size": 5, "deadline_seconds": 5, } if failure == "deadline": ticks = iter((10.0, 16.0)) monkeypatch.setattr(module.time, "monotonic", lambda: next(ticks)) elif failure == "size": kwargs["maximum"] = 2 elif failure == "read": stream.read = lambda _size: (_ for _ in ()).throw(OSError("read failed")) expected = module.PolicyError if failure != "read" else OSError with pytest.raises(expected): module.spool_response(stream, **kwargs)