wrongmove/tests/integration/test_listing_cache.py
Viktor Barzin 8d22c97320
Add comprehensive test suite: 219 new tests across backend and frontend
Backend (103 tests):
- Unit tests for listing_service, export_service, district_service
- Regression tests for API response contracts and query parameter validation
- Integration tests for API workflows, Redis listing cache, listing processor pipeline, and repository advanced queries
- E2E tests for streaming with filters, batching, caching, and task management

Frontend (116 tests):
- Service tests for apiClient, streamingService, taskService, listingService, healthService
- Hook tests for useTaskProgress (WebSocket + polling)
- Component tests for PropertyCard, FilterPanel, Header, ListView, TaskProgressDrawer, TaskIndicator, StreamingProgressBar, HealthIndicator
- E2E tests for filter-stream-display flow

Infrastructure:
- Add pytest-xdist and test markers (regression, integration, e2e)
- Add conftest fixtures: fake_redis, rent_listing_factory, seeded_repository
- Add vitest + testing-library + MSW for frontend testing
2026-02-10 21:59:45 +00:00

132 lines
3.3 KiB
Python

"""Integration tests for Redis-based listing cache."""
import pytest
from models.listing import ListingType, QueryParameters
from services.listing_cache import (
begin_cache_population,
cache_features_batch,
cache_features_batch_staged,
delete_staging_key,
finalize_cache_population,
get_cached_count,
get_cached_features,
invalidate_cache,
make_cache_key,
)
@pytest.fixture(autouse=True)
def patch_redis(fake_redis, monkeypatch: pytest.MonkeyPatch) -> None:
"""Route all cache operations through fakeredis."""
monkeypatch.setattr("services.listing_cache._get_redis_client", lambda: fake_redis)
def _make_qp(**kwargs) -> QueryParameters:
return QueryParameters(listing_type=ListingType.RENT, **kwargs)
def _sample_features(n: int) -> list[dict]:
return [{"type": "Feature", "id": i, "properties": {"price": 1000 + i}} for i in range(n)]
# ---------- Basic read/write ----------
def test_cache_miss_returns_none() -> None:
qp = _make_qp()
assert get_cached_count(qp) is None
def test_cache_write_then_read() -> None:
qp = _make_qp()
features = _sample_features(5)
cache_features_batch(qp, features)
count = get_cached_count(qp)
assert count == 5
def test_batch_retrieval() -> None:
qp = _make_qp()
cache_features_batch(qp, _sample_features(10))
batches = list(get_cached_features(qp, batch_size=3))
sizes = [len(b) for b in batches]
assert sizes == [3, 3, 3, 1]
# ---------- Cache key behaviour ----------
def test_cache_key_deterministic() -> None:
qp1 = _make_qp()
qp2 = _make_qp()
assert make_cache_key(qp1) == make_cache_key(qp2)
def test_cache_key_different_for_different_params() -> None:
rent = _make_qp()
buy = QueryParameters(listing_type=ListingType.BUY)
assert make_cache_key(rent) != make_cache_key(buy)
# ---------- Staged population ----------
def test_staged_population_begin() -> None:
qp = _make_qp()
staging_key = begin_cache_population(qp)
assert isinstance(staging_key, str)
assert "staging" in staging_key
def test_staged_write_then_finalize() -> None:
qp = _make_qp()
staging_key = begin_cache_population(qp)
cache_features_batch_staged(staging_key, _sample_features(4))
finalize_cache_population(staging_key, qp)
assert get_cached_count(qp) == 4
def test_staging_key_deleted_on_cleanup(fake_redis) -> None:
qp = _make_qp()
staging_key = begin_cache_population(qp)
cache_features_batch_staged(staging_key, _sample_features(2))
delete_staging_key(staging_key)
assert fake_redis.exists(staging_key) == 0
# ---------- Invalidation ----------
def test_invalidation() -> None:
qp = _make_qp()
cache_features_batch(qp, _sample_features(5))
assert get_cached_count(qp) == 5
invalidate_cache()
assert get_cached_count(qp) is None
# ---------- Edge cases ----------
def test_empty_features_batch_noop() -> None:
qp = _make_qp()
cache_features_batch(qp, [])
assert get_cached_count(qp) is None
def test_multiple_batches_accumulate() -> None:
qp = _make_qp()
cache_features_batch(qp, _sample_features(3))
cache_features_batch(qp, _sample_features(4))
assert get_cached_count(qp) == 7
def test_get_cached_features_empty() -> None:
qp = _make_qp()
batches = list(get_cached_features(qp))
assert batches == []