from __future__ import annotations import tempfile import unittest from pathlib import Path from sqlalchemy import select from iaai_scraper.core.config import Settings from iaai_scraper.storage.db import PersistenceService from iaai_scraper.storage.models import Car, Image from iaai_scraper.storage.schemas import CarRecord, ImageRecord class TestPersistenceServiceIntegration(unittest.TestCase): def setUp(self) -> None: self.tmp_dir = tempfile.TemporaryDirectory() db_path = Path(self.tmp_dir.name) / "test.sqlite" self.settings = Settings() self.settings.database.url = f"sqlite:///{db_path.as_posix()}" self.settings.database.echo = False self.persistence = PersistenceService(self.settings) self.persistence.create_tables() def tearDown(self) -> None: self.persistence.engine.dispose() self.tmp_dir.cleanup() @staticmethod def _record(origin_id: str, *, price: int = 1000, content_hash: str = "hash1") -> CarRecord: return CarRecord( parser_id=f"iaai:{origin_id}", brand="Toyota", model="Camry", year=2014, price=price, origin_url=f"https://www.iaai.com/VehicleDetail/{origin_id}~US", origin_id=origin_id, slug=f"toyota-camry-{origin_id}", content_hash=content_hash, images=[ ImageRecord( fullres_image="https://vis.iaai.com/resizer?imageKeys=1&width=845&height=633", preview_image="https://vis.iaai.com/resizer?imageKeys=1&width=400&height=300", order_index=0, ) ], raw_attributes={"foo": "bar"}, ) def test_insert_update_and_skip_flow(self) -> None: first = self._record("777", price=1000, content_hash="same") inserted = self.persistence.upsert_car(first) self.assertEqual(inserted["action"], "inserted") self.assertEqual(inserted["images_upserted"], 1) same = self._record("777", price=1000, content_hash="same") updated_same = self.persistence.upsert_car(same) self.assertEqual(updated_same["action"], "skipped") self.assertEqual(updated_same["images_upserted"], 0) changed = self._record("777", price=1500, content_hash="changed") updated = self.persistence.upsert_car(changed) self.assertEqual(updated["action"], "updated") self.assertEqual(updated["images_upserted"], 1) with self.persistence.session_scope() as session: cars = session.execute(select(Car)).scalars().all() images = session.execute(select(Image)).scalars().all() self.assertEqual(len(cars), 1) self.assertEqual(cars[0].price, 1500) self.assertEqual(len(images), 1) def test_update_replaces_old_images(self) -> None: first = self._record("888", content_hash="v1") self.persistence.upsert_car(first) second = self._record("888", content_hash="v2") second.images = [ ImageRecord( fullres_image="https://vis.iaai.com/resizer?imageKeys=2&width=845&height=633", preview_image="https://vis.iaai.com/resizer?imageKeys=2&width=400&height=300", order_index=0, ) ] self.persistence.upsert_car(second) with self.persistence.session_scope() as session: images = session.execute(select(Image)).scalars().all() self.assertEqual(len(images), 1) self.assertIn("imageKeys=2", images[0].fullres_image) def test_same_content_hash_is_skipped(self) -> None: first = self._record("999", content_hash="same-hash") self.persistence.upsert_car(first) second = self._record("999", content_hash="same-hash") result = self.persistence.upsert_car(second) self.assertEqual(result["action"], "skipped") self.assertEqual(result["images_upserted"], 0) if __name__ == "__main__": unittest.main()