added integration tests
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
"""Integration tests configuration."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import Generator
|
||||||
|
import pytest
|
||||||
|
import redis
|
||||||
|
import structlog
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from testcontainers.redis import RedisContainer
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def configure_logging() -> None:
|
||||||
|
"""Configure logging for the test session."""
|
||||||
|
# Configure structlog
|
||||||
|
structlog.configure(
|
||||||
|
processors=[
|
||||||
|
structlog.processors.JSONRenderer(),
|
||||||
|
],
|
||||||
|
logger_factory=structlog.stdlib.LoggerFactory(),
|
||||||
|
wrapper_class=structlog.stdlib.BoundLogger,
|
||||||
|
cache_logger_on_first_use=True,
|
||||||
|
)
|
||||||
|
# Set up basic logging configuration
|
||||||
|
logging.basicConfig(level=logging.ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def redis_container() -> Generator[str, None, None]:
|
||||||
|
"""Set up a Redis container for testing and yield the Redis URI."""
|
||||||
|
# Start container
|
||||||
|
container = RedisContainer(
|
||||||
|
image="redis/redis-stack:7.2.0-v0",
|
||||||
|
port=6379,
|
||||||
|
).with_bind_ports(
|
||||||
|
container=6379,
|
||||||
|
host=6379,
|
||||||
|
)
|
||||||
|
container.start()
|
||||||
|
# Set environment variable for Redis URI
|
||||||
|
redis_host = container.get_container_host_ip()
|
||||||
|
redis_port = container.get_exposed_port(6379)
|
||||||
|
redis_uri = f"redis://{redis_host}:{redis_port}"
|
||||||
|
|
||||||
|
yield redis_uri
|
||||||
|
|
||||||
|
# Stop container
|
||||||
|
container.stop()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session", autouse=True)
|
||||||
|
def set_environment_variables(
|
||||||
|
redis_container: str,
|
||||||
|
) -> Generator[dict[str, str], None, None]:
|
||||||
|
"""Set environment variables needed for tests."""
|
||||||
|
# Build environment variables dictionary
|
||||||
|
env_vars = {"REDIS_URI": redis_container}
|
||||||
|
# Set environment variables
|
||||||
|
for key, value in env_vars.items():
|
||||||
|
os.environ[key] = value
|
||||||
|
|
||||||
|
yield env_vars
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
for key in env_vars:
|
||||||
|
_ = os.environ.pop(key, default=None)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def raw_redis_client(redis_container: str) -> Generator[redis.Redis, None, None]:
|
||||||
|
"""Provide a raw Redis client connected to the test Redis container."""
|
||||||
|
# Connect client
|
||||||
|
client = redis.Redis.from_url(
|
||||||
|
url=redis_container,
|
||||||
|
socket_connect_timeout=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
yield client
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
client.flushall()
|
||||||
|
client.close()
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
"""Integration tests for ConnectionAwareInterface."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from python_repositories.interfaces.connection_aware_interface import ConnectionAwareInterface
|
||||||
|
|
||||||
|
|
||||||
|
def test_instantiation_fails_when_connect_not_implemented() -> None:
|
||||||
|
"""Test that instantiation fails if connect is not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement connect."""
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
_ = Incomplete()
|
||||||
|
|
||||||
|
|
||||||
|
def test_instantiation_fails_when_disconnect_not_implemented() -> None:
|
||||||
|
"""Test that instantiation fails if disconnect is not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement disconnect."""
|
||||||
|
def connect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
_ = Incomplete()
|
||||||
|
|
||||||
|
|
||||||
|
def test_instantiation_fails_when_is_connected_not_implemented() -> None:
|
||||||
|
"""Test that instantiation fails if is_connected is not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement is_connected."""
|
||||||
|
def connect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
_ = Incomplete()
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_raises_not_implemented_if_not_overwritten() -> None:
|
||||||
|
"""Test that connect raises NotImplementedError if not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement connect."""
|
||||||
|
def connect(self) -> None:
|
||||||
|
super().connect()
|
||||||
|
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
instance = Incomplete()
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
instance.connect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_disconnect_raises_not_implemented_if_not_overwritten() -> None:
|
||||||
|
"""Test that disconnect raises NotImplementedError if not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement disconnect."""
|
||||||
|
def connect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
super().disconnect()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
|
instance = Incomplete()
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
instance.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_connected_raises_not_implemented_if_not_overwritten() -> None:
|
||||||
|
"""Test that is_connected raises NotImplementedError if not implemented."""
|
||||||
|
class Incomplete(ConnectionAwareInterface):
|
||||||
|
"""A class that does not implement is_connected."""
|
||||||
|
def connect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def disconnect(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_connected(self) -> bool:
|
||||||
|
return super().is_connected
|
||||||
|
|
||||||
|
instance = Incomplete()
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
_ = instance.is_connected
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
"""Integration tests for ContextAwareInterface."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from python_repositories.interfaces.context_aware_interface import ContextAwareInterface
|
||||||
|
|
||||||
|
|
||||||
|
def test_instantiation_fails_when_enter_not_implemented() -> None:
|
||||||
|
"""Test that instantiation fails if __enter__ is not implemented."""
|
||||||
|
class Incomplete(ContextAwareInterface):
|
||||||
|
"""A class that does not implement __enter__."""
|
||||||
|
def __exit__(
|
||||||
|
self, exc_type: type | None, exc_val: object | None, exc_tb: object | None
|
||||||
|
) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
_ = Incomplete()
|
||||||
|
|
||||||
|
|
||||||
|
def test_instantiation_fails_when_exit_not_implemented() -> None:
|
||||||
|
"""Test that instantiation fails if __exit__ is not implemented."""
|
||||||
|
class Incomplete(ContextAwareInterface):
|
||||||
|
"""A class that does not implement __exit__."""
|
||||||
|
def __enter__(self) -> ContextAwareInterface:
|
||||||
|
return self
|
||||||
|
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
_ = Incomplete()
|
||||||
|
|
||||||
|
|
||||||
|
def test_enter_raises_not_implemented_if_not_overwritten() -> None:
|
||||||
|
"""Test that __enter__ raises NotImplementedError if not implemented."""
|
||||||
|
class Incomplete(ContextAwareInterface):
|
||||||
|
"""A class that does not implement __enter__."""
|
||||||
|
def __enter__(self) -> ContextAwareInterface:
|
||||||
|
super().__enter__()
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self, exc_type: type | None, exc_val: object | None, exc_tb: object | None
|
||||||
|
) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
instance = Incomplete()
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
instance.__enter__()
|
||||||
|
|
||||||
|
|
||||||
|
def test_exit_raises_not_implemented_if_not_overwritten() -> None:
|
||||||
|
"""Test that __exit__ raises NotImplementedError if not implemented."""
|
||||||
|
class Incomplete(ContextAwareInterface):
|
||||||
|
"""A class that does not implement __exit__."""
|
||||||
|
def __enter__(self) -> ContextAwareInterface:
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(
|
||||||
|
self, exc_type: type | None, exc_val: object | None, exc_tb: object | None
|
||||||
|
) -> None:
|
||||||
|
super().__exit__(exc_type, exc_val, exc_tb)
|
||||||
|
|
||||||
|
instance = Incomplete()
|
||||||
|
with pytest.raises(NotImplementedError):
|
||||||
|
instance.__exit__(None, None, None)
|
||||||
@@ -0,0 +1,340 @@
|
|||||||
|
# pylint: disable=protected-access
|
||||||
|
# The above line disables pylint's protected member access warnings for this file,
|
||||||
|
# allowing tests to access RedisAdapter's internal methods as needed for integration testing.
|
||||||
|
"""Integration tests for the RedisAdapter."""
|
||||||
|
|
||||||
|
from typing import Generator
|
||||||
|
import pytest
|
||||||
|
import redis
|
||||||
|
from redis.commands.json.path import Path as RedisPath
|
||||||
|
from python_repositories.adapters.redis_adapter import RedisAdapter
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def data() -> Generator[dict[str, str], None, None]:
|
||||||
|
"""Provide a sample data dictionary for tests."""
|
||||||
|
yield {"foo": "bar"}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def data_in_redis(
|
||||||
|
raw_redis_client: redis.Redis,
|
||||||
|
data: dict[str, str],
|
||||||
|
) -> Generator[tuple[str, dict[str, str]], None, None]:
|
||||||
|
"""Fixture to set up a known value in Redis before each test."""
|
||||||
|
key = "test_key"
|
||||||
|
path = RedisPath.root_path()
|
||||||
|
raw_redis_client.json().set(key, path, data)
|
||||||
|
|
||||||
|
yield key, data
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
raw_redis_client.delete(key)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def redis_adapter(redis_container: str) -> Generator[RedisAdapter, None, None]:
|
||||||
|
"""Fixture to provide a connected RedisAdapter instance."""
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
adapter.connect()
|
||||||
|
yield adapter
|
||||||
|
adapter.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
|
def clear_redis(raw_redis_client: redis.Redis) -> None:
|
||||||
|
"""Fixture to clear all Redis keys before each test."""
|
||||||
|
# Clear all keys before each test
|
||||||
|
raw_redis_client.flushall()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_adhere_to_interface(
|
||||||
|
redis_container: str
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter adheres to the expected interface."""
|
||||||
|
# Instantiation fails if interface not adhered to
|
||||||
|
_ = RedisAdapter()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_have_logger_when_instantiated(
|
||||||
|
redis_container: str
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter has a logger when instantiated."""
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
assert hasattr(adapter, "logger")
|
||||||
|
assert adapter.logger is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_not_be_connected_when_instantiated(
|
||||||
|
redis_container: str
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter is not connected when instantiated."""
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
assert adapter._client is None
|
||||||
|
assert not adapter.is_connected
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_connection_error_when_unable_to_connect(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when unable to connect."""
|
||||||
|
# Arrange
|
||||||
|
monkeypatch.setenv("REDIS_URI", "redis://invalid:6379")
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
# Act & Assert
|
||||||
|
with pytest.raises(ConnectionError):
|
||||||
|
adapter.connect()
|
||||||
|
assert adapter._client is None
|
||||||
|
assert not adapter.is_connected
|
||||||
|
|
||||||
|
|
||||||
|
def test_connect_raises_connection_error_when_unable_to_ping(
|
||||||
|
monkeypatch: pytest.MonkeyPatch
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when ping fails."""
|
||||||
|
# Set an invalid URI
|
||||||
|
monkeypatch.setenv("REDIS_URI", "redis://invalid:6379")
|
||||||
|
|
||||||
|
# Monkeypatch redis.Redis.from_url to return a mock client
|
||||||
|
class MockRedis:
|
||||||
|
"""A mock Redis client that simulates a failed ping."""
|
||||||
|
def ping(self) -> bool:
|
||||||
|
"""Simulate a failed ping."""
|
||||||
|
return False # Simulate failed ping
|
||||||
|
|
||||||
|
monkeypatch.setattr("redis.Redis.from_url", lambda *a, **kw: MockRedis())
|
||||||
|
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
with pytest.raises(ConnectionError, match="Could not connect to Redis"):
|
||||||
|
adapter.connect()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_connect_and_disconnect(
|
||||||
|
redis_container: str,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter can connect and disconnect."""
|
||||||
|
# Connect
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
adapter.connect()
|
||||||
|
# Assert connected
|
||||||
|
assert adapter._client is not None
|
||||||
|
assert adapter.is_connected
|
||||||
|
# Disconnect
|
||||||
|
adapter.disconnect()
|
||||||
|
# Assert disconnected
|
||||||
|
assert adapter._client is None
|
||||||
|
assert not adapter.is_connected
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_log_error_on_exception_during_exit(
|
||||||
|
redis_container: str,
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter logs an error when an exception occurs during context exit."""
|
||||||
|
try:
|
||||||
|
with RedisAdapter() as adapter:
|
||||||
|
assert adapter.is_connected
|
||||||
|
raise ValueError("Simulated error")
|
||||||
|
except ValueError:
|
||||||
|
pass # Expected
|
||||||
|
|
||||||
|
# Assert error was logged
|
||||||
|
assert "Error while exiting context" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_have_context_manager(
|
||||||
|
redis_container: str
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter can be used as a context manager."""
|
||||||
|
with RedisAdapter() as adapter:
|
||||||
|
assert adapter._client is not None
|
||||||
|
assert adapter._client is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_get_value(
|
||||||
|
data_in_redis: tuple[str, dict[str, str]],
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter can get a value."""
|
||||||
|
# Arrange
|
||||||
|
key, data = data_in_redis
|
||||||
|
# Act
|
||||||
|
value = redis_adapter._get(key)
|
||||||
|
# Assert
|
||||||
|
assert value == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_get_none_for_missing_key(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that getting a non-existent key returns None."""
|
||||||
|
# Act
|
||||||
|
value = redis_adapter._get("nonexistent_key")
|
||||||
|
# Assert
|
||||||
|
assert value is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_value_error_on_invalid_get_key(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ValueError when getting with an invalid key."""
|
||||||
|
# Arrange
|
||||||
|
invalid_keys = ["", 123, None]
|
||||||
|
# Act & Assert
|
||||||
|
for key in invalid_keys:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
redis_adapter._get(key)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_connection_error_on_get_when_not_connected(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when getting while not connected."""
|
||||||
|
# Arrange
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
# Act & Assert
|
||||||
|
with pytest.raises(ConnectionError):
|
||||||
|
adapter._get("some_key")
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_set_value(
|
||||||
|
data: dict[str, str],
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter can set a value."""
|
||||||
|
# Arrange
|
||||||
|
key = "test_key"
|
||||||
|
# Act
|
||||||
|
redis_adapter._set(key, data)
|
||||||
|
# Assert
|
||||||
|
assert redis_adapter._get(key) == data
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_update_value(
|
||||||
|
data_in_redis: tuple[str, dict[str, str]],
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter can update an existing value."""
|
||||||
|
# Arrange
|
||||||
|
key, _ = data_in_redis
|
||||||
|
new_data = {"new_key": "new_value"}
|
||||||
|
# Act
|
||||||
|
redis_adapter._set(key, new_data)
|
||||||
|
# Assert
|
||||||
|
assert redis_adapter._get(key) == new_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_value_error_on_invalid_set_key(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
data: dict[str, str],
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ValueError when setting with an invalid key."""
|
||||||
|
# Arrange
|
||||||
|
invalid_keys = ["", 123, None]
|
||||||
|
# Act & Assert
|
||||||
|
for key in invalid_keys:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
redis_adapter._set(key, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_value_error_on_invalid_set_data(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ValueError when setting with invalid data."""
|
||||||
|
# Arrange
|
||||||
|
key = "test_key"
|
||||||
|
invalid_data = ["", 123, None, [], {}]
|
||||||
|
# Act & Assert
|
||||||
|
for data in invalid_data:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
redis_adapter._set(key, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_connection_error_on_set_when_not_connected(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
data: dict[str, str],
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when setting while not connected."""
|
||||||
|
# Arrange
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
key = "test_key"
|
||||||
|
# Act & Assert
|
||||||
|
with pytest.raises(ConnectionError):
|
||||||
|
adapter._set(key, data)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_delete_key(
|
||||||
|
data_in_redis: tuple[str, dict[str, str]],
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that deleting a key removes it from Redis."""
|
||||||
|
# Arrange
|
||||||
|
key, _ = data_in_redis
|
||||||
|
# Act
|
||||||
|
redis_adapter._delete(key)
|
||||||
|
# Assert
|
||||||
|
assert redis_adapter._get(key) is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_value_error_on_invalid_delete_key(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ValueError when deleting with an invalid key."""
|
||||||
|
# Arrange
|
||||||
|
invalid_keys = ["", 123, None]
|
||||||
|
# Act & Assert
|
||||||
|
for key in invalid_keys:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
redis_adapter._delete(key)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_connection_error_on_delete_when_not_connected(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when deleting while not connected."""
|
||||||
|
# Arrange
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
# Act & Assert
|
||||||
|
with pytest.raises(ConnectionError):
|
||||||
|
adapter._delete("some_key")
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_list_keys(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test listing keys matching a pattern returns correct keys."""
|
||||||
|
# Arrange
|
||||||
|
redis_adapter._set("key1", {"a": 1})
|
||||||
|
redis_adapter._set("key2", {"b": 2})
|
||||||
|
# Act
|
||||||
|
keys = redis_adapter._list_keys("key*")
|
||||||
|
# Assert
|
||||||
|
assert set(keys) == {"key1", "key2"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_value_error_on_invalid_list_keys_pattern(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ValueError when listing keys with an invalid pattern."""
|
||||||
|
# Arrange
|
||||||
|
invalid_patterns = ["", 123, None]
|
||||||
|
# Act & Assert
|
||||||
|
for pattern in invalid_patterns:
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
redis_adapter._list_keys(pattern)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_raise_connection_error_on_list_keys_when_not_connected(
|
||||||
|
redis_adapter: RedisAdapter,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the RedisAdapter raises ConnectionError when listing keys while not connected."""
|
||||||
|
# Arrange
|
||||||
|
adapter = RedisAdapter()
|
||||||
|
# Act & Assert
|
||||||
|
with pytest.raises(ConnectionError):
|
||||||
|
adapter._list_keys("some_pattern")
|
||||||
|
|
||||||
|
|
||||||
|
# allows local debugging by running file as script
|
||||||
|
if __name__ == "__main__":
|
||||||
|
pytest.main(["-s", "-v", __file__])
|
||||||
Reference in New Issue
Block a user