コード例 #1
0
    def __init__(self,
                 host,
                 user,
                 password,
                 file_path,
                 section_id,
                 file_format='robot'):
        """
        :param host: test rail host
        :param user: user name
        :param password: password
        :param file_path: path of test case files or directory
        :param section_id: section to store auto test cases
        :param file_format: default to be .robot
        """
        testrail_url = 'http://' + host + '/testrail/'
        self.client = APIClient(testrail_url, user, password)
        self.file = list()
        # to loop through the test suites
        try:
            if os.path.isdir(file_path):
                for files in os.walk(file_path):
                    for robot_file in filter(lambda x: x.endswith('.robot'),
                                             files[2]):
                        self.file.append(
                            TestData(source=os.path.abspath(
                                os.path.join(files[0], robot_file))))
            else:
                self.file.append(TestData(source=file_path))
        except DataError as e:
            # .robot file may have no test cases in it
            logging.warn('[TestRailTagger]' + e.message)

        self.section = section_id
        self.writer = DataFileWriter(format=file_format)
コード例 #2
0
def main():
    # Declare TestRail API
    testrail_api = APIClient(TESTRAIL_URL)
    testrail_api.user = TESTRAIL_EMAIL_ADDRESS
    testrail_api.password = TESTRAIL_API_TOKEN

    # Retrieve all sections for the project
    all_sections = testrail_api.send_get('get_sections/' + str(PROJECT_ID))

    # all_results will hold all test results and will be the body of the result submission to TestRail
    all_results = dict()
    all_results['results'] = list()
    all_results['results'] += run_tests(all_sections, testrail_api)

    # Create test run
    new_run = testrail_api.send_post('add_run/' + str(PROJECT_ID), {
        "name": "Webinar Math Tests",
        "include_all": True
    })
    # add results
    run_results = testrail_api.send_post(
        'add_results_for_cases/' + str(new_run['id']), all_results)

    # Close test run
    testrail_api.send_post('close_run/' + str(new_run['id']), {})

    # Display some stuff
    # print(all_results)
    print('Testing Complete!\nResults available here: ' + TESTRAIL_URL +
          'index.php?/runs/view/' + str(new_run['id']))
    pass
コード例 #3
0
    def __init__(self, run_id, update = None):
        """
        *Args:*\n
        _server_ - the name of TestRail server;
        _user_ - the name of TestRail user;
        _password_ - the password of TestRail user;
        _run_id -  the ID of the test run;
        _update_ - indicator to update test case in TestRail; if exist, then test will be updated.
        """

        user = '******'
        password = '******'
        url = 'https://csod.testrail.net'

        testrail_url = url
        self.client = APIClient(testrail_url)
        self.client.user = user
        self.client.password = password
        self.run_id = run_id
        self.update = update
        self.results = list()
        logger.info('[TestRailListener] url: ' + testrail_url)
        logger.info('[TestRailListener] user: '******'[TestRailListener] password: '******'[TestRailListener] the ID of the test run: ' + run_id)
コード例 #4
0
    def __init__(self, host, user, password,
                 file_path, section_id,
                 file_format='robot'):
        """
        :param host: test rail host
        :param user: user name
        :param password: password
        :param file_path: path of test case files or directory
        :param section_id: section to store auto test cases
        :param file_format: default to be .robot
        """
        testrail_url = 'http://' + host + '/testrail/'
        self.client = APIClient(testrail_url, user, password)
        self.file = list()
        # to loop through the test suites
        try:
            if os.path.isdir(file_path):
                for files in os.walk(file_path):
                    for robot_file in filter(lambda x: x.endswith('.robot'), files[2]):
                            self.file.append(
                                TestData(
                                    source=os.path.abspath(os.path.join(files[0],
                                                                        robot_file))
                                )
                            )
            else:
                self.file.append(TestData(source=file_path))
        except DataError as e:
            # .robot file may have no test cases in it
            logging.warn('[TestRailTagger]' + e.message)

        self.section = section_id
        self.writer = DataFileWriter(format=file_format)
コード例 #5
0
    def __init__(self, username='', password='', url=''):
        self.username = username
        self.password = password
        self.url = url

        if not username:
            self.username = settings.USR
        if not password:
            self.password = settings.PWD
        if not url:
            self.url = settings.URL

        client = APIClient(self.url)
        client.user = self.username
        client.password = self.password

        self.client = client
        self.parser = None
コード例 #6
0
    def __init__(self, server, user, password, run_id, update = None):
        """
        *Args:*\n
        _server_ - the name of TestRail server;
        _user_ - the name of TestRail user;
        _password_ - the password of TestRail user;
        _run_id -  the ID of the test run;
        _update_ - indicator to update test case in TestRail; if exist, then test will be updated.
        """

        testrail_url = 'http://' + server + '/testrail/'
        self.client = APIClient(testrail_url)
        self.client.user = user
        self.client.password = password
        self.run_id = run_id
        self.update = update
        self.results = list()
        logger.info('[TestRailListener] url: ' + testrail_url)
        logger.info('[TestRailListener] user: '******'[TestRailListener] password: '******'[TestRailListener] the ID of the test run: ' + run_id)
コード例 #7
0
    def __init__(self, tr_server, user_name, password):
        """
        This method will initialize the TestRail server using the user name and password provided
        :param tr_server: Name of the Test Rail server
        :param user_name: TestRail user id
        :param password:  TestRail password
        """
        file_dir = os.path.split(os.path.realpath(__file__))[0]
        logging.config.fileConfig(os.path.join(file_dir, "trlogger.ini"))
        # Configure the logger
        self._log = logging.getLogger('testrail')
        self._log.info("Starting TestRail application ")

        # TestRail Connection status
        # Note: This variable is used to ensure we have a valid TestRail Instance
        self._connection_status = False
        try:
            # Check if the URL is valid
            self._client = APIClient(tr_server)
            self._client.password = password
            self._client.user = user_name
            self._connection_status = True
            # Check if the url, user name and password is set correctly by accessing an API
            self._client.send_get(Defines.TR_API_GET_PROJ + "/" +
                                  str(Defines.TR_PROJ_ID_OTG))
            self._log.info(
                "Connected to TestRail server {} with user-id {}".format(
                    tr_server, user_name))
        except err.URLError:
            self._log.exception("Url: {} is not valid".format(tr_server))
            raise err.URLError("Error: Please check the URL")
        except APIError:
            self._log.critical(
                "User-id or Password is not correct. Failed to connect with TestRail url: {}"
                .format(tr_server))
            raise APIError("Error: Please check user id and password")
コード例 #8
0
    def __init__(self, server, user, password, run_id, update = None):
        """
        *Args:*\n
        _server_ - the name of TestRail server;
        _user_ - the name of TestRail user;
        _password_ - the password of TestRail user;
        _run_id -  the ID of the test run;
        _update_ - indicator to update test case in TestRail; if exist, then test will be updated.
        """

        testrail_url = 'http://' + server + '/testrail/'
        self.client = APIClient(testrail_url)
        self.client.user = user
        self.client.password = password
        self.run_id = run_id
        self.update = update
        self.results = list()
        logger.info('[TestRailListener] url: ' + testrail_url)
        logger.info('[TestRailListener] user: '******'[TestRailListener] password: '******'[TestRailListener] the ID of the test run: ' + run_id)
コード例 #9
0
from testrail import APIClient
import sys

#connection information
client = APIClient('https://testplant.testrail.net/')
client.user = '******'
client.password = '******'

#open the RunHistory.csv file, then check if the last line includes the word "Success"
#(The latest result is in the last line)
#f = open('C:/Workspaces/ePF/TestRailSample/TestRail_sample.suite/Results/main/RunHistory.csv')
resultFolder = sys.argv[1]
print resultFolder
sys.exit()

lastLine = f.readlines()[-1] # Read the last line of the results file
f.close()
fields = lastLine.split(',') # Split the line into comma separated fields

if len(fields) != 10:
	print("Error: Last line of RunHistory has fewer than 10 fields")
	sys.exit()

if fields[1].find('Success') >= 0:
    print ('Last Run: Success')

    result = client.send_post(
        'add_result_for_case/1/1',
        {'status_id': 1, 'comment': fields[8]}
    )
elif fields[1].find ('Failure') > 0:
コード例 #10
0
class TestRailTagger(object):
    """
    class to register robot's test cases in test rail
    and then add corresponding tags to robot's test cases
    """

    def __init__(self, host, user, password,
                 file_path, section_id,
                 file_format='robot'):
        """
        :param host: test rail host
        :param user: user name
        :param password: password
        :param file_path: path of test case files or directory
        :param section_id: section to store auto test cases
        :param file_format: default to be .robot
        """
        testrail_url = 'http://' + host + '/testrail/'
        self.client = APIClient(testrail_url, user, password)
        self.file = list()
        # to loop through the test suites
        try:
            if os.path.isdir(file_path):
                for files in os.walk(file_path):
                    for robot_file in filter(lambda x: x.endswith('.robot'), files[2]):
                            self.file.append(
                                TestData(
                                    source=os.path.abspath(os.path.join(files[0],
                                                                        robot_file))
                                )
                            )
            else:
                self.file.append(TestData(source=file_path))
        except DataError as e:
            # .robot file may have no test cases in it
            logging.warn('[TestRailTagger]' + e.message)

        self.section = section_id
        self.writer = DataFileWriter(format=file_format)

    def add_tag(self):
        """
        add specific tags to test cases
        """
        for suite in self.file:
            # to handle force tags, delete force tags in setting table
            # and then add the tag value to each test case in a suite
            force_tags = suite.setting_table.force_tags.value
            suite.setting_table.force_tags.value = None
            for test in suite.testcase_table.tests:
                getattr(self, TAG_TYPE['testRail'])(test, suite, force_tags)

    def add_test_rail_id(self, test, test_case_file, other_tags):
        """
        register test case and add the test case id to .robot file
        :param test: TestData class object, one of test cases
                    read from goven .robot file
        :param test_case_file: the .robot file to write (add tags)
        :param other_tags: param for the force tags(also for other tags)
        """
        if test.tags.value is None:
            test.tags.value = list()
        tags_value = getTagsValue(test.tags.value)
        case_id = tags_value.get('testRailId')
        if case_id is None:
            res = self.client.send_post(
                        'add_case/{section_id}'.format(section_id=self.section),
                        {
                            'title': 'Auto-' + test.name,
                            'type_id': 1,
                            'priority_id': 3,
                            'estimate': '1h',
                            'refs': '',
                            'custom_steps': [
                                {
                                    'content': getattr(step, 'name', ''),
                                    'expected': 'auto-results'
                                } for step in test.steps if step
                            ]
                        }
                    )
            case_id = res.get('id')
            logging.info('[TestRailTagger] register test {case_id} to TestRail'
                         .format(case_id=case_id))
            test.tags.value.append(TEST_RAIL_ID_TEMPLATE.format(case_id=case_id))
            test.tags.value += other_tags
            self.writer.write(test_case_file)
