class AlreadyListeningTest(unittest.TestCase): """Tests for already_listening() method.""" def setUp(self): from letsencrypt.client.standalone_authenticator import \ StandaloneAuthenticator self.authenticator = StandaloneAuthenticator() @mock.patch("letsencrypt.client.standalone_authenticator.subprocess.Popen") def test_subprocess_fails(self, mock_popen): subprocess_object = mock.MagicMock() subprocess_object.communicate.return_value = ("foo", "bar") subprocess_object.wait.return_value = 1 mock_popen.return_value = subprocess_object result = self.authenticator.already_listening(17) self.assertFalse(result) subprocess_object.wait.assert_called_once_with() @mock.patch("letsencrypt.client.standalone_authenticator.subprocess.Popen") def test_no_relevant_line(self, mock_popen): # pylint: disable=line-too-long,trailing-whitespace subprocess_object = mock.MagicMock() subprocess_object.communicate.return_value = ( """Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN 1234/foo tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 2345/bar tcp 0 0 0.0.0.0:180 0.0.0.0:* LISTEN 11111/hello """, "I am the standard error") subprocess_object.wait.return_value = 0 mock_popen.return_value = subprocess_object result = self.authenticator.already_listening(17) self.assertFalse(result) @mock.patch("letsencrypt.client.standalone_authenticator.subprocess.Popen") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_has_relevant_line(self, mock_get_utility, mock_popen): # pylint: disable=line-too-long,trailing-whitespace subprocess_object = mock.MagicMock() subprocess_object.communicate.return_value = ( """Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN 1234/foo tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 2345/bar tcp 0 0 0.0.0.0:17 0.0.0.0:* LISTEN 11111/hello tcp 0 0 0.0.0.0:1728 0.0.0.0:* LISTEN 2345/bar """, "I am the standard error") subprocess_object.wait.return_value = 0 mock_popen.return_value = subprocess_object result = self.authenticator.already_listening(17) self.assertTrue(result) self.assertEqual(mock_get_utility.call_count, 1) @mock.patch("letsencrypt.client.standalone_authenticator.subprocess.Popen") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_has_relevant_ipv6_line(self, mock_get_utility, mock_popen): # pylint: disable=line-too-long,trailing-whitespace subprocess_object = mock.MagicMock() subprocess_object.communicate.return_value = ( """Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.1.1:53 0.0.0.0:* LISTEN 1234/foo tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 2345/bar tcp6 0 0 :::17 :::* LISTEN 11111/hello tcp 0 0 0.0.0.0:1728 0.0.0.0:* LISTEN 2345/bar """, "I am the standard error") subprocess_object.wait.return_value = 0 mock_popen.return_value = subprocess_object result = self.authenticator.already_listening(17) self.assertTrue(result) self.assertEqual(mock_get_utility.call_count, 1)
class AlreadyListeningTest(unittest.TestCase): """Tests for already_listening() method.""" def setUp(self): from letsencrypt.client.standalone_authenticator import \ StandaloneAuthenticator self.authenticator = StandaloneAuthenticator() @mock.patch("letsencrypt.client.standalone_authenticator.psutil." "net_connections") @mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_race_condition(self, mock_get_utility, mock_process, mock_net): # This tests a race condition, or permission problem, or OS # incompatibility in which, for some reason, no process name can be # found to match the identified listening PID. from psutil._common import sconn conns = [ sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30), raddr=(), status='LISTEN', pid=None), sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783), raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234), sconn(fd=-1, family=10, type=1, laddr=('::1', 54321), raddr=('::1', 111), status='CLOSE_WAIT', pid=None), sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17), raddr=(), status='LISTEN', pid=4416)] mock_net.return_value = conns mock_process.side_effect = psutil.NoSuchProcess("No such PID") # We simulate being unable to find the process name of PID 4416, # which results in returning False. self.assertFalse(self.authenticator.already_listening(17)) self.assertEqual(mock_get_utility.generic_notification.call_count, 0) mock_process.assert_called_once_with(4416) @mock.patch("letsencrypt.client.standalone_authenticator.psutil." "net_connections") @mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_not_listening(self, mock_get_utility, mock_process, mock_net): from psutil._common import sconn conns = [ sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30), raddr=(), status='LISTEN', pid=None), sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783), raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234), sconn(fd=-1, family=10, type=1, laddr=('::1', 54321), raddr=('::1', 111), status='CLOSE_WAIT', pid=None)] mock_net.return_value = conns mock_process.name.return_value = "inetd" self.assertFalse(self.authenticator.already_listening(17)) self.assertEqual(mock_get_utility.generic_notification.call_count, 0) self.assertEqual(mock_process.call_count, 0) @mock.patch("letsencrypt.client.standalone_authenticator.psutil." "net_connections") @mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_listening_ipv4(self, mock_get_utility, mock_process, mock_net): from psutil._common import sconn conns = [ sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30), raddr=(), status='LISTEN', pid=None), sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783), raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234), sconn(fd=-1, family=10, type=1, laddr=('::1', 54321), raddr=('::1', 111), status='CLOSE_WAIT', pid=None), sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17), raddr=(), status='LISTEN', pid=4416)] mock_net.return_value = conns mock_process.name.return_value = "inetd" result = self.authenticator.already_listening(17) self.assertTrue(result) self.assertEqual(mock_get_utility.call_count, 1) mock_process.assert_called_once_with(4416) @mock.patch("letsencrypt.client.standalone_authenticator.psutil." "net_connections") @mock.patch("letsencrypt.client.standalone_authenticator.psutil.Process") @mock.patch("letsencrypt.client.standalone_authenticator." "zope.component.getUtility") def test_listening_ipv6(self, mock_get_utility, mock_process, mock_net): from psutil._common import sconn conns = [ sconn(fd=-1, family=2, type=1, laddr=('0.0.0.0', 30), raddr=(), status='LISTEN', pid=None), sconn(fd=3, family=2, type=1, laddr=('192.168.5.10', 32783), raddr=('20.40.60.80', 22), status='ESTABLISHED', pid=1234), sconn(fd=-1, family=10, type=1, laddr=('::1', 54321), raddr=('::1', 111), status='CLOSE_WAIT', pid=None), sconn(fd=3, family=10, type=1, laddr=('::', 12345), raddr=(), status='LISTEN', pid=4420), sconn(fd=3, family=2, type=1, laddr=('0.0.0.0', 17), raddr=(), status='LISTEN', pid=4416)] mock_net.return_value = conns mock_process.name.return_value = "inetd" result = self.authenticator.already_listening(12345) self.assertTrue(result) self.assertEqual(mock_get_utility.call_count, 1) mock_process.assert_called_once_with(4420)