Reach 100% combined coverage with targeted unit tests.
Code Quality Pipeline / code-quality (pull_request) Failing after 29s
Test Python Package / integration-tests (pull_request) Successful in 35s
Test Python Package / unit-tests (pull_request) Successful in 42s
PR Title Check / check-title (pull_request) Successful in 52s
Test Python Package / coverage-report (pull_request) Successful in 12s
Code Quality Pipeline / code-quality (pull_request) Failing after 29s
Test Python Package / integration-tests (pull_request) Successful in 35s
Test Python Package / unit-tests (pull_request) Successful in 42s
PR Title Check / check-title (pull_request) Successful in 52s
Test Python Package / coverage-report (pull_request) Successful in 12s
Add fast unit tests for lazy-import helpers and injected-client connect paths that integration tests miss, and raise the coverage floor to 100%. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
co-authored by
Cursor
parent
ce062be411
commit
beb2b5128e
+1
-1
@@ -43,7 +43,7 @@ markers = [
|
|||||||
source = ["python_repositories"]
|
source = ["python_repositories"]
|
||||||
|
|
||||||
[tool.coverage.report]
|
[tool.coverage.report]
|
||||||
fail_under = 90
|
fail_under = 100
|
||||||
show_missing = true
|
show_missing = true
|
||||||
precision = 2
|
precision = 2
|
||||||
|
|
||||||
|
|||||||
@@ -117,3 +117,24 @@ def test_adapters_subpackage_lazy_import_succeeds() -> None:
|
|||||||
from python_repositories.adapters import RedisAdapter
|
from python_repositories.adapters import RedisAdapter
|
||||||
|
|
||||||
assert RedisAdapter.__name__ == "RedisAdapter"
|
assert RedisAdapter.__name__ == "RedisAdapter"
|
||||||
|
|
||||||
|
|
||||||
|
def test_adapters_dir_exposes_lazy_exports() -> None:
|
||||||
|
"""dir(adapters) includes lazy adapter names for tab completion."""
|
||||||
|
import python_repositories.adapters as adapters
|
||||||
|
|
||||||
|
assert {"RedisAdapter", "MinioAdapter"}.issubset(set(dir(adapters)))
|
||||||
|
|
||||||
|
|
||||||
|
def test_adapters_getattr_raises_for_unknown() -> None:
|
||||||
|
"""Unknown adapter names raise AttributeError."""
|
||||||
|
import python_repositories.adapters as adapters
|
||||||
|
|
||||||
|
with pytest.raises(AttributeError, match="has no attribute 'NoSuchAdapter'"):
|
||||||
|
_ = adapters.NoSuchAdapter
|
||||||
|
|
||||||
|
|
||||||
|
def test_top_level_dir_exposes_lazy_exports() -> None:
|
||||||
|
"""dir(python_repositories) includes lazy adapter names for tab completion."""
|
||||||
|
assert "RedisAdapter" in dir(python_repositories)
|
||||||
|
assert "MinioAdapter" in dir(python_repositories)
|
||||||
|
|||||||
@@ -53,3 +53,43 @@ def test_raises_when_client_provided_without_config() -> None:
|
|||||||
mock_client = MagicMock(spec=Minio)
|
mock_client = MagicMock(spec=Minio)
|
||||||
with pytest.raises(ValueError, match="config is required"):
|
with pytest.raises(ValueError, match="config is required"):
|
||||||
MinioAdapter(client=mock_client)
|
MinioAdapter(client=mock_client)
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_with_injected_client_succeeds() -> None:
|
||||||
|
mock_client = MagicMock(spec=Minio)
|
||||||
|
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
|
||||||
|
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
mock_client.list_buckets.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_with_injected_client_raises_on_failure() -> None:
|
||||||
|
mock_client = MagicMock(spec=Minio)
|
||||||
|
mock_client.list_buckets.side_effect = Exception("connection lost")
|
||||||
|
adapter = MinioAdapter(config=TEST_MINIO_CONFIG, client=mock_client)
|
||||||
|
|
||||||
|
with pytest.raises(ConnectionError, match="Could not connect to Minio"):
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_disconnects_before_reconnect(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
stale_client = MagicMock(spec=Minio)
|
||||||
|
new_client = MagicMock(spec=Minio)
|
||||||
|
adapter = MinioAdapter(config=TEST_MINIO_CONFIG)
|
||||||
|
adapter._client = stale_client
|
||||||
|
adapter._bucket_name = None
|
||||||
|
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"python_repositories.adapters.minio_adapter.minio.Minio",
|
||||||
|
lambda *args, **kwargs: new_client,
|
||||||
|
)
|
||||||
|
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
assert adapter._client is new_client
|
||||||
|
assert adapter._bucket_name == TEST_MINIO_CONFIG.bucket
|
||||||
|
new_client.list_buckets.assert_called_once()
|
||||||
|
new_client.bucket_exists.assert_called_once_with(TEST_MINIO_CONFIG.bucket)
|
||||||
|
|||||||
@@ -69,3 +69,48 @@ def test_subclass_custom_env_var_name(monkeypatch: pytest.MonkeyPatch) -> None:
|
|||||||
monkeypatch.setenv("CUSTOM_REDIS_URI", "redis://custom:6379")
|
monkeypatch.setenv("CUSTOM_REDIS_URI", "redis://custom:6379")
|
||||||
adapter = CustomEnvRedisAdapter()
|
adapter = CustomEnvRedisAdapter()
|
||||||
assert adapter._config.uri == "redis://custom:6379"
|
assert adapter._config.uri == "redis://custom:6379"
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_with_injected_client_succeeds_when_ping_ok() -> None:
|
||||||
|
mock_client = MagicMock(spec=redis.Redis)
|
||||||
|
mock_client.ping.return_value = True
|
||||||
|
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
|
||||||
|
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
mock_client.ping.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_with_injected_client_raises_when_ping_false() -> None:
|
||||||
|
mock_client = MagicMock(spec=redis.Redis)
|
||||||
|
mock_client.ping.return_value = False
|
||||||
|
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
|
||||||
|
|
||||||
|
with pytest.raises(ConnectionError, match="Could not connect to Redis"):
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_with_injected_client_raises_on_redis_error() -> None:
|
||||||
|
mock_client = MagicMock(spec=redis.Redis)
|
||||||
|
mock_client.ping.side_effect = redis.ConnectionError("connection lost")
|
||||||
|
adapter = RedisAdapter(config=TEST_REDIS_CONFIG, client=mock_client)
|
||||||
|
|
||||||
|
with pytest.raises(ConnectionError, match="Could not connect to Redis"):
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_closes_existing_non_injected_client(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
stale_client = MagicMock(spec=redis.Redis)
|
||||||
|
new_client = MagicMock(spec=redis.Redis)
|
||||||
|
new_client.ping.return_value = True
|
||||||
|
adapter = RedisAdapter(config=TEST_REDIS_CONFIG)
|
||||||
|
adapter._client = stale_client
|
||||||
|
|
||||||
|
monkeypatch.setattr("redis.Redis.from_url", lambda *args, **kwargs: new_client)
|
||||||
|
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
stale_client.close.assert_called_once()
|
||||||
|
assert adapter._client is new_client
|
||||||
|
|||||||
Reference in New Issue
Block a user