コード例 #11
0
class TestRailLib:
    """
    This class contains methods for accessing TestRail API's.
    For more information : https://www.gurock.com/testrail
    """
    def __init__(self, tr_server, user_name, password):
        """
        This method will initialize the TestRail server using the user name and password provided
        :param tr_server: Name of the Test Rail server
        :param user_name: TestRail user id
        :param password:  TestRail password
        """
        file_dir = os.path.split(os.path.realpath(__file__))[0]
        logging.config.fileConfig(os.path.join(file_dir, "trlogger.ini"))
        # Configure the logger
        self._log = logging.getLogger('testrail')
        self._log.info("Starting TestRail application ")

        # TestRail Connection status
        # Note: This variable is used to ensure we have a valid TestRail Instance
        self._connection_status = False
        try:
            # Check if the URL is valid
            self._client = APIClient(tr_server)
            self._client.password = password
            self._client.user = user_name
            self._connection_status = True
            # Check if the url, user name and password is set correctly by accessing an API
            self._client.send_get(Defines.TR_API_GET_PROJ + "/" +
                                  str(Defines.TR_PROJ_ID_OTG))
            self._log.info(
                "Connected to TestRail server {} with user-id {}".format(
                    tr_server, user_name))
        except err.URLError:
            self._log.exception("Url: {} is not valid".format(tr_server))
            raise err.URLError("Error: Please check the URL")
        except APIError:
            self._log.critical(
                "User-id or Password is not correct. Failed to connect with TestRail url: {}"
                .format(tr_server))
            raise APIError("Error: Please check user id and password")

    def __extract_dictionary(self,
                             src_dict,
                             extract_list,
                             dict_type=Defines.DICT_SUB,
                             ret_dict_key=Defines.TR_TP_ID):
        """
        This method will extract and create a new dictionary based on the attributes passed.
        The extraction can be done on a single plain dictionary or dictionary within a dictionary.
        Note: The ret_dict_key must be an unique identifier as its the ret_dict key.
        :param src_dict: Source dictionary
        :param extract_list:  List of keys to be extracted
        :param dict_type: This parameter determines if we need to extract values from simple dictionary
        or sub dictionaries
        :param ret_dict_key:  Key that must be used for return dictionary
        :return: List of dictionary with ret_dict_key as key.
        Example output ret_dict = { 1:{'description':'Example 1'} , 2: {'description': 'Example 2} }
        """
        if extract_list:
            # Extracting list containing dictionary of dictionary ( sub dictionary)
            # Example [ 1:{'description':'Example 1'} , 2: {'description': 'Example 2} ]
            if dict_type in Defines.DICT_SUB:
                ret_dict = []
                # This code applies on sub dictionary
                for src_key in src_dict:
                    tmp_list = {}
                    for extract_key in extract_list:
                        # Check if the key is present in source dictionary ( dictionary of dictionary)
                        if extract_key in src_key:
                            tmp_list[extract_key] = src_key[extract_key]
                        else:
                            self._log.info(
                                "{} is invalid key or not present in the source dictionary"
                                .format(extract_key))
                    # update the return dictionary with key as the plan id
                    if dict_type in Defines.DICT_SUB:
                        ret_dict.append({src_key[ret_dict_key]: tmp_list})
                    else:
                        ret_dict.append(tmp_list)
            else:
                # Extracting items from Plain dictionary
                # In simple scenario it will return a dictionary not a list
                ret_dict = {}
                for extract_key in extract_list:
                    if extract_key in src_dict:
                        ret_dict[extract_key] = src_dict[extract_key]
        else:
            self._log.debug("Nothing to extract. All items will be returned")
            ret_dict = src_dict
        return ret_dict

    def count_values_in_sub_dict(self, dict_list, grp_item_key):
        """
        This method will group and count the keys of a sub dictionary
        See the example in the doc string for output
        :param dict_list: Input dictionary
        :param grp_item_key: key which needs to be grouped
        :return: count of the values in the sub dictionary
        Example : [ A:{color:'a'}, B:{color:'b'}, C:{color:'a'}, D:{color:'a'}]
        output: {a:3, b1}
        """
        ret_dict = {}
        cnt = 1
        try:
            for list_items in dict_list:
                for key, value in list_items.items():
                    if value[grp_item_key] in ret_dict:
                        ret_dict[value[grp_item_key]] = ret_dict[
                            value[grp_item_key]] + 1
                    else:
                        ret_dict[value[grp_item_key]] = cnt
        except KeyError:
            self._log.exception("KeyError Exception for key ")
        return ret_dict

    def tr_api_post(self, api, params):
        """
        This method is a wrapper method to call the POST methods of TestRail
        :param api:  Test Rail API
        :param params: Post parameters for the Test Rail API.
        :return: True, message or False, Message
                 True with and the return message will vary depending on
                 the api requested
                 False with and the return message will be the exception caught
        """
        status = False
        try:
            return_msg = self._client.send_post(api, params)
            status = True
            self._log.info(
                "Successfully sent data using POST method. API = {} Data = {}".
                format(api, params))
        except APIError as e:
            self._log.exception(
                "API Exception for api POST {} - Exception: {}".format(api, e))
            return_msg = e
        return status, return_msg

    def tr_api_get(self, api, params):
        """
        This method is a wrapper method to call the GET methods of TestRail
        apends the TestRail API and the parameters.
        :param api: TestRail api to be called ( Example: get_case)
        :param params: The GET parameters for  API Methods
        :return: True, message or False, Message
                 True with and the return message will vary depending on
                 the api requested
                 False with and the return message will be the exception caught
        """
        status = False
        try:
            return_msg = self._client.send_get(api + "/" + str(params))
            status = True
            self._log.info(
                "Successfully sent data using GET method. API = {} Data = {}".
                format(api, params))
        except APIError as e:
            self._log.exception(
                "API Exception for api GET {} - Exception: {}".format(api, e))
            return_msg = e
        return status, return_msg

    # Methods for TestRail Test Plans
    def tr_get_all_plans(self, project_id, project_fields):
        """
        This method will extract all the plans for a project. We can specify what attribute of TestRail project
        We want to extract using project_fields.
        :param project_id: Project id ( Example 1)
        :param project_fields: This is a list of fields needed for project
         Example: project passed count, failed count etc
        :return: status( Boolean) and ret_list : list of Plans with attributes from project_fields
        """
        ret_dict = None
        status, ret_list = self.tr_api_get(Defines.TR_API_GET_PLANS,
                                           project_id)
        if status:
            ret_dict = self.__extract_dictionary(ret_list, project_fields)
        return status, ret_dict

    def tr_get_tc_suites_in_project(self,
                                    project_id=Defines.TR_CURRENT_PROJECT,
                                    extract_list=None):
        """
        This method will get the suites available in the TestRail project
        :param project_id: Project id
        :param extract_list: The attribute required to be extracted from test suites
        :return: Dictionary of project test suites with the attributes mentioned in extract_list
        """
        # If the extract list is none at least extract the description
        if extract_list is None:
            extract_list = [Defines.TR_TS_DESCRIPTION]

        ret_dict = {}
        ret_status, suite_list = self.tr_api_get(Defines.TR_API_GET_SUITES,
                                                 project_id)
        if ret_status:
            ret_dict = self.__extract_dictionary(suite_list,
                                                 extract_list,
                                                 ret_dict_key=Defines.TR_TS_ID)
        else:
            self._log.error("Error in getting test suites")
        return ret_status, ret_dict

    def tr_get_tescase_in_run(self, run_id, extract_list=None):
        """
        This method will extract all the test for a run. You can pass what you want to extract using extract_list.
        :param run_id: Test run id
        :param extract_list: attributes that needs to be extracted
        :return: list of dictionaries containing the test case information
        """
        ret_list = []
        # if the extract list is None. Extract the Description and automated fields
        if extract_list is None:
            extract_list = [
                Defines.TR_TC_CUSTOM_TEST_DESCRIPTION,
                Defines.TR_TC_CUSTOM_AUTOMATED
            ]
        status, tc_list = self.tr_api_get(Defines.TR_TESTS_GET_TESTS, run_id)
        if status:
            # For each test extract the required elements
            for tst in tc_list:
                ret_list.append(
                    self.__extract_dictionary(tst,
                                              extract_list,
                                              dict_type=Defines.DICT_SIMPLE))
            self._log.info(
                "Extracted test cases successfully from run {}".format(run_id))
        else:
            self._log.error(
                "Error in extracting the test cases for run {}".format(run_id))
        return status, ret_list

    def tr_get_test_cases(self, suite_id, extract_list=None):
        """
        This method will get all the test cases of a suite. A suite in TestRail contains collection of
        test cases
        :param suite_id: suite id from TestRail
        :param extract_list: attribuites needed to extract for each test case. Use the TR_TC_XXXX attributes
        :return: Status , dictionary of test cases available for the suite
        """
        ret_dict = {}
        # if the extract list is none extract the description and created by fields
        if extract_list is None:
            extract_list = [
                Defines.TR_TC_CUSTOM_TEST_DESCRIPTION, Defines.TR_TC_CREATED_BY
            ]
        qry_str = str(Defines.TR_CURRENT_PROJECT
                      ) + "&" + Defines.TR_TS_SUITE_ID + "=" + str(suite_id)
        status, ret_list = self.tr_api_get(Defines.TR_API_GET_CASES, qry_str)
        if status:
            ret_dict = self.__extract_dictionary(ret_list,
                                                 extract_list,
                                                 ret_dict_key=Defines.TR_TC_ID)
        else:
            self._log.error("Error in getting the test case")
        return status, ret_dict

    def tr_get_test_case_info(self, tc_id, extract_list=None):
        ret_dict_list = None
        # Extract title as default value
        if extract_list is None:
            extract_list = [Defines.TR_TC_TITLE]
        status, ret_list = self.tr_api_get(Defines.TR_API_GET_CASE, tc_id)
        if status:
            ret_dict_list = self.__extract_dictionary(
                ret_list,
                extract_list,
                dict_type=Defines.DICT_SIMPLE,
                ret_dict_key=Defines.TR_TC_ID)
        else:
            self._log.error("Error in executing API {}".format(
                Defines.TR_API_GET_CASE))
        return status, ret_dict_list

    def tr_get_test_plan(
        self,
        plan_id,
    ):
        """
        This method will get the plan in a test run.
        A run id start with RXXXX format in TestRail
        :param plan_id:
        :return:
        """
        status, ret_msg = self.tr_api_get(Defines.TR_API_GET_PLAN, plan_id)
        if not status:
            self._log.error(
                "Error while getting the plan details for plan {}".format(
                    plan_id))
        return status, ret_msg

    def tr_get_testsuite_info_in_test_plan(self, plan_id):
        """
        This method will get the list of test suites in a test plan. The return dictionary
        will also contain the config information of a test suite.
        :param plan_id:
        :return:
        """
        # Testplan - > Test runs -> config
        ret_dict_list = []
        # First get the test plan details. Test plan will contain test suites.
        # Test suites can have multiple Configurations
        status, ret_msg = self.tr_get_test_plan(plan_id)
        if status:
            # Get the runs of the test plan. This can be extracted using the entries field in the test plan
            tp_entries = ret_msg[Defines.TR_TP_ENTRIES]
            if tp_entries:
                # For each entries ( Test suites) get the suite information and the config information.
                # Ex: a test suite A can be tested on different configs like iOS or Android
                for entries_item in tp_entries:
                    runs = entries_item[Defines.TR_TP_RUNS]
                    for run in runs:
                        tmp = {
                            run[Defines.TR_TS_ID]: {
                                Defines.TR_TP_SUITE_ID:
                                run[Defines.TR_TP_SUITE_ID],
                                Defines.TR_TP_TR_CONFIG:
                                run[Defines.TR_TP_TR_CONFIG],
                                Defines.TR_TP_TR_CONFIG_IDS:
                                run[Defines.TR_TP_TR_CONFIG_IDS]
                            }
                        }
                        ret_dict_list.append(tmp)
            else:
                # The plan has no suites. Make an entry in the logger
                self._log.error(
                    "Test plan has no test suites selected. Check and add test suites to the test plan {}"
                    .format(plan_id))
        else:
            self._log.error(
                "Error in calling tr_get_test_plan for the run_id-{}".format(
                    plan_id))
        return status, ret_dict_list

    def tr_get_testcase_in_test_plan(self, plan_id, extract_list=None):
        """
        This method will collect the test in a test plan using the test plan id and segregates into automated
        and manual test cases.
        :param plan_id:  Test plan id
        :param extract_list: Attribute which need to be extracted
        :return: status (Boolean), automated test cases, manual test cases
        """
        automated_test_case_list = []
        manual_test_case_list = []
        # default extract list to id
        if extract_list is None:
            extract_list = [Defines.TR_TC_ID]
        status, tp_info_list = self.tr_get_testsuite_info_in_test_plan(plan_id)
        # Make sure if the automation key is present in the extract list.
        # This step is required as we need to segregate manual and automated test cases
        if Defines.TR_TC_CUSTOM_AUTOMATED not in extract_list:
            extract_list.append(Defines.TR_TC_CUSTOM_AUTOMATED)
            self._log.info("Adding {} key to the extract list".format(
                Defines.TR_TC_CUSTOM_AUTOMATED))
        if status:
            self._log.error("Extracted dictionary of plan {}".format(plan_id))
            for run_dic in tp_info_list:
                # For each item(suite) in test plan, extract the run-id(key) and the config params (keys)
                for run_id, tp_suite_info in run_dic.items():
                    status, tc_list = self.tr_get_tescase_in_run(
                        run_id, extract_list)
                    for tc in tc_list:
                        if tc['custom_automated']:
                            automated_test_case_list.append(tc)
                        else:
                            manual_test_case_list.append(tc)
        else:
            self._log.error(
                "Error in extracting information from test plan {}".format(
                    plan_id))
        return status, automated_test_case_list, manual_test_case_list

    def get_test_plan_results(self, plan_id, automated):
        """
        This method will get all the test cases status (results) for  a test plan.
        This method will first find the runs of a test plan and then segregates the
        test to manual and automated lists
        :param plan_id: Plan id
        :param automated:
                        Define.TR_MANUAL_TC = Manual test cases
                        Defines.TR_AUTOMATED_TC = Automated test cases
                        Defines.TR_ALL_TC = Manual and automated test cases
        :return:    status ( Boolean),
                    manual_tc ( Manual test case list) ,
                    automated_tc( Automated test case list)

        """
        automated_tc = Defines.TR_TC_RESULTS_DICT.copy()
        manual_tc = Defines.TR_TC_RESULTS_DICT.copy()
        # Get all the test cases for the test plan
        # If automation is True get only automated test case
        status, automated_test_case_list, manual_test_case_list = self.tr_get_testcase_in_test_plan(
            plan_id, extract_list=[Defines.TR_TC_STATUS_ID])
        # Get the results based on automated flag
        if status:
            try:
                if automated in Defines.TR_MANUAL_TC or automated in Defines.TR_ALL_TC:
                    for tc in manual_test_case_list:
                        status_id = tc[Defines.TR_TC_STATUS_ID]
                        manual_tc[
                            Defines.TR_TC_STATUS_DICT[status_id]] = manual_tc[
                                Defines.TR_TC_STATUS_DICT[status_id]] + 1
                if automated in Defines.TR_AUTOMATED_TC or automated in Defines.TR_ALL_TC:
                    for tc in automated_test_case_list:
                        status_id = tc[Defines.TR_TC_STATUS_ID]
                        automated_tc[Defines.TR_TC_STATUS_DICT[
                            status_id]] = automated_tc[
                                Defines.TR_TC_STATUS_DICT[status_id]] + 1
                manual_tc[Defines.TC_TOTAL] = sum(manual_tc.values())
                automated_tc[Defines.TC_TOTAL] = sum(automated_tc.values())
            except KeyError:
                # Raise the error else the result will not match with TestRail. The missing key needs to be fixed.
                self._log.exception(
                    "Please check the TR_TC_STATUS_DICT parameters. Looks like these a mismatch with TestRail"
                )
                raise KeyError(
                    "Please check the TR_TC_STATUS_DICT parameters. Looks like these a mismatch with TestRail"
                )
            self._log.info("Manual test case = {}".format(manual_tc))
            self._log.info("Automated test case = {}".format(automated_tc))
        return status, manual_tc, automated_tc

    def tr_add_test_case_result(self,
                                run_id,
                                case_id,
                                status_id,
                                jir_defect=None,
                                version=None,
                                comments=None,
                                elapsed=None):
        """
        This method will post result for a test case. We meed run id or the test plan and case id of the test
        to post results.
        :param run_id: (Mandatory) Run id of the test plan (Note: Suite id which starts with R example: RXXXX)
        :param case_id: (Mandatory) Case if of the test case (Note: Case id starts with C example: CXXXX)
        :param status_id: (Mandatory) One of the valid status id
        (1:pass,2:blocked,3:Untested,4:retest,5:failed,6:Not implemented,7:Not Testable)
        :param jir_defect: Any old or know jira defect for this test case
        :param version: Test code version ( firmware version)
        :param comments: Amu test comments for failure or pass
        :param elapsed: Time for the test. Default is 2 seconds
        :return: status( Boolean) , updated test case dictionary
        """
        # Set the default values
        if elapsed is None:
            elapsed = Defines.TR_TC_RESULT_DEFAULT_EXEC_TIME

        test_result = {
            Defines.TR_TC_STATUS_ID: status_id,
            Defines.TR_TC_RESULT_COMMENT: comments,
            Defines.TR_TC_RESULT_ELAPSED: elapsed,
            Defines.TR_TC_RESULT_VERSION: version,
            Defines.TR_TC_RESULT_DEFECTS: jir_defect
        }
        # Make the api string
        api_str = Defines.TR_API_ADD_RESULT_FOR_CASES + "/" + str(
            run_id) + "/" + str(case_id)
        self._log.info("Adding results using API string {}".format(api_str))
        # Call the API post method
        status, return_msg = self.tr_api_post(api_str, test_result)
        return status, return_msg

    def tr_add_result(self, run_id, params=None):
        """
        This method will add result to individual test run ( Starts with TXXXXX)
        :param run_id: Test case Test run id
        :param params: Parameters to set like status, comments etc
        :return: status( Boolean) and return dictionary with updates
        """
        if params is None:
            params = {
                Defines.TR_TC_RESULT_ELAPSED: '0',
                Defines.TR_TC_STATUS_ID: 5
            }
        api_str = Defines.TR_API_ADD_RESULT + "/" + str(run_id)
        status, return_msg = self.tr_api_post(api_str, params)
        if not status:
            self._log.error(
                "Error in adding results for run_id {}".format(run_id))
        return status, return_msg

    def add_result_for_entire_test_plan(self,
                                        test_plan_id,
                                        status_id,
                                        automated=Defines.TR_ALL_TC,
                                        comments=None,
                                        elapsed=None,
                                        version=None):
        """
        This method will set the parameters like status, comment version etc for the entire test plan.
        You can use this function for resetting the entire plan before you start. Mostly useful in
        nightly test preparation
        """
        if elapsed is None:
            elapsed = '0'
        return_msg = None
        # Collect all the test cases of a test plan
        status, automated_test_case_list, manual_test_case_list = self.tr_get_testcase_in_test_plan(
            test_plan_id, extract_list=[Defines.TR_RUN_ID])

        tc_list = []
        if automated in Defines.TR_AUTOMATED_TC:
            tc_list.append(automated_test_case_list)
        elif automated in Defines.TR_MANUAL_TC:
            tc_list.append(manual_test_case_list)
        else:
            tc_list.append(manual_test_case_list)
            tc_list.append(automated_test_case_list)

        for item in tc_list:  # manual_test_case_list:
            for tc in item:
                api_str = Defines.TR_API_ADD_RESULT + "/" + str(
                    tc[Defines.TR_RUN_ID])
                param = {
                    Defines.TR_TC_RESULT_ELAPSED: str(elapsed),
                    Defines.TR_TC_STATUS_ID: status_id,
                    Defines.TR_TC_RESULT_COMMENT: comments,
                    Defines.TR_TC_RESULT_VERSION: version
                }
                status, return_msg = self.tr_api_post(api_str, param)
        return status, return_msg
