示例#1
0
    def parse_init_datas(self):
        """
        解析初始化sheet
        1. 序列化testcase,以字典格式存放
        :return:
        """
        init_cases = []
        init_cases_serialize = []
        sheet = self.all_sheets.get('initialize_datas')
        if not sheet:
            log.info('testcase文件没有"数据初始化"sheet')
            self.init_case = []
            return None
        rows = self._read_sheet_rows(sheet)

        rows = list(rows)
        for row in rows[2:]:
            if self.is_valid_case(row):
                init_cases.append(
                    self._read_case_content(row, sheet_type="init"))
        log.info(
            string.Template("initialize test case info: $init_case").
            substitute(init_case=init_cases))

        for case in init_cases:
            init_cases_serialize.append(self._case_format(case))

        self.init_case = init_cases_serialize
示例#2
0
 def restore_serialize(self):
     restore = self.api_info['restore'].strip().replace(
         '\n', '') if self.api_info.get('restore') else None
     log.info(
         string.Template("api request restore info is: $restore").
         substitute(restore=restore))
     if not restore:
         return
     res = self._json_serialize(restore)
     srlz_res = []
     if res:
         for case in res:
             sr = Serialize(case)
             sr.url_prepare()
             sr.method_check()
             sr.wait_time_value_check()
             srlz_res.append(sr.api_info)
         self.api_info['restore'] = srlz_res
         return srlz_res
     else:
         log.error(
             string.Template(
                 "api request restore format error, restore info: $restore"
             ).substitute(restore=self.api_info['restore']))
         return False
示例#3
0
    def parse_restore_datas(self):
        """
        解析restore sheet
        1. 序列化testcase,以字典格式存放
        :return:
        """
        restore_cases = []
        restore_case_serialize = []
        sheet = self.all_sheets.get('restore')
        if not sheet:
            log.info('testcase文件没有"数据恢复"sheet')
            self.restore_case = []
            return None
        rows = self._read_sheet_rows(sheet)

        rows = list(rows)
        for row in rows[2:]:
            if self.is_valid_case(row):
                restore_cases.append(
                    self._read_case_content(row, sheet_type="restore"))
        log.info(
            string.Template("restore test case info: $restore_case").
            substitute(restore_case=restore_cases))
        for case in restore_cases:
            restore_case_serialize.append(self._case_format(case))
        self.restore_case = restore_case_serialize
示例#4
0
 def init_serialize(self):
     init = self.api_info['init'].strip().replace(
         '\n', '') if self.api_info.get('init') else None
     log.info(
         string.Template("api request init info is: $init").substitute(
             init=init))
     if not init:
         return
     res = self._json_serialize(init)
     srlz_res = []
     if res:
         for case in res:
             sr = Serialize(case)
             sr.url_prepare()
             sr.method_check()
             sr.wait_time_value_check()
             srlz_res.append(sr.api_info)
         self.api_info['init'] = srlz_res
         return srlz_res
     else:
         log.error(
             string.Template(
                 "api request init format error, init info: $init").
             substitute(init=self.api_info['init']))
         return False
示例#5
0
    def send_text(self, msg, ats=None):
        """
        func: 发送钉钉群消息
        :param msg: text message conntent
        :param ats: phone list of to @, element "all" equal to @all
        :return:
        """
        timestamp, sign = self._secret()
        url_ = self.token
        url_ = url_ + "&timestamp={}&sign={}".format(timestamp, sign)
        log.debug('dingrobot complete url is: {}'.format(url_))
        if ats is None:
            ats = []
        text_msg = {"msgtype": "text", "text": {"content": msg}}

        at_info = {"atMobiles": [], "isAtAll": False}
        for item in ats:
            if item == "all":
                at_info["isAtAll"] = True
            elif isinstance(item, int):
                at_info["atMobiles"].append(item)
            else:
                pass
        text_msg["at"] = at_info
        header = {"Content-Type": "application/json"}
        with requests.post(url_, json.dumps(text_msg), headers=header) as res:
            log.info('dingrobot response is: {}'.format(res.text))
示例#6
0
 def build_connection(self):
     try:
         self.database = pymysql.connect(**self.cfg)
         log.info('connect mysql success')
         return self.database
     except Exception as e:
         log.error(Template('connect mysql fail, the error info: $e, the database config info: $cfg'
                            '').substitute(e=e, cfg=self.cfg))
