from app.discovery.diff import diff_run, next_lifecycle, observations_changed from app.discovery.enums import DiffStatus, LifecycleStatus, RunStatus PREV = {"best_price": "1298.00", "availability": "in_stock", "seller_count": 8, "normalized_attributes": {"ram_gb": 32}} CURR = {"best_price": "1199.00", "availability": "in_stock", "seller_count": 8, "normalized_attributes": {"ram_gb": 32}} def test_changed_only_for_relevant_fields(): assert observations_changed(PREV, CURR) is True title_only = {**PREV, "normalized_attributes": {"ram_gb": 32, "title": "new title", "html": ""}} assert observations_changed(PREV, title_only) is False assert observations_changed(PREV, {**PREV, "seller_count": 12}) is True assert observations_changed(PREV, {**PREV, "availability": "out_of_stock"}) is True def test_diff_statuses_and_partial_skips_missing(): previous_ids = {"a", "b"} current_ids = {"b", "c"} previous_obs = {"a": PREV, "b": PREV} current_obs = {"b": CURR, "c": PREV} success = diff_run( previous_ids=previous_ids, current_ids=current_ids, previous_obs=previous_obs, current_obs=current_obs, run_status=RunStatus.SUCCESS.value, ) assert success["c"] == DiffStatus.NEW assert success["b"] == DiffStatus.CHANGED assert success["a"] == DiffStatus.MISSING partial = diff_run( previous_ids=previous_ids, current_ids=current_ids, previous_obs=previous_obs, current_obs=current_obs, run_status=RunStatus.PARTIAL.value, ) assert "a" not in partial assert DiffStatus.MISSING not in partial.values() def test_unchanged_and_disappeared_lifecycle(): same = diff_run( previous_ids={"a"}, current_ids={"a"}, previous_obs={"a": PREV}, current_obs={"a": PREV}, run_status=RunStatus.SUCCESS.value, ) assert same["a"] == DiffStatus.UNCHANGED status, streak = next_lifecycle( current=LifecycleStatus.ACTIVE.value, missing_in_success_run=True, consecutive_missing=2, reappeared=False, ) assert status == LifecycleStatus.DISAPPEARED.value assert streak == 3 status, streak = next_lifecycle( current=LifecycleStatus.DISAPPEARED.value, missing_in_success_run=False, consecutive_missing=3, reappeared=True, ) assert status == LifecycleStatus.ACTIVE.value assert streak == 0 archived, _ = next_lifecycle( current=LifecycleStatus.ARCHIVED.value, missing_in_success_run=True, consecutive_missing=5, reappeared=True, ) assert archived == LifecycleStatus.ARCHIVED.value