コード例 #1
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
    def AddTestToTestSet(self, test_case_id, test_set_id):
        '''
        See https://sharenet-ims.inside.nsn.com/livelink/livelink/Download/392499262

        Return value is very intersting, because it tells the test instance ID:
            <return_message>
              <status>True</status>
              <return_value>
                <test_instance_id>62</test_instance_id>
              </return_value>
            </return_message>
        '''
        parameters = ElementTree.Element('parameters')
        ElementTree.SubElement(parameters, 'test_set_id').text = test_set_id
        instances = ElementTree.SubElement(parameters, 'test_instances')
        instance = ElementTree.SubElement(instances, 'test_instance')
        fields = ElementTree.SubElement(instance, 'fields')
        ElementTree.SubElement(fields, 'TC_TEST_ID').text = test_case_id
        ElementTree.SubElement(instance, 'attachments')
        input_xml = self._constructInputXML('AddTests2TestSet', parameters)
        Log.debug(self._removePassword(input_xml))
        returnXML = self._QcXmlApiCall("AddTests2TestSet", input_xml)
        element = ElementTree.XML(returnXML)
        test_instance_ids = element.findall('return_value')[0].findall('test_instance_id')
        if len(test_instance_ids) != 1:
            raise Exception("Did not get unique (or any) test instance ID.")
        else:
            return test_instance_ids[0].text
コード例 #2
0
ファイル: robot2qc.py プロジェクト: shijinyu2011/cciscript
 def _report(self, testset_opt, testset_id_opt, release=None, build=None):
     Log.critical("Trying to connect QualityCenter...")
     # Log.info('Connected to QCXML version %s' % client.GetVersion())
     Log.critical("Validating data...")
     if testset_id_opt:
         testset_qcid = testset_id_opt
     else:
         testset_path, testset_name = self._split_testset_argument(
             testset_opt)
         try:
             testset_qcid = self.client.FindTestSet(testset_path,
                                                    testset_name)
         except:
             testset_qcid = self.client.AddTestSet(testset_path,
                                                   testset_name)
     already_added_cases = self.client.GetTestSetInstances(testset_qcid)
     Log.info(
         'QC internal ID for the test set is "%s". It contains instances for %s test cases'
         % (testset_qcid, len(already_added_cases)))
     results = []
     for result in self.results:
         # Extend result dicts with QC internal IDs for test cases
         try:
             test_case_id = result['test_case_id'].split()[0]
             qcid = self.client.FindTestCase(test_case_id)
             Log.info('QC internal ID for test case "%s" is "%s"' %
                      (test_case_id, qcid))
             result['qcid'] = qcid
             qcstatus = "Passed" if result['status'] == "PASS" else "Failed"
             result['qcstatus'] = qcstatus
             results.append(result)
         except Exception, errmsg:
             Log.info("test case id <%s> error: %s" %
                      (test_case_id, errmsg))
コード例 #3
0
ファイル: qchandler.py プロジェクト: shijinyu2011/cciscript
 def initialize_client(self):
     self.client = QcRestClient(self.config.server_url,
                                self.config.username, self.config.password,
                                self.config.domain, self.config.project,
                                self.config.proxy)
     Log.critical("Authenticating to QC REST API...")
     self.client.authenticate()
コード例 #4
0
 def wait(self):
     if self.attempt >= self.max_attempts:
         raise RetryLimitExceeded(self.max_attempts)
     Log.debug("Retry attempt:%s, next sleep:%s" %
               (self.attempt, self.next_sleep()))
     time.sleep(self.next_sleep())
     self.attempt += 1
コード例 #5
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
    def AddTestSet(self, path, test_set_name):
        '''
        Add test set by path and name
        More details, See: <https://qc-api.inside.nsn.com/QcXmlWebSite/>
        Excpected return value from API
        <return_message>
          <status>True</status>
          <return_value>
            <id>1803</id>
          </return_value>
        </return_message>
        '''
        parameters = ElementTree.Element('parameters')
        ElementTree.SubElement(parameters, 'path').text = path
        test_set = ElementTree.SubElement(parameters, 'test_set')
        ElementTree.SubElement(test_set, 'attachments').text = ''
        fields = ElementTree.SubElement(test_set, 'fields')
        ElementTree.SubElement(fields, 'CY_CYCLE').text = test_set_name
        ElementTree.SubElement(fields, 'CY_USER_01').text = 'RCP0'
        ElementTree.SubElement(fields, 'CY_USER_02').text = 'EnTe - Functional Test'
        ElementTree.SubElement(fields, 'CY_USER_13').text = 'Draft'
        ElementTree.SubElement(fields, 'CY_USER_18').text = 'N/A'
        ElementTree.SubElement(fields, 'CY_USER_51').text = 'cWLC'
        input_xml = self._constructInputXML('AddTestSet', parameters)
        Log.debug(self._removePassword(input_xml))

        returnXML = self._QcXmlApiCall("AddTestSet", input_xml)
        element = ElementTree.XML(returnXML)        
        return element.findall('return_value')[0].findall('id')[0].text
