2026-07-21 01:26:39 +00:00
|
|
|
"""submit_if_changed: the shared skip-when-unchanged logic behind the CLI's
|
|
|
|
|
--if-changed flag and the worker scheduler's periodic ping (no network —
|
|
|
|
|
submit_all/url_signature are stubbed)."""
|
|
|
|
|
import indexnow
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _ok(total=3):
|
|
|
|
|
return {"submitted": total, "total": total, "batches": 1, "statuses": [200]}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_skips_when_url_set_unchanged(monkeypatch, tmp_path):
|
|
|
|
|
monkeypatch.setattr(indexnow, "_STATE_PATH", str(tmp_path / "state.txt"))
|
|
|
|
|
monkeypatch.setattr(indexnow, "url_signature", lambda: "same-sig")
|
|
|
|
|
(tmp_path / "state.txt").write_text("same-sig")
|
|
|
|
|
|
|
|
|
|
def boom(*a, **k):
|
|
|
|
|
raise AssertionError("must not submit when the URL set is unchanged")
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(indexnow, "submit_all", boom)
|
|
|
|
|
assert indexnow.submit_if_changed("https://example.org") is None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_submits_and_persists_state_when_changed(monkeypatch, tmp_path):
|
|
|
|
|
state = tmp_path / "state.txt"
|
|
|
|
|
monkeypatch.setattr(indexnow, "_STATE_PATH", str(state))
|
|
|
|
|
monkeypatch.setattr(indexnow, "url_signature", lambda: "new-sig")
|
|
|
|
|
state.write_text("old-sig")
|
|
|
|
|
|
|
|
|
|
calls = []
|
|
|
|
|
monkeypatch.setattr(indexnow, "submit_all", lambda base, **kw: calls.append(base) or _ok())
|
|
|
|
|
result = indexnow.submit_if_changed("https://example.org")
|
|
|
|
|
assert calls == ["https://example.org"]
|
|
|
|
|
assert result["submitted"] == result["total"] == 3
|
|
|
|
|
assert state.read_text() == "new-sig"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_partial_failure_does_not_persist_state(monkeypatch, tmp_path):
|
|
|
|
|
"""A partial/failed submission must leave the prior state in place so the
|
|
|
|
|
next attempt retries, rather than silently giving up on the missed URLs."""
|
|
|
|
|
state = tmp_path / "state.txt"
|
|
|
|
|
monkeypatch.setattr(indexnow, "_STATE_PATH", str(state))
|
|
|
|
|
monkeypatch.setattr(indexnow, "url_signature", lambda: "new-sig")
|
|
|
|
|
state.write_text("old-sig")
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(indexnow, "submit_all",
|
|
|
|
|
lambda base, **kw: {"submitted": 1, "total": 3, "batches": 1, "statuses": [429]})
|
|
|
|
|
result = indexnow.submit_if_changed("https://example.org")
|
|
|
|
|
assert result["submitted"] < result["total"]
|
|
|
|
|
assert state.read_text() == "old-sig"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_default_base_url_falls_back_to_env(monkeypatch, tmp_path):
|
|
|
|
|
monkeypatch.setattr(indexnow, "_STATE_PATH", str(tmp_path / "state.txt"))
|
|
|
|
|
monkeypatch.setattr(indexnow, "url_signature", lambda: "sig")
|
|
|
|
|
monkeypatch.setenv("THERMOGRAPH_BASE_URL", "https://from-env.example")
|
|
|
|
|
calls = []
|
|
|
|
|
monkeypatch.setattr(indexnow, "submit_all", lambda base, **kw: calls.append(base) or _ok())
|
|
|
|
|
indexnow.submit_if_changed()
|
|
|
|
|
assert calls == ["https://from-env.example"]
|
2026-07-21 20:01:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
# --- submit_all / url_signature / state file, direct (ported from
|
|
|
|
|
# tests/web/test_content.py, repo-split Stage 4) ----------------------------
|
|
|
|
|
|
|
|
|
|
def test_indexnow_submit_all_builds_payload(monkeypatch):
|
|
|
|
|
calls = []
|
|
|
|
|
|
|
|
|
|
class _Resp:
|
|
|
|
|
status_code = 200
|
|
|
|
|
text = "ok"
|
|
|
|
|
|
|
|
|
|
monkeypatch.setattr(indexnow.httpx, "post",
|
|
|
|
|
lambda url, json=None, **kw: (calls.append((url, json)), _Resp())[1])
|
|
|
|
|
res = indexnow.submit_all("https://thermograph.org")
|
|
|
|
|
assert res["submitted"] == res["total"] > 100
|
|
|
|
|
first = calls[0][1]
|
|
|
|
|
assert first["host"] == "thermograph.org"
|
|
|
|
|
assert first["keyLocation"] == f"https://thermograph.org/{indexnow.key()}.txt"
|
|
|
|
|
assert first["urlList"][0] == "https://thermograph.org/"
|
|
|
|
|
assert all(len(c[1]["urlList"]) <= 10000 for c in calls) # batched under the IndexNow cap
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_indexnow_if_changed_state(monkeypatch, tmp_path):
|
|
|
|
|
monkeypatch.setattr(indexnow, "_STATE_PATH", str(tmp_path / "state.txt"))
|
|
|
|
|
sig = indexnow.url_signature()
|
|
|
|
|
assert len(sig) == 40 and sig == indexnow.url_signature() # stable sha1 of the URL set
|
|
|
|
|
assert indexnow._read_state() == "" # first deploy → would submit
|
|
|
|
|
indexnow._write_state(sig)
|
|
|
|
|
assert indexnow._read_state() == sig # unchanged → deploy would skip
|