コード例 #12
0
                    required=True)
parser.add_argument('--tpid',
                    action='store',
                    dest='tpid',
                    help='TestRail test plan ID, ex. R2330 ',
                    required=True)
parser.add_argument(
    '--url',
    action='store',
    dest='url',
    help='TestRail url, default set to https://bsro.testrail.net',
    default='https://bsro.testrail.net')
results = parser.parse_args()

url = results.url
client = APIClient(url)
client.user = results.username
client.password = results.password
tpid_argv = results.tpid[1:]


def get_creds():
    if len(client.user) < 1:
        client.user = input("login: "******"[ha!] forgot something?....where's the password ?")
            sys.exit(0)
    print("[.] k, got the creds for ", client.user)
コード例 #13
0
class TestRailProject(object):
    """TestRailProject."""  # TODO documentation

    def __init__(self, url, user, password, project):
        self.client = APIClient(base_url=url)
        self.client.user = user
        self.client.password = password
        self.project = self._get_project(project)

    def _get_project(self, project_name):
        projects_uri = 'get_projects'
        projects = self.client.send_get(uri=projects_uri)
        for project in projects:
            if project['name'] == project_name:
                return project
        return None

    def test_run_struct(self, name, suite_id, milestone_id, description,
                        config_ids, include_all=True, assignedto=None,
                        case_ids=None):
        struct = {
            'name': name,
            'suite_id': suite_id,
            'milestone_id': milestone_id,
            'description': description,
            'include_all': include_all,
            'config_ids': config_ids
        }
        if case_ids:
            struct['include_all'] = False
            struct['case_ids'] = case_ids
        if assignedto:
            struct['assignedto_id'] = self.get_user(assignedto)['id']
        return struct

    def get_users(self):
        users_uri = 'get_users'
        return self.client.send_get(uri=users_uri)

    def get_user(self, user_id):
        user_uri = 'get_user/{user_id}'.format(user_id=user_id)
        return self.client.send_get(uri=user_uri)

    def get_user_by_name(self, name):
        for user in self.get_users():
            if user['name'] == name:
                return self.get_user(user_id=user['id'])

    def get_configs(self):
        configs_uri = 'get_configs/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(configs_uri)

    def get_config(self, config_id):
        for configs in self.get_configs():
            for config in configs['configs']:
                if config['id'] == int(config_id):
                    return config

    def get_config_by_name(self, name):
        for config in self.get_configs():
            if config['name'] == name:
                return config

    def get_priorities(self):
        priorities_uri = 'get_priorities'
        return self.client.send_get(uri=priorities_uri)

    def get_milestones(self):
        milestones_uri = 'get_milestones/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=milestones_uri)

    def get_milestone(self, milestone_id):
        milestone_uri = 'get_milestone/{milestone_id}'.format(
            milestone_id=milestone_id)
        return self.client.send_get(uri=milestone_uri)

    def get_milestone_by_name(self, name):
        for milestone in self.get_milestones():
            if milestone['name'] == name:
                return self.get_milestone(milestone_id=milestone['id'])

    def get_suites(self):
        suites_uri = 'get_suites/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=suites_uri)

    def get_suite(self, suite_id):
        suite_uri = 'get_suite/{suite_id}'.format(suite_id=suite_id)
        return self.client.send_get(uri=suite_uri)

    def get_suite_by_name(self, name):
        for suite in self.get_suites():
            if suite['name'] == name:
                return self.get_suite(suite_id=suite['id'])

    def get_sections(self, suite_id):
        sections_uri = 'get_sections/{project_id}&suite_id={suite_id}'.format(
            project_id=self.project['id'],
            suite_id=suite_id
        )
        return self.client.send_get(sections_uri)

    def get_section(self, section_id):
        section_uri = 'get_section/{section_id}'.format(section_id=section_id)
        return self.client.send_get(section_uri)

    def get_section_by_name(self, suite_id, section_name):
        for section in self.get_sections(suite_id=suite_id):
            if section['name'] == section_name:
                return self.get_section(section_id=section['id'])

    def create_section(self, suite_id, name, parent_id=None):
        return self.client.send_post('add_section/' + str(self.project['id']),
                                     dict(suite_id=suite_id, name=name,
                                          parent_id=parent_id))

    def delete_section(self, section_id):
        return self.client.send_post('delete_section/' + str(section_id), {})

    def create_suite(self, name, description=None):
        return self.client.send_post('add_suite/' + str(self.project['id']),
                                     dict(name=name, description=description))

    def get_cases(self, suite_id, section_id=None):
        cases_uri = 'get_cases/{project_id}&suite_id={suite_id}'.format(
            project_id=self.project['id'],
            suite_id=suite_id
        )
        if section_id:
            cases_uri = '{0}&section_id={section_id}'.format(
                cases_uri, section_id=section_id
            )
        return self.client.send_get(cases_uri)

    def get_case(self, case_id):
        case_uri = 'get_case/{case_id}'.format(case_id=case_id)
        return self.client.send_get(case_uri)

    def update_case(self, case):
        case_uri = 'update_case/{case_id}'.format(case_id=case["id"])
        return self.client.send_post(case_uri, case)

    def get_case_by_name(self, suite_id, name, cases=None):
        for case in cases or self.get_cases(suite_id):
            if case['title'] == name:
                return self.get_case(case_id=case['id'])

    def get_case_by_group(self, suite_id, group, cases=None):
        for case in cases or self.get_cases(suite_id):
            if case['custom_test_group'] == group:
                return self.get_case(case_id=case['id'])

    def add_case(self, section_id, case):
        add_case_uri = 'add_case/{section_id}'.format(section_id=section_id)
        return self.client.send_post(add_case_uri, case)

    def delete_case(self, case_id):
        return self.client.send_post('delete_case/' + str(case_id), None)

    def get_plans(self):
        plans_uri = 'get_plans/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(plans_uri)

    def get_plan(self, plan_id):
        plan_uri = 'get_plan/{plan_id}'.format(plan_id=plan_id)
        return self.client.send_get(plan_uri)

    def get_plans_by_milestone(self, milestone_id):
        plans = self.get_plans()
        return [self.get_plan(plan['id']) for plan in plans
                if plan['milestone_id'] == milestone_id]

    def get_plan_by_name(self, name):
        for plan in self.get_plans():
            if plan['name'] == name:
                return self.get_plan(plan['id'])

    def add_plan(self, name, description, milestone_id, entries):
        add_plan_uri = 'add_plan/{project_id}'.format(
            project_id=self.project['id'])
        new_plan = {
            'name': name,
            'description': description,
            'milestone_id': milestone_id,
            'entries': entries
        }
        return self.client.send_post(add_plan_uri, new_plan)

    def add_plan_entry(self, plan_id, suite_id, config_ids, runs, name=None):
        add_plan_entry_uri = 'add_plan_entry/{plan_id}'.format(plan_id=plan_id)
        new_entry = {
            'suite_id': suite_id,
            'config_ids': config_ids,
            'runs': runs
        }
        if name:
            new_entry['name'] = name
        return self.client.send_post(add_plan_entry_uri, new_entry)

    def delete_plan(self, plan_id):
        delete_plan_uri = 'delete_plan/{plan_id}'.format(plan_id=plan_id)
        self.client.send_post(delete_plan_uri, {})

    def get_runs(self):
        runs_uri = 'get_runs/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=runs_uri)

    def get_run(self, run_id):
        run_uri = 'get_run/{run_id}'.format(run_id=run_id)
        return self.client.send_get(uri=run_uri)

    def get_run_by_name(self, name):
        for run in self.get_runs():
            if run['name'] == name:
                return self.get_run(run_id=run['id'])

    def get_previous_runs(self, milestone_id, suite_id, config_id):
        all_runs = []
        for plan in self.get_plans_by_milestone(milestone_id=milestone_id):
            for entry in plan['entries']:
                if entry['suite_id'] == suite_id:
                    run_ids = [run for run in entry['runs'] if
                               config_id in run['config_ids']]
                    all_runs.extend(run_ids)
        return all_runs

    def add_run(self, new_run):
        add_run_uri = 'add_run/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_post(add_run_uri, new_run)

    def update_run(self, name, milestone_id=None, description=None,
                   config_ids=None, include_all=None, case_ids=None):
        tests_run = self.get_run(name)
        update_run_uri = 'update_run/{run_id}'.format(run_id=tests_run['id'])
        update_run = {}
        if milestone_id:
            update_run['milestone_id'] = milestone_id
        if description:
            update_run['description'] = description
        if include_all is not None:
            update_run['include_all'] = include_all is True
        if case_ids:
            update_run['case_ids'] = case_ids
        if config_ids:
            update_run['config_ids'] = config_ids
        return self.client.send_post(update_run_uri, update_run)

    def create_or_update_run(self, name, suite, milestone_id, description,
                             config_ids, include_all=True, assignedto=None,
                             case_ids=None):
        if self.get_run(name):
            self.update_run(name=name,
                            milestone_id=milestone_id,
                            description=description,
                            config_ids=config_ids,
                            include_all=include_all,
                            case_ids=case_ids)
        else:
            self.add_run(self.test_run_struct(name, suite, milestone_id,
                                              description, config_ids,
                                              include_all=include_all,
                                              assignedto=assignedto,
                                              case_ids=case_ids))

    def get_statuses(self):
        statuses_uri = 'get_statuses'
        return self.client.send_get(statuses_uri)

    def get_status(self, name):
        for status in self.get_statuses():
            if status['name'] == name:
                return status

    def get_tests(self, run_id, status_id=None):
        tests_uri = 'get_tests/{run_id}'.format(run_id=run_id)
        if status_id:
            tests_uri = '{0}&status_id={1}'.format(tests_uri,
                                                   ','.join(status_id))
        return self.client.send_get(tests_uri)

    def get_test(self, test_id):
        test_uri = 'get_test/{test_id}'.format(test_id=test_id)
        return self.client.send_get(test_uri)

    def get_test_by_name(self, run_id, name):
        for test in self.get_tests(run_id):
            if test['title'] == name:
                return self.get_test(test_id=test['id'])

    def get_test_by_group(self, run_id, group, tests=None):
        for test in tests or self.get_tests(run_id):
            if test['custom_test_group'] == group:
                return self.get_test(test_id=test['id'])

    def get_test_by_name_and_group(self, run_id, name, group):
        for test in self.get_tests(run_id):
            if test['title'] == name and test['custom_test_group'] == group:
                return self.get_test(test_id=test['id'])

    def get_tests_by_group(self, run_id, group, tests=None):
        test_list = []
        for test in tests or self.get_tests(run_id):
            if test['custom_test_group'] == group:
                test_list.append(self.get_test(test_id=test['id']))
        return test_list

    def get_results_for_test(self, test_id, run_results=None):
        if run_results:
            for results in run_results:
                if results['test_id'] == test_id:
                    return results
        results_uri = 'get_results/{test_id}'.format(test_id=test_id)
        return self.client.send_get(results_uri)

    def get_results_for_run(self, run_id):
        results_run_uri = 'get_results_for_run/{run_id}'.format(run_id=run_id)
        return self.client.send_get(results_run_uri)

    def get_results_for_case(self, run_id, case_id):
        results_case_uri = 'get_results_for_case/{run_id}/{case_id}'.format(
            run_id=run_id, case_id=case_id)
        return self.client.send_get(results_case_uri)

    def get_all_results_for_case(self, run_ids, case_id):
        all_results = []
        for run_id in run_ids:
            try:
                results = self.get_results_for_case(run_id=run_id,
                                                    case_id=case_id)
            except APIError as e:
                logger.error("[{0}], run_id={1}, case_id={2}"
                             .format(e, run_id, case_id))
                continue
            all_results.extend(results)
        return all_results

    def add_results_for_test(self, test_id, test_results):
        add_results_test_uri = 'add_result/{test_id}'.format(test_id=test_id)
        new_results = {
            'status_id': self.get_status(test_results.status)['id'],
            'comment': '\n'.join(filter(lambda x: x is not None,
                                        [test_results.description,
                                         test_results.url,
                                         test_results.comments])),
            'elapsed': test_results.duration,
            'version': test_results.version
        }
        if test_results.steps:
            new_results['custom_step_results'] = test_results.steps
        return self.client.send_post(add_results_test_uri, new_results)

    def add_results_for_cases(self, run_id, suite_id, tests_results):
        add_results_test_uri = 'add_results_for_cases/{run_id}'.format(
            run_id=run_id)
        new_results = {'results': []}
        tests_cases = self.get_cases(suite_id)
        for results in tests_results:
            case = self.get_case_by_group(suite_id=suite_id,
                                          group=results.group,
                                          cases=tests_cases)
            case_id = case['id']
            new_result = {
                'case_id': case_id,
                'status_id': self.get_status(results.status)['id'],
                'comment': '\n'.join(filter(lambda x: x is not None,
                                            [results.description,
                                             results.url,
                                             results.comments])),
                'elapsed': results.duration,
                'version': results.version,
                'custom_launchpad_bug': results.launchpad_bug
            }
            if results.steps:
                custom_step_results = []
                steps = case.get('custom_test_case_steps', None)
                if steps and len(steps) == len(results.steps):
                    steps = zip(steps, results.steps)
                    for s in steps:
                        custom_step_results.append({
                            "content": s[0]["content"],
                            "expected": s[0]["expected"],
                            "actual": s[1]['actual'],
                            "status_id": self.get_status(s[1]['status'])['id']
                        })
                else:
                    for s in results.steps:
                        custom_step_results.append({
                            "content": s['name'],
                            "expected": 'pass',
                            "actual": s['actual'],
                            "status_id": self.get_status(s['status'])['id']
                        })
                new_result['custom_test_case_steps_results'] = \
                    custom_step_results
            new_results['results'].append(new_result)
        return self.client.send_post(add_results_test_uri, new_results)

    def add_results_for_tempest_cases(self, run_id, tests_results):
        add_results_test_uri = 'add_results_for_cases/{run_id}'.format(
            run_id=run_id)
        new_results = {'results': tests_results}
        return self.client.send_post(add_results_test_uri, new_results)
