Ejemplo n.º 1
0
def xmlrpc_handle_exception_int(e):
    if isinstance(e, odoo.exceptions.UserError):
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING,
                                odoo.tools.ustr(e.value))
    elif isinstance(e, odoo.exceptions.RedirectWarning):
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, str(e))
    elif isinstance(e, odoo.exceptions.MissingError):
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_WARNING, str(e))
    elif isinstance(e, odoo.exceptions.AccessError):
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_ACCESS_ERROR, str(e))
    elif isinstance(e, odoo.exceptions.AccessDenied):
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_ACCESS_DENIED, str(e))
    elif isinstance(e, odoo.exceptions.DeferredException):
        info = e.traceback
        # Which one is the best ?
        formatted_info = "".join(traceback.format_exception(*info))
        #formatted_info = odoo.tools.exception_to_unicode(e) + '\n' + info
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_APPLICATION_ERROR,
                                formatted_info)
    else:
        info = sys.exc_info()
        # Which one is the best ?
        formatted_info = "".join(traceback.format_exception(*info))
        #formatted_info = odoo.tools.exception_to_unicode(e) + '\n' + info
        fault = xmlrpclib.Fault(RPC_FAULT_CODE_APPLICATION_ERROR,
                                formatted_info)

    return xmlrpclib.dumps(fault, allow_none=None)
Ejemplo n.º 2
0
 def _login(self, method, params):
     try:
         result = _parse_result(
             getattr(self, 'session.%s' % method)(*params))
         print("HERE")
         print(result)
         if result is _RECONNECT_AND_RETRY:
             raise xmlrpclib.Fault(
                 500, 'Received SESSION_INVALID when logging in')
         self._session = result
         self.last_login_method = method
         self.last_login_params = params
         self.API_version = self._get_api_version()
     except socket.error as e:
         if e.errno == socket.errno.ETIMEDOUT:
             raise xmlrpclib.Fault(504, 'The connection timed out')
         else:
             raise e
Ejemplo n.º 3
0
    def test_dump_fault(self):
        f = xmlrpclib.Fault(42, 'Test Fault')
        s = xmlrpclib.dumps((f, ))
        (newf, ), m = xmlrpclib.loads(s)
        self.assertEqual(newf, {'faultCode': 42, 'faultString': 'Test Fault'})
        self.assertEqual(m, None)

        s = xmlrpclib.Marshaller().dumps(f)
        self.assertRaises(xmlrpclib.Fault, xmlrpclib.loads, s)
Ejemplo n.º 4
0
    def _delete_post(self, postid):
        # TODO: a notion of 'trashed', not removed
        result = yield self.settings['db'].posts.remove(ObjectId(postid))

        if result['n'] != 1:
            self.result(xmlrpclib.Fault(404, "Not found"))
        else:
            self.result(True)
            cache.event('post_deleted')
Ejemplo n.º 5
0
def _parse_result(result):
	if type(result) != dict or 'Status' not in result:
		raise xmlrpclib.Fault(500, 'Missing Status in response from server' + result)
	if result['Status'] == 'Success':
		if 'Value' in result:
			return result['Value']
		else:
			raise xmlrpclib.Fault(500,
								  'Missing Value in response from server')
	else:
		if 'ErrorDescription' in result:
			if result['ErrorDescription'][0] == 'SESSION_INVALID':
				return _RECONNECT_AND_RETRY
			else:
				raise Failure(result['ErrorDescription'])
		else:
			raise xmlrpclib.Fault(
				500, 'Missing ErrorDescription in response from server')
