|
3 | 3 | import uuid |
4 | 4 | from copy import deepcopy |
5 | 5 | from datetime import datetime, timedelta |
6 | | -from unittest.mock import patch |
| 6 | +from unittest.mock import AsyncMock, MagicMock, patch |
7 | 7 |
|
8 | 8 | import pytest |
9 | 9 |
|
| 10 | +import stac_fastapi.core.redis_utils as redis_utils |
| 11 | +from stac_fastapi.core.redis_utils import ( |
| 12 | + RedisSentinelSettings, |
| 13 | + RedisSettings, |
| 14 | + connect_redis, |
| 15 | + connect_redis_sentinel, |
| 16 | + get_prev_link, |
| 17 | + save_self_link, |
| 18 | +) |
10 | 19 | from stac_fastapi.types.errors import ConflictError |
11 | 20 |
|
12 | 21 | from ..conftest import create_collection, create_item |
@@ -1623,3 +1632,105 @@ async def test_use_datetime_false(app_client, load_test_data, txn_client, monkey |
1623 | 1632 |
|
1624 | 1633 | assert "test-item-datetime-only" not in found_ids |
1625 | 1634 | assert "test-item-start-end-only" in found_ids |
| 1635 | + |
| 1636 | + |
| 1637 | +@pytest.mark.asyncio |
| 1638 | +async def test_connect_redis(): |
| 1639 | + test_settings = RedisSettings( |
| 1640 | + REDIS_HOST="test-redis-host", |
| 1641 | + REDIS_PORT=6380, |
| 1642 | + REDIS_DB=5, |
| 1643 | + REDIS_MAX_CONNECTIONS=20, |
| 1644 | + REDIS_RETRY_TIMEOUT=False, |
| 1645 | + REDIS_DECODE_RESPONSES=False, |
| 1646 | + REDIS_CLIENT_NAME="custom-client", |
| 1647 | + REDIS_HEALTH_CHECK_INTERVAL=50, |
| 1648 | + ) |
| 1649 | + |
| 1650 | + with patch( |
| 1651 | + "stac_fastapi.core.redis_utils.aioredis.ConnectionPool" |
| 1652 | + ) as mock_pool_class, patch( |
| 1653 | + "stac_fastapi.core.redis_utils.aioredis.Redis" |
| 1654 | + ) as mock_redis_class: |
| 1655 | + |
| 1656 | + mock_pool_instance = AsyncMock() |
| 1657 | + mock_redis_instance = AsyncMock() |
| 1658 | + mock_pool_class.return_value = mock_pool_instance |
| 1659 | + mock_redis_class.return_value = mock_redis_instance |
| 1660 | + |
| 1661 | + # from stac_fastapi.core.redis_utils import redis_pool |
| 1662 | + |
| 1663 | + # redis_pool = None |
| 1664 | + |
| 1665 | + result = await connect_redis(test_settings) |
| 1666 | + |
| 1667 | + mock_pool_class.assert_called_once_with( |
| 1668 | + host="test-redis-host", |
| 1669 | + port=6380, |
| 1670 | + db=5, |
| 1671 | + max_connections=20, |
| 1672 | + decode_responses=False, |
| 1673 | + retry_on_timeout=False, |
| 1674 | + health_check_interval=50, |
| 1675 | + ) |
| 1676 | + |
| 1677 | + mock_redis_class.assert_called_once_with( |
| 1678 | + connection_pool=mock_pool_instance, client_name="custom-client" |
| 1679 | + ) |
| 1680 | + |
| 1681 | + assert result == mock_redis_instance |
| 1682 | + |
| 1683 | + |
| 1684 | +@pytest.mark.asyncio |
| 1685 | +async def test_connect_redis_sentinel(monkeypatch): |
| 1686 | + redis_utils.redis_pool = None |
| 1687 | + |
| 1688 | + master_mock = AsyncMock() |
| 1689 | + |
| 1690 | + sentinel_mock = MagicMock() |
| 1691 | + sentinel_mock.master_for.return_value = master_mock |
| 1692 | + |
| 1693 | + monkeypatch.setattr( |
| 1694 | + "stac_fastapi.core.redis_utils.Sentinel", |
| 1695 | + lambda *a, **k: sentinel_mock, |
| 1696 | + ) |
| 1697 | + |
| 1698 | + settings = RedisSentinelSettings( |
| 1699 | + REDIS_SENTINEL_HOSTS="localhost", |
| 1700 | + REDIS_SENTINEL_PORTS="26379", |
| 1701 | + REDIS_SENTINEL_MASTER_NAME="master", |
| 1702 | + ) |
| 1703 | + |
| 1704 | + redis = await connect_redis_sentinel(settings) |
| 1705 | + |
| 1706 | + assert redis is master_mock |
| 1707 | + |
| 1708 | + sentinel_mock.master_for.assert_called_once_with( |
| 1709 | + service_name="master", |
| 1710 | + db=0, |
| 1711 | + decode_responses=True, |
| 1712 | + retry_on_timeout=True, |
| 1713 | + client_name="stac-fastapi-app", |
| 1714 | + max_connections=10, |
| 1715 | + health_check_interval=30, |
| 1716 | + ) |
| 1717 | + |
| 1718 | + |
| 1719 | +@pytest.mark.asyncio |
| 1720 | +async def test_save_and_get_prev_link(monkeypatch): |
| 1721 | + fake_redis = AsyncMock() |
| 1722 | + |
| 1723 | + await save_self_link(fake_redis, "token123", "http://example.com/page2") |
| 1724 | + fake_redis.setex.assert_awaited_once_with( |
| 1725 | + "nav:self:token123", 1800, "http://example.com/page2" |
| 1726 | + ) |
| 1727 | + |
| 1728 | + fake_redis.get.return_value = "http://example.com/page2" |
| 1729 | + result = await get_prev_link(fake_redis, "token123") |
| 1730 | + assert result == "http://example.com/page2" |
| 1731 | + |
| 1732 | + result_none = await get_prev_link(fake_redis, None) |
| 1733 | + assert result_none is None |
| 1734 | + |
| 1735 | + await get_prev_link(fake_redis, "token456") |
| 1736 | + fake_redis.get.assert_awaited_with("nav:self:token456") |
0 commit comments