def test_it(defer, make_actor1): node1 = Node(nid='localhost:20001', enable_remoting=True) defer(node1.stop) actor1_msgs = obs_list() actor1 = make_actor1(node1, Props(MockActor, actor1_msgs)) # node2 = Node(nid='localhost:20002', enable_remoting=True) defer(node2.stop) actor2_msgs = obs_list() node2.spawn(Props(MockActor, actor2_msgs), name='actor2') # send: node1 -> node2: node1.lookup_str('localhost:20002/actor2') << ('msg-with-ref', actor1) # reply: node2 -> node1: actor2_msgs.wait_eq([ ANY ], "should be able to send messages to explicitly constructed remote refs" ) _, received_ref = actor2_msgs[0] received_ref << ('hello', received_ref) actor1_msgs.wait_eq( [('hello', received_ref)], "should be able to send messages to received remote refs") # send to self without knowing it (_, re_received_ref), = actor1_msgs del actor1_msgs[:] re_received_ref << 'to-myself' actor1_msgs.wait_eq(['to-myself'])
def test_incoming_refs_pointing_to_local_actors_are_converted_to_local_refs( defer): # node1: node1 = Node('localhost:20001', enable_remoting=True) defer(node1.stop) actor1_msgs = obs_list() actor1 = node1.spawn(Props(MockActor, actor1_msgs), name='actor1') # node2: node2 = Node('localhost:20002', enable_remoting=True) defer(node2.stop) actor2_msgs = obs_list() node2.spawn(Props(MockActor, actor2_msgs), name='actor2') # send from node1 -> node2: node1.lookup_str('localhost:20002/actor2') << ('msg-with-ref', actor1) # reply from node2 -> node1: _, received_ref = actor2_msgs.wait_eq([ANY])[0] received_ref << ('msg-with-ref', received_ref) (_, remote_local_ref), = actor1_msgs.wait_eq([ANY]) ok_(remote_local_ref.is_local)
def test_messages_sent_to_nonexistent_remote_actors_are_deadlettered(defer): sender_node, receiver_node = (Node('localhost:20001', enable_remoting=True), Node('localhost:20002', enable_remoting=True)) defer(sender_node.stop, receiver_node.stop) noexist = sender_node.lookup_str('localhost:20002/non-existent-actor') with expect_one_event(DeadLetter): noexist << 'straight-down-the-drain'
def test_node_gc(): node1 = Node(nid='localhost:20001', enable_remoting=False) ref = weakref.ref(node1) node1.stop() node1 = None gc.collect() ok_(not ref()) node2 = Node(nid='localhost:20002', enable_remoting=True) ref = weakref.ref(node2) node2.stop() node2 = None gc.collect() ok_(not ref())
def test_looking_up_addresses_that_actually_point_to_the_local_node_return_a_local_ref( defer): node = Node('localhost:20000', enable_remoting=True) defer(node.stop) node.spawn(Actor, name='localactor') ref = node.lookup_str('localhost:20000/localactor') ok_(ref.is_local)
def test_watching_nonexistent_remote_actor_causes_termination_message(defer): class Watcher(Actor): def pre_start(self): self.watch(watchee) def receive(self, msg): received.set(msg) received = AsyncResult() node1, node2 = (Node('localhost:20001', enable_remoting=True), Node('localhost:20002', enable_remoting=True)) defer(node1.stop, node2.stop) watchee = node1.lookup_str('localhost:20002/nonexistent-watchee') node1.spawn(Watcher) eq_(received.get(), ('terminated', watchee))
def test_watching_running_remote_actor_that_stops_causes_termination_message( defer): class Watcher(Actor): def pre_start(self): self.watch( self.root.node.lookup_str('localhost:20002/remote-watchee')) def receive(self, msg): received.set(msg) received = AsyncResult() node1, node2 = Node('localhost:20001', enable_remoting=True), Node('localhost:20002', enable_remoting=True) defer(node1.stop, node2.stop) remote_watchee = node2.spawn(Actor, name='remote-watchee') node1.spawn(Watcher) remote_watchee.stop() eq_(received.get(), ('terminated', remote_watchee))
def test_urlmatch_with_extra_args_to_responder(defer): node = Node() defer(node.stop) responder = make_responder(lambda req, extra: req.write(str(extra))) rnd_data = bytes(random.random()) responders = [(r'', responder.using(extra=rnd_data))] http_server = node.spawn( HttpServer.using(address=('localhost', 0), responders=responders)) _, port = actor_exec(node, lambda: http_server.ask('get-addr')) eq_(rnd_data, requests.get('http://localhost:%d' % (port, )).text)
def test_sending_to_an_unknown_node_doesnt_start_if_the_node_doesnt_become_visible_and_the_message_is_later_dropped( defer): sender_node = Node('localhost:20001', enable_remoting=True, hub_kwargs={ 'heartbeat_interval': 0.05, 'heartbeat_max_silence': 0.1 }) defer(sender_node.stop) ref = sender_node.lookup_str('localhost:23456/actor2') with expect_one_event(DeadLetter(ref, 'bar', sender=None)): ref << 'bar'
def test_sending_remote_refs(defer): """Sending remote refs. The sender acquires a remote ref to an actor on the target and sends it to the sender, who then sends a message. to the target. It forms a triangle where 1) M obtains a reference to T, 2) sends it over to S, and then 3) S uses it to start communication with T. T ---- S \ / \ / M """ target_node = Node('localhost:20003', enable_remoting=True) defer(target_node.stop) target_msgs = obs_list() target_node.spawn(Props(MockActor, target_msgs), name='T') # sender_node = Node('localhost:20001', enable_remoting=True) defer(sender_node.stop) class SenderActor(Actor): def receive(self, msg): eq_(msg, ('send-msg-to', ANY)) _, target = msg target << 'helo' sender_node.spawn(SenderActor, name='S') # middle_node = Node('localhost:20002', enable_remoting=True) defer(middle_node.stop) ref_to_sender = middle_node.lookup_str('localhost:20001/S') ref_to_target = middle_node.lookup_str('localhost:20003/T') ref_to_sender << ('send-msg-to', ref_to_target) target_msgs.wait_eq(['helo'])
def test_actorref_remote_returns_a_ref_that_when_sent_a_message_delivers_it_on_another_node( defer): # This just tests the routing logic and not heartbeat or reliability or deadletters or anything. # emulate a scenario in which a single node sends many messages to other nodes; # a total of NUM_NODES * NUM_ACTORS messages will be sent out. NUM_NODES = 1 NUM_ACTORS_PER_NODE = 2 sender_node = Node(nid='localhost:20000', enable_remoting=True) defer(sender_node.stop) recipient_nodes = [] for node_ix in range(NUM_NODES): nid = 'localhost:2000%d' % (node_ix + 1, ) remote_node = Node(nid=nid, enable_remoting=True) defer(remote_node.stop) receive_boxes = [] sent_msgs = [] for actor_num in range(1, NUM_ACTORS_PER_NODE + 1): actor_box = obs_list() # collects whatever the MockActor receives actor = remote_node.spawn(Props(MockActor, actor_box), name='actor%d' % actor_num) # we only care about the messages received, not the ref itself receive_boxes.append(actor_box) # format: dummy-<nodename>-<actorname>-<random-stuff-for-good-measure> (just for debuggability) msg = 'dummy-%s-%s-%s' % (nid, actor.uri.name, random.randint(1, 10000000)) sender_node.lookup(actor.uri) << msg sent_msgs.append(msg) recipient_nodes.append((sent_msgs, receive_boxes)) for sent_msgs, receive_boxes in recipient_nodes: for sent_msg, receive_box in zip(sent_msgs, receive_boxes): receive_box.wait_eq(terminator=[sent_msg], timeout=None)
def node(self, nodeid): """Creates a new node with the specified name, with `MockSocket` instances as incoming and outgoing sockets. Returns the implementation object created for the node from the cls, args and address specified, and the sockets. `cls` must be a callable that takes the insock and outsock, and the specified args and kwargs. """ _assert_valid_nodeid(nodeid) # addr = 'tcp://' + nodeid # insock = MockInSocket(addEndpoints=lambda endpoints: self.bind(addr, insock, endpoints)) # outsock = lambda: MockOutSocket(addr, self) return Node(hub=Hub(nodeid=nodeid))
def test_sending_to_an_unknown_host_that_becomes_visible_in_time(defer): node1 = Node('localhost:20001', enable_remoting=True, hub_kwargs={ 'heartbeat_interval': 0.05, 'heartbeat_max_silence': 0.5 }) defer(node1.stop) ref = node1.lookup_str('localhost:20002/actor1') with expect_event_not_emitted(DeadLetter): ref << 'foo' sleep(0.1) node2 = Node('localhost:20002', enable_remoting=True) defer(node2.stop) actor2_msgs = obs_list() node2.spawn(Props(MockActor, actor2_msgs), name='actor1') actor2_msgs.wait_eq(['foo'])
def test_stop(defer): node = Node() defer(node.stop) responders = [] http_server = node.spawn( HttpServer.using(address=('localhost', 0), responders=responders)) _, port = actor_exec(node, lambda: http_server.ask('get-addr')) eq_(404, requests.get('http://localhost:%d' % (port, )).status_code) http_server.stop() with assert_raises(requests.ConnectionError): requests.get('http://localhost:%d' % (port, ))
def test_basic(defer): node = Node() defer(node.stop) responders = [] http_server = node.spawn( HttpServer.using(address=('localhost', 0), responders=responders)) _, port = actor_exec(node, lambda: http_server.ask('get-addr')) eq_(404, requests.get('http://localhost:%d' % (port, )).status_code) rnd_response = str(random.random()) responders[:] = [ (r'^/$', make_responder(lambda request: request.write(rnd_response))), ] eq_(200, requests.get('http://localhost:%d' % (port, )).status_code)
def test_sending_to_a_remote_ref_that_points_to_a_local_ref_is_redirected( defer): node = Node('localhost:20000', enable_remoting=True) defer(node.stop) msgs = obs_list() node.spawn(Props(MockActor, msgs), name='localactor') ref = Ref(cell=None, uri=Uri.parse('localhost:20000/localactor'), is_local=False, node=node) ref << 'foo' msgs.wait_eq(['foo']) ok_(ref.is_local) ref << 'bar' msgs.wait_eq(['foo', 'bar'])
def test_file_upload(defer): node = Node() defer(node.stop) def handle_file(request): request.write(request.files['file'].read()) responders = [(r'^/handle-file$', make_responder(handle_file))] http_server = node.spawn( HttpServer.using(address=('localhost', 0), responders=responders)) _, port = actor_exec(node, lambda: http_server.ask('get-addr')) rnd_data = bytes(random.random()) with tempfile.NamedTemporaryFile() as f: f.write(rnd_data) f.flush() req = requests.post('http://localhost:%d/handle-file' % (port, ), files={'file': open(f.name, 'rb')}) eq_(200, req.status_code) eq_(rnd_data, req.text)
def start_actor(): # if self._nodeid: # log("Setting up remoting; node ID = %s" % (self._nodeid,)) # else: # log("No remoting requested; specify `--remoting/-r <nodeid>` (nodeid=host:port) to set up remoting") self.node = Node(nid=self._nodeid, enable_remoting=True if self._nodeid else False, enable_relay=self._enable_relay) try: self._wrapper = self.node.spawn(Wrapper.using( self._actor_cls.using(**self._init_params), spawn_at=self._name, keep_running=self._keep_running), name='_runner') except Exception: panic("Failed to start wrapper for %s\n" % (actor_path, ), Failure().getTraceback()) reactor.stop() else: if self._initial_message is not _EMPTY: self._wrapper << ('_forward', self._initial_message)
def spin(actor_cls, name=None, init_params={}, node_id=None, initial_messages=[], keep_running=False, enable_relay=False, wrapper_cls=Wrapper): node = Node(nid=node_id, enable_remoting=True if node_id else False, enable_relay=enable_relay) stop_event = Event() node.spawn(wrapper_cls.using(actor_cls.using(**init_params), spawn_at=name, keep_running=keep_running, initial_messages=initial_messages, stop_event=stop_event), name='-runner') try: stop_event.wait() except KeyboardInterrupt: pass finally: node.stop()
def DummyNode(): return Node()