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)