Ejemplo n.º 6
0
    def test_generate_package_cache_duplicate_ids(self, shell):
        """
        Test generate package cache, handling duplicate IDs.

        :param shell:
        :return:
        """
        tst = datetime.datetime(2000, 1, 1, 0, 0)
        logger = MagicMock()

        shell.options.quiet = False
        shell.all_packages = {}
        shell.all_packages_short = {}
        shell.all_packages_by_id = {}
        shell.package_cache_expire = tst
        shell.PACKAGE_CACHE_TTL = 8000
        shell.client.channel.software.listAllPackages = MagicMock(
            side_effect=[
                [
                    {"name": "emacs", "version": 42, "release": 3, "id": 42},
                    {"name": "gedit", "version": 1, "release": 2, "id": 69},
                    {"name": "vim", "version": 1, "release": 2, "id": 69},
                ],
                xmlrpclib.Fault(faultString="Interrupt configuration interference error",
                                faultCode=13)
            ]
        )
        shell.client.channel.listSoftwareChannels = MagicMock(
            return_value=[
                {"label": "basic_channel"},
                {"label": "locked_channel"},
            ]
        )

        with patch("spacecmd.misc.logging", logger) as lgr:
            spacecmd.misc.generate_package_cache(shell, force=False)

        assert logger.debug.called
        assert shell.client.channel.software.listAllPackages.called
        assert shell.client.channel.listSoftwareChannels.called
        assert shell.replace_line_buffer.called
        assert shell.save_package_caches.called
        assert shell.package_cache_expire != tst
        assert shell.package_cache_expire is not None

        assert_args_expect(logger.debug.call_args_list,
                           [(('No access to %s', 'locked_channel',), {}),
                            (('Non-unique package id "69" is detected. '
                              'Taking "vim-1-2" instead of "gedit-1-2"',), {})])

        for pkgname, pkgid in [("emacs-42-3", 42), ("vim-1-2", 69)]:
            assert pkgname in shell.all_packages
            assert shell.all_packages[pkgname] == [pkgid]
            assert pkgid in shell.all_packages_by_id
            assert shell.all_packages_by_id[pkgid] == pkgname
            assert pkgname.split("-")[0] in shell.all_packages_short
Ejemplo n.º 7
0
    def mt_getPostCategories(self, postid, user, password):
        post = yield self.settings['db'].posts.find_one(ObjectId(postid))

        if not post:
            self.result(xmlrpclib.Fault(404, "Not found"))
        else:
            self.result([
                cat.to_metaweblog(self.application)
                for cat in Post(**post).categories
            ])
Ejemplo n.º 8
0
Archivo: server.py Proyecto: wiz21b/koi
    def getTaskInformation(self, task_id):
        try:
            mainlog.debug("getTaskInformation, task id = {}".format(task_id))

            data = BarCodeIdentifier.barcode_to_id(task_id)

            if data[0] == Operation:
                operation_id = data[1]
                t = self.dao.task_dao.task_for_operation(operation_id)
            else:
                e = "Can't get that object, I don't recognize it"
                raise xmlrpclib.Fault(1000, e)

            return rpctools.sqla_to_hash(t)

        except Exception as e:
            mainlog.exception(e)
            e = "Task {} not found".format(task_id)
            mainlog.error(e)
            raise xmlrpclib.Fault(1000, e)
Ejemplo n.º 9
0
	def xenapi_request(self, methodname, params):
		if methodname.startswith('login'):
			self._login(methodname, params)
			return None
		else:
			retry_count = 0
			while retry_count < 3:
				full_params = (self._session,) + params
				result = _parse_result(getattr(self, methodname)(*full_params))
				if result == _RECONNECT_AND_RETRY:
					retry_count += 1
					if self.last_login_method:
						self._login(self.last_login_method,
									self.last_login_params)
					else:
						raise xmlrpclib.Fault(401, 'You must log in')
				else:
					return result
			raise xmlrpclib.Fault(
				500, 'Tried 3 times to get a valid session, but failed')
Ejemplo n.º 10
0
    def test_generate_errata_cache_force(self, shell):
        """
        Test generate errata cache, forced

        :return:
        """
        shell.ERRATA_CACHE_TTL = 86400
        shell.all_errata = {}
        shell.options.quiet = False
        shell.errata_cache_expire = datetime.datetime(2099, 1, 1)
        shell.client.channel.listSoftwareChannels = MagicMock(
            return_value=[{
                "label": "locked_channel"
            }, {
                "label": "base_channel"
            }])
        shell.client.channel.software.listErrata = MagicMock(side_effect=[
            xmlrpclib.Fault(
                faultCode=42,
                faultString="Sales staff sold a product we don't offer"),
            [{
                "id": 123,
                "advisory_name": "cve-123",
                "advisory_type": "mockery",
                "date": "2019.1.1",
                "advisory_synopsis": "some text here",
            }]
        ])

        logger = MagicMock()
        with patch("spacecmd.misc.logging", logger) as lgr:
            spacecmd.misc.generate_errata_cache(shell, force=True)

        assert logger.debug.called
        assert spacecmd.misc.generate_errata_cache(shell) is None
        assert shell.client.channel.listSoftwareChannels.called
        assert shell.client.channel.software.listErrata.called
        assert shell.replace_line_buffer.called
        assert shell.save_errata_cache.called
        assert "cve-123" in shell.all_errata
        assert shell.all_errata["cve-123"]["id"] == 123
        assert shell.all_errata["cve-123"]["advisory_type"] == "mockery"
        assert shell.all_errata["cve-123"][
            "advisory_synopsis"] == "some text here"
        assert shell.all_errata["cve-123"]["advisory_name"] == "cve-123"
        assert shell.all_errata["cve-123"]["date"] == "2019.1.1"
        assert_args_expect(
            logger.debug.call_args_list,
            [(('No access to %s (%s): %s', 'locked_channel', 42,
               "Sales staff sold a product we don't offer"), {})])
