mirror of
https://github.com/trustedsec/hate_crack.git
synced 2026-04-28 03:53:10 -07:00
fix(tests): patch hate_crack.main._notify directly
tests/test_random_rules_attack.py purges and re-imports hate_crack.*
modules, which leaves main._notify pointing at a different notify
object than a top-level patch("hate_crack.notify._send_pushover")
would touch. Under the full suite that caused the test's mock to
miss and the production call to hit the real Pushover API.
Switch to patch.object(hc_main, "_notify") -- same pattern as
tests/test_run_hcat_cmd.py but anchored to the exact module object
already bound as hc_main, so it is immune to sys.modules churn
regardless of import order. Drop the now-redundant _install_settings
helper and _reset_notify_state fixture.
This commit is contained in:
@@ -1,41 +1,41 @@
|
||||
"""Unit tests for main.test_pushover_notification()."""
|
||||
"""Unit tests for main.test_pushover_notification().
|
||||
|
||||
These tests patch ``hate_crack.main._notify`` directly rather than
|
||||
``hate_crack.notify._send_pushover``. The latter is fragile because
|
||||
``tests/test_random_rules_attack.py`` purges ``hate_crack.*`` from
|
||||
``sys.modules`` and re-imports, which leaves ``main._notify`` pointing
|
||||
at a different module object than the one a top-level ``patch`` would
|
||||
touch. Patching the attribute on ``main`` itself is robust to that.
|
||||
|
||||
We use ``patch.object(hc_main, "_notify")`` rather than
|
||||
``patch("hate_crack.main._notify")`` so the patch target is the exact
|
||||
module object whose function we invoke. A string target would re-resolve
|
||||
``hate_crack.main`` through ``sys.modules``, which — again thanks to the
|
||||
purge in ``test_random_rules_attack.py`` — can be a different object from
|
||||
the ``hc_main`` reference bound at test-module import time.
|
||||
"""
|
||||
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from hate_crack import main as hc_main
|
||||
from hate_crack import notify
|
||||
from hate_crack.notify.settings import NotifySettings
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _reset_notify_state():
|
||||
notify.clear_state_for_tests()
|
||||
yield
|
||||
notify.clear_state_for_tests()
|
||||
|
||||
|
||||
def _install_settings(
|
||||
*,
|
||||
enabled: bool = True,
|
||||
token: str = "tok",
|
||||
user: str = "usr",
|
||||
) -> None:
|
||||
"""Swap fresh settings into the notify module for this test."""
|
||||
settings = NotifySettings()
|
||||
settings.enabled = enabled
|
||||
settings.pushover_token = token
|
||||
settings.pushover_user = user
|
||||
notify._settings = settings
|
||||
def _settings(
|
||||
*, enabled: bool = True, token: str = "tok", user: str = "usr"
|
||||
) -> SimpleNamespace:
|
||||
"""Minimal stand-in for ``NotifySettings`` — we only read three fields."""
|
||||
return SimpleNamespace(enabled=enabled, pushover_token=token, pushover_user=user)
|
||||
|
||||
|
||||
class TestTestPushoverNotification:
|
||||
def test_success_prints_confirmation_and_sends(self, capsys):
|
||||
_install_settings(enabled=True, token="tok", user="usr")
|
||||
with patch("hate_crack.notify._send_pushover", return_value=True) as send:
|
||||
with patch.object(hc_main, "_notify") as mock_notify:
|
||||
mock_notify.get_settings.return_value = _settings(enabled=True)
|
||||
mock_notify._send_pushover.return_value = True
|
||||
hc_main.test_pushover_notification()
|
||||
assert send.called
|
||||
args = send.call_args.args
|
||||
mock_notify._send_pushover.assert_called_once()
|
||||
args = mock_notify._send_pushover.call_args.args
|
||||
assert args[0] == "tok"
|
||||
assert args[1] == "usr"
|
||||
assert args[2] == "hate_crack: test notification"
|
||||
@@ -44,34 +44,36 @@ class TestTestPushoverNotification:
|
||||
assert "[+] Test Pushover notification sent" in out
|
||||
|
||||
def test_failure_prints_failure_line(self, capsys):
|
||||
_install_settings(enabled=True, token="tok", user="usr")
|
||||
with patch("hate_crack.notify._send_pushover", return_value=False):
|
||||
with patch.object(hc_main, "_notify") as mock_notify:
|
||||
mock_notify.get_settings.return_value = _settings(enabled=True)
|
||||
mock_notify._send_pushover.return_value = False
|
||||
hc_main.test_pushover_notification()
|
||||
out = capsys.readouterr().out
|
||||
assert "[!] Test Pushover notification failed" in out
|
||||
|
||||
def test_missing_token_skips_send_and_warns(self, capsys):
|
||||
_install_settings(enabled=True, token="", user="usr")
|
||||
with patch("hate_crack.notify._send_pushover") as send:
|
||||
with patch.object(hc_main, "_notify") as mock_notify:
|
||||
mock_notify.get_settings.return_value = _settings(enabled=True, token="")
|
||||
hc_main.test_pushover_notification()
|
||||
send.assert_not_called()
|
||||
mock_notify._send_pushover.assert_not_called()
|
||||
out = capsys.readouterr().out
|
||||
assert "[!] Pushover credentials missing" in out
|
||||
assert "notify_pushover_token" in out
|
||||
|
||||
def test_missing_user_skips_send_and_warns(self, capsys):
|
||||
_install_settings(enabled=True, token="tok", user="")
|
||||
with patch("hate_crack.notify._send_pushover") as send:
|
||||
with patch.object(hc_main, "_notify") as mock_notify:
|
||||
mock_notify.get_settings.return_value = _settings(enabled=True, user="")
|
||||
hc_main.test_pushover_notification()
|
||||
send.assert_not_called()
|
||||
mock_notify._send_pushover.assert_not_called()
|
||||
out = capsys.readouterr().out
|
||||
assert "[!] Pushover credentials missing" in out
|
||||
|
||||
def test_globally_off_still_sends_with_note(self, capsys):
|
||||
_install_settings(enabled=False, token="tok", user="usr")
|
||||
with patch("hate_crack.notify._send_pushover", return_value=True) as send:
|
||||
with patch.object(hc_main, "_notify") as mock_notify:
|
||||
mock_notify.get_settings.return_value = _settings(enabled=False)
|
||||
mock_notify._send_pushover.return_value = True
|
||||
hc_main.test_pushover_notification()
|
||||
send.assert_called_once()
|
||||
mock_notify._send_pushover.assert_called_once()
|
||||
out = capsys.readouterr().out
|
||||
assert "notifications are globally OFF" in out
|
||||
assert "[+] Test Pushover notification sent" in out
|
||||
|
||||
Reference in New Issue
Block a user