5
0
mirror of https://github.com/odoo/runbot.git synced 2025-03-16 07:55:45 +07:00

[FIX] *: handle rate limit in pylint tests

With a concurrency of 3 or more, it ends up being pretty easy to hit
github's rate limit (5000 requests/h), at which point the run hits a
cascading failure where every test from thereon blows up to the rate
limiting.

Add a handling for that case in some of the early github-querying
fixtures, so they can wait for the ratelimit delay to be restored.

This increases the need for a proper fake github thingie I could run
on a per-test basis.
This commit is contained in:
Xavier Morel 2020-07-10 12:52:14 +02:00 committed by xmo-odoo
parent 0b1b36d10c
commit 916fb30e75

View File

@ -55,6 +55,7 @@ import time
import uuid
import xmlrpc.client
from contextlib import closing
from datetime import datetime
import psutil
import pytest
@ -105,7 +106,9 @@ def config(pytestconfig):
return cnf
@pytest.fixture(scope='session')
def rolemap(config):
def rolemap(request, config):
# hack because capsys is not session-scoped
capmanager = request.config.pluginmanager.getplugin("capturemanager")
# only fetch github logins once per session
rolemap = {}
for k, data in config.items():
@ -116,7 +119,8 @@ def rolemap(config):
else:
continue
r = requests.get('https://api.github.com/user', headers={'Authorization': 'token %s' % data['token']})
with capmanager.global_and_fixture_disabled():
r = _rate_limited(lambda: requests.get('https://api.github.com/user', headers={'Authorization': 'token %s' % data['token']}))
r.raise_for_status()
rolemap[role] = data['user'] = r.json()['login']
@ -336,14 +340,15 @@ def env(port, server, db, default_crons):
# users is just so I can avoid autouse on toplevel users fixture b/c it (seems
# to) break the existing local tests
@pytest.fixture
def make_repo(request, config, tunnel, users):
def make_repo(capsys, request, config, tunnel, users):
owner = config['github']['owner']
github = requests.Session()
github.headers['Authorization'] = 'token %s' % config['github']['token']
# check whether "owner" is a user or an org, as repo-creation endpoint is
# different
q = github.get('https://api.github.com/users/{}'.format(owner))
with capsys.disabled():
q = _rate_limited(lambda: github.get('https://api.github.com/users/{}'.format(owner)))
q.raise_for_status()
if q.json().get('type') == 'Organization':
endpoint = 'https://api.github.com/orgs/{}/repos'.format(owner)
@ -399,6 +404,20 @@ def make_repo(request, config, tunnel, users):
for repo in reversed(repos):
repo.delete()
def _rate_limited(req):
while True:
q = req()
if not q.ok and q.headers.get('X-RateLimit-Remaining') == '0':
reset = int(q.headers['X-RateLimit-Reset'])
delay = round(reset - time.time() + 1.0)
print("Hit rate limit, sleeping for", delay, "seconds")
time.sleep(delay)
continue
break
return q
Commit = collections.namedtuple('Commit', 'id tree message author committer parents')
class Repo:
def __init__(self, session, fullname, repos):