diff --git a/modules/p2ptrust/p2ptrust.py b/modules/p2ptrust/p2ptrust.py index 0f2af29075..b06dd7f6bb 100644 --- a/modules/p2ptrust/p2ptrust.py +++ b/modules/p2ptrust/p2ptrust.py @@ -594,7 +594,7 @@ def process_message_report( self.db.publish("new_blame", data) def shutdown_gracefully(self): - if hasattr(self, "pigeon"): + if hasattr(self, "pigeon") and self.pigeon is not None: self.pigeon.send_signal(signal.SIGINT) if hasattr(self, "trust_db"): self.trust_db.__del__() diff --git a/tests/unit/modules/p2ptrust/test_p2ptrust.py b/tests/unit/modules/p2ptrust/test_p2ptrust.py new file mode 100644 index 0000000000..eead4fa2cf --- /dev/null +++ b/tests/unit/modules/p2ptrust/test_p2ptrust.py @@ -0,0 +1,48 @@ +# SPDX-FileCopyrightText: 2021 Sebastian Garcia +# SPDX-License-Identifier: GPL-2.0-only +import signal +import sys +import types +from unittest.mock import MagicMock, patch +import pytest + +# Stub out netifaces before any project import touches it +if "netifaces" not in sys.modules: + sys.modules["netifaces"] = types.ModuleType("netifaces") + + +class TestShutdownGracefully: + """Tests for Trust.shutdown_gracefully (issue #1840).""" + + def _make_trust_instance(self): + """Return a bare Trust instance with only the attributes we need.""" + from modules.p2ptrust.p2ptrust import Trust + + # Build a minimal object without calling __init__ + obj = object.__new__(Trust) + return obj + + def test_shutdown_gracefully_pigeon_none_no_exception(self): + """shutdown_gracefully must not raise when self.pigeon is None.""" + trust = self._make_trust_instance() + trust.pigeon = None # mirrors the state set in _configure when binary missing + + # Should complete without AttributeError + trust.shutdown_gracefully() + + def test_shutdown_gracefully_pigeon_sends_sigint(self): + """shutdown_gracefully sends SIGINT when pigeon process is running.""" + trust = self._make_trust_instance() + mock_pigeon = MagicMock() + trust.pigeon = mock_pigeon + + trust.shutdown_gracefully() + + mock_pigeon.send_signal.assert_called_once_with(signal.SIGINT) + + def test_shutdown_gracefully_no_pigeon_attr(self): + """shutdown_gracefully must not raise when pigeon attribute is absent.""" + trust = self._make_trust_instance() + # Do NOT set trust.pigeon at all + + trust.shutdown_gracefully()