From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- taskcluster/scripts/lib/testrail_conn.py | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 taskcluster/scripts/lib/testrail_conn.py (limited to 'taskcluster/scripts/lib/testrail_conn.py') diff --git a/taskcluster/scripts/lib/testrail_conn.py b/taskcluster/scripts/lib/testrail_conn.py new file mode 100644 index 0000000000..92e3aae275 --- /dev/null +++ b/taskcluster/scripts/lib/testrail_conn.py @@ -0,0 +1,109 @@ +# flake8: noqa + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +"""TestRail API binding for Python 3.x. + +(API v2, available since TestRail 3.0) + +Compatible with TestRail 3.0 and later. + +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. +""" + +import base64 +import json + +import requests + + +class APIClient: + 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, filepath=None): + """Issue a GET request (read) against the API. + + Args: + uri: The API method to call including parameters, e.g. get_case/1. + filepath: The path and file name for attachment download; used only + for 'get_attachment/:attachment_id'. + + Returns: + A dict containing the result of the request. + """ + return self.__send_request("GET", uri, filepath) + + def send_post(self, uri, data): + """Issue a POST request (write) against the API. + + Args: + uri: The API method to call, including parameters, e.g. add_case/1. + data: The data to submit as part of the request as a dict; strings + must be UTF-8 encoded. If adding an attachment, must be the + path to the file. + + Returns: + A dict containing the result of the request. + """ + return self.__send_request("POST", uri, data) + + def __send_request(self, method, uri, data): + url = self.__url + uri + + auth = str( + base64.b64encode(bytes("%s:%s" % (self.user, self.password), "utf-8")), + "ascii", + ).strip() + headers = {"Authorization": "Basic " + auth} + + if method == "POST": + if uri[:14] == "add_attachment": # add_attachment API method + files = {"attachment": (open(data, "rb"))} + response = requests.post(url, headers=headers, files=files) + files["attachment"].close() + else: + headers["Content-Type"] = "application/json" + payload = bytes(json.dumps(data), "utf-8") + response = requests.post(url, headers=headers, data=payload) + else: + headers["Content-Type"] = "application/json" + response = requests.get(url, headers=headers) + + if response.status_code > 201: + try: + error = response.json() + except ( + requests.exceptions.HTTPError + ): # response.content not formatted as JSON + error = str(response.content) + raise APIError( + "TestRail API returned HTTP %s (%s)" % (response.status_code, error) + ) + else: + if uri[:15] == "get_attachment/": # Expecting file, not JSON + try: + open(data, "wb").write(response.content) + return data + except FileNotFoundError: + return "Error saving attachment." + else: + try: + return response.json() + except requests.exceptions.HTTPError: + return {} + + +class APIError(Exception): + pass -- cgit v1.2.3