from __future__ import annotations from datetime import datetime, timezone import pytest from agent_framework.idempotency import IdempotencyStore from agent_framework.cache.cache import InMemoryCache from agent_framework.persistence.oracle_store import OracleStore class BrokenCache: async def get(self, key): raise RuntimeError("db unavailable") async def set(self, key, value, ttl_seconds=None): raise RuntimeError("db unavailable") async def delete(self, key): raise RuntimeError("db unavailable") def test_oracle_cache_datetime_normalization_accepts_naive_and_aware(): naive = datetime(2026, 8, 31, 21, 0, 0) aware = datetime(2026, 8, 31, 21, 0, 0, tzinfo=timezone.utc) normalized_naive = OracleStore._normalize_datetime_for_compare(naive) normalized_aware = OracleStore._normalize_datetime_for_compare(aware) assert normalized_naive.tzinfo is not None assert normalized_aware.tzinfo is not None assert normalized_naive == normalized_aware assert not (normalized_naive < normalized_aware) @pytest.mark.asyncio async def test_idempotency_fail_open_uses_memory_fallback_when_primary_fails(): fallback = InMemoryCache() store = IdempotencyStore( BrokenCache(), namespace="contas", ttl_seconds=60, fallback_backend=fallback, fail_open=True, ) assert await store.get("operation") is None await store.set("operation", {"success": True}) assert await store.get("operation") == {"success": True} await store.delete("operation") assert await store.get("operation") is None @pytest.mark.asyncio async def test_idempotency_fail_closed_preserves_durable_semantics(): store = IdempotencyStore(BrokenCache(), namespace="strict", fail_open=False) with pytest.raises(RuntimeError, match="db unavailable"): await store.get("operation")