|
| 1 | +"""Fixtures for storage strategy contract tests. |
| 2 | +
|
| 3 | +Provides parameterised `storage_strategy` and `unit_of_work` fixtures so |
| 4 | +each backend (JSON, SQL/SQLite, DynamoDB/moto) runs the same contract tests. |
| 5 | +""" |
| 6 | + |
| 7 | +from __future__ import annotations |
| 8 | + |
| 9 | +from contextlib import contextmanager |
| 10 | +from typing import Iterator |
| 11 | + |
| 12 | +import pytest |
| 13 | + |
| 14 | +try: |
| 15 | + from moto import mock_aws as _moto_mock_aws |
| 16 | + |
| 17 | + HAS_MOTO = True |
| 18 | +except ImportError: |
| 19 | + HAS_MOTO = False |
| 20 | + _moto_mock_aws = None |
| 21 | + |
| 22 | + |
| 23 | +@contextmanager |
| 24 | +def _mock_aws(): |
| 25 | + if _moto_mock_aws is None: |
| 26 | + yield |
| 27 | + return |
| 28 | + with _moto_mock_aws(): |
| 29 | + yield |
| 30 | + |
| 31 | + |
| 32 | +_ENTITY_TABLE = "entities" |
| 33 | +_ENTITY_COLUMNS = {"id": "TEXT PRIMARY KEY", "data": "TEXT", "name": "TEXT"} |
| 34 | + |
| 35 | + |
| 36 | +# --------------------------------------------------------------------------- |
| 37 | +# Strategy fixtures (low-level: SQLStorageStrategy / JSONStorageStrategy / DynamoDB) |
| 38 | +# --------------------------------------------------------------------------- |
| 39 | + |
| 40 | + |
| 41 | +@pytest.fixture |
| 42 | +def json_strategy(tmp_path): |
| 43 | + from orb.infrastructure.storage.json.strategy import JSONStorageStrategy |
| 44 | + |
| 45 | + file_path = tmp_path / "entities.json" |
| 46 | + return JSONStorageStrategy(file_path=str(file_path), entity_type="entities") |
| 47 | + |
| 48 | + |
| 49 | +@pytest.fixture |
| 50 | +def sql_strategy(): |
| 51 | + from orb.infrastructure.storage.sql.strategy import SQLStorageStrategy |
| 52 | + |
| 53 | + return SQLStorageStrategy( |
| 54 | + config={"type": "sqlite", "name": ":memory:"}, |
| 55 | + table_name=_ENTITY_TABLE, |
| 56 | + columns=_ENTITY_COLUMNS, |
| 57 | + ) |
| 58 | + |
| 59 | + |
| 60 | +@pytest.fixture |
| 61 | +def dynamodb_strategy() -> Iterator: |
| 62 | + if not HAS_MOTO: |
| 63 | + pytest.skip("moto not installed") |
| 64 | + |
| 65 | + from orb.providers.aws.storage.strategy import DynamoDBStorageStrategy |
| 66 | + |
| 67 | + with _mock_aws(): |
| 68 | + # aws_client=None forces internal boto3 session, which moto intercepts. |
| 69 | + from orb.infrastructure.adapters.logging_adapter import LoggingAdapter |
| 70 | + |
| 71 | + strategy = DynamoDBStorageStrategy( |
| 72 | + logger=LoggingAdapter("test.dynamo"), |
| 73 | + aws_client=None, |
| 74 | + region="us-east-1", |
| 75 | + table_name=_ENTITY_TABLE, |
| 76 | + ) |
| 77 | + yield strategy |
| 78 | + |
| 79 | + |
| 80 | +@pytest.fixture(params=["json", "sql", "dynamodb"]) |
| 81 | +def storage_strategy(request, json_strategy, sql_strategy, dynamodb_strategy): |
| 82 | + """Parameterised strategy fixture used by contract tests.""" |
| 83 | + return { |
| 84 | + "json": json_strategy, |
| 85 | + "sql": sql_strategy, |
| 86 | + "dynamodb": dynamodb_strategy, |
| 87 | + }[request.param] |
| 88 | + |
| 89 | + |
| 90 | +# --------------------------------------------------------------------------- |
| 91 | +# UnitOfWork fixtures |
| 92 | +# --------------------------------------------------------------------------- |
| 93 | + |
| 94 | + |
| 95 | +@pytest.fixture |
| 96 | +def json_uow(tmp_path): |
| 97 | + from orb.infrastructure.storage.json.unit_of_work import JSONUnitOfWork |
| 98 | + |
| 99 | + return JSONUnitOfWork(data_dir=str(tmp_path)) |
| 100 | + |
| 101 | + |
| 102 | +@pytest.fixture |
| 103 | +def sql_uow(): |
| 104 | + from sqlalchemy import create_engine |
| 105 | + |
| 106 | + from orb.infrastructure.storage.sql.unit_of_work import SQLUnitOfWork |
| 107 | + |
| 108 | + engine = create_engine("sqlite:///:memory:") |
| 109 | + return SQLUnitOfWork(engine) |
| 110 | + |
| 111 | + |
| 112 | +@pytest.fixture |
| 113 | +def dynamodb_uow(): |
| 114 | + if not HAS_MOTO: |
| 115 | + pytest.skip("moto not installed") |
| 116 | + |
| 117 | + from orb.providers.aws.storage.unit_of_work import DynamoDBUnitOfWork |
| 118 | + |
| 119 | + from orb.infrastructure.adapters.logging_adapter import LoggingAdapter |
| 120 | + |
| 121 | + with _mock_aws(): |
| 122 | + uow = DynamoDBUnitOfWork( |
| 123 | + aws_client=None, |
| 124 | + logger=LoggingAdapter("test.dynamo.uow"), |
| 125 | + region="us-east-1", |
| 126 | + ) |
| 127 | + yield uow |
| 128 | + |
| 129 | + |
| 130 | +@pytest.fixture(params=["json", "sql", "dynamodb"]) |
| 131 | +def unit_of_work(request, json_uow, sql_uow, dynamodb_uow): |
| 132 | + """Parameterised UoW fixture used by UoW contract tests.""" |
| 133 | + return { |
| 134 | + "json": json_uow, |
| 135 | + "sql": sql_uow, |
| 136 | + "dynamodb": dynamodb_uow, |
| 137 | + }[request.param] |
0 commit comments