Ejemplo n.º 1
0
class SendEmail(object):
    """发送测试报告"""
    _instance_lock = threading.Lock()  # 设置单例锁

    def __new__(cls, *args, **kwargs):
        """单例模式(支持多线程)"""
        if not hasattr(cls, "_instance"):
            with cls._instance_lock:
                if not hasattr(cls, "_instance"):
                    cls._instance = object.__new__(cls)
        return cls._instance

    def __init__(self):
        try:
            self.common = Common()  # 实例化一个common调用公用函数
            self.log = MyLog().get_log().logger  # 实例化一个log打印日志
            self.config = ReadConfig()  # 实例化一个read_config读取email的配置信息
            self.msg = email.mime.multipart.MIMEMultipart(
                'alternative')  # 实例化一个email发送email
            self.log_dir = self.common.get_result_path()  # 获取存储日志的时间目录
            self.principal_name_list = []  # 错误用例负责人list
            self.zip_path = self.log_dir + ".zip"  # 设置存放zip的路径
            self.result = False  # 发送结果标志
            self.num = 0  # 发送失败后重试次数
        except Exception as e:
            self.log.error(e)
            raise Exception("SendEmail.__init__异常!")

    def with_zip(self):
        """附件以zip格式发送邮件"""
        while self.result is False and self.num < 3:  # 发送失败后重试3次
            try:
                # 提取错误用例负责人姓名
                file_list = os.listdir(self.log_dir)  # 获取时间目录下的文件列表
                for file in file_list:
                    file_name = os.path.splitext(file)[0]  # 文件名
                    # 用正则表达式查找文件名为汉字的文件(负责人对应的错误日志文件),正则表达式为:非汉字的字符用""替换掉
                    if file_name == re.sub("[^\u4e00-\u9fa5]+", "", file_name):
                        self.principal_name_list.append(
                            file_name)  # 添加负责人姓名到principal_name_list中

                # 创建一个写入的zip对象
                with zipfile.ZipFile(
                        self.zip_path, mode='w',
                        compression=zipfile.ZIP_DEFLATED) as zip_obj:
                    for path, folders, files in os.walk(self.log_dir):
                        for file in files:
                            zip_obj.write(os.path.join(path, file))  # 将内容写入zip
                # 添加附件
                part = MIMEApplication(open(self.zip_path,
                                            'rb').read())  # 读取内容
                part.add_header('Content-Disposition',
                                'attachment',
                                filename=('gbk', '', "result.zip"))  # 设置附件名
                self.msg.attach(part)
                self.send()  # 发送邮件
                self.result = True
            except Exception as e:
                self.log.error("发送失败 %s" % e)
                self.num += 1
            finally:
                os.remove(self.zip_path)  # 删除zip文件
                self.remove_result()  # 删除之前的结果文件夹

    def with_file(self):
        """附件以单个文件形式发送邮件"""
        while self.result is False and self.num < 3:  # 发送失败后重试3次
            try:
                file_list = os.listdir(self.log_dir)  # 获取时间目录下的文件列表
                for file in file_list:
                    file_name = os.path.splitext(file)[0]  # 文件名
                    file_type = os.path.splitext(file)[1]  # 文件类型

                    # 用正则表达式查找文件名为汉字的文件(负责人对应的错误日志文件),正则表达式为:非汉字的字符用""替换掉
                    if file_name == re.sub("[^\u4e00-\u9fa5]+", "", file_name):
                        self.principal_name_list.append(
                            file_name)  # 添加负责人姓名到错误负责人list中
                        current_file = os.path.join(self.log_dir,
                                                    file)  # 拼接当前的日志路径
                        part = MIMEApplication(
                            open(current_file, 'rb').read())  # 读取当前的日志
                        part.add_header('Content-Disposition',
                                        'attachment',
                                        filename=('gbk', '', file))  # 设置附件名
                        self.msg.attach(part)
                    elif file_type == ".html":  # 查找html文件
                        current_file = os.path.join(self.log_dir,
                                                    file)  # 拼接当前的日志路径
                        part = MIMEApplication(
                            open(current_file, 'rb').read())  # 读取当前的日志
                        part.add_header('Content-Disposition',
                                        'attachment',
                                        filename=('gbk', '', file))  # 设置附件名
                        self.msg.attach(part)
                    elif "error" in file_name:  # 查找错误日志文件
                        current_file = os.path.join(self.log_dir,
                                                    file)  # 拼接当前的日志路径
                        part = MIMEApplication(
                            open(current_file, 'rb').read())  # 读取当前的日志
                        part.add_header('Content-Disposition',
                                        'attachment',
                                        filename=('gbk', '', file))  # 设置附件名
                        self.msg.attach(part)
                self.send()  # 发送邮件
                self.result = True
            except Exception as e:
                self.log.error("发送失败 %s" % e)
                self.num += 1
            finally:
                self.remove_result()  # 删除之前的结果文件夹

    def send(self):
        """发送邮件"""
        try:
            # 从配置文件中读取发件人信息
            sender_name = ""  # 发件人
            sender_email = ""  # 发件箱
            sender_dict = json.loads(self.config.get_email("sender"))
            for key, value in sender_dict.items():
                sender_name = key  # 发件人
                sender_email = value  # 发件箱

            # 从配置文件中读取收件人信息
            # receivers内容为字典时使用(receivers = {"蓝梦":"*****@*****.**", "孟冰":"*****@*****.**")
            receivers_dict = json.loads(self.config.get_email("receivers"))
            name_list = []  # 收件人list
            receivers = []  # 收件箱list
            for key, value in receivers_dict.items():
                if key in self.principal_name_list:
                    name_list.append(key)
                    receivers.append(value)

            # 邮件信息
            name_list_str = ",".join(name_list)  # 收件人姓名,将list转换为str
            mail_host = self.config.get_email("email_host")  # 设置邮箱服务器域名
            mail_port = self.config.get_email("email_port")  # 设置邮箱服务器接口
            mail_user = self.config.get_email("email_user")  # 发件人用户名
            mail_pass = self.config.get_email("email_pass")  # 发件人口令
            subject = self.config.get_email("subject")  # 主题
            content = self.config.get_email("content")  # 正文
            if len(name_list_str) == 0:
                self.log.debug("所有用例都正常通过!")
            else:
                self.log.debug("发件人:%s" % sender_name)
                self.log.debug("收件人:%s" % name_list_str)

                txt = email.mime.text.MIMEText(content, 'plain', 'utf-8')
                self.msg.attach(txt)
                self.msg['Subject'] = Header(subject, 'utf-8')
                self.msg['From'] = Header(sender_name, 'utf-8')
                self.msg['To'] = Header("%s" % name_list_str, 'utf-8')

                # 调用邮箱服务器
                smt_obj = smtplib.SMTP_SSL(mail_host, mail_port)
                # 登录邮箱
                smt_obj.login(mail_user, mail_pass)
                # 发送邮件
                smt_obj.sendmail(sender_email, receivers, self.msg.as_string())
                # 关闭邮箱
                smt_obj.quit()
                self.log.debug("发送成功!")
        except Exception as e:
            self.log.error(e)
            raise Exception("发送email时异常!")

    def remove_result(self):
        """发送报告后删除其他的文件夹"""
        try:
            result_path = os.path.dirname(self.log_dir)  # 获取result目录路径
            result_list = os.listdir(result_path)  # 获取result下的文夹列表
            i = len(result_list)  # 统计文件夹数量
            for file in result_list:
                path = os.path.join(result_path, file)  # 拼接每个文件夹的路径
                if i > 1:  # 保留最新的文件夹
                    shutil.rmtree(path)
                    i -= 1
        except Exception as e:
            self.log.error(e)
            raise Exception("删除result下文件夹时异常!")