コード例 #6
0
 def map_tc2req(self, qc_test_id, requirement_id):
     coverage = self.client.getReqCoverageByTCID(qc_test_id)
     if requirement_id in coverage:
         Log.info('Requirement map already exists - no need to create')
     else:
         Log.info('Requirement map missing - creating')
         self.client.addReqCoverage(qc_test_id, requirement_id)
コード例 #7
0
ファイル: qchandler.py プロジェクト: shijinyu2011/cciscript
 def initialize_client(self):
     self.client = QcXmlClient(self.config.xml_api_url,
                               self.config.username, self.config.password,
                               self.config.domain, self.config.project,
                               self.config.test_case_search_root,
                               self.config.proxy)
     Log.critical("Initialized QC XML API client")
     self.client.initialize()
コード例 #8
0
 def authenticate(self):
     path = 'qcbin/authentication-point/alm-authenticate'
     data = ("<?xml version='1.0' encoding='utf-8'?>"
             "<alm-authentication>"
             "<user>%s</user>"
             "<password>%s</password>"
             "</alm-authentication>") % (self.username, self.password)
     q = RestHeaderQuery(path, "post", data=data)
     headers = q.request(self.server, proxies=self.proxy)
     self.cookie = headers['set-cookie']
     Log.debug("Got cookie: %s" % self.cookie)
コード例 #9
0
 def __init__(self, server, username, password, domain, project, proxy):
     super(QcRestClient, self).__init__()
     self.server = server
     self.username = username
     self.password = password
     self.domain = domain
     self.project = project
     self.proxy = proxy
     self.cookie = None
     logvars = copy.deepcopy(vars())
     del logvars['password']
     Log.debug('Initialized QC REST client with: %s' % logvars)
コード例 #10
0
ファイル: robot2qc.py プロジェクト: shijinyu2011/cciscript
 def _split_testset_argument(testset_input):
     Log.debug("Parsing test set '%s'" % testset_input)
     match = re.search(r'\\', testset_input)
     if not match:
         raise QcReporterException(
             "Test set path must look like 'Root\\Folder\\...\\Test set name' "
             "and it must contain at least one path separator character ('\\')"
         )
     testset_components = testset_input.rsplit('\\', 1)
     testset_path = testset_components[0]
     testset_name = testset_components[1]
     Log.debug("Looking for test set %s in path %s" %
               (testset_name, testset_path))
     return (testset_path, testset_name)
コード例 #11
0
 def add_tc(self, test_path, test_id, test_name, test_prio):
     parent_id = self.client.resolveTestFolderQcId(test_path)
     existing_test_id = self.client.getTestCaseByTCID(
         test_id, parent_id=parent_id, raise_on_empty_match=False)
     if existing_test_id:
         Log.info('test %s: id=%s already exists - updating' %
                  (test_id, existing_test_id))
         self.client.updateTestCase(existing_test_id, parent_id, test_id,
                                    test_name, test_prio)
     else:
         Log.info('test %s: not existing - adding' % (test_id))
         existing_test_id = self.client.addTestCase(parent_id, test_id,
                                                    test_name, test_prio)
     return int(existing_test_id)
コード例 #12
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
 def _QcXmlApiCall(self, method_name, inputXML):
     Log.debug('Calling %s on %s' % (method_name, self.url))
     delay = RetryDelay(40)
     while True:
         try:
             ret = getattr(self.client.service, method_name)(inputXML)
             return self._FilterQcXmlExceptions(ret)
         except QcXmlException:
             raise
         except Exception, e:
             Log.warn('Temporary problem in QualityCenter (%s). Retrying in %s s...' %
                                 (e, delay.next_sleep()))
             delay.wait()  # Will throw exception after max attempts
             self.initialize()
