def testTimeout(self): # NOTE: This method uses ping/pong packets only because MT connections # don't accept any other packet without specifying a queue. self.handler = EventHandler(self.app) conn = self._makeClientConnection() use_case_list = ( # (a) For a single packet sent at T, # the limit time for the answer is T + (1 * CRITICAL_TIMEOUT) ((), (1., 0)), # (b) Same as (a), even if send another packet at (T + CT/2). # But receiving a packet (at T + CT - ε) resets the timeout # (which means the limit for the 2nd one is T + 2*CT) ((.5, None), (1., 0, 2., 1)), # (c) Same as (b) with a first answer at well before the limit # (T' = T + CT/2). The limit for the second one is T' + CT. ((.1, None, .5, 1), (1.5, 0)), ) def set_time(t): connection.time = lambda: int(CRITICAL_TIMEOUT * (1000 + t)) closed = [] conn.close = lambda: closed.append(connection.time()) def answer(packet_id): p = Packets.Pong() p.setId(packet_id) conn.connector.receive = lambda read_buf: \ read_buf.append(''.join(p.encode())) conn.readable() checkTimeout() conn.process() def checkTimeout(): timeout = conn.getTimeout() if timeout and timeout <= connection.time(): conn.onTimeout() try: for use_case, expected in use_case_list: i = iter(use_case) conn.cur_id = 0 set_time(0) # No timeout when no pending request self.assertEqual(conn._handlers.getNextTimeout(), None) conn.ask(Packets.Ping()) for t in i: set_time(t) checkTimeout() packet_id = i.next() if packet_id is None: conn.ask(Packets.Ping()) else: answer(packet_id) i = iter(expected) for t in i: set_time(t - .1) checkTimeout() set_time(t) # this test method relies on the fact that only # conn.close is called in case of a timeout checkTimeout() self.assertEqual(closed.pop(), connection.time()) answer(i.next()) self.assertFalse(conn.isPending()) self.assertFalse(closed) finally: connection.time = time
def checkTimeout(): timeout = conn.getTimeout() if timeout and timeout <= connection.time(): conn.onTimeout()