Skip to content

Commit 88f360f

Browse files
Yuri ZmytrakovYuri Zmytrakov
authored andcommitted
fix: implement recommendations
1 parent ab6e1db commit 88f360f

File tree

7 files changed

+163
-17
lines changed

7 files changed

+163
-17
lines changed

Makefile

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,15 @@ docker-shell-os:
6363

6464
.PHONY: test-elasticsearch
6565
test-elasticsearch:
66-
-$(run_es) /bin/bash -c 'export && ./scripts/wait-for-it-es.sh elasticsearch:9200 && cd stac_fastapi/tests/ && pytest'
67-
docker compose down
66+
docker compose -f compose-redis.yml up -d
67+
-$(run_es) /bin/bash -c 'export REDIS_ENABLE=true REDIS_HOST=redis REDIS_PORT=6379 && ./scripts/wait-for-it-es.sh elasticsearch:9200 && cd stac_fastapi/tests/ && pytest'
68+
docker compose -f compose-redis.yml down
6869

69-
.PHONY: test-opensearch
70+
.PHONY: test-opensearch
7071
test-opensearch:
71-
-$(run_os) /bin/bash -c 'export && ./scripts/wait-for-it-es.sh opensearch:9202 && cd stac_fastapi/tests/ && pytest'
72-
docker compose down
72+
docker compose -f compose-redis.yml up -d
73+
-$(run_os) /bin/bash -c 'export REDIS_ENABLE=true REDIS_HOST=redis REDIS_PORT=6379 && ./scripts/wait-for-it-es.sh opensearch:9202 && cd stac_fastapi/tests/ && pytest'
74+
docker compose -f compose-redis.yml down
7375

7476
.PHONY: test-datetime-filtering-es
7577
test-datetime-filtering-es:
@@ -82,7 +84,7 @@ test-datetime-filtering-os:
8284
docker compose down
8385

8486
.PHONY: test
85-
test: test-elasticsearch test-datetime-filtering-es test-opensearch test-datetime-filtering-os
87+
test: test-elasticsearch test-datetime-filtering-es test-opensearch test-datetime-filtering-os test-redis-es test-redis-os
8688

8789
.PHONY: run-database-es
8890
run-database-es:
@@ -117,4 +119,16 @@ docs-image:
117119
.PHONY: docs
118120
docs: docs-image
119121
docker compose -f compose.docs.yml \
120-
run docs
122+
run docs
123+
124+
.PHONY: test-redis-es
125+
test-redis-es:
126+
docker compose -f compose-redis.yml up -d
127+
-$(run_es) /bin/bash -c 'export REDIS_ENABLE=true REDIS_HOST=redis REDIS_PORT=6379 && ./scripts/wait-for-it-es.sh elasticsearch:9200 && cd stac_fastapi/tests/ && pytest redis/ -v'
128+
docker compose -f compose-redis.yml down
129+
130+
.PHONY: test-redis-os
131+
test-redis-os:
132+
docker compose -f compose-redis.yml up -d
133+
-$(run_os) /bin/bash -c 'export REDIS_ENABLE=true REDIS_HOST=redis REDIS_PORT=6379 && ./scripts/wait-for-it-es.sh opensearch:9202 && cd stac_fastapi/tests/ && pytest redis/ -v'
134+
docker compose -f compose-redis.yml down

compose-redis.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: '3.8'
2+
3+
services:
4+
redis:
5+
image: redis:7-alpine
6+
ports:
7+
- "6379:6379"
8+
volumes:
9+
- redis_test_data:/data
10+
command: redis-server --appendonly yes
11+
12+
volumes:
13+
redis_test_data:

stac_fastapi/core/stac_fastapi/core/core.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,15 @@
1919
from stac_pydantic.links import Relations
2020
from stac_pydantic.shared import BBox, MimeTypes
2121
from stac_pydantic.version import STAC_VERSION
22-
from stac_fastapi.core.utilities import get_bool_env
2322

