async def test_cancellable_wait_cancels_subtasks_when_cancelled(event_loop): token = CancelToken("") future = asyncio.ensure_future(token.cancellable_wait(asyncio.sleep(2))) with pytest.raises(asyncio.TimeoutError): # asyncio.wait_for() will timeout and then cancel our cancellable_wait() future, but # Task.cancel() doesn't immediately cancels the task # (https://docs.python.org/3/library/asyncio-task.html#asyncio.Task.cancel), so we need # the sleep below before we check that the task is actually cancelled. await asyncio.wait_for(future, timeout=0.01) await asyncio.sleep(0) assert future.cancelled() await assert_only_current_task_not_done()
def test_token_chain_trigger_chain(): token = CancelToken("token") token2 = CancelToken("token2") token3 = CancelToken("token3") intermediate_chain = token.chain(token2) chain = intermediate_chain.chain(token3) assert not chain.triggered chain.trigger() assert chain.triggered assert not intermediate_chain.triggered assert chain.triggered_token == chain assert not token.triggered assert not token2.triggered assert not token3.triggered
async def test_wait_cancel_pending_tasks_on_cancellation(event_loop): """Test that cancelling a pending CancelToken.wait() coroutine doesn't leave .wait() coroutines for any chained tokens behind. """ token = ( CancelToken("token").chain(CancelToken("token2")).chain(CancelToken("token3")) ) token_wait_coroutine = token.wait() done, pending = await asyncio.wait([token_wait_coroutine], timeout=0.1) assert len(done) == 0 assert len(pending) == 1 pending_task = pending.pop() assert pending_task._coro == token_wait_coroutine pending_task.cancel() await assert_only_current_task_not_done()
def __init__(self, env, master_server, loop): self.loop = loop self.env = env self.master_server = master_server master_server.network = self # cannot say this is a good design self.cancel_token = CancelToken("p2pserver") if env.cluster_config.P2P.BOOT_NODES: bootstrap_nodes = env.cluster_config.P2P.BOOT_NODES.split(",") else: bootstrap_nodes = [] if env.cluster_config.P2P.PRIV_KEY: privkey = keys.PrivateKey(bytes.fromhex(env.cluster_config.P2P.PRIV_KEY)) else: privkey = ecies.generate_privkey() self.server = QuarkServer( privkey=privkey, port=env.cluster_config.P2P_PORT, network_id=env.cluster_config.P2P.NETWORK_ID, bootstrap_nodes=tuple( [kademlia.Node.from_uri(enode) for enode in bootstrap_nodes] ), token=self.cancel_token, upnp=env.cluster_config.P2P.UPNP, )
def get_discovery_protocol(seed=b"seed", address=None): privkey = keys.PrivateKey(keccak(seed)) if address is None: address = random_address() return discovery.DiscoveryProtocol( privkey, address, [], CancelToken("discovery-test") )
def main(): Logger.set_logging_level("debug") loop = asyncio.get_event_loop() loop.set_debug(True) parser = argparse.ArgumentParser() parser.add_argument( "--bootnode", default="enode://c571e0db93d17cc405cb57640826b70588a6a28785f38b21be471c609ca12fcb06cb306ac44872908f5bed99046031a5af82072d484e3ef9029560c1707193a0@127.0.0.1:29000", type=str, ) parser.add_argument("--listen_host", default="127.0.0.1", type=str) parser.add_argument( "--listen_port", default=29000, help="port for discovery UDP and P2P TCP connection", type=int, ) parser.add_argument("--max_peers", default=10, type=int) # private key of the bootnode above is 31552f186bf90908ce386fb547dd0410bf443309125cc43fd0ffd642959bf6d9 parser.add_argument( "--privkey", default="", help="hex string of private key; if empty, will be auto-generated", type=str, ) args = parser.parse_args() if args.privkey: privkey = keys.PrivateKey(bytes.fromhex(args.privkey)) else: privkey = ecies.generate_privkey() addr = kademlia.Address(args.listen_host, args.listen_port, args.listen_port) bootstrap_nodes = tuple([kademlia.Node.from_uri(args.bootnode)]) cancel_token = CancelToken("discovery") discovery = DiscoveryProtocol(privkey, addr, bootstrap_nodes, cancel_token) async def run() -> None: await loop.create_datagram_endpoint( lambda: discovery, local_addr=("0.0.0.0", args.listen_port) ) try: await discovery.bootstrap() while True: Logger.info("Routing table size={}".format(len(discovery.routing))) await cancel_token.cancellable_wait(asyncio.sleep(5)) except OperationCancelled: pass finally: await discovery.stop() for sig in [signal.SIGINT, signal.SIGTERM]: loop.add_signal_handler(sig, cancel_token.trigger) loop.run_until_complete(run()) loop.close()
def main(): parser = argparse.ArgumentParser() parser.add_argument( "--privkey", default="", help="hex string of private key; if empty, will be auto-generated", type=str, ) parser.add_argument( "--listen_port", default=29000, help="port for discovery UDP and P2P TCP connection", type=int, ) parser.add_argument("--logging_level", default="info", type=str) args = parser.parse_args() Logger.set_logging_level(args.logging_level) if args.privkey: privkey = keys.PrivateKey(bytes.fromhex(args.privkey)) else: privkey = ecies.generate_privkey() cancel_token = CancelToken("server") server = ParagonServer( privkey=privkey, port=args.listen_port, network_id=NETWORK_ID, token=cancel_token, ) loop = asyncio.get_event_loop() loop.set_debug(True) for sig in [signal.SIGINT, signal.SIGTERM]: loop.add_signal_handler(sig, cancel_token.trigger) loop.run_until_complete(server.run()) loop.run_until_complete(server.cancel()) loop.close()
def test_token_chain_event_loop_mismatch(): token = CancelToken("token") token2 = CancelToken("token2", loop=asyncio.new_event_loop()) with pytest.raises(EventLoopMismatch): token.chain(token2)
async def test_cancellable_wait_operation_cancelled(event_loop): token = CancelToken("token") token.trigger() with pytest.raises(OperationCancelled): await token.cancellable_wait(asyncio.sleep(0.02)) await assert_only_current_task_not_done()
def test_token_single(): token = CancelToken("token") assert not token.triggered token.trigger() assert token.triggered assert token.triggered_token == token