示例#7
0
 def __init__(self, *args, **kwargs):
     self.api_infos = []
     # log.debug(Template("**************$k").substitute(k=kwargs))
     if kwargs.get("file"):
         log.info("处理文件api调试接口")
         self._file_parse(kwargs.get('file'))
     else:
         log.info("处理命令行参数api调试接口")
         self._params_parse(**kwargs)
示例#8
0
 def parse_testsuite_fields_lines(self, content):
     """
     func: 解析测试sheet中局部变量、初始化数据、接口测试、数据恢复所在的行位置
     :param content: sheet所有行的数据
     :return: 局部变量、初始化数据、接口测试、数据恢复所在的行位置
     """
     lines_info = {}
     lines_info_result = {}
     if not isinstance(content, list):
         raise TypeError("params is not a list object")
     print(content)
     for num in range(0, len(content)):
         if '局部变量' == content[num][0].value:
             lines_info[self.testsuite_local_vars_line_name] = num
         if '初始化数据' == content[num][0].value:
             lines_info[self.testsuite_init_line_name] = num
         elif '接口测试' == content[num][0].value:
             lines_info[self.testsuites_testcase_line_name] = num
         elif '数据恢复' == content[num][0].value:
             lines_info[self.testsuites_restore_line_name] = num
     log.info(
         string.Template("line info: $lines_info").substitute(
             lines_info=lines_info))
     lines_info_order = sorted(lines_info.items(),
                               key=lambda x: x[1],
                               reverse=False)
     fields_num = len(lines_info_order)
     if fields_num == 4:
         lines_info_result[lines_info_order[0][0]] = (
             lines_info_order[0][1], lines_info_order[1][1])
         lines_info_result[lines_info_order[1][0]] = (
             lines_info_order[1][1], lines_info_order[2][1])
         lines_info_result[lines_info_order[2][0]] = (
             lines_info_order[2][1], lines_info_order[3][1])
         lines_info_result[lines_info_order[3][0]] = (
             lines_info_order[3][1], len(content))
     if fields_num == 3:
         lines_info_result[lines_info_order[0][0]] = (
             lines_info_order[0][1], lines_info_order[1][1])
         lines_info_result[lines_info_order[1][0]] = (
             lines_info_order[1][1], lines_info_order[2][1])
         lines_info_result[lines_info_order[2][0]] = (
             lines_info_order[2][1], len(content))
     elif fields_num == 2:
         lines_info_result[lines_info_order[0][0]] = (
             lines_info_order[0][1], lines_info_order[1][1])
         lines_info_result[lines_info_order[1][0]] = (
             lines_info_order[1][1], len(content))
     elif fields_num == 1:
         lines_info_result[lines_info_order[0][0]] = (
             lines_info_order[0][1], len(content))
     log.debug(
         string.Template("lines_info_result: $lines_info_result").
         substitute(lines_info_result=lines_info_result))
     return lines_info_result
示例#9
0
 def generate_common_test(self):
     py_code = ""
     py_code += self._create_common_header()
     py_code += self._create_common_init_case_code(self.init_case)
     py_code += self._create_common_restore_class_code()
     py_code += self._create_common_restore_case_code(self.restore_case)
     with open(os.path.join(self.testcase_dir, "test_task_common.py"),
               'w',
               encoding='utf-8') as f:
         f.write(py_code)
     log.info(Template("create common test files complete").substitute())
示例#10
0
    def db_verify_serialize(self):
        """
        func:对测试用例中的db_verify项进行json格式化和基本字段校验
        首先判断db_verify字段是否符合json格式,如果符合,则该字段进行sql语句判断有无,db配置是否在基础配置中已配置,检查的类型是否正确
        能检查的类型为:= or == 表示查询的值和预期值要相等,~ or ~=表示预期值包含在查询结果中,! or != 表示查询值不能等于预期值,
                     ~ or !~ 表示预期值不能包含在查询值中
        :return:json格式化之后的db_verify字段
        """
        db_verify = self.api_info['db_verify'].strip() if self.api_info.get(
            'db_verify') else None
        log.info(
            string.Template("api request db_verify info is: $db_verify").
            substitute(db_verify=db_verify))
        if not db_verify:
            return
        res = self._json_serialize(db_verify)
        if res:
            flag = True
            databases_list = Process.base_configs.get('database') or {}
            type_list = ["=", '==', '!', '!=', '~', '~=', '!~', '~!']
            error_msg = ""
            for k, v in res.items():
                sql_ = v.get('sql')
                db = v.get('db')
                type_ = v.get('type') or '='
                if not sql_:
                    flag = False
                    error_msg += "{} sql键不能为空,请检查\n".format(k)
                if not db or db not in databases_list:
                    flag = False
                    error_msg += "{} 配置的db选项没有在基础配置中配置相关的参数\n".format(k)
                else:
                    v['ip'] = databases_list[db].get('ip')
                    v['port'] = databases_list[db].get('port')
                    v['db_type'] = databases_list[db].get('type')
                    v['user'] = databases_list[db].get('user')
                    v['pwd'] = databases_list[db].get('pwd')
                if type_ not in type_list:
                    flag = False
                    error_msg += "{} 配置的type目前无法识别,请检查type选项是否以下选项:{}\n".format(
                        k, type_list)
                res[k] = v
            if not flag:
                log.error(error_msg)
                raise JsonSerializeException

            self.api_info['db_verify'] = res
            return res
        else:
            log.error(
                string.Template(
                    "api request db_verify format error, db_verify info: $db_verify"
                ).substitute(db_verify=self.api_info['db_verify']))
            return False
