def main(): parser = OptionParser( description="Upload tests cases to TestRail. " "See settings.py for configuration." ) parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Enable debug output") parser.add_option('-j', '--job-name', dest='job_name', default=None, help='Jenkins swarm runner job name') parser.add_option('-N', '--build-number', dest='build_number', default='latest', help='Jenkins swarm runner build number') parser.add_option('-o', '--check_one_section', action="store_true", dest='check_one_section', default=False, help='Look for existing test case only in specified ' 'section of test suite.') (options, args) = parser.parse_args() if options.verbose: logger.setLevel(DEBUG) project = TestRailProject( url=TestRailSettings.url, user=TestRailSettings.user, password=TestRailSettings.password, project=TestRailSettings.project ) testrail_section = project.get_section_by_name( suite_id=project.get_suite_by_name(TestRailSettings.tests_suite)['id'], section_name=TestRailSettings.tests_section ) testrail_milestone = project.get_milestone_by_name( name=TestRailSettings.milestone) tests_groups = get_tests_groups_from_jenkins( options.job_name, options.build_number) if options.job_name else [] # If Jenkins job build is specified, but it doesn't have downstream builds # with tests groups in jobs names, then skip tests cases uploading because # ALL existing tests cases will be uploaded if options.job_name and not tests_groups: return tests_descriptions = get_tests_descriptions( milestone_id=testrail_milestone['id'], tests_include=TestRailSettings.tests_include, tests_exclude=TestRailSettings.tests_exclude, groups=tests_groups ) upload_tests_descriptions(testrail_project=project, section_id=testrail_section['id'], tests=tests_descriptions, check_all_sections=not options.check_one_section)
def main(): rally_name = TestRailSettings.tests_suite + ' ' + \ TestRailSettings.tests_section cluster_description = os.environ.get('BUILD_URL', '') + '\n---\n' # # Collect info about cluster # # Initialize Nailgun client fuelmaster = os.environ.get('FUEL_IP', 'localhost') fuel_client = fuel.NailgunClient(fuelmaster) # Get Fuel version mos_version = os.environ.get('MOS_VERSION') mos_build = os.environ.get('MOS_BUILD') if mos_version and mos_build: fuel_version = { 'release': mos_version, 'build_number': mos_build, } else: fuel_version = fuel_client.get_api_version() # Build number should be an integer fuel_version['build_number'] = int(fuel_version['build_number']) cluster_description += 'Fuel version: {}-{}\n\n'.format( fuel_version['release'], fuel_version['build_number'] ) # Fuel cluster is needed only to get releases fuel_cluster = fuel_client.list_clusters()[0] # Release contains info about operating system fuel_release = fuel_client.get_releases_details(fuel_cluster['release_id']) cluster_description += 'Cluster configuration: {}\n\n'.format( fuel_release['name'] ) # Networking parameters cluster_network = fuel_client.get_networks(fuel_cluster['id']) # Network segmentation cluster_ns = cluster_network['networking_parameters']['segmentation_type'] cluster_description += 'Network segmentation: {}\n\n'.format( cluster_ns ) # Cluster nodes controllers = 0 computes = 0 for node in fuel_client.list_nodes(): if(node['cluster'] == fuel_cluster['id']): if('controller' in node['roles']): controllers += 1 if('compute' in node['roles']): computes += 1 cluster_description += 'Total nodes: {}\n'.format(controllers + computes) cluster_description += '+ controllers: {}\n'.format(controllers) cluster_description += '+ computes: {}\n\n'.format(computes) # Other cluster options cluster_attributes = fuel_client.get_cluster_attributes(fuel_cluster['id']) cluster_components = get_enabled_attributes(cluster_attributes, 'additional_components') cluster_description += 'Optional components: {}\n\n'.format( ', '.join(map(str.capitalize, cluster_components)) ) # Storage cluster_storage = get_enabled_attributes(cluster_attributes, 'storage') cluster_description += 'Storage: {}\n'.format( ', '.join(cluster_storage) ) # Display Fuel info and cluster configuration print(cluster_description) # # Find appropriate existing or create new one test run in TestRail # # Initialize TestRail testrail = TestRailProject( url=TestRailSettings.url, user=TestRailSettings.user, password=TestRailSettings.password, project=TestRailSettings.project ) # Find milestone for ms in testrail.get_milestones(): if(ms['name'] == fuel_version['release']): milestone = ms break print('Testrail milestone: {}'.format(milestone['name'])) # Find config for cf in testrail.get_configs(): if(cf['name'] == 'Operation System'): for ccf in cf['configs']: if(ccf['name'].lower() in fuel_release['name'].lower()): test_config = ccf break print('Testrail configuration: {}'.format(test_config['name'])) # Get test suite test_suite = testrail.get_suite_by_name(rally_name) if not test_suite: testrail.create_suite( name=rally_name, description='Periodic deployment tests by MOS Infra team.\nSee: ' 'https://jenkins.mosi.mirantis.net/view/Periodic%20(deployment)/' ) # Get test cases for test section in suite test_cases = testrail.get_cases( suite_id=test_suite['id'] ) print('Testrail test suite "{}" contains {} test cases'.format( test_suite['name'], len(test_cases)) ) job_name = os.environ.get('CUSTOM_JOB', fuel_version['release'] + '.all') prefix = os.environ.get('ISO_PREFIX', '') # Test plans have names like "<fuel-version> iso #<fuel-build>" test_plan_name = '{milestone}{prefix} iso #{iso_number}'.format( milestone=milestone['name'], prefix=' ' + prefix if prefix else '', iso_number=fuel_version['build_number']) # Find appropriate test plan test_plan = testrail.get_plan_by_name(test_plan_name) if not test_plan: test_plan = testrail.add_plan( test_plan_name, description='{url}/job/{job}/{build}'.format( url=PRODUCT_JENKINS['url'], job=job_name, build=fuel_version['build_number'] ), milestone_id=milestone['id'], entries=[] ) # Create test plan entry (run) plan_entries = [] plan_entries.append( testrail.test_run_struct( name=JENKINS_JOB, suite_id=test_suite['id'], milestone_id=milestone['id'], description=cluster_description, config_ids=[test_config['id']] ) ) # Add newly created plan entry to test plan and renew plan on success re_storage = re.compile('^([^_]+)') plan_entry_name = rally_name plan_entry_name += ' ({} controllers, {} computes)'.format(controllers, computes) plan_entry_name += ': ' + cluster_ns.upper() if('volumes_lvm' in cluster_storage): plan_entry_name += '; LVM' else: plan_entry_name += '; Ceph for ' plan_entry_name += ', '.join([ re_storage.match(storage).group(1).capitalize() for storage in sorted(cluster_storage) ]) if(cluster_components > 0): plan_entry_name += '; ' plan_entry_name += ', '.join(map(str.capitalize, cluster_components)) # Find appropriate run test_run = None for e in test_plan['entries']: if(e['suite_id'] == test_suite['id'] and e['name'] == plan_entry_name): plan_entry = e test_run = get_run_by_config( plan_entry['runs'], test_suite['id'], milestone['id'], test_config['id'] ) if test_run: break # ... if not found, create new one if not test_run: plan_entry = testrail.add_plan_entry( plan_id=test_plan['id'], name=plan_entry_name, suite_id=test_suite['id'], config_ids=[test_config['id']], runs=plan_entries ) test_run = get_run_by_config( plan_entry['runs'], test_suite['id'], milestone['id'], test_config['id'] ) print('Using Testrail run "{}" (ID {})'.format( test_run['name'], test_run['id'] )) # Create list of test case names with ids for further use test_cases_exist = {} for tc in test_cases: test_cases_exist[tc['title']] = tc['id'] # Will contain test results for publishing test_results = [] # Will contain list of runned tests test_cases_run = [] # # Proceed Rally results # # Get Rally config CONF(sys.argv[1:], project='rally') # Prepare regexp for component matching re_comp = re.compile('([A-Z]+[a-z]+)(.*)\.') # Use first avalable rally deployment deployment = rally.db.deployment_list()[0] # Get all tasks for specified deployment for task in rally.db.task_list(deployment=deployment.uuid): # Single task may have many scenarios for res in rally.db.task_result_get_all_by_uuid(task.uuid): atomic_actions = [] # Create test case if it is not exists if res.key['name'] not in test_cases_exist.keys(): print('Create new test case: {}'.format( res.key['name']) ) # Get atomic actions as steps if any if(len(res.data['raw']) > 0): atomic_actions = [{ 'content': aa, 'expected': 'Any positive value (seconds)' } for aa in res.data['raw'][0]['atomic_actions']] test_section_name = re_comp.match(res.key['name']).group(1) # Check existense of tests section test_section = testrail.get_section_by_name( suite_id=test_suite['id'], section_name=test_section_name ) # Create tests section if it doesn't exists if not test_section: test_section = testrail.create_section( suite_id=test_suite['id'], name=test_section_name ) # Create test case object test_case = { 'title': res.key['name'], 'type_id': 1, 'priority_id': 5, 'custom_test_group': re_comp.match( res.key['name']).group(2), 'custom_test_case_description': res.key['name'], 'custom_test_case_steps': atomic_actions } # Create test case in Testrail new_test_case = testrail.add_case( section_id=test_section['id'], case=test_case ) # Register test case as existing test_cases.append(new_test_case) test_cases_exist[res.key['name']] = new_test_case['id'] # Add test case to list of runned tests test_cases_run.append(test_cases_exist[res.key['name']]) # Create test results del test_results[:] new_result = { 'case_id': test_cases_exist[res.key['name']], 'status_id': 1, 'version': test_plan_name, 'elapsed': '{}s'.format(int(res.data["full_duration"])) if(int(res.data["full_duration"]) > 0) else '0', } # Each test can have many iterations, so many results for result in res.data['raw']: # Fail entire test case if any iteration is failed if(len(result['error']) > 0): new_result['status_id'] = 5 # Collect info about atomic actions # atomic_actions is array of dicts containing keys # "content" and "expected" # so need to add "actual" and "status_id" for aa in atomic_actions: # Get name of already defined atomic action aa_name = aa['content'] # Try to get duration of named atomic action aa_duration = result['atomic_actions'].get(aa_name, 0.0) aa_duration = round(float(aa_duration), 3) # Summarize atomic actions durations old_duration = aa.get('actual', '0.0') aa['actual'] = str(float(old_duration) + aa_duration) # Set atomic action status # Assume that it is not failed old_status = aa.get('status_id', 1) # Fail atomic action if it's duration unset # Atomic action doesn't contain key status_id, so it's must # be set explicitly to failure (5) or success (1) if(old_status == 1 and aa_duration == 0): aa['status_id'] = 5 else: aa['status_id'] = old_status new_result['custom_test_case_steps_results'] = atomic_actions # Append result to array test_results.append(new_result) # Send results if(test_run and test_results): print('Send results "{}"'.format(res.key['name'])) testrail.add_results_for_cases( run_id=test_run['id'], results=test_results )
def main(): parser = OptionParser(description="Upload tests cases to TestRail. " "See settings.py for configuration.") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Enable debug output") parser.add_option('-j', '--job-name', dest='job_name', default=None, help='Jenkins swarm runner job name') parser.add_option('-N', '--build-number', dest='build_number', default='latest', help='Jenkins swarm runner build number') parser.add_option('-o', '--check_one_section', action="store_true", dest='check_one_section', default=False, help='Look for existing test case only in specified ' 'section of test suite.') (options, args) = parser.parse_args() if options.verbose: logger.setLevel(DEBUG) project = TestRailProject(url=TestRailSettings.url, user=TestRailSettings.user, password=TestRailSettings.password, project=TestRailSettings.project) testrail_section = project.get_section_by_name( suite_id=project.get_suite_by_name(TestRailSettings.tests_suite)['id'], section_name=TestRailSettings.tests_section) testrail_milestone = project.get_milestone_by_name( name=TestRailSettings.milestone) testrail_default_test_priority = [ priority['id'] for priority in project.get_priorities() if priority['is_default'] is True ][0] distros = [ config['name'].split()[0].lower() for config in project.get_config_by_name('Operation System')['configs'] if config['name'] in TestRailSettings.operation_systems ] tests_groups = get_tests_groups_from_jenkins( options.job_name, options.build_number, distros) if options.job_name else [] # If Jenkins job build is specified, but it doesn't have downstream builds # with tests groups in jobs names, then skip tests cases uploading because # ALL existing tests cases will be uploaded if options.job_name and not tests_groups: return tests_descriptions = get_tests_descriptions( milestone_id=testrail_milestone['id'], tests_include=TestRailSettings.tests_include, tests_exclude=TestRailSettings.tests_exclude, groups=tests_groups, default_test_priority=testrail_default_test_priority) upload_tests_descriptions(testrail_project=project, section_id=testrail_section['id'], tests=tests_descriptions, check_all_sections=not options.check_one_section)
def main(): parser = OptionParser(description="Upload tests cases to TestRail. " "See settings.py for configuration.") parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="Enable debug output") parser.add_option("-j", "--job-name", dest="job_name", default=None, help="Jenkins swarm runner job name") parser.add_option( "-N", "--build-number", dest="build_number", default="latest", help="Jenkins swarm runner build number" ) parser.add_option( "-o", "--check_one_section", action="store_true", dest="check_one_section", default=False, help="Look for existing test case only in specified " "section of test suite.", ) (options, args) = parser.parse_args() if options.verbose: logger.setLevel(DEBUG) project = TestRailProject( url=TestRailSettings.url, user=TestRailSettings.user, password=TestRailSettings.password, project=TestRailSettings.project, ) testrail_section = project.get_section_by_name( suite_id=project.get_suite_by_name(TestRailSettings.tests_suite)["id"], section_name=TestRailSettings.tests_section, ) testrail_milestone = project.get_milestone_by_name(name=TestRailSettings.milestone) distros = [ config["name"].split()[0].lower() for config in project.get_config_by_name("Operation System")["configs"] if config["name"] in TestRailSettings.operation_systems ] tests_groups = ( get_tests_groups_from_jenkins(options.job_name, options.build_number, distros) if options.job_name else [] ) # If Jenkins job build is specified, but it doesn't have downstream builds # with tests groups in jobs names, then skip tests cases uploading because # ALL existing tests cases will be uploaded if options.job_name and not tests_groups: return tests_descriptions = get_tests_descriptions( milestone_id=testrail_milestone["id"], tests_include=TestRailSettings.tests_include, tests_exclude=TestRailSettings.tests_exclude, groups=tests_groups, ) upload_tests_descriptions( testrail_project=project, section_id=testrail_section["id"], tests=tests_descriptions, check_all_sections=not options.check_one_section, )