from __future__ import annotations from dataclasses import dataclass from iaai_scraper.browser.fast_client import FastListingVehicle from iaai_scraper.core.config import Settings from iaai_scraper.core.runtime_config import RuntimeConfig, RuntimeFiltersConfig from iaai_scraper.fast_sync import FastSyncEngine from iaai_scraper.parsing.fast_mapper import FastCarMapper def _listing_vehicle(inventory_id: str, *, status: str = "RS") -> FastListingVehicle: return FastListingVehicle( inventory_id=inventory_id, tenant="US", auction_id="1_1", auction_date="2026-04-08T08:30:00+00:00", inventory_status=status, currency="USD", timed_auction_closed=False, timed_auction_indicator=False, prebid_indicator=True, buynow_indicator=False, ) def _detail_payload(inventory_id: str, *, make: str = "ACURA", model: str = "RSX", bid: int = 500) -> dict: return { "inventoryView": { "attributes": { "Id": inventory_id, "Year": "2002", "Make": make, "Model": model, "Series": "BASE", "Currency": "USD", "ODOValue": "219187", "ExteriorColor": "GRAY", "DriveLineTypeDesc": "FWD", "Transmission": "Automatic", "BodyStyleName": "COUPE", "EngineSize": "2.0L I-4", "VehicleGrade": "50", "PrimaryDamageDesc": "NORMAL WEAR & TEAR", }, "imageDimensions": { "keys": {"$values": [{"k": f"{inventory_id}~I1", "w": 1600, "h": 1200, "i": 0}]} }, }, "auctionInformation": { "prebidInformation": {"decimalHighBidAmount": str(bid), "highBidAmount": f"${bid}"}, "biddingInformation": {"buyNowPrice": "$0"}, }, } class FakeFastClient: def __init__(self, listing: list[FastListingVehicle], details: dict[str, dict]) -> None: self.listing = listing self.details = details self.detail_calls = 0 self.persist_calls = 0 def iter_listing_vehicles(self, *, listing_start_url=None, make=None, max_pages=None): # noqa: ANN001, ANN202 del listing_start_url, make, max_pages return iter(self.listing) def fetch_vehicle_detail_payload(self, inventory_id: str) -> dict: self.detail_calls += 1 return self.details[inventory_id] def persist_session_state(self) -> None: self.persist_calls += 1 @dataclass class FakePersistence: inserted: int = 0 images: int = 0 def get_existing_urls_and_ids(self, origin_urls, origin_ids): # noqa: ANN001, ANN202 del origin_urls, origin_ids return set(), set() def upsert_cars_batch(self, records): # noqa: ANN001, ANN202 self.inserted += len(records) self.images += sum(len(record.images) for record in records) return {"inserted": len(records), "updated": 0, "images_upserted": sum(len(record.images) for record in records)} def mark_sold_not_in_listing_by_urls(self, active_origin_urls, lane="iaai"): # noqa: ANN001, ANN202 del active_origin_urls, lane return 0 def test_fast_sync_engine_collects_details_and_bulk_upserts() -> None: listing = [_listing_vehicle("45078011~US"), _listing_vehicle("45268167~US")] details = { "45078011~US": _detail_payload("45078011~US", make="ACURA", model="RSX", bid=500), "45268167~US": _detail_payload("45268167~US", make="BMW", model="X5", bid=900), } client = FakeFastClient(listing, details) persistence = FakePersistence() engine = FastSyncEngine( client=client, # type: ignore[arg-type] mapper=FastCarMapper(), persistence=persistence, # type: ignore[arg-type] batch_size=10, fetch_concurrency=2, ) result = engine.sync_listing(runtime_config=RuntimeConfig(), only_new=False) assert result["status"] == "success" assert result["cars_upserted"] == 2 assert result["images_upserted"] == 2 assert result["listing"]["mode"] == "fast_hidden_payload" assert client.detail_calls == 2 assert client.persist_calls == 1 def test_fast_sync_engine_applies_runtime_filters_before_db() -> None: listing = [_listing_vehicle("45078011~US"), _listing_vehicle("45268167~US")] details = { "45078011~US": _detail_payload("45078011~US", make="ACURA", model="RSX", bid=500), "45268167~US": _detail_payload("45268167~US", make="BMW", model="X5", bid=900), } runtime = RuntimeConfig(filters=RuntimeFiltersConfig.from_dict({"brands": ["BMW"]})) persistence = FakePersistence() engine = FastSyncEngine( client=FakeFastClient(listing, details), # type: ignore[arg-type] mapper=FastCarMapper(), persistence=persistence, # type: ignore[arg-type] batch_size=10, fetch_concurrency=2, ) result = engine.sync_listing(runtime_config=runtime, only_new=False) assert result["cars_upserted"] == 1 assert result["cars_filtered"] == 1 assert persistence.inserted == 1