示例#11
0
 def query(self, sql):
     with self.__conn.cursor() as cursor:
         log.info('query sql is: {}'.format(sql))
         try:
             cursor.execute(sql)
             # data_one = cursor.fetchone()
             data_all = cursor.fetchall()
             log.debug(Template('query results is: $all').substitute(all=data_all))
             return data_all
         except Exception as e:
             log.error('query fail, error info: {}, the sql is: {}'.format(str(e), str(sql)))
             return False
示例#12
0
    def _read_file(self):
        """
        读取Excel文件,解析基础配置sheet,数据初始化sheet, 数据恢复sheet, 公共方法sheet和所有测试套sheet
        :return:
        """
        all_sheets = {}
        test_suite = []
        try:
            workbook = xlrd.open_workbook(self.filepath)

        except Exception as e:
            log.exception(
                string.Template("open testcase file fail, please check! %e").
                substitute(e=e))
            return False

        sheet_names = workbook.sheet_names()
        log.debug(
            string.Template("testcase sheets: $sheet_names").substitute(
                sheet_names=sheet_names))
        # print(sheet_names)

        if '基础配置' in sheet_names:
            base_configs = workbook.sheet_by_name('基础配置')
            all_sheets['base_configs'] = base_configs
            sheet_names.remove('基础配置')
        if '数据初始化' in sheet_names:
            initialize_datas = workbook.sheet_by_name('数据初始化')
            all_sheets['initialize_datas'] = initialize_datas
            sheet_names.remove('数据初始化')
        if '数据恢复' in sheet_names:
            restore = workbook.sheet_by_name('数据恢复')
            all_sheets['restore'] = restore
            sheet_names.remove('数据恢复')
        if '公共方法' in sheet_names:
            common_func = workbook.sheet_by_name('公共方法')
            all_sheets['common_func'] = common_func
            sheet_names.remove('公共方法')
        if '全局变量' in sheet_names:
            global_vars = workbook.sheet_by_name('全局变量')
            all_sheets['global_vars'] = global_vars
            sheet_names.remove('全局变量')
        for sheet in sheet_names:
            test_suite.append(workbook.sheet_by_name(sheet))
        log.info(
            string.Template(
                "All the test suite that need to be tested: $test_suite").
            substitute(test_suite=test_suite))
        all_sheets['testsuites'] = test_suite

        return all_sheets
示例#13
0
    def smtp_link(self):
        """
        func: 连接smtp服务器,判断当前所在的平台,连接smtp服务
        :return:
        """

        if "win" in sys.platform.lower():
            log.info('mail server in windows platform')
            smtp = smtplib.SMTP_SSL(self.server)
        elif "linux" in sys.platform.lower():
            log.info('mail server in linux platform')
            smtp = smtplib.SMTP_SSL(self.server)
        else:
            log.error('mail server not support this system platform')
            raise SystemError('mail server not support this system platform')
        try:
            smtp.connect(self.server, self.port)
            log.info('smtp connect server success')
            smtp.login(self.sender, self.pwd)
            log.info('login mail server success')
            self.smtp_handler = smtp
            return smtp
        except Exception as e:
            log.error('login mail server fail, error info is: {}'.format(e))
            return False