コード例 #14
0
class TestRailProject(object):
    """TestRailProject."""  # TODO documentation

    def __init__(self, url, user, password, project):
        self.client = APIClient(base_url=url)
        self.client.user = user
        self.client.password = password
        self.project = self._get_project(project)

    def _get_project(self, project_name):
        projects_uri = 'get_projects'
        projects = self.client.send_get(uri=projects_uri)
        for project in projects:
            if project['name'] == project_name:
                return project
        return None

    def test_run_struct(self,
                        name,
                        suite_id,
                        milestone_id,
                        description,
                        config_ids,
                        include_all=True,
                        assignedto=None,
                        case_ids=None):
        struct = {
            'name': name,
            'suite_id': suite_id,
            'milestone_id': milestone_id,
            'description': description,
            'include_all': include_all,
            'config_ids': config_ids
        }
        if case_ids:
            struct['include_all'] = False
            struct['case_ids'] = case_ids
        if assignedto:
            struct['assignedto_id'] = self.get_user(assignedto)['id']
        return struct

    def get_users(self):
        users_uri = 'get_users'
        return self.client.send_get(uri=users_uri)

    def get_user(self, user_id):
        user_uri = 'get_user/{user_id}'.format(user_id=user_id)
        return self.client.send_get(uri=user_uri)

    def get_user_by_name(self, name):
        for user in self.get_users():
            if user['name'] == name:
                return self.get_user(user_id=user['id'])

    def get_configs(self):
        configs_uri = 'get_configs/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(configs_uri)

    def get_config(self, config_id):
        for configs in self.get_configs():
            for config in configs['configs']:
                if config['id'] == int(config_id):
                    return config

    def get_config_by_name(self, name):
        for config in self.get_configs():
            if config['name'] == name:
                return config

    def get_priorities(self):
        priorities_uri = 'get_priorities'
        return self.client.send_get(uri=priorities_uri)

    def get_milestones(self):
        milestones_uri = 'get_milestones/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=milestones_uri)

    def get_milestone(self, milestone_id):
        milestone_uri = 'get_milestone/{milestone_id}'.format(
            milestone_id=milestone_id)
        return self.client.send_get(uri=milestone_uri)

    def get_milestone_by_name(self, name):
        for milestone in self.get_milestones():
            if milestone['name'] == name:
                return self.get_milestone(milestone_id=milestone['id'])

    def get_suites(self):
        suites_uri = 'get_suites/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=suites_uri)

    def get_suite(self, suite_id):
        suite_uri = 'get_suite/{suite_id}'.format(suite_id=suite_id)
        return self.client.send_get(uri=suite_uri)

    def get_suite_by_name(self, name):
        for suite in self.get_suites():
            if suite['name'] == name:
                return self.get_suite(suite_id=suite['id'])

    def get_sections(self, suite_id):
        sections_uri = 'get_sections/{project_id}&suite_id={suite_id}'.format(
            project_id=self.project['id'], suite_id=suite_id)
        return self.client.send_get(sections_uri)

    def get_section(self, section_id):
        section_uri = 'get_section/{section_id}'.format(section_id=section_id)
        return self.client.send_get(section_uri)

    def get_section_by_name(self, suite_id, section_name):
        for section in self.get_sections(suite_id=suite_id):
            if section['name'] == section_name:
                return self.get_section(section_id=section['id'])

    def create_section(self, suite_id, name, parent_id=None):
        return self.client.send_post(
            'add_section/' + str(self.project['id']),
            dict(suite_id=suite_id, name=name, parent_id=parent_id))

    def delete_section(self, section_id):
        return self.client.send_post('delete_section/' + str(section_id), {})

    def create_suite(self, name, description=None):
        return self.client.send_post('add_suite/' + str(self.project['id']),
                                     dict(name=name, description=description))

    def get_cases(self, suite_id, section_id=None):
        cases_uri = 'get_cases/{project_id}&suite_id={suite_id}'.format(
            project_id=self.project['id'], suite_id=suite_id)
        if section_id:
            cases_uri = '{0}&section_id={section_id}'.format(
                cases_uri, section_id=section_id)
        return self.client.send_get(cases_uri)

    def get_case(self, case_id):
        case_uri = 'get_case/{case_id}'.format(case_id=case_id)
        return self.client.send_get(case_uri)

    def update_case(self, case):
        case_uri = 'update_case/{case_id}'.format(case_id=case["id"])
        return self.client.send_post(case_uri, case)

    def get_case_by_name(self, suite_id, name, cases=None):
        for case in cases or self.get_cases(suite_id):
            if case['title'] == name:
                return self.get_case(case_id=case['id'])

    def get_case_by_group(self, suite_id, group, cases=None):
        for case in cases or self.get_cases(suite_id):
            if case['custom_test_group'] == group:
                return self.get_case(case_id=case['id'])

    def add_case(self, section_id, case):
        add_case_uri = 'add_case/{section_id}'.format(section_id=section_id)
        return self.client.send_post(add_case_uri, case)

    def delete_case(self, case_id):
        return self.client.send_post('delete_case/' + str(case_id), None)

    def get_plans(self):
        plans_uri = 'get_plans/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(plans_uri)

    def get_plan(self, plan_id):
        plan_uri = 'get_plan/{plan_id}'.format(plan_id=plan_id)
        return self.client.send_get(plan_uri)

    def get_plans_by_milestone(self, milestone_id):
        plans = self.get_plans()
        return [
            self.get_plan(plan['id']) for plan in plans
            if plan['milestone_id'] == milestone_id
        ]

    def get_plan_by_name(self, name):
        for plan in self.get_plans():
            if plan['name'] == name:
                return self.get_plan(plan['id'])

    def add_plan(self, name, description, milestone_id, entries):
        add_plan_uri = 'add_plan/{project_id}'.format(
            project_id=self.project['id'])
        new_plan = {
            'name': name,
            'description': description,
            'milestone_id': milestone_id,
            'entries': entries
        }
        return self.client.send_post(add_plan_uri, new_plan)

    def add_plan_entry(self, plan_id, suite_id, config_ids, runs, name=None):
        add_plan_entry_uri = 'add_plan_entry/{plan_id}'.format(plan_id=plan_id)
        new_entry = {
            'suite_id': suite_id,
            'config_ids': config_ids,
            'runs': runs
        }
        if name:
            new_entry['name'] = name
        return self.client.send_post(add_plan_entry_uri, new_entry)

    def delete_plan(self, plan_id):
        delete_plan_uri = 'delete_plan/{plan_id}'.format(plan_id=plan_id)
        self.client.send_post(delete_plan_uri, {})

    def get_runs(self):
        runs_uri = 'get_runs/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_get(uri=runs_uri)

    def get_run(self, run_id):
        run_uri = 'get_run/{run_id}'.format(run_id=run_id)
        return self.client.send_get(uri=run_uri)

    def get_run_by_name(self, name):
        for run in self.get_runs():
            if run['name'] == name:
                return self.get_run(run_id=run['id'])

    def get_previous_runs(self, milestone_id, suite_id, config_id):
        all_runs = []
        for plan in self.get_plans_by_milestone(milestone_id=milestone_id):
            for entry in plan['entries']:
                if entry['suite_id'] == suite_id:
                    run_ids = [
                        run for run in entry['runs']
                        if config_id in run['config_ids']
                    ]
                    all_runs.extend(run_ids)
        return all_runs

    def add_run(self, new_run):
        add_run_uri = 'add_run/{project_id}'.format(
            project_id=self.project['id'])
        return self.client.send_post(add_run_uri, new_run)

    def update_run(self,
                   name,
                   milestone_id=None,
                   description=None,
                   config_ids=None,
                   include_all=None,
                   case_ids=None):
        tests_run = self.get_run(name)
        update_run_uri = 'update_run/{run_id}'.format(run_id=tests_run['id'])
        update_run = {}
        if milestone_id:
            update_run['milestone_id'] = milestone_id
        if description:
            update_run['description'] = description
        if include_all is not None:
            update_run['include_all'] = include_all is True
        if case_ids:
            update_run['case_ids'] = case_ids
        if config_ids:
            update_run['config_ids'] = config_ids
        return self.client.send_post(update_run_uri, update_run)

    def create_or_update_run(self,
                             name,
                             suite,
                             milestone_id,
                             description,
                             config_ids,
                             include_all=True,
                             assignedto=None,
                             case_ids=None):
        if self.get_run(name):
            self.update_run(name=name,
                            milestone_id=milestone_id,
                            description=description,
                            config_ids=config_ids,
                            include_all=include_all,
                            case_ids=case_ids)
        else:
            self.add_run(
                self.test_run_struct(name,
                                     suite,
                                     milestone_id,
                                     description,
                                     config_ids,
                                     include_all=include_all,
                                     assignedto=assignedto,
                                     case_ids=case_ids))

    def get_statuses(self):
        statuses_uri = 'get_statuses'
        return self.client.send_get(statuses_uri)

    def get_status(self, name):
        for status in self.get_statuses():
            if status['name'] == name:
                return status

    def get_tests(self, run_id, status_id=None):
        tests_uri = 'get_tests/{run_id}'.format(run_id=run_id)
        if status_id:
            tests_uri = '{0}&status_id={1}'.format(tests_uri,
                                                   ','.join(status_id))
        return self.client.send_get(tests_uri)

    def get_test(self, test_id):
        test_uri = 'get_test/{test_id}'.format(test_id=test_id)
        return self.client.send_get(test_uri)

    def get_test_by_name(self, run_id, name):
        for test in self.get_tests(run_id):
            if test['title'] == name:
                return self.get_test(test_id=test['id'])

    def get_test_by_group(self, run_id, group, tests=None):
        for test in tests or self.get_tests(run_id):
            if test['custom_test_group'] == group:
                return self.get_test(test_id=test['id'])

    def get_test_by_name_and_group(self, run_id, name, group):
        for test in self.get_tests(run_id):
            if test['title'] == name and test['custom_test_group'] == group:
                return self.get_test(test_id=test['id'])

    def get_tests_by_group(self, run_id, group, tests=None):
        test_list = []
        for test in tests or self.get_tests(run_id):
            if test['custom_test_group'] == group:
                test_list.append(self.get_test(test_id=test['id']))
        return test_list

    def get_results_for_test(self, test_id, run_results=None):
        if run_results:
            for results in run_results:
                if results['test_id'] == test_id:
                    return results
        results_uri = 'get_results/{test_id}'.format(test_id=test_id)
        return self.client.send_get(results_uri)

    def get_results_for_run(self, run_id):
        results_run_uri = 'get_results_for_run/{run_id}'.format(run_id=run_id)
        return self.client.send_get(results_run_uri)

    def get_results_for_case(self, run_id, case_id):
        results_case_uri = 'get_results_for_case/{run_id}/{case_id}'.format(
            run_id=run_id, case_id=case_id)
        return self.client.send_get(results_case_uri)

    def get_all_results_for_case(self, run_ids, case_id):
        all_results = []
        for run_id in run_ids:
            try:
                results = self.get_results_for_case(run_id=run_id,
                                                    case_id=case_id)
            except APIError as e:
                logger.error("[{0}], run_id={1}, case_id={2}".format(
                    e, run_id, case_id))
                continue
            all_results.extend(results)
        return all_results

    def add_results_for_test(self, test_id, test_results):
        add_results_test_uri = 'add_result/{test_id}'.format(test_id=test_id)
        new_results = {
            'status_id':
            self.get_status(test_results.status)['id'],
            'comment':
            '\n'.join(
                filter(lambda x: x is not None, [
                    test_results.description, test_results.url,
                    test_results.comments
                ])),
            'elapsed':
            test_results.duration,
            'version':
            test_results.version
        }
        if test_results.steps:
            new_results['custom_step_results'] = test_results.steps
        return self.client.send_post(add_results_test_uri, new_results)

    def add_results_for_cases(self, run_id, suite_id, tests_results):
        add_results_test_uri = 'add_results_for_cases/{run_id}'.format(
            run_id=run_id)
        new_results = {'results': []}
        tests_cases = self.get_cases(suite_id)
        for results in tests_results:
            case = self.get_case_by_group(suite_id=suite_id,
                                          group=results.group,
                                          cases=tests_cases)
            case_id = case['id']
            new_result = {
                'case_id':
                case_id,
                'status_id':
                self.get_status(results.status)['id'],
                'comment':
                '\n'.join(
                    filter(
                        lambda x: x is not None,
                        [results.description, results.url, results.comments])),
                'elapsed':
                results.duration,
                'version':
                results.version,
                'custom_launchpad_bug':
                results.launchpad_bug
            }
            if results.steps:
                custom_step_results = []
                steps = case.get('custom_test_case_steps', None)
                if steps and len(steps) == len(results.steps):
                    steps = zip(steps, results.steps)
                    for s in steps:
                        custom_step_results.append({
                            "content":
                            s[0]["content"],
                            "expected":
                            s[0]["expected"],
                            "actual":
                            s[1]['actual'],
                            "status_id":
                            self.get_status(s[1]['status'])['id']
                        })
                else:
                    for s in results.steps:
                        custom_step_results.append({
                            "content":
                            s['name'],
                            "expected":
                            'pass',
                            "actual":
                            s['actual'],
                            "status_id":
                            self.get_status(s['status'])['id']
                        })
                new_result['custom_test_case_steps_results'] = \
                    custom_step_results
            new_results['results'].append(new_result)
        return self.client.send_post(add_results_test_uri, new_results)
