def test_with_get_protocolinfo(self): """ Tests the authenticate() function when it needs to make a get_protocolinfo. """ # tests where get_protocolinfo succeeds protocolinfo_response = mocking.get_protocolinfo_response( auth_methods=(stem.connection.AuthMethod.NONE, ), ) mocking.mock(stem.connection.get_protocolinfo, mocking.return_value(protocolinfo_response)) stem.connection.authenticate(None) # tests where get_protocolinfo raises an exception raised_exc = stem.ProtocolError(None) mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc)) self.assertRaises(stem.connection.IncorrectSocketType, stem.connection.authenticate, None) raised_exc = stem.SocketError(None) mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc)) self.assertRaises(stem.connection.AuthenticationFailure, stem.connection.authenticate, None)
def test_get_protocolinfo(self): """ Exercises the get_protocolinfo() method. """ # Use the handy mocked protocolinfo response. mocking.mock(stem.connection.get_protocolinfo, mocking.return_value(mocking.get_protocolinfo_response())) # Compare the str representation of these object, because the class # does not have, nor need, a direct comparison operator. self.assertEqual(str(mocking.get_protocolinfo_response()), str(self.controller.get_protocolinfo())) # Raise an exception in the stem.connection.get_protocolinfo() call. mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(ProtocolError)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_protocolinfo(default="default returned")) # No default value, accept the error. self.assertRaises(ProtocolError, self.controller.get_protocolinfo)
def test_get_protocolinfo(self): """ Exercises the get_protocolinfo() method. """ # Use the handy mocked protocolinfo response. mocking.mock(stem.connection.get_protocolinfo, mocking.return_value( mocking.get_protocolinfo_response() )) # Compare the str representation of these object, because the class # does not have, nor need, a direct comparison operator. self.assertEqual(str(mocking.get_protocolinfo_response()), str(self.controller.get_protocolinfo())) # Raise an exception in the stem.connection.get_protocolinfo() call. mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(ProtocolError)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_protocolinfo(default = "default returned") ) # No default value, accept the error. self.assertRaises(ProtocolError, self.controller.get_protocolinfo)
def test_get_socks_listeners_old(self): """ Exercises the get_socks_listeners() method as though talking to an old tor instance. """ # An old tor raises stem.InvalidArguments for get_info about socks, but # get_socks_listeners should work anyway. mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments)) mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "9050", ("SocksListenAddress", "multiple=True"): ["127.0.0.1"] }, is_method = True)) self.assertEqual([('127.0.0.1', 9050)], self.controller.get_socks_listeners()) # Again, an old tor, but SocksListenAddress overrides the port number. mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "9050", ("SocksListenAddress", "multiple=True"): ["127.0.0.1:1112"] }, is_method = True)) self.assertEqual([('127.0.0.1', 1112)], self.controller.get_socks_listeners()) # Again, an old tor, but multiple listeners mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "9050", ("SocksListenAddress", "multiple=True"): ["127.0.0.1:1112", "127.0.0.1:1114"] }, is_method = True)) self.assertEqual([('127.0.0.1', 1112), ('127.0.0.1', 1114)], self.controller.get_socks_listeners()) # Again, an old tor, but no SOCKS listeners mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "0", ("SocksListenAddress", "multiple=True"): [] }, is_method = True)) self.assertEqual([], self.controller.get_socks_listeners()) # Where tor provides invalid ports or addresses mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "blarg", ("SocksListenAddress", "multiple=True"): ["127.0.0.1"] }, is_method = True)) self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners) mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "0", ("SocksListenAddress", "multiple=True"): ["127.0.0.1:abc"] }, is_method = True)) self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners) mocking.mock_method(Controller, "get_conf", mocking.return_for_args({ ("SocksPort",): "40", ("SocksListenAddress", "multiple=True"): ["500.0.0.1"] }, is_method = True)) self.assertRaises(stem.ProtocolError, self.controller.get_socks_listeners)
def test_with_get_protocolinfo(self): """ Tests the authenticate() function when it needs to make a get_protocolinfo. """ # tests where get_protocolinfo succeeds protocolinfo_response = mocking.get_protocolinfo_response(auth_methods=(stem.connection.AuthMethod.NONE,)) mocking.mock(stem.connection.get_protocolinfo, mocking.return_value(protocolinfo_response)) stem.connection.authenticate(None) # tests where get_protocolinfo raises an exception raised_exc = stem.ProtocolError(None) mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc)) self.assertRaises(stem.connection.IncorrectSocketType, stem.connection.authenticate, None) raised_exc = stem.SocketError(None) mocking.mock(stem.connection.get_protocolinfo, mocking.raise_exception(raised_exc)) self.assertRaises(stem.connection.AuthenticationFailure, stem.connection.authenticate, None)
def test_get_version(self): """ Exercises the get_version() method. """ try: # Use one version for first check. version_2_1 = "0.2.1.32" version_2_1_object = stem.version.Version(version_2_1) mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_1)) # Return a version with a cold cache. self.assertEqual(version_2_1_object, self.controller.get_version()) # Use a different version for second check. version_2_2 = "0.2.2.39" version_2_2_object = stem.version.Version(version_2_2) mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_2)) # Return a version with a hot cache, so it will be the old version. self.assertEqual(version_2_1_object, self.controller.get_version()) # Turn off caching. self.controller._is_caching_enabled = False # Return a version without caching, so it will be the new version. self.assertEqual(version_2_2_object, self.controller.get_version()) # Raise an exception in the get_info() call. mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_version(default="default returned")) # No default value, accept the error. self.assertRaises(InvalidArguments, self.controller.get_version) # Give a bad version. The stem.version.Version ValueError should bubble up. version_A_42 = "0.A.42.spam" mocking.mock_method(Controller, "get_info", mocking.return_value(version_A_42)) self.assertRaises(ValueError, self.controller.get_version) finally: # Turn caching back on before we leave. self.controller._is_caching_enabled = True
def test_get_version(self): """ Exercises the get_version() method. """ try: # Use one version for first check. version_2_1 = "0.2.1.32" version_2_1_object = stem.version.Version(version_2_1) mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_1)) # Return a version with a cold cache. self.assertEqual(version_2_1_object, self.controller.get_version()) # Use a different version for second check. version_2_2 = "0.2.2.39" version_2_2_object = stem.version.Version(version_2_2) mocking.mock_method(Controller, "get_info", mocking.return_value(version_2_2)) # Return a version with a hot cache, so it will be the old version. self.assertEqual(version_2_1_object, self.controller.get_version()) # Turn off caching. self.controller._is_caching_enabled = False # Return a version without caching, so it will be the new version. self.assertEqual(version_2_2_object, self.controller.get_version()) # Raise an exception in the get_info() call. mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_version(default = "default returned") ) # No default value, accept the error. self.assertRaises(InvalidArguments, self.controller.get_version) # Give a bad version. The stem.version.Version ValueError should bubble up. version_A_42 = "0.A.42.spam" mocking.mock_method(Controller, "get_info", mocking.return_value(version_A_42)) self.assertRaises(ValueError, self.controller.get_version) finally: # Turn caching back on before we leave. self.controller._is_caching_enabled = True
def test_get_network_status(self): """ Exercises the get_network_status() method. """ # Build a single router status entry. nickname = "Beaver" fingerprint = "/96bKo4soysolMgKn5Hex2nyFSY" desc = "r %s %s u5lTXJKGsLKufRLnSyVqT7TdGYw 2012-12-30 22:02:49 77.223.43.54 9001 0\ns Fast Named Running Stable Valid\nw Bandwidth=75" % ( nickname, fingerprint) router = stem.descriptor.router_status_entry.RouterStatusEntryV2(desc) # Always return the same router status entry. mocking.mock_method(Controller, "get_info", mocking.return_value(desc)) # Pretend to get the router status entry with its name. self.assertEqual(router, self.controller.get_network_status(nickname)) # Pretend to get the router status entry with its fingerprint. hex_fingerprint = stem.descriptor.router_status_entry._base64_to_hex( fingerprint, False) self.assertEqual(router, self.controller.get_network_status(hex_fingerprint)) # Mangle hex fingerprint and try again. hex_fingerprint = hex_fingerprint[2:] self.assertRaises(ValueError, self.controller.get_network_status, hex_fingerprint) # Raise an exception in the get_info() call. mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_network_status(nickname, default="default returned")) # No default value, accept the error. self.assertRaises(InvalidArguments, self.controller.get_network_status, nickname)
def test_get_network_status(self): """ Exercises the get_network_status() method. """ # Build a single router status entry. nickname = "Beaver" fingerprint = "/96bKo4soysolMgKn5Hex2nyFSY" desc = "r %s %s u5lTXJKGsLKufRLnSyVqT7TdGYw 2012-12-30 22:02:49 77.223.43.54 9001 0\ns Fast Named Running Stable Valid\nw Bandwidth=75" % (nickname, fingerprint) router = stem.descriptor.router_status_entry.RouterStatusEntryV2(desc) # Always return the same router status entry. mocking.mock_method(Controller, "get_info", mocking.return_value(desc)) # Pretend to get the router status entry with its name. self.assertEqual(router, self.controller.get_network_status(nickname)) # Pretend to get the router status entry with its fingerprint. hex_fingerprint = stem.descriptor.router_status_entry._decode_fingerprint(fingerprint, False) self.assertEqual(router, self.controller.get_network_status(hex_fingerprint)) # Mangle hex fingerprint and try again. hex_fingerprint = hex_fingerprint[2:] self.assertRaises(ValueError, self.controller.get_network_status, hex_fingerprint) # Raise an exception in the get_info() call. mocking.mock_method(Controller, "get_info", mocking.raise_exception(InvalidArguments)) # Get a default value when the call fails. self.assertEqual( "default returned", self.controller.get_network_status(nickname, default = "default returned") ) # No default value, accept the error. self.assertRaises(InvalidArguments, self.controller.get_network_status, nickname)
def test_all_use_cases(self): """ Does basic validation that all valid use cases for the PROTOCOLINFO input and dependent functions result in either success or a AuthenticationFailed subclass being raised. """ # mute the logger for this test since otherwise the output is overwhelming stem_logger = log.get_logger() stem_logger.setLevel(log.logging_level(None)) # exceptions that the authentication functions are documented to raise all_auth_none_exc = (None, stem.connection.OpenAuthRejected(None)) all_auth_password_exc = (None, stem.connection.PasswordAuthRejected(None), stem.connection.IncorrectPassword(None)) all_auth_cookie_exc = (None, stem.connection.IncorrectCookieSize(None, None), stem.connection.UnreadableCookieFile(None, None), stem.connection.CookieAuthRejected(None, None), stem.connection.IncorrectCookieValue(None, None)) # authentication functions might raise a controller error when # 'suppress_ctl_errors' is False, so including those control_exc = ( stem.socket.ProtocolError(None), stem.socket.SocketError(None), stem.socket.SocketClosed(None)) all_auth_none_exc += control_exc all_auth_password_exc += control_exc all_auth_cookie_exc += control_exc for protocolinfo_auth_methods in _get_all_auth_method_combinations(): # protocolinfo input for the authenticate() call we'll be making protocolinfo_arg = mocking.get_protocolinfo_response( auth_methods = protocolinfo_auth_methods, cookie_path = "/tmp/blah", ) for auth_none_exc in all_auth_none_exc: for auth_password_exc in all_auth_password_exc: for auth_cookie_exc in all_auth_cookie_exc: # determine if the authenticate() call will succeed and mock each # of the authenticate_* function to raise its given exception expect_success = False auth_mocks = { stem.connection.AuthMethod.NONE: (stem.connection.authenticate_none, auth_none_exc), stem.connection.AuthMethod.PASSWORD: (stem.connection.authenticate_password, auth_password_exc), stem.connection.AuthMethod.COOKIE: (stem.connection.authenticate_cookie, auth_cookie_exc), } for auth_method in auth_mocks: auth_function, raised_exc = auth_mocks[auth_method] if not raised_exc: # Mocking this authentication method so it will succeed. If # it's among the protocolinfo methods then expect success. mocking.mock(auth_function, mocking.no_op()) expect_success |= auth_method in protocolinfo_auth_methods else: mocking.mock(auth_function, mocking.raise_exception(raised_exc)) if expect_success: stem.connection.authenticate(None, "blah", None, protocolinfo_arg) else: self.assertRaises(stem.connection.AuthenticationFailure, stem.connection.authenticate, None, "blah", None, protocolinfo_arg) # revert logging back to normal stem_logger.setLevel(log.logging_level(log.TRACE))
def test_all_use_cases(self): """ Does basic validation that all valid use cases for the PROTOCOLINFO input and dependent functions result in either success or a AuthenticationFailed subclass being raised. """ # mute the logger for this test since otherwise the output is overwhelming stem_logger = log.get_logger() stem_logger.setLevel(log.logging_level(None)) # exceptions that the authentication functions are documented to raise all_auth_none_exc = (None, stem.connection.OpenAuthRejected(None)) all_auth_password_exc = ( None, stem.connection.PasswordAuthRejected(None), stem.connection.IncorrectPassword(None)) all_auth_cookie_exc = ( None, stem.connection.IncorrectCookieSize(None, False, None), stem.connection.UnreadableCookieFile(None, False, None), stem.connection.CookieAuthRejected(None, False, None), stem.connection.IncorrectCookieValue(None, False, None), stem.connection.UnrecognizedAuthChallengeMethod(None, None, None), stem.connection.AuthChallengeFailed(None, None), stem.connection.AuthSecurityFailure(None, None), stem.connection.InvalidClientNonce(None, None)) # authentication functions might raise a controller error when # 'suppress_ctl_errors' is False, so including those control_exc = ( stem.ProtocolError(None), stem.SocketError(None), stem.SocketClosed(None)) all_auth_none_exc += control_exc all_auth_password_exc += control_exc all_auth_cookie_exc += control_exc auth_method_combinations = mocking.get_all_combinations([ stem.connection.AuthMethod.NONE, stem.connection.AuthMethod.PASSWORD, stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE, stem.connection.AuthMethod.UNKNOWN, ], include_empty = True) for protocolinfo_auth_methods in auth_method_combinations: # protocolinfo input for the authenticate() call we'll be making protocolinfo_arg = mocking.get_protocolinfo_response( auth_methods = protocolinfo_auth_methods, cookie_path = "/tmp/blah", ) for auth_none_exc in all_auth_none_exc: for auth_password_exc in all_auth_password_exc: for auth_cookie_exc in all_auth_cookie_exc: # Determine if the authenticate() call will succeed and mock each # of the authenticate_* function to raise its given exception. # # This implementation is slightly inaccurate in a couple regards... # a. it raises safecookie exceptions from authenticate_cookie() # b. exceptions raised by authenticate_cookie() and # authenticate_safecookie() are always the same # # However, adding another loop for safe_cookie exceptions means # multiplying our runtime many fold. This exercises everything that # matters so the above inaccuracies seem fine. expect_success = False auth_mocks = { stem.connection.AuthMethod.NONE: (stem.connection.authenticate_none, auth_none_exc), stem.connection.AuthMethod.PASSWORD: (stem.connection.authenticate_password, auth_password_exc), stem.connection.AuthMethod.COOKIE: (stem.connection.authenticate_cookie, auth_cookie_exc), stem.connection.AuthMethod.SAFECOOKIE: (stem.connection.authenticate_safecookie, auth_cookie_exc), } for auth_method in auth_mocks: auth_function, raised_exc = auth_mocks[auth_method] if not raised_exc: # Mocking this authentication method so it will succeed. If # it's among the protocolinfo methods then expect success. mocking.mock(auth_function, mocking.no_op()) expect_success |= auth_method in protocolinfo_auth_methods else: mocking.mock(auth_function, mocking.raise_exception(raised_exc)) if expect_success: stem.connection.authenticate(None, "blah", None, protocolinfo_arg) else: self.assertRaises(stem.connection.AuthenticationFailure, stem.connection.authenticate, None, "blah", None, protocolinfo_arg) # revert logging back to normal stem_logger.setLevel(log.logging_level(log.TRACE))
def test_all_use_cases(self): """ Does basic validation that all valid use cases for the PROTOCOLINFO input and dependent functions result in either success or a AuthenticationFailed subclass being raised. """ # mute the logger for this test since otherwise the output is overwhelming stem_logger = log.get_logger() stem_logger.setLevel(log.logging_level(None)) # exceptions that the authentication functions are documented to raise all_auth_none_exc = (None, stem.connection.OpenAuthRejected(None)) all_auth_password_exc = (None, stem.connection.PasswordAuthRejected(None), stem.connection.IncorrectPassword(None)) all_auth_cookie_exc = ( None, stem.connection.IncorrectCookieSize(None, False, None), stem.connection.UnreadableCookieFile(None, False, None), stem.connection.CookieAuthRejected(None, False, None), stem.connection.IncorrectCookieValue(None, False, None), stem.connection.UnrecognizedAuthChallengeMethod(None, None, None), stem.connection.AuthChallengeFailed(None, None), stem.connection.AuthSecurityFailure(None, None), stem.connection.InvalidClientNonce(None, None)) # authentication functions might raise a controller error when # 'suppress_ctl_errors' is False, so including those control_exc = (stem.ProtocolError(None), stem.SocketError(None), stem.SocketClosed(None)) all_auth_none_exc += control_exc all_auth_password_exc += control_exc all_auth_cookie_exc += control_exc auth_method_combinations = mocking.get_all_combinations( [ stem.connection.AuthMethod.NONE, stem.connection.AuthMethod.PASSWORD, stem.connection.AuthMethod.COOKIE, stem.connection.AuthMethod.SAFECOOKIE, stem.connection.AuthMethod.UNKNOWN, ], include_empty=True) for protocolinfo_auth_methods in auth_method_combinations: # protocolinfo input for the authenticate() call we'll be making protocolinfo_arg = mocking.get_protocolinfo_response( auth_methods=protocolinfo_auth_methods, cookie_path="/tmp/blah", ) for auth_none_exc in all_auth_none_exc: for auth_password_exc in all_auth_password_exc: for auth_cookie_exc in all_auth_cookie_exc: # Determine if the authenticate() call will succeed and mock each # of the authenticate_* function to raise its given exception. # # This implementation is slightly inaccurate in a couple regards... # a. it raises safecookie exceptions from authenticate_cookie() # b. exceptions raised by authenticate_cookie() and # authenticate_safecookie() are always the same # # However, adding another loop for safe_cookie exceptions means # multiplying our runtime many fold. This exercises everything that # matters so the above inaccuracies seem fine. expect_success = False auth_mocks = { stem.connection.AuthMethod.NONE: (stem.connection.authenticate_none, auth_none_exc), stem.connection.AuthMethod.PASSWORD: (stem.connection.authenticate_password, auth_password_exc), stem.connection.AuthMethod.COOKIE: (stem.connection.authenticate_cookie, auth_cookie_exc), stem.connection.AuthMethod.SAFECOOKIE: (stem.connection.authenticate_safecookie, auth_cookie_exc), } for auth_method in auth_mocks: auth_function, raised_exc = auth_mocks[auth_method] if not raised_exc: # Mocking this authentication method so it will succeed. If # it's among the protocolinfo methods then expect success. mocking.mock(auth_function, mocking.no_op()) expect_success |= auth_method in protocolinfo_auth_methods else: mocking.mock( auth_function, mocking.raise_exception(raised_exc)) if expect_success: stem.connection.authenticate( None, "blah", None, protocolinfo_arg) else: self.assertRaises( stem.connection.AuthenticationFailure, stem.connection.authenticate, None, "blah", None, protocolinfo_arg) # revert logging back to normal stem_logger.setLevel(log.logging_level(log.TRACE))