Ejemplo n.º 11
0
    def _edit_post(self, postid, struct, post_type):
        new_post = Post.from_metaweblog(struct, post_type, is_edit=True)
        db = self.settings['db']

        old_post_doc = yield db.posts.find_one(ObjectId(postid))

        if not old_post_doc:
            self.result(xmlrpclib.Fault(404, "Not found"))
        else:
            old_post = Post(**old_post_doc)
            if not old_post.pub_date and new_post.status == 'publish':
                new_post.pub_date = datetime.datetime.utcnow()

            # TODO: more general solution for fields that must be preserved.
            new_post.guest_access_tokens = old_post.guest_access_tokens
            update_result = yield db.posts.update(
                {'_id': old_post_doc['_id']},
                {'$set': new_post.to_python()})  # set fields to new values

            if update_result['n'] != 1:
                self.result(xmlrpclib.Fault(404, "Not found"))
            else:
                # If link changes, add redirect from old
                if (old_post.slug != new_post.slug
                        and old_post['status'] == 'publish'):
                    redirect_post = Post(
                        redirect=new_post.slug,
                        slug=old_post.slug,
                        status='publish',
                        type='redirect',
                        mod=datetime.datetime.utcnow())

                    yield db.posts.insert(redirect_post.to_python())

                # Done
                self.result(True)
                cache.event('post_changed')
Ejemplo n.º 12
0
    def _marshaled_dispatch(self, request):
        try:
            params, method = xmlrpc_client.loads(request.body)

            response = self._dispatch(request, method, params)
            # wrap response in a singleton tuple
            response = (response, )
            response = self.dumps(response, methodresponse=1)
        except xmlrpc_client.Fault as fault:
            response = self.dumps(fault)
        except Exception:  # noqa
            # report exception back to server
            response = self.dumps(
                xmlrpc_client.Fault(
                    1, '%s:%s' % (sys.exc_info()[0], sys.exc_info()[1])), )

        return response
Ejemplo n.º 13
0
    def test_user_details_invalid_users(self, shell):
        """
        Test do_user_details with invalid/not-found users.

        :param shell:
        :return:
        """
        shell.help_user_details = MagicMock()
        shell.client.user.getDetails = MagicMock(side_effect=xmlrpclib.Fault(
            faultCode=42, faultString="User caused disks spinning backwards"))
        shell.client.user.listRoles = MagicMock()
        shell.client.user.listAssignedSystemGroups = MagicMock()
        shell.client.user.listDefaultSystemGroups = MagicMock()
        shell.client.org.getDetails = MagicMock()
        mprint = MagicMock()
        logger = MagicMock()

        with patch("spacecmd.user.print", mprint) as prt, \
                patch("spacecmd.user.logging", logger) as lgr:
            spacecmd.user.do_user_details(shell, "hairypointed othermissing")

        assert not shell.client.user.listRoles.called
        assert not shell.client.user.listAssignedSystemGroups.called
        assert not shell.client.user.listDefaultSystemGroups.called
        assert not shell.client.org.getDetails.called
        assert not shell.help_user_details.called
        assert not mprint.called
        assert logger.warning.called
        assert logger.debug.called
        assert shell.client.user.getDetails.called

        assert_list_args_expect(logger.warning.call_args_list, [
            "hairypointed is not a valid user",
            "othermissing is not a valid user"
        ])
        assert_list_args_expect(logger.debug.call_args_list, [
            "Error '42' while getting data about user "
            "'hairypointed': User caused disks spinning backwards",
            "Error '42' while getting data about user "
            "'othermissing': User caused disks spinning backwards"
        ])
