def test_forward(self): """ Test the `ipalib.rpc.xmlclient.forward` method. """ class user_add(Command): pass o, _api, _home = self.instance('Backend', user_add, in_server=False) args = (binary_bytes, utf8_bytes, unicode_str) kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str) params = [args, kw] result = (unicode_str, binary_bytes, utf8_bytes) conn = DummyClass( ( 'user_add', rpc.xml_wrap(params, API_VERSION), {}, rpc.xml_wrap(result, API_VERSION), ), ( 'user_add', rpc.xml_wrap(params, API_VERSION), {}, Fault(3007, u"'four' is required"), # RequirementError ), ( 'user_add', rpc.xml_wrap(params, API_VERSION), {}, Fault(700, u'no such error'), # There is no error 700 ), ) # Create connection for the current thread setattr(context, o.id, Connection(conn, lambda: None)) context.xmlclient = Connection(conn, lambda: None) # Test with a successful return value: assert o.forward('user_add', *args, **kw) == result # Test with an errno the client knows: e = raises(errors.RequirementError, o.forward, 'user_add', *args, **kw) assert_equal(e.args[0], u"'four' is required") # Test with an errno the client doesn't know e = raises(errors.UnknownError, o.forward, 'user_add', *args, **kw) assert_equal(e.code, 700) assert_equal(e.error, u'no such error') assert context.xmlclient.conn._calledall() is True
def forward(self, name, *args, **kw): """ Forward call to command named ``name`` over XML-RPC. This method will encode and forward an XML-RPC request, and will then decode and return the corresponding XML-RPC response. :param command: The name of the command being forwarded. :param args: Positional arguments to pass to remote command. :param kw: Keyword arguments to pass to remote command. """ server = getattr(context, 'request_url', None) self.log.info("Forwarding '%s' to %s server '%s'", name, self.protocol, server) command = getattr(self.conn, name) params = [args, kw] try: return self._call_command(command, params) except Fault as e: e = decode_fault(e) self.debug('Caught fault %d from server %s: %s', e.faultCode, server, e.faultString) if e.faultCode in errors_by_code: error = errors_by_code[e.faultCode] raise error(message=e.faultString) raise UnknownError( code=e.faultCode, error=e.faultString, server=server, ) except SSLError as e: raise NetworkError(uri=server, error=str(e)) except ProtocolError as e: # By catching a 401 here we can detect the case where we have # a single IPA server and the session is invalid. Otherwise # we always have to do a ping(). session_cookie = getattr(context, 'session_cookie', None) if session_cookie and e.errcode == 401: # Unauthorized. Remove the session and try again. delattr(context, 'session_cookie') try: principal = getattr(context, 'principal', None) delete_persistent_client_session_data(principal) except Exception as e: # This shouldn't happen if we have a session but it isn't fatal. pass # Create a new serverproxy with the non-session URI serverproxy = self.create_connection( os.environ.get('KRB5CCNAME'), self.env.verbose, self.env.fallback, self.env.delegate) setattr(context, self.id, Connection(serverproxy, self.disconnect)) return self.forward(name, *args, **kw) raise NetworkError(uri=server, error=e.errmsg) except socket.error as e: raise NetworkError(uri=server, error=str(e)) except (OverflowError, TypeError) as e: raise XMLRPCMarshallError(error=str(e))
def test_forward(self): """ Test the `ipalib.rpc.xmlclient.forward` method. """ class user_add(Command): pass # Test that ValueError is raised when forwarding a command that is not # in api.Command: (o, api, home) = self.instance('Backend', in_server=False) e = raises(ValueError, o.forward, 'user_add') assert str(e) == '%s.forward(): %r not in api.Command' % ('xmlclient', 'user_add') (o, api, home) = self.instance('Backend', user_add, in_server=False) args = (binary_bytes, utf8_bytes, unicode_str) kw = dict(one=binary_bytes, two=utf8_bytes, three=unicode_str) params = [args, kw] result = (unicode_str, binary_bytes, utf8_bytes) conn = DummyClass( ( 'user_add', rpc.xml_wrap(params), {}, rpc.xml_wrap(result), ), ( 'user_add', rpc.xml_wrap(params), {}, Fault(3007, u"'four' is required"), # RequirementError ), ( 'user_add', rpc.xml_wrap(params), {}, Fault(700, u'no such error'), # There is no error 700 ), ) context.xmlclient = Connection(conn, lambda: None) # Test with a successful return value: assert o.forward('user_add', *args, **kw) == result # Test with an errno the client knows: e = raises(errors.RequirementError, o.forward, 'user_add', *args, **kw) assert_equal(e.args[0], u"'four' is required") # Test with an errno the client doesn't know e = raises(errors.UnknownError, o.forward, 'user_add', *args, **kw) assert_equal(e.code, 700) assert_equal(e.error, u'no such error') assert context.xmlclient.conn._calledall() is True
def connect(self, *args, **kw): """ Create thread-local connection. """ if hasattr(context, self.id): raise Exception("{0} is already connected ({1} in {2})".format( self.name, self.id, threading.currentThread().getName())) conn = self.create_connection(*args, **kw) setattr(context, self.id, Connection(conn, self.disconnect)) assert self.conn is conn logger.debug('Created connection context.%s', self.id)
def test_conn(self): """ Test the `ipalib.backend.Connectible.conn` property. """ msg = 'no context.%s in thread %r' class example(self.cls): pass for klass in (self.cls, example): o = klass(shared_instance=True) e = raises(AttributeError, getattr, o, 'conn') assert str(e) == msg % (klass.__name__, threading.currentThread().getName()) conn = Connection('The connection.', Disconnect()) setattr(context, klass.__name__, conn) assert o.conn is conn.conn delattr(context, klass.__name__)
def test_conn(self): """ Test the `ipalib.backend.Connectible.conn` property. """ api = 'the api instance' msg = '{0} is not connected ({1} in {2})' class example(self.cls): pass for klass in (self.cls, example): o = klass(api, shared_instance=True) e = raises(AttributeError, getattr, o, 'conn') assert str(e) == msg.format(klass.__name__, o.id, threading.currentThread().getName()) conn = Connection('The connection.', Disconnect()) setattr(context, klass.__name__, conn) assert o.conn is conn.conn delattr(context, klass.__name__)
def test_execute(self): """ Test the `ipalib.backend.Executioner.execute` method. """ (api, home) = create_test_api(in_server=True) class echo(Command): takes_args = ('arg1', 'arg2+') takes_options = ('option1?', 'option2?') def execute(self, *args, **options): assert type(args[1]) is tuple return dict(result=args + (options, )) api.register(echo) class good(Command): def execute(self, **options): raise errors.ValidationError( name='nurse', error=u'Not naughty!', ) api.register(good) class bad(Command): def execute(self, **options): raise ValueError('This is private.') api.register(bad) class with_name(Command): """ Test that a kwarg named 'name' can be used. """ takes_options = 'name' def execute(self, **options): return dict(result=options['name'].upper()) api.register(with_name) api.finalize() o = self.cls() o.set_api(api) o.finalize() # Test that CommandError is raised: conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn print str(context.__dict__.keys()) e = raises(errors.CommandError, o.execute, 'nope') assert e.name == 'nope' assert conn.disconnect.called is True # Make sure destroy_context() was called print str(context.__dict__.keys()) assert context.__dict__.keys() == [] # Test with echo command: arg1 = unicode_str arg2 = (u'Hello', unicode_str, u'world!') args = (arg1, ) + arg2 options = dict(option1=u'How are you?', option2=unicode_str, version=API_VERSION) conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn print o.execute('echo', arg1, arg2, **options) print dict(result=(arg1, arg2, options)) assert o.execute('echo', arg1, arg2, **options) == dict(result=(arg1, arg2, options)) assert conn.disconnect.called is True # Make sure destroy_context() was called assert context.__dict__.keys() == [] conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn assert o.execute('echo', *args, **options) == dict(result=(arg1, arg2, options)) assert conn.disconnect.called is True # Make sure destroy_context() was called assert context.__dict__.keys() == [] # Test with good command: conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn e = raises(errors.ValidationError, o.execute, 'good') assert e.name == 'nurse' assert e.error == u'Not naughty!' assert conn.disconnect.called is True # Make sure destroy_context() was called assert context.__dict__.keys() == [] # Test with bad command: conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn e = raises(errors.InternalError, o.execute, 'bad') assert conn.disconnect.called is True # Make sure destroy_context() was called assert context.__dict__.keys() == [] # Test with option 'name': conn = Connection('The connection.', Disconnect('someconn')) context.someconn = conn expected = dict(result=u'TEST') assert expected == o.execute('with_name', name=u'test', version=API_VERSION)
# is an existing connection we need to save the NSS dbdir so # we can skip an unnecessary NSS_Initialize() and avoid # NSS_Shutdown issues. serverproxy = self.create_connection( os.environ.get('KRB5CCNAME'), self.env.verbose, self.env.fallback, self.env.delegate) dbdir = None current_conn = getattr(context, self.id, None) if current_conn is not None: dbdir = getattr(current_conn.conn._ServerProxy__transport, 'dbdir', None) if dbdir is not None: self.debug('Using dbdir %s' % dbdir) setattr(context, self.id, Connection(serverproxy, self.disconnect)) if dbdir is not None: current_conn = getattr(context, self.id, None) current_conn.conn._ServerProxy__transport.dbdir = dbdir return self.forward(name, *args, **kw) raise NetworkError(uri=server, error=e.errmsg) except socket.error, e: raise NetworkError(uri=server, error=str(e)) except (OverflowError, TypeError), e: raise XMLRPCMarshallError(error=str(e)) class xmlclient(RPCClient): session_path = '/ipa/session/xml' server_proxy_class = ServerProxy protocol = 'xml'