car-tracker/tests/test_detail_policy.py
Antoine Vandeplanque c9ee4bde30
All checks were successful
CI / Lint, PostgreSQL tests, and package (push) Successful in 19s
CI / Build and publish tested image (push) Successful in 1m31s
fetch details incrementally on listing changes or weekly refresh
2026-10-12 19:55:15 +02:00

54 lines
2.6 KiB
Python

from datetime import datetime, timedelta, timezone
import unittest
from unittest.mock import Mock
from car_tracker.detail_policy import DetailPolicy, load_policy, signature
class DetailPolicyTests(unittest.TestCase):
def setUp(self):
self.current = datetime(2026, 10, 12, 12, tzinfo=timezone.utc)
self.ad = {"list_id": 123, "price": [12000], "subject": "Synthetic car",
"attributes": [{"key": "mileage", "value": "100000"}]}
def policy(self, age=1, baseline=True):
return DetailPolicy({"123": (self.current - timedelta(days=age), self.ad if baseline else None)},
clock=lambda: self.current)
def test_no_successful_detail_is_eligible(self):
self.assertEqual(DetailPolicy({}, clock=lambda: self.current)(self.ad), "never_detailed")
def test_unchanged_fresh_ad_is_skipped(self):
self.assertEqual(self.policy()(self.ad), "fresh_unchanged")
def test_exact_week_boundary_is_eligible(self):
self.assertEqual(self.policy(age=7)(self.ad), "weekly_refresh")
self.assertEqual(self.policy(age=6)(self.ad), "fresh_unchanged")
def test_price_and_source_timestamp_changes_are_eligible(self):
self.assertEqual(self.policy()({**self.ad, "price": [11000]}), "search_changed")
self.assertEqual(self.policy()({**self.ad, "index_date": "2026-10-12"}), "search_changed")
def test_unknown_baseline_and_future_timestamp_are_conservative(self):
self.assertEqual(self.policy(baseline=False)(self.ad), "missing_search_baseline")
self.assertEqual(self.policy(age=-1)(self.ad), "invalid_history_time")
def test_counters_and_promotions_do_not_trigger_enrichment(self):
other = {**self.ad, "counters": {"views": 123}, "is_boosted": True,
"options": {"highlight": True}, "owner": {"name": "private"}}
self.assertEqual(self.policy()(other), "fresh_unchanged")
def test_attribute_order_and_sensitive_fields_do_not_trigger_changes(self):
a = {**self.ad, "attributes": [*self.ad["attributes"], {"key": "fuel", "value": "petrol"}]}
b = {**a, "attributes": [*reversed(a["attributes"]), {"key": "phone", "value": "secret"}]}
self.assertEqual(signature(a), signature(b))
def test_loads_only_imported_history(self):
conn = Mock()
conn.execute.return_value.fetchall.return_value = [("123", self.current, self.ad)]
policy = load_policy(conn)
self.assertEqual(policy.history["123"], (self.current, self.ad))
query = conn.execute.call_args.args[0]
self.assertIn("observed_at <= d.observed_at", query)
self.assertIn("record_type = 'detail'", query)