コード例 #15
0
def get_testrail_client():
    client = APIClient(TESTRAIL_URL)
    client.user = TESTRAIL_USER
    client.password = TESTRAIL_PASSWORD

    return client
コード例 #16
0
class TestRailLibraryExt:
    """
    Intercommunication with TestRail

    """

    ROBOT_LIBRARY_SCOPE = 'GLOBAL'
    ROBOT_LIBRARY_VERSION = '0.1'

    #__all__ = ['Add_Result_To_TestRail_Case']

    def __init__(self, TestRailURL='', user='', APIkey=''):
        self._client = APIClient(TestRailURL)
        self._client.user = user
        self._client.password = APIkey

    def __str__(self):
        return 'RobotFramework TestRailLibrary'

    def Add_Result_To_TestRail_Case(self, project_name, test_run_name, caseID,
                                    status, **kwargs):
        runID = self.Get_TestRail_RunID(self, project_name, test_run_name)
        body = {}
        for key in kwargs:
            body[key] = kwargs[key]

        statusID = 5
        if status == 'PASS':
            statusID = 1

        body['status_id'] = statusID
        result = self._client.send_post(
            'add_result_for_case/' + str(runID) + '/' + str(caseID), body)
        return result

    def Add_Result_To_TestRail_Case_Run_Config(self, project_name, plan_name,
                                               test_run_name, config, caseID,
                                               status, **kwargs):
        runID = self.Get_TestRail_RunID_by_plan_configs(
            self, project_name, plan_name, test_run_name, config)
        body = {}
        for key in kwargs:
            body[key] = kwargs[key]

        statusID = 5
        if status == 'PASS':
            statusID = 1

        body['status_id'] = statusID
        result = self._client.send_post(
            'add_result_for_case/' + str(runID) + '/' + str(caseID), body)
        return result

    @staticmethod
    def Get_TestRail_ProjectID(self, name):
        projects = self._client.send_get('get_projects')
        for project in projects:
            if project['name'] == name:
                return project['id']
        return 0

    @staticmethod
    def Get_TestRail_ProjectRuns(self, project_name):
        projectID = self.Get_TestRail_ProjectID(self, project_name)
        runs = self._client.send_get('get_runs/' + str(projectID))
        return runs

    @staticmethod
    def Get_TestRail_RunID(self, project_name, run_name):
        runs = self.Get_TestRail_ProjectRuns(self, project_name)
        for run in runs:
            if run['name'] == run_name:
                return run['id']
        return 0

    @staticmethod
    def Get_TestRail_Plans(self, project_name):
        projectID = self.Get_TestRail_ProjectID(self, project_name)
        plans = self._client.send_get('get_plans/' + str(projectID))
        print(projectID)
        print(plans)
        print("I am in plans")
        return plans

    @staticmethod
    def Get_TestRail_PlanID(self, project_name, plan_name):
        plans = self.Get_TestRail_Plans(self, project_name)
        for plan in plans:
            print(plan)
            if plan['name'] == plan_name:
                return plan['id']
        return 0

    @staticmethod
    def Get_TestRail_PlanRuns(self, project_name, plan_name):
        planID = self.Get_TestRail_PlanID(self, project_name, plan_name)
        planRuns = self._client.send_get('get_plan/' + str(planID))
        return planRuns['entries']

    @staticmethod
    def Get_TestRail_RunID_by_plan_configs(self, project_name, plan_name,
                                           run_name, configs):
        planRuns = self.Get_TestRail_PlanRuns(self, project_name, plan_name)
        for run in planRuns:
            if configs is None:
                if run['name'] == run_name:
                    return run['runs'][0]['id']
            else:
                for subrun in run['runs']:
                    if subrun['name'] == run_name and subrun[
                            'config'] == configs:
                        return subrun['id']
        return 0

    @staticmethod
    def Get_TestRail_configIDs_by_names(self, project_name, names):
        projectID = self.Get_TestRail_ProjectID(self, project_name)
        config_groups = self._client.send_get('get_configs/' + str(projectID))
        ids = []
        for group in config_groups:
            for config in group['configs']:
                if config['name'] in names:
                    ids.append(config['id'])
        return ids

    @staticmethod
    def Get_TestRail_Suite(self, project_name, name):
        projectID = self.Get_TestRail_ProjectID(self, project_name)
        suites = self._client.send_get('get_suites/' + str(projectID))
        print('printing suites')
        print(suites)
        for suite in suites:
            if suite['name'] == name:
                return suite

        return None

    @staticmethod
    def Create_Test_Run_with_all_cases(self, project_name, run_name,
                                       description):
        projectID = self.Get_TestRail_ProjectID(self, project_name)
        data = {}
        data['name'] = run_name
        data['description'] = description

        result = self._client.send_post('add_run/' + str(projectID), data)
        return result

    @staticmethod
    def Add_Test_Run_to_Plan_with_all_cases_configs(self, project_name, suite,
                                                    plan_name, run_name,
                                                    description, configs):
        planID = self.Get_TestRail_PlanID(self, project_name, plan_name)
        configIDs = self.Get_TestRail_configIDs_by_names(
            self, project_name, configs)
        suite = self.Get_TestRail_Suite(self, project_name, suite)
        run = {}
        plan = {}
        plan['suite_id'] = suite['id']
        plan['name'] = run_name
        plan['config_ids'] = configIDs
        # run['name'] = run_name
        run['description'] = description
        run['include_all'] = True
        run['config_ids'] = configIDs
        # run['suite_id'] = suite['id']
        plan['runs'] = [run]

        result = self._client.send_post('add_plan_entry/' + str(planID), plan)
        return result

    @staticmethod
    def Add_Test_Run_to_Plan_with_all_cases_configs_set(
            self, project_name, suite, plan_name, run_name, description,
            configs_set):

        allPlanRuns = self.Get_TestRail_PlanRuns(self, project_name, plan_name)

        for existingRun in allPlanRuns:
            if existingRun['name'] == run_name:
                return 'Test Run already created. No actions needed'

        planID = self.Get_TestRail_PlanID(self, project_name, plan_name)
        allConfigIds = []
        for conf in configs_set:
            configIDs = self.Get_TestRail_configIDs_by_names(
                self, project_name, conf)
            allConfigIds.extend(configIDs)

        suite = self.Get_TestRail_Suite(self, project_name, suite)
        plan = {}
        plan['suite_id'] = suite['id']
        plan['name'] = run_name
        plan['config_ids'] = list(set(allConfigIds))

        runs = []
        for conf in configs_set:
            run = {}
            confIDs = self.Get_TestRail_configIDs_by_names(
                self, project_name, conf)
            run['description'] = description
            run['include_all'] = True
            run['config_ids'] = confIDs
            runs.append(run)

        plan['runs'] = runs
        pprint.pprint(plan)

        result = self._client.send_post('add_plan_entry/' + str(planID), plan)
        return result

    def Pretty_Print_Test_Comment(self, header='EXECUTION INFO', **kwargs):
        comment = header + '\n\n'
        for key in kwargs:
            val = ''
            if isinstance(kwargs[key], list):
                val = ', '.join(str(x) for x in kwargs[key])
            else:
                val = kwargs[key]

            comment = comment + str(key) + ": " + val + '\n\n'
        return comment

    def Extract_CaseID_From_Robot_Tags(self, tags):
        for tag in tags:
            st = str(tag)
            match = re.findall(r'^C(\d{0,}\d$)', st)
            if len(match) > 0:
                return int(match[0])
            else:
                return 0
        return 0

    def get_case(self, caseID):
        case = self._client.send_get('get_case/' + str(caseID))
        return case
