Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
  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)
Beispiel #4
0
  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)
Beispiel #5
0
  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)
Beispiel #6
0
    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)
Beispiel #7
0
    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
Beispiel #8
0
  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
Beispiel #9
0
    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)
Beispiel #10
0
  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)
Beispiel #11
0
 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))
Beispiel #12
0
  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))
Beispiel #13
0
    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))