Add services layer, tests, streaming UI, and cleanup legacy code
This commit is contained in:
parent
5514fa6381
commit
d205d15c74
62 changed files with 3729 additions and 1024 deletions
227
crawler/tests/unit/test_repository.py
Normal file
227
crawler/tests/unit/test_repository.py
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
"""Unit tests for ListingRepository."""
|
||||
from datetime import datetime, timedelta
|
||||
import pytest
|
||||
from sqlalchemy import Engine
|
||||
|
||||
from models.listing import (
|
||||
FurnishType,
|
||||
ListingType,
|
||||
QueryParameters,
|
||||
RentListing,
|
||||
)
|
||||
from repositories.listing_repository import ListingRepository
|
||||
|
||||
|
||||
class TestListingRepository:
|
||||
"""Tests for ListingRepository methods."""
|
||||
|
||||
async def test_get_listings_empty_db(
|
||||
self, listing_repository: ListingRepository
|
||||
) -> None:
|
||||
"""Test that get_listings returns empty list for empty database."""
|
||||
listings = await listing_repository.get_listings()
|
||||
assert listings == []
|
||||
|
||||
async def test_get_listings_returns_inserted_listings(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listing: RentListing,
|
||||
) -> None:
|
||||
"""Test that get_listings returns listings that were inserted."""
|
||||
await listing_repository.upsert_listings([sample_rent_listing])
|
||||
listings = await listing_repository.get_listings()
|
||||
assert len(listings) == 1
|
||||
assert listings[0].id == sample_rent_listing.id
|
||||
|
||||
async def test_upsert_listings_creates_new(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listing: RentListing,
|
||||
) -> None:
|
||||
"""Test that upsert_listings creates new listings."""
|
||||
result = await listing_repository.upsert_listings([sample_rent_listing])
|
||||
assert len(result) == 1
|
||||
assert result[0].id == sample_rent_listing.id
|
||||
|
||||
# Verify it's in the database
|
||||
listings = await listing_repository.get_listings()
|
||||
assert len(listings) == 1
|
||||
|
||||
async def test_upsert_listings_updates_existing(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listing: RentListing,
|
||||
) -> None:
|
||||
"""Test that upsert_listings updates existing listings."""
|
||||
# Insert initial listing
|
||||
await listing_repository.upsert_listings([sample_rent_listing])
|
||||
|
||||
# Update the listing
|
||||
sample_rent_listing.price = 3000.0
|
||||
await listing_repository.upsert_listings([sample_rent_listing])
|
||||
|
||||
# Verify update
|
||||
listings = await listing_repository.get_listings()
|
||||
assert len(listings) == 1
|
||||
assert listings[0].price == 3000.0
|
||||
|
||||
async def test_mark_seen_updates_timestamp(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listing: RentListing,
|
||||
) -> None:
|
||||
"""Test that mark_seen updates the last_seen timestamp."""
|
||||
# Set an old timestamp
|
||||
old_time = datetime.now() - timedelta(days=7)
|
||||
sample_rent_listing.last_seen = old_time
|
||||
await listing_repository.upsert_listings([sample_rent_listing])
|
||||
|
||||
# Mark as seen
|
||||
await listing_repository.mark_seen(sample_rent_listing.id)
|
||||
|
||||
# Verify timestamp was updated
|
||||
listings = await listing_repository.get_listings()
|
||||
assert len(listings) == 1
|
||||
assert listings[0].last_seen > old_time
|
||||
|
||||
async def test_mark_seen_nonexistent_listing(
|
||||
self, listing_repository: ListingRepository
|
||||
) -> None:
|
||||
"""Test that mark_seen handles nonexistent listings gracefully."""
|
||||
# Should not raise an exception
|
||||
await listing_repository.mark_seen(999999)
|
||||
|
||||
async def test_get_listings_with_only_ids(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test that get_listings filters by only_ids."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
# Request only specific IDs
|
||||
listings = await listing_repository.get_listings(only_ids=[1, 3])
|
||||
assert len(listings) == 2
|
||||
listing_ids = [l.id for l in listings]
|
||||
assert 1 in listing_ids
|
||||
assert 3 in listing_ids
|
||||
assert 2 not in listing_ids
|
||||
|
||||
async def test_get_listings_with_limit(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test that get_listings respects limit parameter."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
listings = await listing_repository.get_listings(limit=2)
|
||||
assert len(listings) == 2
|
||||
|
||||
|
||||
class TestListingRepositoryFilters:
|
||||
"""Tests for ListingRepository query parameter filtering."""
|
||||
|
||||
async def test_filter_by_bedrooms(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test filtering by bedroom count."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
min_bedrooms=2,
|
||||
max_bedrooms=2,
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
assert len(listings) == 1
|
||||
assert listings[0].number_of_bedrooms == 2
|
||||
|
||||
async def test_filter_by_price_range(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test filtering by price range."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
min_price=1800,
|
||||
max_price=2500,
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
assert len(listings) == 1
|
||||
assert listings[0].price == 2000.0
|
||||
|
||||
async def test_filter_by_min_sqm(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test filtering by minimum square meters."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
min_sqm=60,
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
assert len(listings) == 1
|
||||
assert listings[0].square_meters == 80.0
|
||||
|
||||
async def test_filter_by_furnish_type(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test filtering by furnish type."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
furnish_types=[FurnishType.UNFURNISHED],
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
assert len(listings) == 1
|
||||
assert listings[0].furnish_type == FurnishType.UNFURNISHED
|
||||
|
||||
async def test_filter_by_last_seen_days(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test filtering by last_seen_days."""
|
||||
# Make one listing old
|
||||
sample_rent_listings[0].last_seen = datetime.now() - timedelta(days=30)
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
last_seen_days=7,
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
# Only 2 should be recent enough
|
||||
assert len(listings) == 2
|
||||
|
||||
async def test_combined_filters(
|
||||
self,
|
||||
listing_repository: ListingRepository,
|
||||
sample_rent_listings: list[RentListing],
|
||||
) -> None:
|
||||
"""Test combining multiple filters."""
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
|
||||
query_params = QueryParameters(
|
||||
listing_type=ListingType.RENT,
|
||||
min_bedrooms=1,
|
||||
max_bedrooms=2,
|
||||
min_price=1000,
|
||||
max_price=2500,
|
||||
furnish_types=[FurnishType.FURNISHED, FurnishType.UNFURNISHED],
|
||||
)
|
||||
listings = await listing_repository.get_listings(query_parameters=query_params)
|
||||
# Should match listings with 1-2 bedrooms in price range
|
||||
assert len(listings) == 2
|
||||
Loading…
Add table
Add a link
Reference in a new issue