def pull(self, project_id, branch, root_path): project = self.get_project_id(project_id) info = project.repository_tree(all=True, recursive=True, as_list=True) file_list = [] if not os.path.isdir(root_path): os.makedirs(root_path) os.chdir(root_path) # 调用创建目录的函数并生成文件名列表 for info_dir in range(len(info)): if info[info_dir]['type'] == 'tree': dir_name = info[info_dir]['path'] self.create_dir(dir_name) else: file_name = info[info_dir]['path'] file_list.append(file_name) for info_file in range(len(file_list)): # 开始下载 getf = project.files.get(file_path=file_list[info_file], ref=branch) content = getf.decode() with open(file_list[info_file], 'wb') as code: logger.info("\033[0;32;40m开始下载文件: \033[0m{0}".format( file_list[info_file])) code.write(content)
def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) if request.data.get('timer_enable') and request.data.get('crontab'): crontab = request.data.get('crontab').replace('?', '*') crontab = crontab.split(' ') if len(crontab) == 7: # 包含秒 包含年 crontab = crontab[1:-1] elif len(crontab) == 6: # 包含秒 不包含年 crontab = crontab[1:] crontab_kwargs = { 'minute': crontab[0], 'hour': crontab[1], 'day_of_week': crontab[4], 'day_of_month': crontab[2], 'month_of_year': crontab[3] } with transaction.atomic(): save_id = transaction.savepoint() try: schedule, _ = CrontabSchedule.objects.get_or_create( minute=crontab_kwargs.get('minute', '*'), hour=crontab_kwargs.get('hour', '*'), day_of_week=crontab_kwargs.get('day_of_week', '*'), day_of_month=crontab_kwargs.get('day_of_month', '*'), month_of_year=crontab_kwargs.get('month_of_year', '*'), timezone=pytz.timezone(TIME_ZONE)) dt = datetime.now().strftime('%Y%m%d%H%M%S') _periodic_task = PeriodicTask.objects.create( name=dt + '-' + 'case测试计划定时任务' + '-' + serializer.data.get('plan_id'), task='case_test_task_timing_executor', args=json.dumps([ serializer.data.get('project_id'), serializer.data.get('plan_id') ]), enabled=True, crontab=schedule) logger.info( "timing case testplan:{} create success!".format( serializer.data.get('plan_id'))) except Exception as e: transaction.savepoint_rollback(save_id) logger.error( 'timing case testplan:{} create failed!,error:{}'. format(serializer.data.get('plan_id'), e)) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def executor(cls, case_job, project_id, test_plan_uid, task_id): """ 执行器 :param case_job: :param project_id: :param test_plan_uid: :param task_id: :return: """ default_venv = ConfigParser.get_config('python_venv', 'venv_path') case_job.state = CaseJobState.RUNNING case_job.save() case_path = case_job.case_path case_dir = '/'.join(case_path.split('/')[0:3]) case_venv = os.path.join(settings.BASE_DIR, 'case_house', case_dir, 'venv') cmd_path = os.path.join(settings.BASE_DIR, 'case_house', case_dir) if os.path.exists(case_venv): venv_path = case_venv else: venv_path = default_venv file_path, file_name = os.path.split(case_path) report_name = case_path.split('/')[-1].split('.')[0] + '.html' result_log_name = case_path.split('/')[-1].split('.')[0] + '.log' xml_name = case_path.split('/')[-1].split('.')[0] + '.xml' report_path = os.path.join(MEDIA_ROOT, 'html-report', str(project_id), test_plan_uid, str(task_id)) try: if not os.path.exists(report_path): os.makedirs(report_path) except FileExistsError: pass if 'test' in os.path.splitext(file_name)[0] and os.path.splitext(file_name)[1].startswith('.py'): # 是pytest 脚本 try: cmd = '{} {} -vv -s --html={} --self-contained-html --result-log={} --junit-xml={}'.format( os.path.join(venv_path, 'bin/pytest'), os.path.join(settings.BASE_DIR, 'case_house', case_path), os.path.join(report_path, report_name), os.path.join(report_path, result_log_name), os.path.join(report_path, xml_name)) logger.info(cmd) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, cwd=cmd_path) out = p.stdout read_data = out.read().decode("utf-8", "ignore") case_job.log = read_data case_job.report_path = '/media/html-report/{}/{}/{}/{}'.format(project_id, test_plan_uid, task_id, report_name) case_result = read_data.split('\n')[-2] case_job.result = case_result.replace('=', '').strip(' ') case_job.state = CaseJobState.FINISH case_job.save() return True except Exception as es: logger.error("case job excepted:{}".format(es)) case_job.state = CaseJobState.FAILED case_job.save() return False elif os.path.splitext(file_name)[1] == '.py': # 普通python脚本 try: p = subprocess.Popen( '{} {}'.format( os.path.join(venv_path, 'bin/python'), os.path.join(settings.BASE_DIR, 'case_house', case_path)), shell=True, stdout=subprocess.PIPE, cwd=cmd_path) out = p.stdout read_data = out.read().decode("utf-8", "ignore") case_job.log = read_data case_job.state = CaseJobState.FINISH case_job.save() return True except Exception as es: logger.error("case job excepted:{}".format(es)) case_job.state = CaseJobState.FAILED case_job.save() return False elif os.path.splitext(file_name)[1] == '.yml': # HttpRunner脚本 try: case_task_id = case_job.case_task_id test_plan_uid = CaseTestPlanTaskModel.objects.get(id=case_task_id).test_plan_uid env_file = CaseTestPlanModel.objects.get(plan_id=test_plan_uid).env_file if env_file: p = subprocess.Popen( '{} {} --dot-env-path {} --report-file {}'.format( os.path.join(venv_path, 'bin/hrun'), os.path.join(settings.BASE_DIR, 'case_house', case_path), os.path.join(settings.BASE_DIR, 'case_house', env_file), os.path.join(report_path, report_name)), shell=True, stdout=subprocess.PIPE, cwd=cmd_path) else: p = subprocess.Popen('{} {} --report-file {}'.format( os.path.join(venv_path, 'bin/hrun'), os.path.join(settings.BASE_DIR, 'case_house', case_path), os.path.join(report_path, report_name)), shell=True, stdout=subprocess.PIPE, cwd=cmd_path) out = p.stdout read_data = out.read().decode("utf-8", "ignore") case_job.report_path = '/media/html-report/{}/{}/{}/{}'.format(project_id, test_plan_uid, task_id, report_name) case_job.log = read_data # case_job.result = case_result.replace('=', '').strip(' ') case_job.state = CaseJobState.FINISH case_job.save() return True except Exception as es: logger.error("case job excepted:{}".format(es)) case_job.state = CaseJobState.FAILED case_job.save() return False
def dispose_response(self, interface, response): """ 请求处理器 """ # 处理断言 for _assert in interface.asserts: if _assert['assertType'] == "regular": # 正则判断逻辑 if not isRegular(_assert['expressions']): logger.error( 'interface Id:{}, testPlan Id:{} expressions:{} is not regular'.format(interface.id, self.test_plan_id, _assert['expressions'])) update_api_job_fail(self.test_plan_id, interface.id, response) break else: pattern = isRegular(_assert['expressions']) re_result = assert_regular(pattern, response.text) logger.info("正则匹配结果:{}".format(re_result)) if not re_result: # 断言失败 update_api_job_fail(self.test_plan_id, interface.id, response) # 跟新interfaceJob状态失败 break else: try: calculate_fun = getattr(operation, _assert['calculate']) except AttributeError as es: logger.error("calculate rule {} is not exist!".format(_assert['calculate'])) update_api_job_fail(self.test_plan_id, interface.id, response) break if not calculate_fun(re_result, _assert['expect']): update_api_job_fail(self.test_plan_id, interface.id, response) # 跟新interfaceJob状态失败 break elif _assert['assertType'] == "delimiter": # 分隔符取值 delimiter_result = assert_delimiter(_assert['expressions'], response) logger.info("分隔符匹配结果: {}".format(delimiter_result)) if delimiter_result == 'EXCEPTION': logger.error( "delimiter error:{}, interfaceJobId: {}, test_plan Id:{}".format(_assert['expressions'], interface.id, self.test_plan_id)) update_api_job_fail(self.test_plan_id, interface.id, response) break elif delimiter_result == dict(): update_api_job_fail(self.test_plan_id, interface.id, response) break else: try: calculate_fun = getattr(operation, _assert['calculate']) except AttributeError as es: logger.error("calculate rule {} is not exist!".format(_assert['calculate'])) update_api_job_fail(self.test_plan_id, interface.id, response) break if not calculate_fun(delimiter_result, _assert['expect']): update_api_job_fail(self.test_plan_id, interface.id, response) break else: # 所有断言验证通过 update_api_job_success(self.test_plan_id, interface.id, response) # 处理提取规则 extracts_result = {} # 提取结果的集合 for extract in interface.extract: if extract['extractType'] == "regular": if not isRegular(extract['expressions']): logger.error( 'interface Id:{}, testPlan Id:{} expressions:{} is not regular'.format(interface.id, self.test_plan_id, extract['expressions'])) pattern = isRegular(extract['expressions']) re_result = assert_regular(pattern, response.text) if not re_result: # 没有匹配到结果 extracts_result[extract['variable_name']] = '' else: extracts_result[extract['variable_name']] = re_result elif extract['extractType'] == "delimiter": delimiter_result = assert_delimiter(extract['expressions'], response) if delimiter_result == 'EXCEPTION': logger.error( "delimiter error:{}, interfaceJobId: {}, test_plan Id:{}".format(extract['expressions'], interface.id, self.test_plan_id)) extracts_result[extract['variable_name']] = '' else: extracts_result[extract['variable_name']] = delimiter_result return extracts_result
def branch_pull(gitlab_info, project_id, branch_name): """ 录取gitlab指定分支代码 """ instance = GitlabAPI(gitlab_url=gitlab_info.get('gitlab_url'), private_token=gitlab_info.get('private_token')) project = instance.gl.projects.get(project_id) obj_tuple = GitCaseModel.objects.update_or_create( gitlab_url=gitlab_info.get('gitlab_url'), gitlab_project_name=project.name, gitlab_project_id=project.id, branch_name=branch_name) obj_tuple[0].status = BranchState.PULLING obj_tuple[0].save() cache_key = "private_token:" + gitlab_info.get( 'private_token') + "-" + "project_id:" + str( project_id) + "-" + "branch_name:" + branch_name cache.set(cache_key, BranchState.PULLING) try: info = project.repository_tree(ref=branch_name, all=True, recursive=True, as_list=True) file_list = [] root_path = os.path.join( BASE_DIR, 'case_house', gitlab_info.get('gitlab_url').replace(':', '-').replace( '.', '-').replace('/', ''), branch_name, project.name) if not os.path.isdir(root_path): os.makedirs(root_path) os.chdir(root_path) # 调用创建目录的函数并生成文件名列表 for info_dir in range(len(info)): if info[info_dir]['type'] == 'tree': dir_name = info[info_dir]['path'] create_dir(dir_name) else: file_name = info[info_dir]['path'] file_list.append(file_name) file_list_len = len(file_list) for index, info_file in enumerate(range(file_list_len)): # 开始下载 getf = project.files.get(file_path=file_list[info_file], ref=branch_name) content = getf.decode() with open(file_list[info_file], 'wb') as code: logger.info("\033[0;32;40m开始下载文件: \033[0m{0}".format( file_list[info_file])) code.write(content) finish_progress = float('%.2f' % ((index + 1) / file_list_len)) * 100 cache.set(cache_key + "progress", finish_progress, 3) branch_obj = GitCaseModel.objects.get( gitlab_url=gitlab_info.get('gitlab_url'), gitlab_project_id=project.id, gitlab_project_name=project.name, branch_name=branch_name, ) branch_obj.status = BranchState.DONE branch_obj.save() cache.set(cache_key, BranchState.DONE) return True except Exception as es: logger.error(str(es)) branch_obj = GitCaseModel.objects.get( gitlab_url=gitlab_info.get('gitlab_url'), gitlab_project_id=project.id, gitlab_project_name=project.name, branch_name=branch_name, ) branch_obj.status = BranchState.FAILED branch_obj.save() cache.set(cache_key, BranchState.FAILED) return False
def create_dir(dir_name): if not os.path.isdir(dir_name): logger.info("\033[0;32;40m开始创建目录: \033[0m{0}".format(dir_name)) os.makedirs(dir_name) time.sleep(0.1)