コード例 #13
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
 def GetUserProjects(self):
     '''
     Excpected return value from API
     <return_message>
       <status>True</status>
       <return_value>
         <project_name>FP</project_name>
       </return_value>
     </return_message>
     '''
     input_xml = self._constructInputXML('GetUserProjects')
     Log.debug(self._removePassword(input_xml))
     returnXML = self._QcXmlApiCall("GetUserProjects", input_xml)
     element = ElementTree.XML(returnXML)
     return [x.text for x in element.findall('return_value')[0].findall('project_name')]
コード例 #14
0
 def equals_query(queries):
     """
     Query to be appended to URL after "?"
     queries - dict of key-value pairs that must match. e.g. {'user-01': 'EXAMPLE_001'}}
     No support for spaces or special characters. Add the support in this fuction if you need them.
     """
     key_value_pair_strings = []
     for key, value in queries.items():
         if type(value) is str:
             value = value.replace('&', '%26')
         if type(value) == int:
             value_str = '%s' % value
         else:
             value_str = "'%s'" % value
         Log.debug("############################# STR: %s" % value_str)
         key_value_pair_strings.append('%s[%s]' % (key, value_str))
     return "query={%s}" % (';'.join(key_value_pair_strings))
コード例 #15
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
    def FindTestCase(self, test_case_id, path=None):
        '''
        Finds test case's numeric ID by the test_case_id string.
        test_case_id is the "Test Case ID" in QC web UI. In the database
        this field is called TS_USER_01. Numeric test case id is internal
        to QC and not visible in the web user interface.

        Expected return value, e.g.
            <return_message>
              <status>True</status>
              <return_value>
                <test_case>
                  <id>28</id>
                  <name>Authentication configuration of NTP</name>
                  <path>\Subject\VGP&amp;LCC\NECC\Operability Interfaces\NTP\NECC provides clock synchronization to vNE</path>
                </test_case>
              </return_value>
            </return_message>
        '''
        if not path:
            path = self.test_case_search_root
        parameters = ElementTree.Element('parameters')
        path_elem = ElementTree.SubElement(parameters, 'path')
        ElementTree.SubElement(parameters, 'recursive').text = 'true'
        ElementTree.SubElement(parameters, 'include_attachments').text = 'false'
        ElementTree.SubElement(parameters, 'include_test_case_details').text = 'false'
        fields = ElementTree.SubElement(parameters, 'fields')
        test_case_id_elem = ElementTree.SubElement(fields, 'TS_USER_01')
        path_elem.text = path
        test_case_id_elem.text = '"%s"' % test_case_id
        input_xml = self._constructInputXML('GetTestCaseList', parameters)
        Log.debug(self._removePassword(input_xml))
        returnXML = self._QcXmlApiCall("GetTestCaseList", input_xml)
        element = ElementTree.XML(returnXML)
        testcases = element.findall('return_value')[0].findall('test_case')
        if len(testcases) > 1:
            raise QcClientException("Test case ID %s is not unique. Candidates are: %s" %
                                    (test_case_id, [x.findall('name')[0].text for x in testcases]))
        elif len(testcases) < 1:
            raise QcClientException('No test cases found with ID "%s" under path "%s"' %
                                    (test_case_id, self.test_case_search_root))
        else:
            return testcases[0].findall('id')[0].text
コード例 #16
0
ファイル: query.py プロジェクト: shijinyu2011/cciscript
    def _analyze_result(self, response, headers=None):
        """ This function could be overriden if the response might contain more than one acceptable return codes """
        Log.debug("result: %d" % response.status_code)
        Log.log(5, "response text: %s" % response.text)
        Log.log(5, "response headers: %s" % response.headers)
        if headers:
            Log.log(5, "headers: %s" % headers)

        if response.status_code == self.result:
            return self._parse_result_parameters(response)

        raise RestQueryException("Status code mismatch, expected %d, got %d" %
                                 (self.result, response.status_code), response.text)
