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