#!/usr/bin/env python3 """Standalone tests for backend/smtp_send.py — config parsing + send paths. No network: smtplib.SMTP / SMTP_SSL are monkeypatched with a fake that records the calls. Run directly or via backend/run_tests.py. """ import os import smtplib import smtp_send FAILS = [] def check(cond, label): print(f" {'ok' if cond else 'XX'} {label}") if not cond: FAILS.append(label) class FakeServer: def __init__(self, kind, log): self.kind, self.log = kind, log self.logged_in = None self.sent = [] def ehlo(self, *a): self.log.append(("ehlo", self.kind)) def starttls(self, *a, **k): self.log.append(("starttls", self.kind)) def login(self, user, pw): self.logged_in = (user, pw) self.log.append(("login", user)) def send_message(self, msg, from_addr=None, to_addrs=None): self.sent.append({"from_addr": from_addr, "to_addrs": to_addrs}) self.log.append(("send", from_addr)) def quit(self): self.log.append(("quit", self.kind)) def install_fakes(): """Patch smtplib; return (log, holder) where holder['last'] is the server.""" log, holder = [], {} def mk(kind): def factory(host, port, timeout=None, context=None): log.append((kind, host, port)) srv = FakeServer(kind, log) holder["last"] = srv return srv return factory smtplib.SMTP = mk("SMTP") smtplib.SMTP_SSL = mk("SMTP_SSL") return log, holder def set_env(**kw): for k in ("SMTP_HOST", "SMTP_PORT", "SMTP_FROM", "SMTP_USERNAME", "SMTP_PASSWORD", "SMTP_SECURITY"): os.environ.pop(k, None) for k, v in kw.items(): os.environ["SMTP_" + k.upper()] = str(v) def main(): # 1. unconfigured set_env() check(not smtp_send.smtp_configured(), "smtp_configured() false when unset") try: smtp_send.load_smtp_config(); ok = False except smtp_send.SMTPNotConfigured: ok = True check(ok, "load_smtp_config raises SMTPNotConfigured without host") # 2. parse + normalize garbage set_env(host="smtp.x.com", port="nope", security="WEIRD", username="u@x", password="p") os.environ["SMTP_FROM"] = "f@x" cfg = smtp_send.load_smtp_config() check(cfg["host"] == "smtp.x.com", "host parsed") check(cfg["port"] == 587, "non-numeric port falls back to 587") check(cfg["security"] == "starttls", "unknown security falls back to starttls") # 3. STARTTLS path: plain SMTP, upgrade, auth, multi-recipient log, holder = install_fakes() set_env(host="h", port="587", security="starttls", username="u@x", password="pw") os.environ["SMTP_FROM"] = "f@x" res = smtp_send.send_email(["a@x.com", "b@x.com"], "s", "body") srv = holder["last"] check(log[0] == ("SMTP", "h", 587), "starttls connects via plain SMTP") check(("starttls", "SMTP") in log, "starttls negotiated") check(srv.logged_in == ("u@x", "pw"), "login with username/password") check(srv.sent[0]["from_addr"] == "f@x", "from = SMTP_FROM") check(srv.sent[0]["to_addrs"] == ["a@x.com", "b@x.com"], "recipients passed through") check(res["sent_to"] == ["a@x.com", "b@x.com"] and res["from"] == "f@x", "result reports send") # 4. implicit TLS path: SMTP_SSL, no STARTTLS log, holder = install_fakes() set_env(host="h", port="465", security="tls", username="u@x", password="pw") os.environ["SMTP_FROM"] = "f@x" smtp_send.send_email("a@x.com", "s", "b") check(log[0][0] == "SMTP_SSL", "tls uses SMTP_SSL") check(all(e[0] != "starttls" for e in log), "no STARTTLS on implicit TLS") # 5. security=none, from falls back to username log, holder = install_fakes() set_env(host="h", port="25", security="none", username="relay@x", password="") smtp_send.send_email("a@x.com", "s", "b") srv = holder["last"] check(all(e[0] != "starttls" for e in log), "no STARTTLS when security=none") check(srv.sent[0]["from_addr"] == "relay@x", "from falls back to username") # 6. no username -> no login attempted log, holder = install_fakes() set_env(host="h", port="25", security="none") os.environ["SMTP_FROM"] = "f@x" smtp_send.send_email("a@x.com", "s", "b") check(holder["last"].logged_in is None, "no login when username blank") # 7. no sender at all -> SMTPNotConfigured set_env(host="h", port="25", security="none") try: smtp_send.send_email("a@x.com", "s", "b"); ok = False except smtp_send.SMTPNotConfigured: ok = True check(ok, "no from/username raises SMTPNotConfigured") # 8. empty recipients -> ValueError set_env(host="h", port="587", security="starttls", username="u", password="p") os.environ["SMTP_FROM"] = "f@x" try: smtp_send.send_email([], "s", "b"); ok = False except ValueError: ok = True check(ok, "empty recipients raises ValueError") print() if FAILS: print(f"FAILED ({len(FAILS)}):") for f in FAILS: print(f" - {f}") raise SystemExit(1) print("ALL PASS (smtp_send)") if __name__ == "__main__": main()