コード例 #17
0
 def __init__(self, TestRailURL='', user='', APIkey=''):
     self._client = APIClient(TestRailURL)
     self._client.user = user
     self._client.password = APIkey
コード例 #18
0
class TestRailListener(object):
    """
    Fixing of testing results and update test case in [ http://www.gurock.com/testrail/ | TestRail ].\n
    == Dependency ==
    - [ http://docs.gurock.com/testrail-api2/bindings-python | TestRail API2 python binding]
    == Preconditions ==
    1. [ http://docs.gurock.com/testrail-api2/introduction | Enable TestRail API] \n
    2. Create custom field "case_description" with type "text", which corresponds to the Robot Framework's test case documentation.
    == Example ==
    1. Create test case in TestRail with case_id = 10\n
    2. Add it to test run with id run_id = 20\n
    3. Create autotest in Robot Framework
    | *** Settings ***
    | *** Test Cases ***
    | Autotest name
    |    [Documentation]    Autotest documentation
    |    [Tags]    testrailid=10    defects=BUG-1, BUG-2    references=REF-3, REF-4
    |    Fail    Test fail message
    4. Run Robot Framework with listener:\n
    | set ROBOT_SYSLOG_FILE=syslog.txt
    | pybot.bat --listener TestRailListener.py:testrail_server_name:tester_user_name:tester_user_password:20:update  autotest.txt
    5. Test with case_id=10 will be marked as failed in TestRail with message "Test fail message" and defects "BUG-1, BUG-2".
    Also title, description and references of this test will be updated in TestRail. Parameter "update" is optional.
    """

    ROBOT_LISTENER_API_VERSION = 3

    def __init__(self, server, user, password, run_id, update = None):
        """
        *Args:*\n
        _server_ - the name of TestRail server;
        _user_ - the name of TestRail user;
        _password_ - the password of TestRail user;
        _run_id -  the ID of the test run;
        _update_ - indicator to update test case in TestRail; if exist, then test will be updated.
        """

        testrail_url = 'http://' + server + '/testrail/'
        self.client = APIClient(testrail_url)
        self.client.user = user
        self.client.password = password
        self.run_id = run_id
        self.update = update
        self.results = list()
        logger.info('[TestRailListener] url: ' + testrail_url)
        logger.info('[TestRailListener] user: '******'[TestRailListener] password: '******'[TestRailListener] the ID of the test run: ' + run_id)

    def end_test(self, name, attrs):
        """
        Update test case in TestRail
        
        *Args:*\n
        _name_ - the name of test case in Robot Framework\n
        _attrs_ - attributes of test case in Robot Framework
        """

        tags_value = self._getTagsValue (attrs['tags'])
        case_id = tags_value['testrailid']
        defects = tags_value['defects']
        references = tags_value['references']
        if attrs['status'] == 'PASS':
            status_id = 1
        else :
            status_id = 5
        if case_id:
            # Add results to list
            test_result = {
                'case_id': case_id,
                'status_id': status_id,
                'comment': attrs['message'],
                'defects': defects
            }
            self.results.append(test_result)

            # Update test case
            if self.update:
                logger.info ('[TestRailListener] update of test ' + case_id + ' in TestRail')
                description = attrs['doc'] + '\n' + 'Path to test: ' + attrs['longname']
                result = self.client.send_post(
                                               'update_case/' + case_id,
                                               {
                                                   'title': name,
                                                   'type_id': 1,
                                                   'custom_case_description': description,
                                                   'refs': references
                                               }
                )
                logger.info (
                    '[TestRailListener] result for method update_case '
                    + json.dumps(result, sort_keys=True, indent=4)
                )
                tag = 'testRailId={case_id}'.format(case_id=case_id)
                logger.info('[TestRailListener] remove tag {tag} from test case report'.format(tag=tag))
                BuiltIn().run_keyword('remove tags', tag)

    def close (self):
        """
        Save test results for all tests in TestRail
        """

        self.client.send_post('add_results_for_cases/' + self.run_id, {'results': self.results})

    def _getTagsValue (self, tags):
        """
        Get value from robot framework's tags for TestRail.
        """
        attributes = dict()
        matchers = ['testrailid', 'defects', 'references']
        for matcher in matchers:
            for tag in tags:
                match = re.match(matcher, tag)
                if match:
                    split_tag = tag.split('=')
                    tag_value = split_tag[1]
                    attributes[matcher] = tag_value
                    break
                else:
                    attributes[matcher] = None
        return attributes
