fuel-qa/fuelweb_test/testrail/testrail.py
Artem Panchenko b5333c09ab [TestRail] Wait up to 10 min for API is up
Since time to time TestRail goes down (service
unavailable error is recieved on all requests),
added 503 code to known errors and 10 retries w/
60 seconds sleep for such cases.

Default sleep value was increased from 5 to 60
seconds, because 429 error is always returned
w/ 'retry-after' header, so it will be used
for handling 503 error only.

Change-Id: I87cf4b422d992267d39623d552de19664f000af9
Closes-bug: #1588793
2016-06-05 21:45:18 +00:00

117 lines
3.6 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# TestRail API binding for Python 2.x (API v2, available since
# TestRail 3.0)
#
# Learn more:
#
# http://docs.gurock.com/testrail-api2/start
# http://docs.gurock.com/testrail-api2/accessing
#
# Copyright Gurock Software GmbH. See license.md for details.
#
from __future__ import unicode_literals
import base64
import time
import requests
from requests.exceptions import HTTPError
from requests.packages.urllib3 import disable_warnings
from fuelweb_test.testrail.settings import logger
disable_warnings()
def request_retry(codes):
log_msg = "Got {0} Error! Waiting {1} seconds and trying again..."
def retry_request(func):
def wrapper(*args, **kwargs):
iter_number = 0
while True:
try:
response = func(*args, **kwargs)
response.raise_for_status()
except HTTPError as e:
error_code = e.response.status_code
if error_code in codes:
if iter_number < codes[error_code]:
wait = 60
if 'Retry-After' in e.response.headers:
wait = int(e.response.headers['Retry-after'])
logger.debug(log_msg.format(error_code, wait))
time.sleep(wait)
iter_number += 1
continue
raise
else:
return response.json()
return wrapper
return retry_request
class APIClient(object):
"""APIClient.""" # TODO documentation
def __init__(self, base_url):
self.user = ''
self.password = ''
if not base_url.endswith('/'):
base_url += '/'
self.__url = base_url + 'index.php?/api/v2/'
def send_get(self, uri):
return self.__send_request('GET', uri, None)
def send_post(self, uri, data):
return self.__send_request('POST', uri, data)
def __send_request(self, method, uri, data):
retry_codes = {429: 3,
503: 10}
@request_retry(codes=retry_codes)
def __get_response(_url, _headers, _data):
if method == 'POST':
return requests.post(_url, json=_data, headers=_headers)
return requests.get(_url, headers=_headers)
url = self.__url + uri
auth = base64.encodestring(
'{0}:{1}'.format(self.user, self.password)).strip()
headers = {'Authorization': 'Basic {}'.format(auth),
'Content-Type': 'application/json'}
try:
return __get_response(url, headers, data)
except HTTPError as e:
if e.message:
error = e.message
else:
error = 'No additional error message received'
raise APIError('TestRail API returned HTTP {0}: "{1}"'.format(
e.response.status_code, error))
class APIError(Exception):
"""APIError.""" # TODO documentation
pass