From bca1f951ae2567343d5b83cc986e11d6447d492b Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 22 Sep 2021 07:38:12 +0200 Subject: [PATCH] [IMP] ngrok setup / runner Make the startup of ngrok more reliable: in some cases where the machine is heavily loaded a 2s sleep after Popen-ing ngrok is not sufficient, and the following POST still fails. Add a small loop, with a more explicit availability check (and lower the initial check to 1s wait). Also: - make the comments clearer as I'd forgotten half the things - extract the ngrok API base URL (well it should not include /api but...) to its own variable --- conftest.py | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/conftest.py b/conftest.py index 9c441d4f..2bb1d779 100644 --- a/conftest.py +++ b/conftest.py @@ -42,6 +42,7 @@ logic errors. import base64 import collections import configparser +import contextlib import copy import http.client import itertools @@ -174,32 +175,40 @@ def tunnel(pytestconfig, port): """ Creates a tunnel to localhost: using ngrok or localtunnel, should yield the publicly routable address & terminate the process at the end of the session """ - tunnel = pytestconfig.getoption('--tunnel') if tunnel == 'ngrok': + web_addr = 'http://localhost:4040/api' addr = 'localhost:%d' % port - # if ngrok is not running, start it + # try to find out if ngrok is running, and if it's not attempt + # to start it try: - # FIXME: use lockfile instead - time.sleep(random.randint(1, 10)) + # FIXME: this is for xdist to avoid workers running ngrok at the + # exact same time, use lockfile instead + time.sleep(random.SystemRandom().randint(1, 10)) # FIXME: use config file so we can set web_addr to something else # than localhost:4040 (otherwise we can't disambiguate # between the ngrok we started and an ngrok started by # some other user) - requests.get('http://localhost:4040/api') + requests.get(web_addr) except requests.exceptions.ConnectionError: subprocess.Popen(NGROK_CLI, stdout=subprocess.DEVNULL) - time.sleep(2) + for _ in range(5): + time.sleep(1) + with contextlib.suppress(requests.exceptions.ConnectionError): + requests.get(web_addr) + break + else: + raise Exception("Unable to connect to ngrok") - requests.post('http://localhost:4040/api/tunnels', json={ + requests.post(f'{web_addr}/tunnels', json={ 'name': str(port), 'proto': 'http', 'bind_tls': True, # only https 'addr': addr, 'inspect': True, }).raise_for_status() - tunnel = 'http://localhost:4040/api/tunnels/%s' % port + tunnel = f'{web_addr}/tunnels/{port}' for _ in range(10): time.sleep(2) r = requests.get(tunnel) @@ -211,7 +220,7 @@ def tunnel(pytestconfig, port): try: yield r.json()['public_url'] finally: - requests.delete('http://localhost:4040/api/tunnels/%s' % port) + requests.delete(tunnel) for _ in range(10): time.sleep(1) r = requests.get(tunnel) @@ -222,7 +231,7 @@ def tunnel(pytestconfig, port): else: raise TimeoutError("ngrok tunnel deletion failed") - r = requests.get('http://localhost:4040/api/tunnels') + r = requests.get(f'{web_addr}/tunnels') # there are still tunnels in the list -> bail if r.ok and r.json()['tunnels']: return @@ -841,6 +850,10 @@ class PR: def state(self): return self._pr['state'] + @property + def body(self): + return self._pr['body'] + @property def comments(self): r = self.repo._session.get('https://api.github.com/repos/{}/issues/{}/comments'.format(self.repo.name, self.number))