コード例 #19
0
def main():
    server = "http://SERVER.COM"
    login = "******"
    password = "******"

    START_DATE = "01/08/2018"
    END_DATE = "31/08/2018"

    TESTERS = ['USER1EMAIL', 'USER2EMAIL']

    start_date = mktime(datetime.strptime(START_DATE, "%d/%m/%Y").timetuple())
    end_date = mktime(datetime.strptime(END_DATE, "%d/%m/%Y").timetuple())

    client = APIClient(server)
    client.user = login
    client.password = password

    print "Getting testers... "
    testers = {}
    for tester_email in TESTERS:
        try:
            tester = client.send_get('get_user_by_email&email={}'.format(tester_email))
            testers.update({
                tester["id"]: {
                    'email': tester_email,
                    'created': 0,
                    'updated': 0
                }
            })
        except APIError:
            print "Tester's email is not valid", tester_email

    projects = client.send_get('get_projects/')
    for project in projects:
        print "=" * 80
        print "PROJECT", project["id"]

        project_id = project["id"]
        project_suites = client.send_get('get_suites/{}'.format(project_id))

        for suite in project_suites:
            print "-" * 80
            print "SUITE", suite["id"]

            suite_id = suite["id"]

            created = client.send_get(
                'get_cases/{0}&suite_id={1}&created_after={2}&created_before={3}'.format(
                    project_id, suite_id, int(start_date), int(end_date)))

            updated = client.send_get(
                'get_cases/{0}&suite_id={1}&updated_after={2}&updated_before={3}'.format(
                    project_id, suite_id, int(start_date), int(end_date)))

            for c in created:
                tid = c['created_by']
                if tid in testers:
                    testers[tid]['created'] += 1
                # import pdb; pdb.set_trace()

            for c in updated:
                tid = c['updated_by']
                if tid in testers:
                    testers[tid]['updated'] += 1

    # ------------------------------------------------------------------------

    print "=" * 80
    pprint(testers)
