def test_13_rpc1_pub_sub_with_pub_sub_proxy(self): # RPC invoke method over PUB/SUB sockets and a PUB/SUB proxy print "Test if invoking a method works over PUB/SUB RPC socket and a PUB/SUB proxy in between" server_thread = ZmqRpcServerThread(zmq_sub_connect_addresses=["tcp://localhost:4567"], rpc_functions={"invoke_test": invoke_test}) server_thread.start() proxy_pub_sub_thread = ZmqProxySub2PubThread(zmq_pub_bind_address="tcp://*:4567", zmq_sub_connect_addresses=['tcp://localhost:4566']) proxy_pub_sub_thread.start() client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:4566") # Wait a bit to avoid slow joiner... time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value2sub", "param2": "value2pub"}, time_out_waiting_for_response_in_sec=3) # Wait a bit to make sure message is sent... time.sleep(1) server_thread.stop() server_thread.join() proxy_pub_sub_thread.stop() proxy_pub_sub_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) # Response should be empty with PUB/SUB self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value2sub")
def test_05_rpc1_req_rep(self): # RPC invoke method over REQ/REP sockets print( "Test if invoking a method works over REQ/REP RPC socket, includes a username/password" ) client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:55000", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value1", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) self.assertEquals(response, "value1:value2")
def test_08_rpc1_pub_sub(self): # RPC invoke method over REQ/REP sockets print("Test if invoking a method works over PUB/SUB RPC socket") client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:54000") server_thread = ZmqRpcServerThread( zmq_sub_connect_addresses=["tcp://localhost:54000"], rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() # Wait a bit to avoid slow joiner... time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value1sub", "param2": "value2pub" }, time_out_waiting_for_response_in_sec=3) # Wait a bit to make sure message is sent... time.sleep(1) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) # Response should be empty with PUB/SUB self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value1sub")
def test_11_rpc1_req_rep_with_rep_req_proxy_without_password(self): # RPC invoke method over REQ/REP sockets with an extra rep/req proxy in between print "Test if invoking a method works over REQ/REP RPC socket, using an extra rep/req proxy" client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:53000"]) proxy_rep_req_thread = ZmqProxyRep2ReqThread(zmq_rep_bind_address='tcp://*:53000', zmq_req_connect_addresses=["tcp://localhost:53001"]) proxy_rep_req_thread.start() server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:53001", rpc_functions={"invoke_test": invoke_test}) server_thread.start() time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value1", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) server_thread.stop() server_thread.join() proxy_rep_req_thread.stop() proxy_rep_req_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) self.assertEquals(response, "value1:value2")
def __init__(self, name, address='localhost', port=8080, user=None, password=None, **kwargs): super().__init__(name, **kwargs) self._client_ = ZmqRpcClient(["tcp://{0}:{1}".format(address, port)], username=user, password=password)
def test_05_rpc1_req_rep(self): # RPC invoke method over REQ/REP sockets print "Test if invoking a method works over REQ/REP RPC socket, includes a username/password" client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:55000", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value1", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) self.assertEquals(response, "value1:value2")
def test_15_rpc1_req_rep_with_rep_req_buffered_proxy(self): # RPC invoke method over REQ/REP sockets with an extra rep/req proxy in between print "Test if invoking a method works over Buffered REQ/REP RPC socket, includes a username/password" test_state.last_invoked_param1 = None client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:51000"], username="******", password="******") buf_proxy_rep_req_thread = ZmqBufferedProxyRep2ReqThread(zmq_rep_bind_address='tcp://*:51000', zmq_req_connect_addresses=["tcp://localhost:51001"], buffered_pub_address="tcp://*:59878", buffered_sub_address="tcp://localhost:59878", username_rep="username", password_rep="password", username_req="username2", password_req="password2") buf_proxy_rep_req_thread.start() server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:51001", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value1viaproxy", "param2": "value2viaproxy"}, time_out_waiting_for_response_in_sec=30) time.sleep(1) self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value1viaproxy") #Now send a couple of messages while nothing is receiving to validate buffering is owrking fine server_thread.stop() server_thread.join() test_state.last_invoked_param1 = None response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value1-2viaproxy", "param2": "value2viaproxy"}, time_out_waiting_for_response_in_sec=30) # Wait some time to be sure it has been processed and the system is retrying delivery. time.sleep(5) server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:51001", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() # Wait some time to be sure it has been processed and the system is retrying delivery. A retry cycle is max 1 sec. time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "value1-2viaproxy") server_thread.stop() server_thread.join() buf_proxy_rep_req_thread.stop() buf_proxy_rep_req_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
def test_07_rpc1_req_rep_exception_raised(self): # RPC invoke method over REQ/REP sockets print "Test if invoking an existing method that throws an exception over REQ/REP RPC socket, includes a username/password" client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:55000", rpc_functions={"invoke_test_that_throws_exception": invoke_test_that_throws_exception}, username="******", password="******") server_thread.start() try: client.invoke(function_name="invoke_test_that_throws_exception", function_parameters={"param1": "value1", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) except Exception as e: self.assertEqual(e.message, "Exception raised when calling function invoke_test_that_throws_exception. Exception: Something went wrong ") server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
def test_06_rpc1_req_rep_invalid_function(self): # RPC invoke method over REQ/REP sockets print "Test if invoking a non existing method throws proper error over REQ/REP RPC socket, includes a username/password" client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread(zmq_rep_bind_address="tcp://*:55000", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() try: client.invoke(function_name="invoke_test_does_not_exist", function_parameters={"param1": "value1", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) except Exception as e: self.assertEquals(e.message, "Function 'invoke_test_does_not_exist' is not implemented on server. Check rpc_functions on server if it contains the function name") server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
def test_12_rpc1_req_rep_with_rep_req_proxy(self): # RPC invoke method over REQ/REP sockets with an extra rep/req proxy in between print( "Test if invoking a method works over REQ/REP RPC socket, includes a username/password and also an extra rep/req proxy" ) client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:52000"], username="******", password="******") proxy_rep_req_thread = ZmqProxyRep2ReqThread( zmq_rep_bind_address='tcp://*:52000', zmq_req_connect_addresses=["tcp://localhost:52001"], username_rep="username", password_rep="password", username_req="username2", password_req="password2") proxy_rep_req_thread.start() server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:52001", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value1", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) server_thread.stop() server_thread.join() proxy_rep_req_thread.stop() proxy_rep_req_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) self.assertEquals(response, "value1:value2")
def test_13_rpc1_pub_sub_with_pub_sub_proxy(self): # RPC invoke method over PUB/SUB sockets and a PUB/SUB proxy print( "Test if invoking a method works over PUB/SUB RPC socket and a PUB/SUB proxy in between" ) server_thread = ZmqRpcServerThread( zmq_sub_connect_addresses=["tcp://localhost:4567"], rpc_functions={"invoke_test": invoke_test}) server_thread.start() proxy_pub_sub_thread = ZmqProxySub2PubThread( zmq_pub_bind_address="tcp://*:4567", zmq_sub_connect_addresses=['tcp://localhost:4566']) proxy_pub_sub_thread.start() client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:4566") # Wait a bit to avoid slow joiner... time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value2sub", "param2": "value2pub" }, time_out_waiting_for_response_in_sec=3) # Wait a bit to make sure message is sent... time.sleep(1) server_thread.stop() server_thread.join() proxy_pub_sub_thread.stop() proxy_pub_sub_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) # Response should be empty with PUB/SUB self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value2sub")
def test_06_rpc1_req_rep_invalid_function(self): # RPC invoke method over REQ/REP sockets print( "Test if invoking a non existing method throws proper error over REQ/REP RPC socket, includes a username/password" ) client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:55000", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() try: client.invoke(function_name="invoke_test_does_not_exist", function_parameters={ "param1": "value1", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) except Exception as e: self.assertEquals( str(e), "Function 'invoke_test_does_not_exist' is not implemented on server. Check rpc_functions on server if it contains the function name" ) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
class InstrumentDataClient(Instrument): ''' A proxy client for collecting instrument measurable quantities from a server. Args: name (str): the name of the instrument. address (str): the ip-address of the server. port (int): the port number of the proxy server. user (str): a username for protection. password (str): a password for protection. ''' def __init__(self, name, address='localhost', port=8080, user=None, password=None, **kwargs): super().__init__(name, **kwargs) self._client_ = ZmqRpcClient(["tcp://{0}:{1}".format(address, port)], username=user, password=password) def __proxy_wrapper__(self, command_name, default_value, params, sec_time_out=3): try: return self._client_.invoke(command_name, params, sec_time_out) except: return default_value def add_measurable_quantity(self, name='quantity', unit='arb.', default_value=None, doc_string='Unknown', command_name='', params=None): '''Adds a instument function to the dataclient.''' if not command_name: command_name = name command = partial(self.__proxy_wrapper__, command_name=command_name, default_value=default_value, params=params) self.add_parameter(name, unit=unit, get_cmd=command, docstring=doc_string)
def test_08_rpc1_pub_sub(self): # RPC invoke method over REQ/REP sockets print "Test if invoking a method works over PUB/SUB RPC socket" client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:54000") server_thread = ZmqRpcServerThread(zmq_sub_connect_addresses=["tcp://localhost:54000"], rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() # Wait a bit to avoid slow joiner... time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={"param1": "value1sub", "param2": "value2pub"}, time_out_waiting_for_response_in_sec=3) # Wait a bit to make sure message is sent... time.sleep(1) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1) # Response should be empty with PUB/SUB self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value1sub")
def test_07_rpc1_req_rep_exception_raised(self): # RPC invoke method over REQ/REP sockets print( "Test if invoking an existing method that throws an exception over REQ/REP RPC socket, includes a username/password" ) client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:55000"], username="******", password="******") server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:55000", rpc_functions={ "invoke_test_that_throws_exception": invoke_test_that_throws_exception }, username="******", password="******") server_thread.start() try: client.invoke(function_name="invoke_test_that_throws_exception", function_parameters={ "param1": "value1", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) except Exception as e: self.assertEqual( str(e), "Exception raised when calling function invoke_test_that_throws_exception. Exception: Something went wrong " ) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
def test_10a_pub_sub_timeout_per_socket_using_heartbeat_function(self): # Basic send/receive over PUB/SUB sockets print("Test a timeout per socket with RPC using heartbeat") client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:47001") server_thread = ZmqRpcServerThread( zmq_sub_connect_addresses=[("tcp://localhost:47001", 3)], rpc_functions={"invoke_test": invoke_test}, recreate_sockets_on_timeout_of_sec=10) server_thread.start() # Slow joiner time.sleep(0.1) first_socket = server_thread.server.sub_sockets[0].zmq_socket client.invoke(function_name="invoke_test", function_parameters={ "param1": "testxx-value1", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) # Take 2 seconds to see if it works in case of within the 3 seconds window. time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value1") # Now send another but with 2 seconds delay, which should be ok, then followed by a couple of heartbeats which should keep the existing socket. client.invoke(function_name="invoke_test", function_parameters={ "param1": "testxx-value2", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) time.sleep(2) client.send_heartbeat() time.sleep(2) client.send_heartbeat() time.sleep(2) client.send_heartbeat() time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value2") self.assertEqual(server_thread.server.sub_sockets[0].zmq_socket, first_socket) # Now send another but with 4 seconds delay, which should restart the sockets, but message should arrive client.invoke(function_name="invoke_test", function_parameters={ "param1": "testxx-value3", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) time.sleep(4) self.assertEquals(test_state.last_invoked_param1, "testxx-value3") second_socket = server_thread.server.sub_sockets[0].zmq_socket self.assertNotEqual(second_socket, first_socket) # Now send another but with 2 seconds delay, which should be ok client.invoke(function_name="invoke_test", function_parameters={ "param1": "testxx-value4", "param2": "value2" }, time_out_waiting_for_response_in_sec=3) time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value4") self.assertEqual(server_thread.server.sub_sockets[0].zmq_socket, second_socket) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
Created on Apr 8, 2014 @author: Jan Verhoeven @copyright: MIT license, see http://opensource.org/licenses/MIT ''' from zmqrpc.ZmqRpcClient import ZmqRpcClient from zmqrpc.ZmqRpcServer import ZmqRpcServerThread import time def test_method(param1, param2): print "test_method invoked with params '{0}' and '{1}'".format(param1, param2) if __name__ == '__main__': client = ZmqRpcClient( zmq_pub_endpoint="tcp://*:30000") server = ZmqRpcServerThread( zmq_sub_connect_addresses=["tcp://localhost:30000"], # Must be a list rpc_functions={"test_method": test_method}) # Dict server.start() # Wait a bit since sockets may not have been connected immediately time.sleep(2) client.invoke( function_name="test_method", function_parameters={"param1": "param1", "param2": "param2"}) # Must be dict # Wait a bit to make sure message has been received
def test_15_rpc1_req_rep_with_rep_req_buffered_proxy(self): # RPC invoke method over REQ/REP sockets with an extra rep/req proxy in between print( "Test if invoking a method works over Buffered REQ/REP RPC socket, includes a username/password" ) test_state.last_invoked_param1 = None client = ZmqRpcClient(zmq_req_endpoints=["tcp://localhost:51000"], username="******", password="******") buf_proxy_rep_req_thread = ZmqBufferedProxyRep2ReqThread( zmq_rep_bind_address='tcp://*:51000', zmq_req_connect_addresses=["tcp://localhost:51001"], buffered_pub_address="tcp://*:59878", buffered_sub_address="tcp://localhost:59878", username_rep="username", password_rep="password", username_req="username2", password_req="password2") buf_proxy_rep_req_thread.start() server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:51001", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() time.sleep(1) response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value1viaproxy", "param2": "value2viaproxy" }, time_out_waiting_for_response_in_sec=30) time.sleep(1) self.assertEquals(response, None) self.assertEquals(test_state.last_invoked_param1, "value1viaproxy") #Now send a couple of messages while nothing is receiving to validate buffering is owrking fine server_thread.stop() server_thread.join() test_state.last_invoked_param1 = None response = client.invoke(function_name="invoke_test", function_parameters={ "param1": "value1-2viaproxy", "param2": "value2viaproxy" }, time_out_waiting_for_response_in_sec=30) # Wait some time to be sure it has been processed and the system is retrying delivery. time.sleep(5) server_thread = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:51001", rpc_functions={"invoke_test": invoke_test}, username="******", password="******") server_thread.start() # Wait some time to be sure it has been processed and the system is retrying delivery. A retry cycle is max 1 sec. time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "value1-2viaproxy") server_thread.stop() server_thread.join() buf_proxy_rep_req_thread.stop() buf_proxy_rep_req_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
def test_10a_pub_sub_timeout_per_socket_using_heartbeat_function(self): # Basic send/receive over PUB/SUB sockets print "Test a timeout per socket with RPC using heartbeat" client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:47001") server_thread = ZmqRpcServerThread(zmq_sub_connect_addresses=[("tcp://localhost:47001", 3)], rpc_functions={"invoke_test": invoke_test}, recreate_sockets_on_timeout_of_sec=10) server_thread.start() # Slow joiner time.sleep(0.1) first_socket = server_thread.server.sub_sockets[0].zmq_socket client.invoke(function_name="invoke_test", function_parameters={"param1": "testxx-value1", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) # Take 2 seconds to see if it works in case of within the 3 seconds window. time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value1") # Now send another but with 2 seconds delay, which should be ok, then followed by a couple of heartbeats which should keep the existing socket. client.invoke(function_name="invoke_test", function_parameters={"param1": "testxx-value2", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) time.sleep(2) client.send_heartbeat() time.sleep(2) client.send_heartbeat() time.sleep(2) client.send_heartbeat() time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value2") self.assertEqual(server_thread.server.sub_sockets[0].zmq_socket, first_socket) # Now send another but with 4 seconds delay, which should restart the sockets, but message should arrive client.invoke(function_name="invoke_test", function_parameters={"param1": "testxx-value3", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) time.sleep(4) self.assertEquals(test_state.last_invoked_param1, "testxx-value3") second_socket = server_thread.server.sub_sockets[0].zmq_socket self.assertNotEqual(second_socket, first_socket) # Now send another but with 2 seconds delay, which should be ok client.invoke(function_name="invoke_test", function_parameters={"param1": "testxx-value4", "param2": "value2"}, time_out_waiting_for_response_in_sec=3) time.sleep(2) self.assertEquals(test_state.last_invoked_param1, "testxx-value4") self.assertEqual(server_thread.server.sub_sockets[0].zmq_socket, second_socket) server_thread.stop() server_thread.join() client.destroy() # Cleaning up sockets takes some time time.sleep(1)
@copyright: MIT license, see http://opensource.org/licenses/MIT ''' from zmqrpc.ZmqRpcClient import ZmqRpcClient from zmqrpc.ZmqRpcServer import ZmqRpcServerThread import time def test_method(param1, param2): print "test_method invoked with params '{0}' and '{1}'".format( param1, param2) return "test_method response text" if __name__ == '__main__': client = ZmqRpcClient( zmq_req_endpoints=["tcp://localhost:30000"], # List username="******", password="******") server = ZmqRpcServerThread( zmq_rep_bind_address="tcp://*:30000", rpc_functions={"test_method": test_method}, # Dict username="******", password="******") server.start() # Wait a bit since sockets may not have been connected immediately time.sleep(2) # REQ/REQ sockets can carry a response response = client.invoke(function_name="test_method", function_parameters={
@author: Jan Verhoeven @copyright: MIT license, see http://opensource.org/licenses/MIT ''' from zmqrpc.ZmqRpcClient import ZmqRpcClient from zmqrpc.ZmqRpcServer import ZmqRpcServerThread import time def test_method(param1, param2): print "test_method invoked with params '{0}' and '{1}'".format( param1, param2) if __name__ == '__main__': client = ZmqRpcClient(zmq_pub_endpoint="tcp://*:30000") server = ZmqRpcServerThread( zmq_sub_connect_addresses=["tcp://localhost:30000"], # Must be a list rpc_functions={"test_method": test_method}) # Dict server.start() # Wait a bit since sockets may not have been connected immediately time.sleep(2) client.invoke(function_name="test_method", function_parameters={ "param1": "param1", "param2": "param2" }) # Must be dict