コード例 #17
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
    def FindTestSetFolder(self, path, folder_name):
        '''
        Finds test set folder by the folder name
        More details, See: <https://qc-api.inside.nsn.com/QcXmlWebSite/>
        Excpected return value from API
        <return_message>
            <status>True</status>
            <return_value>
                <folder_tree_node>
                    <folder>
                        <name>lidong_test</name>
                        <path>Root\lidong_test</path>
                    </folder>
                  <folder_tree_node>
                      <folder>
                          <name>testfolder_cj_01</name>
                          <path>Root\lidong_test\testfolder_cj_01</path>
                      </folder>
                    </folder_tree_node>
                    <folder_tree_node>
                        <folder>
                            <name>testfolder_cj_02</name>
                            <path>Root\lidong_test\testfolder_cj_02</path>
                        </folder>
                    </folder_tree_node>
                </folder_tree_node>
            </return_value>
        </return_message>
        '''
        parameters = ElementTree.Element('parameters')
        ElementTree.SubElement(parameters, 'path').text = path
        ElementTree.SubElement(parameters, 'include_attachments').text = 'false'        
        ElementTree.SubElement(parameters, 'recursive').text = 'false'
        input_xml = self._constructInputXML('GetTestSetFolderTree', parameters)
        Log.debug(self._removePassword(input_xml))
        returnXML = self._QcXmlApiCall("GetTestSetFolderTree", input_xml)
        element = ElementTree.XML(returnXML)
        nodes = element.findall('return_value')[0].findall('folder_tree_node')
#         parent = nodes[0].findall('folder')[0].findall('name')[0].text
        childrens = [n[0].findall('name')[0].text for n in nodes[0].findall('folder_tree_node')]
        return (folder_name in childrens)    
コード例 #18
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
 def FindTestSet(self, path, test_set_name):
     '''
     Finds test set id by the test set name
     '''
     parameters = ElementTree.Element('parameters')
     ElementTree.SubElement(parameters, 'path').text = path
     ElementTree.SubElement(parameters, 'include_attachments').text = 'false'
     ElementTree.SubElement(parameters, 'include_test_set_details').text = 'false'
     ElementTree.SubElement(parameters, 'recursive').text = 'false'
     fields = ElementTree.SubElement(parameters, 'fields')
     ElementTree.SubElement(fields, 'CY_CYCLE').text = '"%s"' % test_set_name
     input_xml = self._constructInputXML('GetTestSetList', parameters)
     Log.debug(self._removePassword(input_xml))
     returnXML = self._QcXmlApiCall("GetTestSetList", input_xml)
     element = ElementTree.XML(returnXML)
     testsets = element.findall('return_value')[0].findall('test_set')
     if len(testsets) > 1:
         raise QcClientException("Test set %s is not unique. Candidates are: %s" %
                                 (test_set_name, [x.findall('name')[0].text for x in testsets]))
     elif len(testsets) < 1:
         raise QcClientException("No test sets found with name %s" % (test_set_name))
     else:
         return testsets[0].findall('id')[0].text
コード例 #19
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
 def AddTestSetFolder(self, path, folder_name):
     '''
     Add test set folder by path and folder name
     More details, See: <https://qc-api.inside.nsn.com/QcXmlWebSite/>
     Excpected return value from API
     <return_message>
       <status>True</status>
       <return_value>
         <id>62</id>
       </return_value>
     </return_message>
     '''
     parameters = ElementTree.Element('parameters')        
     test_set_folder = ElementTree.SubElement(parameters, 'folder')
     ElementTree.SubElement(test_set_folder, 'attachments').text = ''
     ElementTree.SubElement(test_set_folder, 'name').text = folder_name
     ElementTree.SubElement(test_set_folder, 'path').text = path        
     input_xml = self._constructInputXML('AddTestSetFolder', parameters)
     Log.debug(self._removePassword(input_xml))
     
     returnXML = self._QcXmlApiCall("AddTestSetFolder", input_xml)
     element = ElementTree.XML(returnXML)             
     return element.findall('return_value')[0].findall('id')[0].text        
コード例 #20
0
 def debug_print_fields(entity, title=None):
     if title:
         Log.debug(title)
     else:
         Log.debug("----------------------------------")
     for field in entity['Fields']:
         for value in field['values']:
             if 'value' in value:
                 Log.debug("%-20s: %s" % (field['Name'], value['value']))
コード例 #21
0
 def resolveTestFolderQcId(self, folder_path):
     folder_path_dirs = re.split(r'[/\\]', folder_path)
     parent_id = 0
     parent_name = ""
     for d in folder_path_dirs:
         path_frag = 'test-folders?' + self.equals_query({
             'parent-id': parent_id,
             'name': d
         })
         response = self.query(path_frag)
         if int(response['TotalResults']) < 1:
             raise QcClientException(
                 'No matches found with dir "%s" and parent \"%s\"' %
                 (d, parent_name))
         if int(response['TotalResults']) > 1:
             raise QcClientException(
                 'More than one match found with dir "%s" and parent \"%s\"'
                 % (d, parent_name))
         entity = response['entities'][0]
         self.debug_print_fields(entity)
         Log.debug('dir \"%s\" found' % (d))
         parent_id = self.get_field_value(entity, 'id')
         parent_name = self.get_field_value(entity, 'name')
     return self.get_field_value(entity, 'id')
