"""TC-10: independent Telegram transport. The sidecar sends through its OWN bot_token/chat_id from env and must NOT import ``src.notifications`` or the orchestrator's code (C-1 / BR-8). """ import pathlib from watchdog import notify as notify_mod from watchdog.notify import Notifier, send_telegram def test_notify_uses_own_token_and_chat(monkeypatch): captured = {} def _fake_opener(req, timeout=None): captured["url"] = req.full_url captured["data"] = req.data class _R: status = 200 def getcode(self): return 200 def __enter__(self_inner): return self_inner def __exit__(self_inner, *a): return False return _R() ok = send_telegram( "MYTOKEN", "MYCHAT", "hello", opener=_fake_opener, api_base="https://tg.test" ) assert ok is True assert "botMYTOKEN" in captured["url"] assert b"MYCHAT" in captured["data"] def test_missing_credentials_is_failsafe_no_send(): # Absent token/chat -> logs and returns False, never raises (fail-safe). assert send_telegram("", "chat", "x") is False assert send_telegram("tok", "", "x") is False def test_send_failure_is_swallowed(): def _boom(req, timeout=None): raise OSError("network down") assert send_telegram("t", "c", "x", opener=_boom) is False def test_notifier_wraps_credentials(monkeypatch): sent = {} monkeypatch.setattr( notify_mod, "send_telegram", lambda tok, chat, text, timeout: sent.update(tok=tok, chat=chat, text=text) or True, ) Notifier("TOK", "CHAT").send("body") assert sent == {"tok": "TOK", "chat": "CHAT", "text": "body"} def test_watchdog_package_does_not_import_src(): # No watchdog/*.py file may reference the orchestrator's src package (C-1). # (Source scan, not sys.modules: the global test conftest imports src.* for # every test, so a runtime check would be polluted.) pkg_root = pathlib.Path(notify_mod.__file__).resolve().parent offenders = [] for py in pkg_root.rglob("*.py"): text = py.read_text(encoding="utf-8") for needle in ("import src", "from src", "src.notifications"): if needle in text: offenders.append(f"{py.name}: {needle}") assert offenders == [], f"watchdog references the orchestrator src: {offenders}" def test_notify_source_has_no_src_notifications_import(): import inspect src = inspect.getsource(notify_mod) assert "src.notifications" not in src assert "from src" not in src assert "import src" not in src