Ejemplo n.º 14
0
    def test_should_raise_an_exception_after_the_user_provides_wrong_credentials_three_times_in_a_row(self):
        interactive_credentials = [
            ["interactive_username1", "interactive_password1"],
            ["interactive_username2", "interactive_password2"],
            ["interactive_username3", "interactive_password3"]
        ]
        cached_credentials = ["cached_username", "cached_password"]
        exception = xmlrpc_client.Fault(
            2950,
            "Either the password or username is incorrect")
        login_mocked_return_values = [
            exception,  # raised by the cached credentials
            exception,  # raised by the 1st pair of interactive credentials
            exception,  # raised by the 2nd pair of interactive credentials
            exception   # raised by the 3rd pair of interactive credentials
        ]

        auth = Authenticator(
            connection=self.mock_connection,
            user=cached_credentials[0],
            password=cached_credentials[1],
            token=None)
        auth.connection.auth.login.side_effect = lambda username, password: _side_effect_return_from_list(
            login_mocked_return_values)

        auth._get_credentials_interactive = MagicMock()
        auth._get_credentials_interactive.side_effect = lambda: _set_username_and_password(
            auth, interactive_credentials)

        with self.assertRaises(MaximumNumberOfAuthenticationFailures):
            auth.token()
        self.assertEqual(
            Authenticator.MAX_NUM_OF_CREDENTIAL_FAILURES_ALLOWED,
            auth._get_credentials_interactive.call_count)

        expected_login_calls = []
        for c in [cached_credentials] + interactive_credentials:
            expected_login_calls.append(call.login(c[0], c[1]))
        auth.connection.auth.assert_has_calls(expected_login_calls)
        self.assertEqual(4, auth.connection.auth.login.call_count)
Ejemplo n.º 15
0
    def __marshaled_dispatch(self, data, dispatch_method=None):
        params, method = my_xmlrpclib_loads(data)

        # generate response
        try:
            if dispatch_method is not None:
                response = dispatch_method(method, params)
            else:
                response = self._dispatch(method, params)
            # wrap response in a singleton tuple
            response = (response, )
            response = xmlrpclib.dumps(response, methodresponse=True)
        except xmlrpclib.Fault:
            fault = sys.exc_info()[1]
            response = xmlrpclib.dumps(fault)
        except:
            # report exception back to server
            response = xmlrpclib.dumps(
                xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)))
            print_debug_exception()

        return response
Ejemplo n.º 16
0
    def test_use_cached_credentials_and_then_keep_asking_credentials_if_they_are_wrong(self):
        interactive_credentials = [
            ["interactive_username1", "interactive_password1"],
            ["interactive_username2", "interactive_password2"],
            ["interactive_username3", "interactive_password3"]
        ]
        cached_credentials = ["cached_username", "cached_password"]
        expected_token = "test token"
        exception = xmlrpc_client.Fault(
            2950,
            "Either the password or username is incorrect")
        login_mocked_return_values = [
            exception,      # raised by the cached credentials
            exception,      # raised by the 1st pair of interactive credentials
            exception,      # raised by the 2nd pair of interactive credentials
            expected_token  # 3rd pair of interactive credentials works fine
        ]

        auth = Authenticator(
            connection=self.mock_connection,
            user=cached_credentials[0],
            password=cached_credentials[1],
            token=None)
        auth.connection.auth.login.side_effect = lambda username, password: _side_effect_return_from_list(
            login_mocked_return_values)

        auth._get_credentials_interactive = MagicMock()
        auth._get_credentials_interactive.side_effect = lambda: _set_username_and_password(
            auth, interactive_credentials)

        self.assertEqual(expected_token, auth.token())

        self.assertEqual(3, auth._get_credentials_interactive.call_count)

        expected_login_calls = []
        for c in [cached_credentials] + interactive_credentials:
            expected_login_calls.append(call.login(c[0], c[1]))
        auth.connection.auth.assert_has_calls(expected_login_calls)
        self.assertEqual(4, auth.connection.auth.login.call_count)
Ejemplo n.º 17
0
    def mt_setPostCategories(self, postid, user, password, categories):
        # Sometimes we receive only id from categories, e.g. from Windows
        # Live Writer, so we must query for the names.
        if categories and 'categoryName' not in categories[0]:
            categories_ids = [
                ObjectId(category.get('categoryId')) for category in categories
            ]

            cursor = self.settings['db'].categories.find(
                {"_id": {
                    '$in': categories_ids
                }}, fields=["name"])

            categories = []
            while (yield cursor.fetch_next):
                category = cursor.next_object()
                categories.append(
                    dict(categoryId=category['_id'],
                         categoryName=category['name']))

        embedded_cats = [
            EmbeddedCategory.from_metaweblog(cat).to_python()
            for cat in categories
        ]

        result = yield self.settings['db'].posts.update(
            {'_id': ObjectId(postid)}, {
                '$set': {
                    'categories': embedded_cats,
                    'mod': datetime.datetime.utcnow(),
                }
            })

        if result['n'] != 1:
            self.result(xmlrpclib.Fault(404, 'Not found'))
        else:
            self.result('')
            cache.event('post_changed')