Ejemplo n.º 2
0
    def extraction_error_log(self):
        """按负责人提取错误日志"""
        try:
            log_path = self.common.get_result_path("result.log")  # 生成原始日志文件路径
            error_log_path = self.common.get_result_path(
                "error.log")  # 生成错误日志文件路径

            # 从邮件的收件人信息中读取所有的负责人姓名,实现错误日志按人分类
            config = ReadConfig()
            receivers = config.get_email("receivers")  # 收件人列表str类型(姓名,邮箱)
            receivers_dict = json.loads(receivers)  # 收件人列表dict类型(姓名,邮箱)
            principal_list = []  # 收件人姓名列表
            for key, value in receivers_dict.items():
                principal_list.append(key)

            data = ""  # 单个错误日志临时存储器
            error = False  # 错误日志标识
            all_error_num = 0  # 错误用例总的编号
            # principal_error_num = 0  # 负责人的错误编号
            i = 1  # 原始日志中的文本行数
            j = 1  # 单个用例内的行数

            with open(log_path, "r", encoding="utf-8") as log:  # 以read方式打开原始日志
                with open(error_log_path, "w",
                          encoding="utf-8") as error_log:  # 以write方式打开错误日志
                    lines = log.readlines()  # 读取原始日志

                    principal = ""  # 用例负责人
                    for line in lines:
                        # 匹配负责人姓名,以便是错误日志时创建负责人对应的错误日志文件名,负责人姓名在单个用例的第一行
                        if j == 1:
                            for name in principal_list:
                                if name in line:
                                    principal = name

                        data = data + line  # 临时存储一个用例的日志
                        if "failed!" in line:  # line中包含"ERROR"的标记为错误日志
                            error = True
                        # "*"不可改,出现"*"表示一个用例结束,一个用例结束并被标记为错误日志的内容被写入error_log和principal_log文件
                        if "*" * 100 in line and error is True:
                            all_error_num += 1
                            error_log.write("\n错误用例%s:" % str(all_error_num))
                            error_log.write(data)  # 所有错误日志写入一个文件中

                            # 将错误日志提取到对应负责人的日志文件中
                            principal_log_name = "%s.log" % principal  # 负责人对应的错误日志名
                            principal_log_path = self.common.get_result_path(
                                principal_log_name)  # 生成负责人对应的错误日志路径

                            # 按负责人分类写入对应的文件中
                            if os.path.exists(
                                    principal_log_path
                            ):  # 判断principal_log_path是否存在,存在时添加,不存在时创建
                                with open(principal_log_path,
                                          "a+",
                                          encoding="utf-8") as principal_log:
                                    principal_log.write(data)
                            else:
                                with open(principal_log_path,
                                          "w+",
                                          encoding="utf-8") as principal_log:
                                    principal_log.write(data)

                            # 有错误日志时恢复初始化
                            data = ""
                            error = False
                            j = 1

                        # 没有错误日志时恢复初始化
                        elif "*" * 100 in line:  # "*"不可改
                            data = ""
                            error = False
                            j = 1
                        i += 1

            if os.path.exists(error_log_path) and os.path.getsize(
                    error_log_path) == 0:  # 如果没有错误日志,就删除空的error_log文件
                os.remove(error_log_path)
        except Exception as e:
            raise Exception("MyLog.extraction_error_log异常 %s" % e)