def run(self): client = RPCClient(self.addr) qt = client._import('pyqtgraph.Qt') # widget creation happens in main GUI thread; we are working with # proxies from here. self.l = qt.QtGui.QLabel('remote-controlled label') self.l.show() time.sleep(0.3) self.l.hide() with self.lock: self.done = True
def test_host1(): process_host0 = ProcessSpawner(Host, 'host0', 'tcp://127.0.0.1:*') process_host1 = ProcessSpawner(Host, 'host1', 'tcp://127.0.0.1:*') client0 = RPCClient('host0', process_host0.addr) print('on ping: ', client0.ping()) time.sleep(1.) process_host0.stop() process_host1.stop()
def test_host2(): process_host0 = ProcessSpawner(Host, 'host0', 'tcp://127.0.0.1:*') client0 = RPCClient('host0', process_host0.addr) client0.create_nodegroup('nodegroup 0.1', 'tcp://127.0.0.1:*') client0.create_nodegroup('nodegroup 0.2', 'tcp://127.0.0.1:*') time.sleep(2.) client0.close_nodegroup('nodegroup 0.1') client0.close_nodegroup('nodegroup 0.2') time.sleep(1.) process_host0.stop()
def test_remotly_show_qwidget_node(): name, addr = 'nodegroup0', 'tcp://127.0.0.1:*' process_nodegroup0 = ProcessSpawner(NodeGroup, name, addr) client0 = RPCClient(name, process_nodegroup0.addr) client0.create_node('mynode', '_MyTestNodeQWidget') client0.control_node('mynode', 'show') name, addr = 'nodegroup1', 'tcp://127.0.0.1:*' process_nodegroup1 = ProcessSpawner(NodeGroup, name, addr) client1 = RPCClient(name, process_nodegroup1.addr) client1.create_node('mynode', '_MyTestNodeQWidget') client1.control_node('mynode', 'show') time.sleep(3.) process_nodegroup0.stop() process_nodegroup1.stop()
def bench_ping_pong_nodegroup(): # compare Qt4 mainloop of NodeGroup vs Host main loop which is infinite loop (fastest possible) for name, class_ in [ ('Host', Host), ('NodeGroup', NodeGroup)]: addr = 'tcp://127.0.0.1:*' process = ProcessSpawner(class_, name, addr) client = RPCClient(name, process.addr) N =1000 t1 = time.time() for i in range(N): client.ping() t2 = time.time() print(name, ' : sync ping per second', N/(t2-t1)) t1 = time.time() rets = [] for i in range(N): rets.append(client.ping(_sync=False)) for ret in rets: ret.result() t2 = time.time() print(name, ' : async ping per second', N/(t2-t1)) client.close()
def test_rpc(): previous_level = logger.level #logger.level = logging.DEBUG class TestClass(object): count = 0 def __init__(self, name): self.name = name TestClass.count += 1 def __del__(self): TestClass.count -= 1 def add(self, x, y): return x + y def array(self): return np.arange(20).astype('int64') def sleep(self, t): time.sleep(t) def get_list(self): return [0, 'x', 7] def test(self, obj): return self.name, obj.name, obj.add(5, 7), obj.array(), obj.get_list() def types(self): return {'int': 7, 'float': 0.5, 'str': 'xxx', 'bytes': bytes('xxx', 'utf8'), 'ndarray': np.arange(10), 'dict': {}, 'list': [], 'ObjectProxy': self} def type(self, x): return type(x).__name__ server1 = RPCServer() server1['test_class'] = TestClass server1['my_object'] = TestClass('obj1') serve_thread = threading.Thread(target=server1.run_forever, daemon=True) serve_thread.start() client = RPCClient.get_client(server1.address) # test clients are cached assert client == RPCClient.get_client(server1.address) try: # can't manually create client for the same address RPCClient(server1.address) assert False, "Should have raised KeyError." except KeyError: pass # get proxy to TestClass instance obj = client['my_object'] assert isinstance(obj, ObjectProxy) # check equality with duplicate proxy obj2 = client['my_object'] assert obj == obj2 assert obj._obj_id == obj2._obj_id assert obj._ref_id != obj2._ref_id # check hashability assert obj in {obj2: None} assert obj in set([obj2]) logger.info("-- Test call with sync return --") add = obj.add assert isinstance(add, ObjectProxy) assert add(7, 5) == 12 # test return types for k, v in obj.types().items(): assert type(v).__name__ == k if k != 'ObjectProxy': assert obj.type(v) == k # NOTE: msgpack converts list to tuple. # See: https://github.com/msgpack/msgpack-python/issues/98 assert obj.get_list() == [0, 'x', 7] logger.info("-- Test async return --") fut = obj.sleep(0.1, _sync='async') assert not fut.done() assert fut.result() is None logger.info("-- Test no return --") assert obj.add(1, 2, _sync='off') is None logger.info("-- Test return by proxy --") list_prox = obj.get_list(_return_type='proxy') assert isinstance(list_prox, ObjectProxy) assert list_prox._type_str == "<class 'list'>" assert len(list_prox) == 3 assert list_prox[2] == 7 logger.info("-- Test proxy access to server --") srv = client['self'] assert srv.address == server1.address logger.info("-- Test remote exception raising --") try: obj.add(7, 'x') except RemoteCallException as err: if err.type_str != 'TypeError': raise else: raise AssertionError('should have raised TypeError') try: client.asdffhgk raise AssertionError('should have raised AttributeError') except AttributeError: pass logger.info("-- Test deferred getattr --") arr = obj.array(_return_type='proxy') dt1 = arr.dtype.name._get_value() assert isinstance(dt1, str) arr._set_proxy_options(defer_getattr=True) dt2 = arr.dtype.name assert isinstance(dt2, ObjectProxy) assert dt2._obj_id == arr._obj_id assert dt2._attributes == ('dtype', 'name') dt3 = dt2._undefer() assert dt3 == dt2 logger.info("-- Test remote object creation / deletion --") class_proxy = client['test_class'] obj2 = class_proxy('obj2') assert class_proxy.count == 2 assert obj2.add(3, 4) == 7 obj2._delete() handler.flush_records() # log records might have refs to the object assert class_proxy.count._get_value() == 1 try: obj2.array() assert False, "Should have raised RemoteCallException" except RemoteCallException: pass logger.info("-- Test proxy auto-delete --") obj2 = class_proxy('obj2') obj2._set_proxy_options(auto_delete=True) assert class_proxy.count == 2 del obj2 handler.flush_records() # log records might have refs to the object assert class_proxy.count._get_value() == 1 logger.info("-- Test timeouts --") try: obj.sleep(0.2, _timeout=0.01) except TimeoutError: pass else: raise AssertionError('should have raised TimeoutError') obj.sleep(0.2, _timeout=0.5) logger.info("-- Test result order --") a = obj.add(1, 2, _sync='async') b = obj.add(3, 4, _sync='async') assert b.result() == 7 assert a.result() == 3 logger.info("-- Test transfer --") arr = np.ones(10, dtype='float32') arr_prox = client.transfer(arr) assert arr_prox.dtype.name == 'float32' print(arr_prox, arr_prox.shape) assert arr_prox.shape._get_value() == [10] logger.info("-- Test import --") import os.path as osp rosp = client._import('os.path') assert osp.abspath(osp.dirname(__file__)) == rosp.abspath(rosp.dirname(__file__)) logger.info("-- Test proxy sharing between servers --") obj._set_proxy_options(defer_getattr=True) r1 = obj.test(obj) server2 = RPCServer() server2['test_class'] = TestClass serve_thread2 = threading.Thread(target=server2.run_forever, daemon=True) serve_thread2.start() client2 = RPCClient(server2.address) client2.default_proxy_options['defer_getattr'] = True obj3 = client2['test_class']('obj3') # send proxy from server1 to server2 r2 = obj3.test(obj) # check that we have a new client between the two servers assert (serve_thread2.ident, server1.address) in RPCClient.clients_by_thread # check all communication worked correctly assert r1[0] == 'obj1' assert r2[0] == 'obj3' assert r1[1] == r2[1] == 'obj1' assert r1[2] == r2[2] == 12 assert np.all(r1[3] == r2[3]) assert r1[4] == r2[4] logger.info("-- Test publishing objects --") arr = np.arange(5, 10) client['arr'] = arr # publish to server1 s2rpc = client2._import('pyacq.core.rpc') s2cli = s2rpc.RPCClient.get_client(client.address) # server2's client for server1 assert np.all(s2cli['arr'] == arr) # retrieve via server2 logger.info("-- Test JSON client --") # Start a JSON client in a remote process cli_proc = ProcessSpawner() cli = cli_proc.client._import('pyacq.core.rpc').RPCClient(server2.address, serializer='json') # Check everything is ok.. assert cli.serializer.type._get_value() == 'json' assert cli['test_class']('json-tester').add(3, 4) == 7 cli_proc.kill() logger.info("-- Setup reentrant communication test.. --") class PingPong(object): def set_other(self, o): self.other = o def pingpong(self, depth=0): if depth > 6: return "reentrant!" return self.other.pingpong(depth+1) server1['pp1'] = PingPong() server2['pp2'] = PingPong() pp1 = client['pp1'] pp2 = client2['pp2'] pp1.set_other(pp2) pp2.set_other(pp1) logger.info("-- Test reentrant communication --") assert pp1.pingpong() == 'reentrant!' logger.info("-- Shut down servers --") client2.close_server() serve_thread2.join() client.close_server() client.close() serve_thread.join() logger.level = previous_level
def basic_test_manager(): # Create a local Host to communicate with test_host = ProcessSpawner(Host, name="test-host", addr="tcp://127.0.0.1:*") host_cli = RPCClient(test_host.name, test_host.addr) mgr = ProcessSpawner(Manager, name="manager", addr="tcp://127.0.0.1:*") mcli = RPCClient(mgr.name, mgr.addr) # test connection to host host_name = test_host.name mcli.connect_host(host_name, test_host.addr) assert mcli.list_hosts() == [host_name] # create nodegroup and nodes assert mcli.list_nodegroups(host_name) == [] mcli.create_nodegroup(host_name, "nodegroup1") assert mcli.list_nodegroups(host_name) == ["nodegroup1"] assert mcli.list_nodes("nodegroup1") == [] mcli.create_node("nodegroup1", "node1", "_MyTestNode") assert mcli.list_nodes("nodegroup1") == ["node1"] mcli.control_node("node1", "start") mcli.control_node("node1", "stop") mcli.delete_node("node1") assert mcli.list_nodes("nodegroup1") == [] # mcli.close() # host_cli.close() mgr.stop() test_host.stop()
def test_rpc(): previsous_level = logging.getLogger().level logging.getLogger().level=logging.INFO class Server1(RPCServer): def add(self, a, b): return a + b def sleep(self, t): time.sleep(t) server = Server1(name='some_server', addr='tcp://*:5152') serve_thread = threading.Thread(target=server.run_forever, daemon=True) serve_thread.start() client = RPCClient('some_server', 'tcp://localhost:5152') # atexit.register(client.close) # test call / sync return assert client.add(7, 5) == 12 # test async return fut = client.sleep(0.1, _sync=False) assert not fut.done() assert fut.result() is None # Test remote exception raising try: client.add(7, 'x') except RemoteCallException as err: if err.type_str != 'TypeError': raise else: raise AssertionError('should have raised TypeError') try: client.fn() except RemoteCallException as err: if err.type_str != 'AttributeError': raise else: raise AssertionError('should have raised AttributeError') # test timeouts try: client.sleep(0.2, _timeout=0.01) except TimeoutError: pass else: raise AssertionError('should have raised TimeoutError') # test result order a = client.add(1, 2, _sync=False) b = client.add(3, 4, _sync=False) assert b.result() == 7 assert a.result() == 3 # test multiple clients per server client2 = RPCClient('some_server', 'tcp://localhost:5152') a = client2.add(1, 2, _sync=False) b = client.add(3, 4, _sync=False) c = client2.add(5, 6, _sync=False) assert b.result() == 7 assert a.result() == 3 assert c.result() == 11 # test multiple clients sharing one socket server2 = Server1(name='some_server2', addr='tcp://*:5153') serve_thread2 = threading.Thread(target=server2.run_forever, daemon=True) serve_thread2.start() client3 = RPCClient('some_server2', 'tcp://localhost:5153', rpc_socket=client2._rpc_socket) a = client2.add(1, 2, _sync=False) b = client3.add(3, 4, _sync=False) assert b.result() == 7 assert a.result() == 3 client.close() serve_thread.join() client3.close() serve_thread2.join() logging.getLogger().level=previsous_level
def test_cannot_delete_node_while_running(): name, addr = 'nodegroup', 'tcp://127.0.0.1:*' process_nodegroup0 = ProcessSpawner(NodeGroup, name, addr) client0 = RPCClient(name, process_nodegroup0.addr) client0.create_node('mynode', '_MyTestNode') client0.control_node('mynode', 'configure') client0.control_node('mynode', 'initialize') client0.control_node('mynode', 'start') with pytest.raises(RemoteCallException): # a running node cannot be delete client0.delete_node('mynode') client0.control_node('mynode', 'stop') client0.delete_node('mynode') process_nodegroup0.stop()
def test_nodegroup0(): name, addr = 'nodegroup', 'tcp://127.0.0.1:*' process_nodegroup0 = ProcessSpawner(NodeGroup, name, addr) client0 = RPCClient(name, process_nodegroup0.addr) n = 5 for i in range(n): client0.create_node('mynode{}'.format(i), '_MyTestNode') for i in range(n): client0.control_node('mynode{}'.format(i), 'configure') for i in range(n): client0.control_node('mynode{}'.format(i), 'initialize') for i in range(n): client0.control_node('mynode{}'.format(i), 'start') for i in range(n): client0.control_node('mynode{}'.format(i), 'stop') for i in range(n): client0.delete_node('mynode{}'.format(i)) process_nodegroup0.stop()