示例#14
0
 def url_prepare(self):
     url = self.api_info['url'].strip().replace(
         '\n', '') if self.api_info.get('url') else None
     log.info(
         string.Template("api info url info is: $url").substitute(url=url))
     if not url:
         log.error(string.Template("url params are required").substitute())
         raise JsonSerializeException
     elif not url.startswith('http://'):
         res = Process.base_configs['hostname'] + url
         self.api_info['url'] = res
         return res
     else:
         return url
示例#15
0
    def trend_detail(self, report_dir):
        log.info('处理allure测试报告trend内容')
        if not os.path.isdir(report_dir):
            log.error('需要处理trend的目录不是一个有效路径,请检查')
            return False
        allure_json_file_dirs = []  # 所有allure json报告的所有目录
        suffix_dir = os.path.split(report_dir)[0]  # 测试报告路径前缀
        relative_path = os.path.split(report_dir)[1]  # 当前测试报告目录
        for item in os.listdir(suffix_dir):
            if re.match(r'^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}', item):
                allure_json_file_dirs.append(item)

        allure_json_file_dirs = sorted(allure_json_file_dirs, reverse=True)
        log.info(
            'all the allure report dirs is: {}'.format(allure_json_file_dirs))

        last_allure_report_dir = os.path.join(
            suffix_dir, self.allure_report)  # 最近一次allure json报告的目录
        log.info(
            'last_allure_report_dir is: {}'.format(last_allure_report_dir))
        if not os.path.isdir(last_allure_report_dir):
            log.info('no last_allure_report_dir, no need to detail trend')
            return None
        else:
            last_allure_report_history_dir = os.path.join(
                last_allure_report_dir,
                "history")  # 最近一次allure_report目录中的history目录
            last_allure_json_dir = os.path.join(
                suffix_dir, allure_json_file_dirs[0])  # 最近一次allure json文件目录
            last_history_dir = os.path.join(
                last_allure_json_dir,
                "history")  #最近一次allure json文件目录中history目录

            self.manual_join_trend_file(last_allure_report_history_dir,
                                        last_history_dir, report_dir)
示例#16
0
    def send(self,
             mail_body,
             receivers,
             attachs=None,
             subject="auto-test mail notify"):
        """
        func: 发送邮件功能
        :param mail_body: 邮件文本主体,字符串类型
        :param receivers: 接收者列表,list类型
        :param attachs: 需要添加的附件,list类型,list中的每个元素需要是dict类型,并且需要有filename和filepath两个属性
        :param subject: 邮件主题
        :return:
        """
        if not attachs:
            if not isinstance(attachs, list):
                log.error('attach param is not a list')
                attach = None
        msg = MIMEMultipart()  # 支持邮件中附带附件
        msg['Subject'] = Header(subject, 'utf-8')
        msg['From'] = Header(self.sender, 'utf-8')
        for receiver in receivers:
            msg['To'] = Header(receiver, 'utf-8')

        mail_body = "(本邮件是程序自动下发的,请勿回复!)\r\n" + mail_body
        text_content = MIMEText(mail_body, 'plain', 'utf-8')
        msg.attach(text_content)
        # 添加附件
        if attachs:
            attachs = self.attach_check(attachs)
            for att in attachs:
                filepath = att.get('filepath')
                filename = att.get('filename')
                log.debug('filepath is: {}'.format(filepath))
                att_tmp = MIMEText(
                    open(filepath, 'rb').read(), 'base64', 'utf-8')
                att_tmp['Content-type'] = 'application/octet-stream'
                att_tmp[
                    'Content-Disposition'] = 'attachment; filename="{}"'.format(
                        filename)
                msg.attach(att_tmp)
        try:
            if self.smtp_link():
                self.smtp_handler.sendmail(self.sender, receivers,
                                           msg.as_string())
                log.info("send mail success!")

        except Exception as e:
            log.error("发送邮件异常, 错误信息:{}".format(e))