コード例 #22
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
 def AddRunToTestSet(self, test_case_id, test_set_id, result, release=None, build=None, set_date=True):
     '''
     See https://sharenet-ims.inside.nsn.com/livelink/livelink/Download/392499262
     '''
     parameters = ElementTree.Element('parameters')
     ElementTree.SubElement(parameters, 'test_set_id').text = test_set_id
     runs = ElementTree.SubElement(parameters, 'runs')
     run = ElementTree.SubElement(runs, 'run')
     ElementTree.SubElement(run, 'attachments')
     fields = ElementTree.SubElement(run, 'fields')
     ElementTree.SubElement(fields, 'RN_RUN_NAME').text = 'CloudTAF %s' % time.ctime()
     if set_date:
         ElementTree.SubElement(fields, 'RN_EXECUTION_DATE').text = time.strftime("%Y-%m-%d", time.gmtime())
         ElementTree.SubElement(fields, 'RN_EXECUTION_TIME').text = time.strftime("%H:%M:%S", time.gmtime())
     if release:
         ElementTree.SubElement(fields, 'RN_USER_03').text = release
     if build:
         ElementTree.SubElement(fields, 'RN_USER_01').text = build
     ElementTree.SubElement(fields, 'RN_TESTCYCL_ID').text = test_case_id
     ElementTree.SubElement(fields, 'RN_STATUS').text = result
     run = ElementTree.SubElement(run, 'steps')
     input_xml = self._constructInputXML('AddTestSetRuns', parameters)
     Log.debug(self._removePassword(input_xml))
     self._QcXmlApiCall("AddTestSetRuns", input_xml)
コード例 #23
0
ファイル: qcxmlclient.py プロジェクト: shijinyu2011/cciscript
    def GetTestSetInstances(self, test_set_id):
        '''
        Get a list of test case IDs that have already been added in this test set.

        Return value from GetTestSet api call is very long. We need to check if the test
        instance corresponding the test case is already added, so the essentials are:
            <return_message>
              <status>True</status>
              <return_value>
                <test_set>
                  <id>1207</id>
                  <name>QC Integration Test Test Set</name>
                  <fields>
                    ...
                  </fields>
                  <test_instance>
                    <id>63</id>
                    <name>[7]Example TC</name>
                    <fields>
                      ...
                      <TC_TEST_ID label="Test" type="number" size="10">1</TC_TEST_ID>
                      ...
                    </fields>
                  </test_instance>
                  ...
                </test_set>
              </return_value>
            </return_message>
        '''
        parameters = ElementTree.Element('parameters')
        ElementTree.SubElement(parameters, 'include_attachments').text = 'false'
        ElementTree.SubElement(parameters, 'include_test_cases').text = 'false'
        set_fields = ElementTree.SubElement(parameters, 'testset_fields')
        ElementTree.SubElement(set_fields, 'CY_CYCLE_ID').text = 'CY_CYCLE_ID'
        instance_fields = ElementTree.SubElement(parameters, 'testinstance_fields')
        ElementTree.SubElement(instance_fields, 'TC_TEST_ID').text = 'TC_TEST_ID'
        ElementTree.SubElement(parameters, 'id').text = test_set_id
        input_xml = self._constructInputXML('GetTestSetByID', parameters)
        Log.debug(self._removePassword(input_xml))
        returnXML = self._QcXmlApiCall("GetTestSetByID", input_xml)
        Log.debug(returnXML)
        element = ElementTree.XML(returnXML)
        test_instances = element.findall('return_value')[0].findall('test_set')[0].findall('test_instance')
        instances_for_cases = dict()
        for i in test_instances:
            instance_qcid = i.findall('id')[0].text
            test_qcid = i.findall('fields')[0].findall('TC_TEST_ID')[0].text
            Log.debug('Test Case "%s" has a Test Instance "%s" in this test set' % (test_qcid, instance_qcid))
            instances_for_cases[test_qcid] = instance_qcid
        return instances_for_cases