コード例 #20
0
from creds import *
from testrail import APIClient
import sys
import datetime

client = APIClient(TESTRAIL_URL)
client.user = TESTRAIL_USER
client.password = TESTRAIL_API_TOKEN

RUN_ID = 371
project_id = 0
status_styles = {}


def make_report(test_run_id):
    indent = 1

    html_output = ''

    # Import structured header info
    with open('html_headers.html', 'r') as head_file:
        html_output += head_file.read()

    # Add body of html details
    html_output += get_run_info(test_run_id, indent + 1)

    # Add closing html elements
    html_output += close_element('div', indent)
    html_output += close_element('body', 0)
    html_output += close_element('html', 0)
コード例 #21
0
from pprint import pprint
import json
from testrail import APIClient, APIError

import requests

client = APIClient('')
client.user = ''
client.password = ''


class TestRailClient:
    def add_result(self, test_id, status: str):
        _ = client.send_post(f'add_result/{test_id}', {"status_id": 5})

    def add_result_for_case(self, run_id: int, case_id: int, status: str,
                            msg: str):
        """Add test case and update result

        """
        if status.lower() == "pass":
            result = client.send_post(
                'add_result_for_case/%d/%d' % (run_id, case_id), {
                    'status_id': 1,
                    'comment': msg
                })
            return result
        elif status.lower() == "fail":
            result = client.send_post(
                'add_result_for_case/%d/%d' % (run_id, case_id), {
                    'status_id': 5,
コード例 #22
0
 def __init__(self, url, user, password, project):
     self.client = APIClient(base_url=url)
     self.client.user = user
     self.client.password = password
     self.project = self._get_project(project)
コード例 #23
0
class TestRailListener(object):
    """
    Fixing of testing results and update test case in [ http://www.gurock.com/testrail/ | TestRail ].\n
    == Dependency ==
    - [ http://docs.gurock.com/testrail-api2/bindings-python | TestRail API2 python binding]
    == Preconditions ==
    1. [ http://docs.gurock.com/testrail-api2/introduction | Enable TestRail API] \n
    2. Create custom field "case_description" with type "text", which corresponds to the Robot Framework's test case documentation.
    == Example ==
    1. Create test case in TestRail with case_id = 10\n
    2. Add it to test run with id run_id = 20\n
    3. Create autotest in Robot Framework
    | *** Settings ***
    | *** Test Cases ***
    | Autotest name
    |    [Documentation]    Autotest documentation
    |    [Tags]    testrailid=10    defects=BUG-1, BUG-2    references=REF-3, REF-4
    |    Fail    Test fail message
    4. Run Robot Framework with listener:\n
    | set ROBOT_SYSLOG_FILE=syslog.txt
    | pybot.bat --listener TestRailListener.py:testrail_server_name:tester_user_name:tester_user_password:20:update  autotest.txt
    5. Test with case_id=10 will be marked as failed in TestRail with message "Test fail message" and defects "BUG-1, BUG-2".
    Also title, description and references of this test will be updated in TestRail. Parameter "update" is optional.
    """

    ROBOT_LISTENER_API_VERSION = 2

    def __init__(self, server, user, password, run_id, update = None):
        """
        *Args:*\n
        _server_ - the name of TestRail server;
        _user_ - the name of TestRail user;
        _password_ - the password of TestRail user;
        _run_id -  the ID of the test run;
        _update_ - indicator to update test case in TestRail; if exist, then test will be updated.
        """

        testrail_url = 'http://' + server + '/testrail/'
        self.client = APIClient(testrail_url)
        self.client.user = user
        self.client.password = password
        self.run_id = run_id
        self.update = update
        self.results = list()
        logger.info('[TestRailListener] url: ' + testrail_url)
        logger.info('[TestRailListener] user: '******'[TestRailListener] password: '******'[TestRailListener] the ID of the test run: ' + run_id)

    def end_test(self, name, attrs):
        """
        Update test case in TestRail
        
        *Args:*\n
        _name_ - the name of test case in Robot Framework\n
        _attrs_ - attributes of test case in Robot Framework
        """

        tags_value = self._getTagsValue (attrs['tags'])
        case_id = tags_value['testrailid']
        defects = tags_value['defects']
        references = tags_value['references']
        if attrs['status'] == 'PASS':
            status_id = 1
        else :
            status_id = 5
        if case_id:
            # Add results to list
            test_result = {'case_id': case_id, 'status_id': status_id, 'comment': attrs['message'], 'defects': defects}
            self.results.append(test_result)

            # Update test case
            if self.update:
                logger.info ('[TestRailListener] update of test ' + case_id + ' in TestRail')
                description = attrs['doc'] + '\n' + 'Path to test: ' + attrs['longname']
                result = self.client.send_post(
                                               'update_case/' + case_id,
                                               { 'title': name, 'type_id': 1, 'custom_case_description': description, 'refs': references}
                )
                logger.info ('[TestRailListener] result for method update_case ' + json.dumps(result, sort_keys = True, indent = 4))

    def close (self):
        """
        Save test results for all tests in TestRail
        """

        self.client.send_post('add_results_for_cases/' + self.run_id, { 'results':self.results })

    def _getTagsValue (self, tags):
        """
        Get value from robot framework's tags for TestRail.
        """
        attributes = dict()
        matchers = ['testrailid', 'defects', 'references']
        for matcher in matchers :
            for tag in tags:
                match = re.match(matcher, tag)
                if match :
                    split_tag = tag.split('=')
                    tag_value = split_tag[1]
                    attributes [matcher] = tag_value
                    break
                else:
                    attributes [matcher] = None
        return attributes
コード例 #24
0
 def __init__(self, url, user, password, project):
     self.client = APIClient(base_url=url)
     self.client.user = user
     self.client.password = password
     self.project = self._get_project(project)
コード例 #25
0
class TestRailTagger(object):
    """
    class to register robot's test cases in test rail
    and then add corresponding tags to robot's test cases
    """
    def __init__(self,
                 host,
                 user,
                 password,
                 file_path,
                 section_id,
                 file_format='robot'):
        """
        :param host: test rail host
        :param user: user name
        :param password: password
        :param file_path: path of test case files or directory
        :param section_id: section to store auto test cases
        :param file_format: default to be .robot
        """
        testrail_url = 'http://' + host + '/testrail/'
        self.client = APIClient(testrail_url, user, password)
        self.file = list()
        # to loop through the test suites
        try:
            if os.path.isdir(file_path):
                for files in os.walk(file_path):
                    for robot_file in filter(lambda x: x.endswith('.robot'),
                                             files[2]):
                        self.file.append(
                            TestData(source=os.path.abspath(
                                os.path.join(files[0], robot_file))))
            else:
                self.file.append(TestData(source=file_path))
        except DataError as e:
            # .robot file may have no test cases in it
            logging.warn('[TestRailTagger]' + e.message)

        self.section = section_id
        self.writer = DataFileWriter(format=file_format)

    def add_tag(self):
        """
        add specific tags to test cases
        """
        for suite in self.file:
            # to handle force tags, delete force tags in setting table
            # and then add the tag value to each test case in a suite
            force_tags = suite.setting_table.force_tags.value
            suite.setting_table.force_tags.value = None
            for test in suite.testcase_table.tests:
                getattr(self, TAG_TYPE['testRail'])(test, suite, force_tags)

    def add_test_rail_id(self, test, test_case_file, other_tags):
        """
        register test case and add the test case id to .robot file
        :param test: TestData class object, one of test cases
                    read from goven .robot file
        :param test_case_file: the .robot file to write (add tags)
        :param other_tags: param for the force tags(also for other tags)
        """
        if test.tags.value is None:
            test.tags.value = list()
        tags_value = getTagsValue(test.tags.value)
        case_id = tags_value.get('testRailId')
        if case_id is None:
            res = self.client.send_post(
                'add_case/{section_id}'.format(section_id=self.section), {
                    'title':
                    'Auto-' + test.name,
                    'type_id':
                    1,
                    'priority_id':
                    3,
                    'estimate':
                    '1h',
                    'refs':
                    '',
                    'custom_steps': [{
                        'content': getattr(step, 'name', ''),
                        'expected': 'auto-results'
                    } for step in test.steps if step]
                })
            case_id = res.get('id')
            logging.info(
                '[TestRailTagger] register test {case_id} to TestRail'.format(
                    case_id=case_id))
            test.tags.value.append(
                TEST_RAIL_ID_TEMPLATE.format(case_id=case_id))
            test.tags.value += other_tags
            self.writer.write(test_case_file)
コード例 #26
0
import sys
import getpass
import json
import pprint
from testrail import APIClient

url = 'https://bsro.testrail.net'
client = APIClient(url)
client.user = '******'
client.password = sys.argv[1]

#def usage():
#  print("[!] Usage: tr_conn.py -p password")
#  for eachArg in sys.argv:
#        print(eachArg)


def get_creds():
    print("[<] Enter TestRail login:\n")
    if len(client.user) < 1:
        client.user = input("login: "******"[ha!] forgot something?....where's the password ?")
            sys.exit(0)

    print("[.] k, got the creds for ", client.user)


def input_yes_no(question, default="yes"):
コード例 #27
0
def testrail_requester():
    config = load_configuration()
    client = APIClient("https://dromeroa.testrail.io")
    client.user = "******"
    client.password = config["TESTRAIL_TOKEN"]
    return client