示例#17
0
def dyparam_parse(testcase: dict, var_object: object):
    """
    func: 根据dyparam里的sql信息,进行数据库查询,将查询到的结果存入var_object对象的interface_vars属性中
    :param dyparam: 测试用例中的dyparam信息经过json转换后的内容
    :param var_object: 用于存放测试sheet接口变量的对象
    :return: 添加了从数据库中查询出来的值之后的var_object对象
    """
    if not isinstance(testcase, dict):
        return "testcase is not a dict"
    dyparam = testcase.get('dyparam')
    if not dyparam:
        return None
    if not isinstance(dyparam, dict):
        return "dyparam is not a dict type"
    if not hasattr(var_object, "interface_vars"):
        var_object.interface_vars = {}
    log.info('进入dyparam解析')
    for name_, sql_info in dyparam.items():
        ip = sql_info.get('ip')
        port = sql_info.get('port')
        pwd = sql_info.get('pwd')
        user = sql_info.get('user')
        db_type = sql_info.get('db_type')
        values = sql_info.get('values')
        sql = sql_info.get('sql')
        rs = DbHelper().query(ip=ip,
                              port=port,
                              user=user,
                              pwd=pwd,
                              db_type=db_type,
                              sql=sql)
        if not rs:
            log.warning("sql: {} 查询结果为空".format(sql))
            for var_name, reslut_key in values.items():
                var_object.interface_vars[var_name] = ""
            continue

        rs = rs[0]
        try:
            for var_name, reslut_key in values.items():
                log.info('添加interface_var: {}={}'.format(
                    var_name, rs.get(reslut_key)))
                var_object.interface_vars[var_name] = rs.get(reslut_key)
        except Exception as e:
            log.error('add interface_vars fail, error info is: {}'.format(e))
            return False
    return var_object
示例#18
0
 def order_fields_check(self):
     order = self.api_info['order'] if self.api_info.get("order") else None
     log.info(
         string.Template("api request order info is: $order").substitute(
             order=order))
     if not order:
         return None
     try:
         res = int(order)
         self.api_info['order'] = res
         return res
     except Exception as e:
         log.error(
             string.Template(
                 "api order param format error, please input a integer number "
                 "error info: $e").substitute(e=e))
         raise JsonSerializeException
示例#19
0
 def dyparam_serialize(self):
     dyparam = self.api_info['dyparam'].strip().replace(
         '\n', '') if self.api_info.get('dyparam') else None
     log.info(
         string.Template("api request dyparam info is: $dyparam").
         substitute(dyparam=dyparam))
     if not dyparam:
         return
     res = self._json_serialize(dyparam)
     if res:
         self.api_info['dyparam'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request dyparam format error, dyparam info: $dyparam"
             ).substitute(dyparam=self.api_info['dyparam']))
         return False
示例#20
0
 def restore_serialize(self):
     restore = self.api_info['restore'].strip().replace(
         '\n', '') if self.api_info.get('restore') else None
     log.info(
         string.Template("api request restore info is: $restore").
         substitute(restore=restore))
     if not restore:
         return
     res = self._json_serialize(restore)
     if res:
         self.api_info['restore'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request restore format error, restore info: $restore"
             ).substitute(restore=self.api_info['restore']))
         return False
示例#21
0
 def init_serialize(self):
     init = self.api_info['init'].strip().replace(
         '\n', '') if self.api_info.get('init') else None
     log.info(
         string.Template("api request init info is: $init").substitute(
             init=init))
     if not init:
         return
     res = self._json_serialize(init)
     if res:
         self.api_info['init'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request init format error, init info: $init").
             substitute(init=self.api_info['init']))
         return False
示例#22
0
 def expression_serialize(self):
     expression = self.api_info['expression'].strip().replace(
         '\n', '') if self.api_info.get('expression') else None
     log.info(
         string.Template("api request expression info is: $expression").
         substitute(expression=expression))
     if not expression:
         return
     res = self._json_serialize(expression)
     if res:
         self.api_info['expression'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request expression format error, expression info: $expression"
             ).substitute(expression=self.api_info['expression']))
         return False
示例#23
0
 def verify_fields_serialize(self):
     verify = self.api_info['verify_fields'].strip().replace(
         '\n', '') if self.api_info.get('verify_fields') else None
     log.info(
         string.Template("api request verify_fields info is: $verify").
         substitute(verify=verify))
     if not verify:
         return
     res = self._json_serialize(verify)
     if res:
         self.api_info['verify_fields'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request verify_fields format error, verify_fields info: $verify_fields"
             ).substitute(verify_fields=self.api_info['verify_fields']))
         return False
示例#24
0
 def interface_var_serialize(self):
     var = self.api_info['interface_var'].strip().replace(
         '\n', '') if self.api_info.get("interface_var") else None
     log.info(
         string.Template(
             "api request interface_var info is: $var").substitute(var=var))
     if not var:
         return
     res = self._json_serialize(var)
     if res:
         self.api_info['interface_var'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request interface_var format error, interface_var info: $var"
             ).substitute(var=self.api_info['interface_var']))
         return False