Ejemplo n.º 18
0
    def more(self):
        if self.finished:
            return ''
        try:
            try:
                value = self.callback()
                if value is NOT_DONE_YET:
                    return NOT_DONE_YET
            except RPCError:
                err = sys.exc_info()[1]
                value = xmlrpclib.Fault(err.code, err.text)

            body = xmlrpc_marshal(value)

            self.finished = True

            return self.getresponse(body)

        except:
            # report unexpected exception back to server
            traceback.print_exc()
            self.finished = True
            self.request.error(500)
Ejemplo n.º 19
0
def xmlrpc_handle_exception_string(e):
    if isinstance(e, flectra.exceptions.RedirectWarning):
        fault = xmlrpclib.Fault('warning -- Warning\n\n' + str(e), '')
    elif isinstance(e, flectra.exceptions.MissingError):
        fault = xmlrpclib.Fault('warning -- MissingError\n\n' + str(e), '')
    elif isinstance(e, flectra.exceptions.AccessError):
        fault = xmlrpclib.Fault('warning -- AccessError\n\n' + str(e), '')
    elif isinstance(e, flectra.exceptions.AccessDenied):
        fault = xmlrpclib.Fault('AccessDenied', str(e))
    elif isinstance(e, flectra.exceptions.UserError):
        fault = xmlrpclib.Fault('warning -- UserError\n\n' + str(e), '')
    #InternalError
    else:
        info = sys.exc_info()
        formatted_info = "".join(traceback.format_exception(*info))
        fault = xmlrpclib.Fault(flectra.tools.exception_to_unicode(e), formatted_info)

    return xmlrpclib.dumps(fault, allow_none=None, encoding=None)
Ejemplo n.º 20
0
    def test_schedule_getoutput_no_any_results(self, shell):
        """
        Test do_schedule_getoutput with no any results available

        :param shell:
        :return:
        """
        shell.client.schedule.listCompletedSystems = MagicMock(return_value=[])
        shell.client.schedule.listFailedSystems = MagicMock(return_value=[])
        shell.client.system.getScriptResults = MagicMock(
            side_effect=xmlrpclib.Fault(faultCode=42,
                                        faultString="Happy NPE!"))
        shell.help_schedule_getoutput = MagicMock()

        mprint = MagicMock()
        logger = MagicMock()

        with patch("spacecmd.schedule.print", mprint) as prt, \
                patch("spacecmd.schedule.logging", logger) as lgr:
            spacecmd.schedule.do_schedule_getoutput(shell, "42")

        assert not logger.warning.called
        assert not shell.help_schedule_getoutput.called
        assert not mprint.called
        assert shell.client.system.getScriptResults.called
        assert shell.client.schedule.listCompletedSystems.called
        assert shell.client.schedule.listFailedSystems.called
        assert logger.debug.called
        assert logger.error.called

        assert_args_expect(
            logger.debug.call_args_list,
            [(('Exception occurrect while get script results: %s',
               "<Fault 42: 'Happy NPE!'>"), {})])
        assert_args_expect(logger.error.call_args_list,
                           [(("No systems found", ), {})])
