59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
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")
|