示例#25
0
 def header_serialize(self):
     header = self.api_info['header'].strip().replace(
         '\n', '') if self.api_info.get("header") else None
     log.info(
         string.Template("api request header info is: $header").substitute(
             header=header))
     if not header:
         return
     res = self._json_serialize(header)
     if res:
         self.api_info['header'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request header format error, header info: $header").
             substitute(header=self.api_info['header']))
         return False
示例#26
0
 def case_vars_serialize(self):
     case_vars = self.api_info['case_vars'].strip().replace(
         '\n', '') if self.api_info.get("case_vars") else None
     log.info(
         string.Template("api request case_vars info is: $case_vars").
         substitute(case_vars=case_vars))
     if not case_vars:
         return
     res = self._json_serialize(case_vars)
     if res:
         self.api_info['case_vars'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request case_vars format error, case_vars info: $case_vars"
             ).substitute(_vars=self.api_info['case_vars']))
         return False
示例#27
0
 def method_serialize(self):
     method = self.api_info['method'].strip().replace(
         '\n', '') if self.api_info.get('method') else None
     log.info(
         string.Template("api info method info is: $method").substitute(
             method=method))
     supported = ['get', 'post', 'delete', 'put']
     if not method:
         log.error(
             string.Template("method params are required").substitute())
         raise JsonSerializeException
     elif method.lower() not in supported:
         log.error(
             string.Template("method params only support $s").substitute(
                 s=supported))
         raise JsonSerializeException
     else:
         self.api_info['method'] = method.upper()
         return method.upper()
示例#28
0
 def params_serialize(self):
     # params = self.api_info['params'].strip().replace('\n', '')
     params = self.api_info['params'].strip().replace(
         '\n', '') if self.api_info.get("params") else None
     log.info(
         string.Template("api request params info is: $params").substitute(
             params=params))
     if not params:
         return
     res = self._json_serialize(params)
     if res:
         self.api_info['params'] = res
         return res
     else:
         log.error(
             string.Template(
                 "api request params format error, params info: $params").
             substitute(params=self.api_info['params']))
         return False
示例#29
0
 def generate_testsuite(self):
     for sheet_name, testsuites in self.testsuites.items():
         if not testsuites:
             continue
         py_code = ""
         py_code += self._create_header_code()
         py_code += self._create_save_interface_vars_code()
         py_code += self._create_setup_class_case_code(
             testsuites['init_case'])
         py_code += self._create_teardown_class_case_code(
             testsuites['restore_case'])
         py_code += self._create_testcase_code(testsuites['testcase'])
         py_code += self._create_testcase_common_func_code()
         with open(os.path.join(self.testcase_dir,
                                "test_{}.py".format(sheet_name)),
                   'w',
                   encoding='utf-8') as f:
             f.write(py_code)
         log.info(Template("create testsuite files complete").substitute())
示例#30
0
 def open_report_server(self, report_dir, ip=None, port=None):
     if not port:
         port = 55555
     suffix_dir = os.path.split(report_dir)[0]
     relative_path = os.path.split(report_dir)[1]
     self.trend_detail(report_dir)
     os.chdir(suffix_dir)
     self.check_port_is_open(port)
     generate_cmd = "allure generate {} -o {} -c".format(
         relative_path, self.allure_report)
     if ip:
         open_server_cmd = "allure open {} -h {} -p {}".format(
             self.allure_report, ip, port)
     else:
         open_server_cmd = "allure open {} -p {}".format(
             self.allure_report, port)
     obj = subprocess.Popen(generate_cmd, shell=True)
     obj.communicate()
     obj = subprocess.Popen(open_server_cmd,
                            shell=True,
                            stdout=subprocess.PIPE,
                            stdin=subprocess.PIPE,
                            stderr=subprocess.PIPE)
     couter = 0
     for item in iter(obj.stdout.readline, 'b'):
         couter += 1
         encode_type = chardet.detect(item)
         if encode_type['encoding'] == 'utf-8':
             item = item.decode('utf-8')
         elif encode_type['encoding'] == 'Windows-1252':
             item = item.decode('Window-1252')
         else:
             pass
         log.debug('subprocess out is: {}'.format(str(item)))
         pattern = re.compile(r'Server started at <(.+?)>\.')
         rs = re.search(pattern, str(item))
         if rs:
             url = rs.group(1)
             log.info('reports server is: {}'.format(url))
             return url
         time.sleep(0.5)
         if couter > 100:
             return "获取allure报告服务地址失败"