2423
from stac_fastapi.core.base_database_logic import BaseDatabaseLogic
2524
from stac_fastapi.core.base_settings import ApiBaseSettings
2625
from stac_fastapi.core.datetime_utils import format_datetime_range
2726
from stac_fastapi.core.models.links import PagingLinks
28-
from stac_fastapi.core.redis_utils import (
29-
connect_redis_sentinel,
30-
get_prev_link,
31-
save_self_link,
32-
)
27+
from stac_fastapi.core.redis_utils import connect_redis, get_prev_link, save_self_link
3328
from stac_fastapi.core.serializers import CollectionSerializer, ItemSerializer
3429
from stac_fastapi.core.session import Session
35-
from stac_fastapi.core.utilities import filter_fields
30+
from stac_fastapi.core.utilities import filter_fields, get_bool_env
3631
from stac_fastapi.extensions.core.transaction import AsyncBaseTransactionsClient
3732
from stac_fastapi.extensions.core.transaction.request import (
3833
PartialCollection,
@@ -282,7 +277,7 @@ async def all_collections(
282277

283278
if redis_enable:
284279
try:
285-
redis = await connect_redis_sentinel()
280+
redis = await connect_redis()
286281
except Exception:
287282
redis = None
288283

@@ -565,7 +560,7 @@ async def post_search(
565560
redis = None
566561
if redis_enable:
567562
try:
568-
redis = await connect_redis_sentinel()
563+
redis = await connect_redis()
569564
except Exception:
570565
redis = None
571566

stac_fastapi/core/stac_fastapi/core/redis_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class RedisSettings(BaseSettings):
3939

4040

4141
# Select the Redis or Redis Sentinel configuration
42-
redis_settings: BaseSettings = RedisSentinelSettings()
42+
redis_settings: BaseSettings = RedisSettings()
4343

4444

4545
async def connect_redis_sentinel(

stac_fastapi/tests/redis/__init__.py

Whitespace-only changes.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import uuid
2+
3+
import pytest
4+
5+
from ..conftest import create_collection, create_item
6+
7+
8+
@pytest.mark.asyncio
9+
async def test_search_pagination_uses_redis_cache(
10+
app_client, txn_client, load_test_data
11+
):
12+
"""Test Redis caching and navigation for the /search endpoint."""
13+
14+
collection = load_test_data("test_collection.json")
15+
collection_id = f"test-pagination-collection-{uuid.uuid4()}"
16+
collection["id"] = collection_id
17+
await create_collection(txn_client, collection)
18+
19+
for i in range(5):
20+
item = load_test_data("test_item.json")
21+
item["id"] = f"test-pagination-item-{uuid.uuid4()}"
22+
item["collection"] = collection_id
23+
await create_item(txn_client, item)
24+
25+
resp = await app_client.post(
26+
"/search", json={"collections": [collection_id], "limit": 1}
27+
)
28+
resp_json = resp.json()
29+
30+
next_link = next(
31+
(link for link in resp_json["links"] if link["rel"] == "next"), None
32+
)
33+
next_token = next_link["body"]["token"]
34+
35+
# Expect the previous link on the second page to be retrieved from Redis cache
36+
resp2 = await app_client.post(
37+
"/search",
38+
json={"collections": [collection_id], "limit": 1, "token": next_token},
39+
)
40+
resp2_json = resp2.json()
41+
42+
prev_link = next(
43+
(link for link in resp2_json["links"] if link["rel"] == "prev"), None
44+
)
45+
assert prev_link is not None
46+
47+
48+
@pytest.mark.asyncio
49+
async def test_collections_pagination_uses_redis_cache(
50+
app_client, txn_client, load_test_data
51+
):
52+
"""Test Redis caching and navigation for the /collection endpoint."""
53+
54+
collection_data = load_test_data("test_collection.json")
55+
for i in range(5):
56+
collection = collection_data.copy()
57+
collection["id"] = f"test-collection-pagination-{uuid.uuid4()}"
58+
collection["title"] = f"Test Collection Pagination {i}"
59+
await create_collection(txn_client, collection)
60+
61+
resp = await app_client.get("/collections", params={"limit": 1})
62+
assert resp.status_code == 200
63+
resp1_json = resp.json()
64+
65+
next_link = next(
66+
(link for link in resp1_json["links"] if link["rel"] == "next"), None
67+
)
68+
next_token = next_link["href"].split("token=")[1]
69+
70+
# Expect the previous link on the second page to be retrieved from Redis cache
71+
resp2 = await app_client.get(
72+
"/collections", params={"limit": 1, "token": next_token}
73+
)
74+
assert resp2.status_code == 200
75+
resp2_json = resp2.json()
76+
77+
prev_link = next(
78+
(link for link in resp2_json["links"] if link["rel"] == "prev"), None
79+
)
80+
assert prev_link is not None
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import pytest
2+
3+
from stac_fastapi.core.redis_utils import connect_redis, get_prev_link, save_self_link
4+
5+
6+
@pytest.mark.asyncio
7+
async def test_redis_connection():
8+
"""Test Redis connection."""
9+
redis = await connect_redis()
10+
assert redis is not None
11+
12+
# Test set/get
13+
await redis.set("string_key", "string_value")
14+
string_value = await redis.get("string_key")
15+
assert string_value == "string_value"
16+
17+
# Test key retrieval operation
18+
exists = await redis.exists("string_key")
19+
assert exists == 1
20+
21+
# Test key deletion
22+
await redis.delete("string_key")
23+
deleted_value = await redis.get("string_key")
24+
assert deleted_value is None
25+
26+
27+
@pytest.mark.asyncio
28+
async def test_redis_utils_functions():
29+
redis = await connect_redis()
30+
assert redis is not None
31+
32+
token = "test_token_123"
33+
self_link = "http://mywebsite.com/search?token=test_token_123"
34+
35+
await save_self_link(redis, token, self_link)
36+
retrieved_link = await get_prev_link(redis, token)
37+
assert retrieved_link == self_link
38+
39+
await save_self_link(redis, None, "should_not_save")
40+
null_result = await get_prev_link(redis, None)
41+
assert null_result is None
42+
43+
non_existent = await get_prev_link(redis, "non_existent_token")
44+
assert non_existent is None

0 commit comments

Comments
 (0)