コード例 #24
0
ファイル: qcutilscli.py プロジェクト: shijinyu2011/cciscript
 def main(self, args=None):
     args = QcUtilsParser().parse_args(args)
     Log.set_logging(args.verbosity)
     Log.debug('args:%s' % (args))
     try:
         command = args.cmd()
         command.initialize_client()
         command.run(args)
         self._exit(0)
     except QcUtilsDetailedException as e:
         Log.critical('\n\n----- Start error trace -----\n%s\n----- End error trace -----\n' % e.detail)
         Log.critical('Error: "%s"' % e)
         Log.critical('See stack trace above for more details')
         self._exit(1)
     except QcUtilsException as e:
         Log.critical('Error: "%s"' % e)
         self._exit(1)
コード例 #25
0
ファイル: query.py プロジェクト: shijinyu2011/cciscript
 def _send_request(self, url, headers, payload, proxies):
     print_payload = self._remove_xml_password(payload)
     Log.log(5, "payload: %s" % print_payload)
     Log.debug("url: %s" % url)
     Log.log(5, "headers: %s" % headers)
     return self._analyze_result(self.method(url, data=payload, headers=headers, proxies=proxies), headers=headers)
コード例 #26
0
ファイル: qcconfig.py プロジェクト: shijinyu2011/cciscript
 def test_case_search_root(self):
     Log.info('Password not given in configuration %s' % self.config_path)
     tc_root = self.config.get('test_case_search_root')
     return re.sub('&', '&amp;', tc_root)
コード例 #27
0
 def print_results(results):
     Log.debug("Found the following test results to report")
     for r in results:
         Log.debug('%s (%s): %s' %
                   (r['name'], r['test_case_id'], r['status']))
コード例 #28
0
ファイル: robot2qc.py プロジェクト: shijinyu2011/cciscript
class RobotToQcReporter(QcXmlHandler):
    def __init__(self):
        super(RobotToQcReporter, self).__init__()
        self.results = None

    def run(self, args):
        self.results = RobotResultParser(args.report).get_results()
        self._report(args.testset, args.testset_id, args.release, args.build)

    @staticmethod
    def _split_testset_argument(testset_input):
        Log.debug("Parsing test set '%s'" % testset_input)
        match = re.search(r'\\', testset_input)
        if not match:
            raise QcReporterException(
                "Test set path must look like 'Root\\Folder\\...\\Test set name' "
                "and it must contain at least one path separator character ('\\')"
            )
        testset_components = testset_input.rsplit('\\', 1)
        testset_path = testset_components[0]
        testset_name = testset_components[1]
        Log.debug("Looking for test set %s in path %s" %
                  (testset_name, testset_path))
        return (testset_path, testset_name)

    def _report(self, testset_opt, testset_id_opt, release=None, build=None):
        Log.critical("Trying to connect QualityCenter...")
        # Log.info('Connected to QCXML version %s' % client.GetVersion())
        Log.critical("Validating data...")
        if testset_id_opt:
            testset_qcid = testset_id_opt
        else:
            testset_path, testset_name = self._split_testset_argument(
                testset_opt)
            try:
                testset_qcid = self.client.FindTestSet(testset_path,
                                                       testset_name)
            except:
                testset_qcid = self.client.AddTestSet(testset_path,
                                                      testset_name)
        already_added_cases = self.client.GetTestSetInstances(testset_qcid)
        Log.info(
            'QC internal ID for the test set is "%s". It contains instances for %s test cases'
            % (testset_qcid, len(already_added_cases)))
        results = []
        for result in self.results:
            # Extend result dicts with QC internal IDs for test cases
            try:
                test_case_id = result['test_case_id'].split()[0]
                qcid = self.client.FindTestCase(test_case_id)
                Log.info('QC internal ID for test case "%s" is "%s"' %
                         (test_case_id, qcid))
                result['qcid'] = qcid
                qcstatus = "Passed" if result['status'] == "PASS" else "Failed"
                result['qcstatus'] = qcstatus
                results.append(result)
            except Exception, errmsg:
                Log.info("test case id <%s> error: %s" %
                         (test_case_id, errmsg))

        Log.critical("Reporting results...")
        for r in results:
            Log.info('Reporting "%s" ("%s", QC: %s) as "%s"' %
                     (r['name'], r['test_case_id'], r['qcid'], r['qcstatus']))
            if r['qcid'] in already_added_cases:
                instance_qcid = already_added_cases[r['qcid']]
            else:
                instance_qcid = self.client.AddTestToTestSet(
                    r['qcid'], testset_qcid)
            self.client.AddRunToTestSet(instance_qcid, testset_qcid,
                                        r['qcstatus'], release, build)
        Log.info("Source result [%s] -> uploaded result [%s]" %
                 (self.results.__len__(), results.__len__()))
        Log.critical("Reporting completed")