def test(self): msg_out = clients_msg_f.outgoing_error(tc.SERVER_NODE, 1).stamp(tc.TID) assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(msg_out, tc.CLIENT_ADDR)) # Unknown error doesn't raise m.MsgError msg_out = clients_msg_f.outgoing_error(tc.SERVER_NODE, (1, 1)).stamp(tc.TID) _ = servers_msg_f.incoming_msg(Datagram(msg_out, tc.SERVER_ADDR))
def setup(self): self.ping_r = servers_msg_f.incoming_msg( Datagram(b_ping_r, tc.SERVER_ADDR)) self.fn2_r = servers_msg_f.incoming_msg( Datagram(b_fn2_r, tc.SERVER_ADDR)) self.gp_r = servers_msg_f.incoming_msg(Datagram( b_gp_r, tc.SERVER_ADDR)) self.ap_r = servers_msg_f.incoming_msg(Datagram( b_ap_r, tc.SERVER_ADDR))
def setup(self): self.ping_d = servers_msg_f.incoming_msg( Datagram(b_ping_q, tc.CLIENT_ADDR))._msg_dict self.fn_d = servers_msg_f.incoming_msg(Datagram( b_fn_q, tc.CLIENT_ADDR))._msg_dict self.gp_d = servers_msg_f.incoming_msg(Datagram( b_gp_q, tc.CLIENT_ADDR))._msg_dict self.ap_d = servers_msg_f.incoming_msg(Datagram( b_ap_q, tc.CLIENT_ADDR))._msg_dict
def test_weird_msg(self): self.ping_d[m.ARGS] = [] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.ARGS] = 1 assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.ARGS] = 'ZZZZ' assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR))
def _exchange_msgs(self, outgoing_query, outgoing_response): #client data = outgoing_query.stamp(tc.TID) #server incoming_query = servers_msg_f.incoming_msg( Datagram(data, tc.CLIENT_ADDR)) eq_(incoming_query.type, m.QUERY) data = outgoing_response.stamp(incoming_query.tid) #client incoming_response = clients_msg_f.incoming_msg( Datagram(data, tc.SERVER_ADDR)) ok_(outgoing_query.match_response(incoming_response)) assert incoming_response.type is m.RESPONSE
def test_many_queries(self): # Client creates a query msgs = [ clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) for i in xrange(10) ] queries = msgs # Client registers query bencoded_msg = self.querier.register_queries(queries) # Client sends bencoded_msg time.sleep(1) # response for queries[3] ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp(msgs[3].tid) ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is msgs[3] # error for queries[2] ping_r_msg_out = servers_msg_f.outgoing_error(tc.CLIENT_NODE, message.GENERIC_E) bencoded_r = ping_r_msg_out.stamp(msgs[2].tid) ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is msgs[2] # response to wrong addr ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp(msgs[5].tid) ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER2_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is None # response with wrong tid ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp('ZZ') ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is None # Still no time to trigger timeouts eq_(self.querier.get_timeout_queries()[1], []) time.sleep(1) # Now, the timeouts can be triggered timeout_queries = self.querier.get_timeout_queries() expected_msgs = msgs[:2] + msgs[4:] eq_(len(timeout_queries[1]), len(expected_msgs)) for related_query, expected_msg in zip(timeout_queries[1], expected_msgs): assert related_query is expected_msg
def test_tid_error(self): # no TID del self.msg_d[m.TID] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) # invalid m.TID self.msg_d[m.TID] = 1 assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) self.msg_d[m.TID] = [] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) self.msg_d[m.TID] = {} assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR))
def test_announce_peer(self): #client outgoing_query = clients_msg_f.outgoing_announce_peer_query( tc.SERVER_NODE, tc.INFO_HASH, tc.BT_PORT, tc.TOKEN) data = outgoing_query.stamp(tc.TID) #server incoming_query = servers_msg_f.incoming_msg( Datagram(data, tc.CLIENT_ADDR)) assert incoming_query.type is m.QUERY outgoing_response = servers_msg_f.outgoing_announce_peer_response( tc.CLIENT_NODE) data = outgoing_response.stamp(incoming_query.tid) #client incoming_response = clients_msg_f.incoming_msg( Datagram(data, tc.SERVER_ADDR)) assert incoming_response.type is m.RESPONSE
def test_printing(self): out_msg = clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) in_msg = servers_msg_f.incoming_msg( Datagram(out_msg.stamp(tc.TID), tc.CLIENT_ADDR)) str(out_msg) repr(out_msg) repr(in_msg)
def test_capture(self): self.reactor.start_capture() ts1 = time.time() time.sleep(tc.TASK_INTERVAL/2) # out > DATAGRAM1 (main_loop) self.reactor.run_one_step() ts2 = time.time() incoming_datagram = Datagram(DATA1, tc.SERVER_ADDR) self.reactor.s.put_datagram_received(incoming_datagram) time.sleep(tc.TASK_INTERVAL/2) self.reactor.run_one_step() # in < incoming_datagram (socket) # out > DATAGRAM3 (on_datagram_received) captured_msgs = self.reactor.stop_and_get_capture() eq_(len(captured_msgs), 3) for msg in captured_msgs: print msg assert ts1 < captured_msgs[0][0] < ts2 eq_(captured_msgs[0][1], tc.SERVER_ADDR) eq_(captured_msgs[0][2], True) #outgoing eq_(captured_msgs[0][3], DATA1) assert captured_msgs[1][0] > ts2 eq_(captured_msgs[1][1], DATAGRAM1.addr) eq_(captured_msgs[1][2], False) #incoming eq_(captured_msgs[1][3], DATAGRAM1.data) assert captured_msgs[2][0] > captured_msgs[1][0] eq_(captured_msgs[2][1], DATAGRAM3.addr) eq_(captured_msgs[2][2], True) #outgoing eq_(captured_msgs[2][3], DATAGRAM3.data)
def test_successful_get_peers(self): ts, datagrams = self.controller.main_loop() ping_timeout_ts = ts #FIXME: assert_almost_equal(ts, time.time()+2) ping = datagrams[0].data addr = datagrams[0].addr #fabricate response ping = self.servers_msg_f.incoming_msg(Datagram(ping, addr)) pong = self.servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) data = pong.stamp(ping.tid) # get a node in the routing table self.controller.on_datagram_received(message.Datagram(data, addr)) #The lookup starts with a single node lookup_result = [] datagrams = self.controller.get_peers(lookup_result, tc.INFO_HASH, lambda x, y: x.append(y), 0) #FIXME: assert_almost_equal(ts, ping_timeout_ts)#time.time()+2) #FIXME: eq_(len(datagrams), 1) # Now a get_peers with local results info_hash = identifier.Id('info_hash info_hash ') self.controller._tracker.put(info_hash, tc.CLIENT_ADDR) lookup_result = [] self.controller.get_peers(lookup_result, info_hash, lambda x, y: x.append(y), 0)
def sendto(self, data, addr): if self.raise_error_on_sendto: self.raise_error_on_sendto = False self.num_send_errors += 1 raise socket.error with self.lock: self.datagrams_sent.append(Datagram(data, addr)) return min(20, len(data))
def test_sender_id(self): # no sender_id del self.ping_d[m.ARGS][m.ID] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) # bad ID self.ping_d[m.ARGS][m.ID] = 'a' assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.ARGS][m.ID] = 1 assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.ARGS][m.ID] = [] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.ARGS][m.ID] = {} assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR))
def test_unknown_error(self): error_code = (999, "some weird error string") b_err = clients_msg_f.outgoing_error(tc.SERVER_NODE, error_code).stamp(tc.TID) logger.info( "TEST LOGGING ** IGNORE EXPECTED INFO ** Unknown error: %r", error_code) _ = servers_msg_f.incoming_msg(Datagram(b_err, tc.CLIENT_ADDR))
def test_on_datagram_received_callback(self): eq_(self.datagrams_received, []) self.reactor.run_one_step() eq_(self.datagrams_received, []) datagram = Datagram(DATA1, tc.SERVER_ADDR) # This is equivalent to sending a datagram to reactor self.reactor.s.put_datagram_received(datagram) self.reactor.run_one_step() eq_(len(self.datagrams_received), 1) eq_(self.datagrams_received[0], datagram)
def test_find_node(self): #client outgoing_query = clients_msg_f.outgoing_find_node_query( tc.SERVER_NODE, tc.NODE_ID, None) data = outgoing_query.stamp(tc.TID) #server incoming_query = servers_msg_f.incoming_msg( Datagram(data, tc.CLIENT_ADDR)) assert incoming_query.type is m.QUERY outgoing_response = servers_msg_f.outgoing_find_node_response( tc.CLIENT_NODE, tc.NODES) data = outgoing_response.stamp(incoming_query.tid) #client incoming_response = servers_msg_f.incoming_msg( Datagram(data, tc.SERVER_ADDR)) eq_(incoming_response.type, m.RESPONSE) #incoming_response.sanitize_response(outgoing_query.query) for n1, n2 in zip(tc.NODES, incoming_response.all_nodes): eq_(n1, n2)
def test_get_peers_nodes(self): #client outgoing_query = clients_msg_f.outgoing_get_peers_query( tc.SERVER_NODE, tc.INFO_HASH, None) data = outgoing_query.stamp(tc.TID) #server incoming_query = servers_msg_f.incoming_msg( Datagram(data, tc.CLIENT_ADDR)) assert incoming_query.type is m.QUERY outgoing_response = servers_msg_f.outgoing_get_peers_response( tc.CLIENT_NODE, tc.TOKEN, tc.NODES) data = outgoing_response.stamp(incoming_query.tid) #client incoming_response = clients_msg_f.incoming_msg( Datagram(data, tc.SERVER_ADDR)) assert incoming_response.type is m.RESPONSE #incoming_response.sanitize_response(outgoing_query.query) for n1, n2 in zip(tc.NODES, incoming_response.all_nodes): assert n1 == n2
def test_type_error(self): # no TYPE del self.msg_d[m.TYPE] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) # invalid m.TYPE self.msg_d[m.TYPE] = 1 assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) self.msg_d[m.TYPE] = [] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) self.msg_d[m.TYPE] = {} assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR)) # unknown m.TYPE self.msg_d[m.TYPE] = 'z' assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.msg_d), tc.CLIENT_ADDR))
def test_query(self): # no m.QUERY del self.ping_d[m.QUERY] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) # bad m.QUERY self.ping_d[m.QUERY] = 1 assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.QUERY] = [] assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) self.ping_d[m.QUERY] = {} assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR)) # unknown m.QUERY is not an error at this point # responder will process it and send an errror msg if necesary self.ping_d[m.QUERY] = 'a' servers_msg_f.incoming_msg( Datagram(bencode.encode(self.ping_d), tc.CLIENT_ADDR))
def test_announce_peer_error(self): low_port_announce = clients_msg_f.outgoing_announce_peer_query( tc.SERVER_NODE, tc.INFO_HASH, m.MIN_BT_PORT - 1, tc.TOKEN) high_port_announce = clients_msg_f.outgoing_announce_peer_query( tc.SERVER_NODE, tc.INFO_HASH, m.MAX_BT_PORT + 1, tc.TOKEN) for outgoing_query in (low_port_announce, high_port_announce): #client data = outgoing_query.stamp(tc.TID) #server (port is too low or too high) assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(data, tc.CLIENT_ADDR))
def test_bad_tids(self): # tid must be a non-empty string bad_tids = self.bad_non_empty_string for tid in bad_tids: for msg in self._get_queries() + self._get_responses(): # no tid # msg.stamp adds tid # a direct stamp of the msg._dict produces bencode without tid data = bencode.encode(msg._dict) assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(data, tc.CLIENT_ADDR)) self._check_bad_msg(msg, tid)
def test_unsolicited_response(self): # Server creates unsolicited response # It might well be that the server responds using another port, # and therefore, the addr is not matched # TODO: consider accepting responses from a different port ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp('zz') # The client receives the bencoded message ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is None
def test(self): private_client1 = m.MsgFactory(PYMDHT_VERSION, tc.CLIENT_ID, 'private1') private_server1 = m.MsgFactory(PYMDHT_VERSION, tc.SERVER_ID, 'private1') private_client2 = m.MsgFactory(PYMDHT_VERSION, tc.CLIENT_ID, 'private2') private_server2 = m.MsgFactory(PYMDHT_VERSION, tc.SERVER_ID, 'private2') # Sender doesn't use private flag ping_public = clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) bencoded_public = ping_public.stamp(tc.TID) # Sender uses private flag PRIVATE1 ping_private1 = private_client1.outgoing_ping_query(tc.SERVER_NODE) bencoded_private1 = ping_private1.stamp(tc.TID) # Sender uses private flag PRIVATE2 ping_private2 = private_client2.outgoing_ping_query(tc.SERVER_NODE) bencoded_private2 = ping_private2.stamp(tc.TID) # Receiver in the public DHT accepts messages (ignores private flag) m.private_dht_name = None servers_msg_f.incoming_msg(Datagram(bencoded_public, tc.CLIENT_ADDR)) private_server1.incoming_msg( Datagram(bencoded_private1, tc.CLIENT_ADDR)) private_server2.incoming_msg( Datagram(bencoded_private2, tc.CLIENT_ADDR)) # Receiver in the private DHT accepts ONLY messages from the # private DHT it belongs to assert_raises(m.MsgError, private_server1.incoming_msg, Datagram(bencoded_public, tc.CLIENT_ADDR)) private_server1.incoming_msg( Datagram(bencoded_private1, tc.CLIENT_ADDR)) assert_raises(m.MsgError, private_server1.incoming_msg, Datagram(bencoded_private2, tc.CLIENT_ADDR))
def test_block_flood(self): from floodbarrier import MAX_PACKETS_PER_PERIOD as FLOOD_LIMIT for _ in xrange(FLOOD_LIMIT * 2): self.reactor.s.put_datagram_received(Datagram(DATA1, tc.SERVER_ADDR)) for i in xrange(FLOOD_LIMIT): eq_(len(self.datagrams_received), i) self.reactor.run_one_step() eq_(len(self.datagrams_received), FLOOD_LIMIT) for i in xrange(FLOOD_LIMIT): eq_(len(self.datagrams_received), FLOOD_LIMIT) logger.warning( "TESTING LOGS ** IGNORE EXPECTED WARNING **") self.reactor.run_one_step() eq_(len(self.datagrams_received), FLOOD_LIMIT)
def run_one_step(self): """Main loop activated by calling self.start()""" # Deal with call_asap requests # TODO: retry for 5 seconds if no msgs_to_send (inside controller?) call_asap_tuple = None self._lock.acquire() try: if self._call_asap_queue: call_asap_tuple = self._call_asap_queue.pop(0) finally: self._lock.release() if call_asap_tuple: callback_f, args, kwds = call_asap_tuple datagrams_to_send = callback_f(*args, **kwds) for datagram in datagrams_to_send: self._sendto(datagram) # Call main_loop if time.time() >= self._next_main_loop_call_ts: (self._next_main_loop_call_ts, datagrams_to_send) = self._main_loop_f() for datagram in datagrams_to_send: self._sendto(datagram) # Get data from the network try: data, addr = self.s.recvfrom(BUFFER_SIZE) except (socket.timeout): pass # timeout except (socket.error) as e: logger.warning('Got socket.error when receiving data:\n%s' % e) else: self._add_capture((time.time(), addr, False, data)) ip_is_blocked = self.floodbarrier_active and \ self.floodbarrier.ip_blocked(addr[0]) if ip_is_blocked: import sys # print >>sys.stderr, '>>>>>>>>>>>>>>>>>>', addr # print >>sys.stderr, '>>>>>>>>>>>>>>>>>>', `addr` logger.warning("blocked") # print >>sys.stderr, '>>>>>>>>>>>>>>>>>> DONE' return datagram_received = Datagram(data, addr) (self._next_main_loop_call_ts, datagrams_to_send ) = self._on_datagram_received_f(datagram_received) for datagram in datagrams_to_send: self._sendto(datagram)
def test_bad_bencode(self): bencodes = ( '11', '11:', '2:zzz', 'a', # invalid bencode 'l' * 20 + 'e' * 20, # invalid bencode (recursivity) 'li1ee', 'i1e', '1:a', 'llee', # not a dictionary 'de', # empty dictionary ) for data in bencodes: assert_raises(m.MsgError, servers_msg_f.incoming_msg, Datagram(data, tc.CLIENT_ADDR))
def test_response_with_different_tid(self): # Client creates a query ping_msg = clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) q = ping_msg # Client registers query bencoded_msg = self.querier.register_queries([q]) # Client sends bencoded_msg time.sleep(1) # Server gets bencoded_msg and creates response ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp('zz') # The client receives the bencoded message ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is None
def test_error_received(self): # Client creates a query msg = clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) q = msg # Client registers query bencoded_msg = self.querier.register_queries([q]) # Client sends bencoded_msg time.sleep(1) # Server gets bencoded_msg and creates response ping_r_msg_out = servers_msg_f.outgoing_error(tc.CLIENT_NODE, message.GENERIC_E) bencoded_r = ping_r_msg_out.stamp(msg.tid) # The client receives the bencoded message ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is msg
def test_ping_with_reponse(self): # Client creates a query ping_msg = clients_msg_f.outgoing_ping_query(tc.SERVER_NODE) q = ping_msg # Client registers query timeout_ts, bencoded_msgs = self.querier.register_queries([q]) # Client sends bencoded_msg # Server gets bencoded_msg and creates response ping_r_msg_out = servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE) bencoded_r = ping_r_msg_out.stamp(ping_msg.tid) time.sleep(1) eq_(self.querier.get_timeout_queries()[1], []) # The client receives the bencoded message (after 1 second) ping_r_in = clients_msg_f.incoming_msg( Datagram(bencoded_r, tc.SERVER_ADDR)) related_query = self.querier.get_related_query(ping_r_in) assert related_query is ping_msg
def test_adding_and_removing_node(self): # The routing table is initially empty eq_(self.controller._routing_m.get_main_rnodes(), []) q = self.controller.msg_f.outgoing_ping_query(tc.SERVER_NODE) expected_ts, expected_datagrams = self.querier2.register_queries([q]) # main_loop is called by reactor.start() # It returns a maintenance ping ts, datagrams = self.controller.main_loop() #FIXME: assert_almost_equal(ts, expected_ts) eq_(len(datagrams), 1) eq_(datagrams[0], expected_datagrams[0]) time.sleep((ts - time.time()) / 2) # SERVER_NODE gets msg and replies before the timeout tid = self.servers_msg_f.incoming_msg( Datagram(datagrams[0].data, tc.CLIENT_ADDR)).tid data = self.servers_msg_f.outgoing_ping_response( tc.CLIENT_NODE).stamp(tid) eq_(self.controller._routing_m.get_main_rnodes(), []) datagram = message.Datagram(data, tc.SERVER_ADDR) self.controller.on_datagram_received(datagram) # SERVER_NODE is added to the routing table eq_(self.controller._routing_m.get_main_rnodes(), [tc.SERVER_NODE]) time.sleep((ts - time.time())) # main_loop is called to trigger timeout # It returns a maintenance lookup ts, datagrams = self.controller.main_loop() q = self.controller.msg_f.outgoing_find_node_query( tc.SERVER_NODE, self.my_id, None) expected_ts, expected_datagrams = self.querier2.register_queries([q]) #FIXME: assert_almost_equal(ts, expected_ts) #FIXME: eq_(len(datagrams), 1) #FIXME: eq_(datagrams[0], expected_datagrams[0]) time.sleep(ts - time.time()) # main_loop is called to trigger timeout # It triggers a timeout (removing SERVER_NODE from the routing table # returns a maintenance ping ts, datagrams = self.controller.main_loop() #FIXME: eq_(self.controller._routing_m.get_main_rnodes(), []) # No reply for this query #this call should trigger timeout self.controller.main_loop()