54 lines
2.6 KiB
Python
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)
|