Ejemplo n.º 21
0
    def test_schedule_getoutput_no_script_results(self, shell):
        """
        Test do_schedule_getoutput with no script results (failed or None)

        :param shell:
        :return:
        """
        shell.client.schedule.listCompletedSystems = MagicMock(return_value=[
            {
                "server_name": "web.foo.com",
                "timestamp": "2019-01-01",
                "message": "Message from the web.foo.com"
            }, {
                "server_name": "web1.foo.com",
                "timestamp": "2019-01-01",
                "message": "Message from the web1.foo.com as well"
            }, {
                "server_name": "web2.foo.com",
                "timestamp": "2019-01-01",
                "message": "And some more message from web2.foo.com here"
            }
        ])
        shell.client.schedule.listFailedSystems = MagicMock(return_value=[
            {
                "server_name": "faulty.foo.com",
                "timestamp": "2019-01-01",
                "message": "Nothing good is happening on faulty.foo.com"
            },
        ])
        shell.client.system.getScriptResults = MagicMock(
            side_effect=xmlrpclib.Fault(faultCode=42,
                                        faultString="Happy NPE!"))
        shell.help_schedule_getoutput = MagicMock()

        mprint = MagicMock()
        logger = MagicMock()

        with patch("spacecmd.schedule.print", mprint) as prt, \
                patch("spacecmd.schedule.logging", logger) as lgr:
            spacecmd.schedule.do_schedule_getoutput(shell, "42")

        assert not logger.warning.called
        assert not shell.help_schedule_getoutput.called
        assert shell.client.system.getScriptResults.called
        assert shell.client.schedule.listCompletedSystems.called
        assert shell.client.schedule.listFailedSystems.called
        assert mprint.called
        assert logger.debug.called

        assert_args_expect(
            logger.debug.call_args_list,
            [(('Exception occurrect while get script results: %s',
               "<Fault 42: 'Happy NPE!'>"), {})])
        assert_list_args_expect(mprint.call_args_list, [
            'System:    web.foo.com', 'Completed: 2019-01-01', '', 'Output',
            '------', 'Message from the web.foo.com', '----------',
            'System:    web1.foo.com', 'Completed: 2019-01-01', '', 'Output',
            '------', 'Message from the web1.foo.com as well', '----------',
            'System:    web2.foo.com', 'Completed: 2019-01-01', '', 'Output',
            '------', 'And some more message from web2.foo.com here',
            '----------', 'System:    faulty.foo.com', 'Completed: 2019-01-01',
            '', 'Output', '------',
            'Nothing good is happening on faulty.foo.com'
        ])
Ejemplo n.º 22
0
 def _fault(self, error):
     return xmlrpclib.Fault(*error)
Ejemplo n.º 23
0
 def fake_execute_kw(self, dbs, uid, password, model, method, payload):
     raise xc.Fault(data['faultCode'], data['faultString'])
Ejemplo n.º 24
0
 def test_repr(self):
     f = xmlrpclib.Fault(42, 'Test Fault')
     self.assertEqual(repr(f), "<Fault 42: 'Test Fault'>")
     self.assertEqual(repr(f), str(f))
Ejemplo n.º 25
0
    def test_login_no_cached_session_bad_credentials(self, shell):
        """
        Test fail to create new session due to wrong credentials.

        :param shell:
        :return:
        """
        mprint = MagicMock()
        logger = MagicMock()
        prompter = MagicMock(return_value="bofh")
        gpass = MagicMock(return_value=None)
        mkd = MagicMock()
        file_writer = MagicMock()

        client = MagicMock()
        rpc_server = MagicMock(return_value=client)

        shell.session = None
        shell.options.debug = 2
        shell.options.password = None
        shell.options.username = None
        shell.config = {"server": "no.mans.land", "password": "******"}
        shell.conf_dir = "/tmp"
        shell.MINIMUM_API_VERSION = 10.8
        client.api.getVersion = MagicMock(return_value=11.5)
        client.auth.login = MagicMock(side_effect=xmlrpclib.Fault(
            faultCode=42, faultString="Click harder"))

        with patch("spacecmd.misc.print", mprint) as prt, \
            patch("spacecmd.misc.prompt_user", prompter) as pmt, \
            patch("spacecmd.misc.getpass", gpass) as gtp, \
            patch("spacecmd.misc.os.mkdir", mkd) as mkdr, \
            patch("spacecmd.misc.xmlrpclib.Server", rpc_server) as rpcs, \
            patch("spacecmd.misc.open", file_writer) as fmk, \
            patch("spacecmd.misc.logging", logger) as lgr:
            out = spacecmd.misc.do_login(shell, "")

        assert not gpass.called
        assert not mprint.called
        assert not logger.warning.called
        assert logger.error.called
        assert not client.user.listAssignableRoles.called
        assert client.auth.login.called
        assert prompter.called
        assert not logger.info.called
        assert not shell.load_caches.called
        assert shell.load_config_section.called
        assert logger.debug.called
        assert shell.client is not None
        assert shell.session is None
        assert not out
        assert not mkd.called

        assert_args_expect(client.auth.login.call_args_list,
                           [(('bofh', "foobar"), {})])
        assert_args_expect(
            logger.debug.call_args_list,
            [(('Connecting to %s', 'https://no.mans.land/rpc/api'), {}),
             (('Server API Version = %s', 11.5), {}),
             (('Login error: %s (%s)', 'Click harder', 42), {})])
        assert_args_expect(logger.error.call_args_list,
                           [(('Invalid credentials', ), {})])