예제 #1
0
 def __init__(self, env, dbname, auth_dict=None):
     """
     指定所处环境及数据库名称
     :param env: 所处环境
     :param dbname: 数据库名称
     :param auth_dict: 授权字典,样例格式为{"auth_db":"admin", "auth_username":"******", "auth_password":"******"}
     """
     mongodbParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
         "mongodb", 1).get(env)
     self.mongodb = MongoClient(host=mongodbParam['host'],
                                port=mongodbParam['port'])
     if not mongodbParam.__contains__("auth") and auth_dict is None:
         logger.warning("请在应用配置文件中指定MongoDB授权信息,或者通过auth_dict字典进行指定!")
         sys.exit(1)
     if auth_dict is not None:
         if isinstance(auth_dict, dict):
             auth_db = auth_dict.get("auth_db")
             auth_username = auth_dict.get("auth_username")
             auth_password = str(auth_dict.get("auth_password"))
             auth = eval("self.mongodb.{}".format(auth_db))
             auth.authenticate(auth_username, auth_password)
             self.db_client = eval("self.mongodb.{}".format(dbname))
         else:
             logger.warning("auth_dict授权信息必须为字典形式,请检查!")
             sys.exit(1)
     if auth_dict is None and mongodbParam.__contains__("auth"):
         mongodbAuth = mongodbParam.get("auth")
         auth_db = mongodbAuth.get("db")
         auth_username = mongodbAuth.get("username")
         auth_password = str(mongodbAuth.get("password"))
         auth = eval("self.mongodb.{}".format(auth_db))
         auth.authenticate(auth_username, auth_password)
         self.db_client = eval("self.mongodb.{}".format(dbname))
예제 #2
0
 def __init__(self):
     """
     根据环境配置初始化ELK连接信息
     """
     env_params = YamlConfig(config=APPLICATION_CONFIG_FILE).get("elk")
     username = str(env_params.get("username"))
     password = str(env_params.get("password"))
     ElkSupport.__init__(self, username=username, password=password)
예제 #3
0
 def __init__(self):
     """
     从应用配置文件获取钉钉请求token及签名secret
     """
     self.token = YamlConfig(
         config=APPLICATION_CONFIG_FILE).get("ding")["token"]
     self.secret = YamlConfig(
         config=APPLICATION_CONFIG_FILE).get("ding")["secret"]
     self.timestamp = str(round(time.time() * 1000))
예제 #4
0
 def __init__(self):
     """
     根据环境配置初始化Jenkins连接信息
     """
     env_params = YamlConfig(config=APPLICATION_CONFIG_FILE).get("jenkins")
     url = str(env_params.get("url"))
     username = str(env_params.get("username"))
     password = str(env_params.get("password"))
     JenkinsTools.__init__(self,
                           url=url,
                           username=username,
                           password=password)
예제 #5
0
 def create_session(self):
     """
     创建数据库连接会话
     :return session:会话实例
     :return:
     """
     try:
         if self.dbtype == r'mysql':
             mysqlParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
                 "mysql", 1).get(self.env)
             self.session = pymysql.connect(host=mysqlParam['host'],
                                            user=mysqlParam['username'],
                                            password=str(
                                                mysqlParam['password']),
                                            port=mysqlParam['port'],
                                            database=str(self.dbname))
             return self.session
         elif self.dbtype == r'redis':
             redisParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
                 'redis', 1)[self.env]
             pool = redis.ConnectionPool(
                 host=redisParam['host'],
                 port=redisParam['port'],
                 db=self.dbname,
                 decode_responses=True,
             )
             self.session = redis.StrictRedis(connection_pool=pool,
                                              charset='utf-8')
             return self.session
         elif self.dbtype == r'mongodb':
             mongoParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
                 'mongodb', 1)[self.env]
             self.session = MongoClient(host=mongoParam['host'],
                                        port=mongoParam['port'])
             return self.session
         else:
             raise DatabaseTypeError
     except InternalError:
         logger.exception('[Exception]:当前指定的MySQL数据库"{}"并不存在.'.format(
             self.dbname))
     except DatabaseTypeError:
         logger.exception('[Exception]:数据库类型{}不支持创建连接会话.'.format(
             self.dbtype.upper()))
     except ConnectionError:
         logger.exception('[Exception]:Redis会话连接错误, 请检查连接会话参数和当前网络状况.')
     except ResponseError:
         logger.exception(
             '[Exception]:Redis数据库索引值"{}"非法, 请输入合法的数据库索引(int类型标识).'.format(
                 self.dbname))
     except Exception:
         logger.exception('[Exception]:创建{}数据库会话实例过程中发生异常,请检查!'.format(
             self.dbtype.upper()))
 def __init__(self, project="bus", env="stg"):
     """
     初始化环境信息。
     :param project: 所属项目名称
     :param env: 当前环境名称
     """
     env_params = YamlConfig(config=ENVIRONMENT_CONFIG_FILE).get(project).get(env)
     web_params = env_params.get("doctor_admin")
     self.login_url = web_params.get("login_url")
     self.username = web_params.get("username")
     self.password = web_params.get("password")
     self.validcode = web_params.get("validcode")
     self.env = env
     self.token = None
예제 #7
0
 def __init__(self, env, domain=True):
     """
     根据环境配置初始化Swagger接口文档。
     :param env: 项目环境
     :param domain: 域名替换开关(默认开启)
     """
     env_params = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
         "swagger", 2).get(env)
     swagger_doc_urls = env_params.get("swagger_docs")
     if domain is True:
         domain_urls = env_params.get("domain_urls")
         SwaggerTools.__init__(self,
                               swagger_doc_urls=swagger_doc_urls,
                               swagger_domain_urls=domain_urls)
     else:
         SwaggerTools.__init__(self, swagger_doc_urls=swagger_doc_urls)
예제 #8
0
 def __init__(self, env, dbname):
     """
     指定所处环境及数据库名称
     :param env: 所处环境
     :param dbname: 数据库名称
     """
     mysqlParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get(
         "mysql", 1).get(env)
     self.mysql_engine = create_engine(
         "mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8".format(
             mysqlParam['username'], str(mysqlParam['password']),
             mysqlParam['host'], mysqlParam['port'], dbname))
예제 #9
0
 def __init__(self, ding_notify_file, preview_mode=False):
     """
     从应用配置文件获取钉钉请求token及签名secret
     :param ding_notify_file: 钉钉消息模板文件
     :param preview_mode: 测试报告截图预览
     """
     try:
         DingTools.__init__(self)
         if not os.path.exists(ding_notify_file):
             raise FileNotFoundError
         with open(file=ding_notify_file, mode=r'r',
                   encoding='utf-8') as ding_file:
             if preview_mode is False:
                 self.ding = json.loads(ding_file.read().replace(
                     "ip_address",
                     get_ip()).replace("![Allure](report_url)",
                                       ">      🐾🐾🐾 ~ {}".format(get_ip())))
             else:
                 self.ding = json.loads(ding_file.read().replace(
                     "ip_address", get_ip()).replace(
                         "report_url",
                         face_bed(pic=capture_image(
                             width=1440,
                             height=797,
                             url="http://localhost:5000/allure",
                             sleep=10,
                             pic=os.path.join(RESOURCE_PATH, "Allure",
                                              "Allure.png")),
                                  alias="Allure.png")))
         self.token = YamlConfig(
             config=APPLICATION_CONFIG_FILE).get("ding")["token"]
         self.secret = YamlConfig(
             config=APPLICATION_CONFIG_FILE).get("ding")["secret"]
         self.timestamp = str(round(time.time() * 1000))
     except FileNotFoundError:
         logger.warning(
             '[WARNING]:钉钉消息通知模板文件"{}"当前并不存在,请检查!'.format(ding_notify_file))
         sys.exit(1)
예제 #10
0
class EnvironmentDingTools(DingTools):
    """
    钉钉机器人消息提醒工具类(依赖环境配置文件)
    """
    def __init__(self, ding_notify_file, preview_mode=False):
        """
        从应用配置文件获取钉钉请求token及签名secret
        :param ding_notify_file: 钉钉消息模板文件
        :param preview_mode: 测试报告截图预览
        """
        try:
            DingTools.__init__(self)
            if not os.path.exists(ding_notify_file):
                raise FileNotFoundError
            with open(file=ding_notify_file, mode=r'r',
                      encoding='utf-8') as ding_file:
                if preview_mode is False:
                    self.ding = json.loads(ding_file.read().replace(
                        "ip_address",
                        get_ip()).replace("![Allure](report_url)",
                                          ">      🐾🐾🐾 ~ {}".format(get_ip())))
                else:
                    self.ding = json.loads(ding_file.read().replace(
                        "ip_address", get_ip()).replace(
                            "report_url",
                            face_bed(pic=capture_image(
                                width=1440,
                                height=797,
                                url="http://localhost:5000/allure",
                                sleep=10,
                                pic=os.path.join(RESOURCE_PATH, "Allure",
                                                 "Allure.png")),
                                     alias="Allure.png")))
            self.token = YamlConfig(
                config=APPLICATION_CONFIG_FILE).get("ding")["token"]
            self.secret = YamlConfig(
                config=APPLICATION_CONFIG_FILE).get("ding")["secret"]
            self.timestamp = str(round(time.time() * 1000))
        except FileNotFoundError:
            logger.warning(
                '[WARNING]:钉钉消息通知模板文件"{}"当前并不存在,请检查!'.format(ding_notify_file))
            sys.exit(1)

    @property
    def get_sign(self):
        """
        生成钉钉机器人签名字串
        :return:
        """
        try:
            secret_enc = self.secret.encode('utf-8')
            string_to_sign = '{}\n{}'.format(self.timestamp, self.secret)
            string_to_sign_enc = string_to_sign.encode('utf-8')
            hmac_code = hmac.new(secret_enc,
                                 string_to_sign_enc,
                                 digestmod=hashlib.sha256).digest()
            sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
            return sign
        except Exception:
            logger.exception("[Exception]:生成钉钉机器人签名字串过程中发生异常,请检查!")

    def generate_msg(self, msgtype):
        """
        构造钉钉机器人消息体
        :param msgtype: 消息提醒类型(当前仅支持Text/Link/MarkDown/ActionCard/FeedCard)
        :return:
        """
        try:
            if msgtype == 'text':
                return json.dumps(self.ding.get('text'))
            if msgtype == 'link':
                return json.dumps(self.ding.get('link'))
            if msgtype == 'markdown':
                return json.dumps(self.ding.get('markdown'))
            if msgtype == 'actionCard':
                return json.dumps(self.ding.get('actionCard'))
            if msgtype == 'feedCard':
                return json.dumps(self.ding.get('feedCard'))
        except Exception:
            logger.warning("[WARNING]:构造钉钉机器人消息体过程中发生异常,请检查!")

    @retry(stop_max_attempt_number=2,
           wait_random_min=2000,
           wait_random_max=5000)
    def send(self, msgtype):
        """
        发送钉钉机器人消息提醒
        :param msgtype: 消息提醒类型
        :return:
        """
        try:
            if msgtype not in [
                    'text', 'link', 'markdown', 'actionCard', 'feedCard'
            ]:
                logger.warning(
                    '[WARNING]:检测到非法消息类型"{}",当前仅支持text、link、markdown、actionCard、feedCard,请重新指定!'
                    .format(msgtype))
                sys.exit(1)
            url = "https://oapi.dingtalk.com/robot/send?access_token={}&timestamp={}&sign={}".format(
                self.token, self.timestamp, self.get_sign)
            headers = {'Content-Type': 'application/json'}
            response = requests.request("POST",
                                        url,
                                        headers=headers,
                                        data=self.generate_msg(msgtype))
            result = response.json()
            if result.get("errcode") == 0 and result.get("errmsg") == 'ok':
                logger.info("[Done]:钉钉机器人消息提醒成功.")
            else:
                logger.warning(
                    "[WARNING]:钉钉机器人消息提醒失败,接口响应为【{}】,开始重试...".format(result))
                sys.exit(1)
        except Exception:
            logger.exception("[Exception]:发送钉钉机器人消息提醒过程中发生异常,请检查!")
            sys.exit(1)
예제 #11
0
class DingTools(object):
    """
    钉钉机器人消息提醒工具类
    """
    def __init__(self):
        """
        从应用配置文件获取钉钉请求token及签名secret
        """
        self.token = YamlConfig(
            config=APPLICATION_CONFIG_FILE).get("ding")["token"]
        self.secret = YamlConfig(
            config=APPLICATION_CONFIG_FILE).get("ding")["secret"]
        self.timestamp = str(round(time.time() * 1000))

    @property
    def get_sign(self):
        """
        生成钉钉机器人签名字串
        :return:
        """
        try:
            secret_enc = self.secret.encode('utf-8')
            string_to_sign = '{}\n{}'.format(self.timestamp, self.secret)
            string_to_sign_enc = string_to_sign.encode('utf-8')
            hmac_code = hmac.new(secret_enc,
                                 string_to_sign_enc,
                                 digestmod=hashlib.sha256).digest()
            sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
            return sign
        except Exception:
            logger.exception("[Exception]:生成钉钉机器人签名字串过程中发生异常,请检查!")

    @retry(stop_max_attempt_number=2,
           wait_random_min=2000,
           wait_random_max=5000)
    def send(self, message):
        """
        发送钉钉机器人消息提醒
        :param message: 消息提醒
        :return:
        """
        try:
            if not isinstance(message, dict):
                logger.warning("[WARNING]:参数message必须以字典形式入参,请检查!")
                sys.exit(1)
            if not message.__contains__('msgtype'):
                logger.warning("[WARNING]:消息体message必须包含消息类型msgtype,请检查!")
                sys.exit(1)
            if message.get('msgtype') not in [
                    'text', 'link', 'markdown', 'actionCard', 'feedCard'
            ]:
                logger.warning(
                    '[WARNING]:检测到非法消息类型"{}",当前仅支持text、link、markdown、actionCard、feedCard,请重新指定!'
                    .format(message.get('msgtype')))
                sys.exit(1)
            url = "https://oapi.dingtalk.com/robot/send?access_token={}&timestamp={}&sign={}".format(
                self.token, self.timestamp, self.get_sign)
            headers = {'Content-Type': 'application/json'}
            response = requests.request("POST",
                                        url,
                                        headers=headers,
                                        data=json.dumps(message))
            result = response.json()
            if result.get("errcode") == 0 and result.get("errmsg") == 'ok':
                logger.info("[Done]:钉钉机器人消息提醒成功.")
            else:
                logger.warning(
                    "[WARNING]:钉钉机器人消息提醒失败,接口响应为【{}】,开始重试...".format(result))
                sys.exit(1)
        except Exception:
            logger.exception("[Exception]:发送钉钉机器人消息提醒过程中发生异常,请检查!")
            sys.exit(1)
예제 #12
0
class Email(object):
    '''
    邮件发送模块
    '''

    emailParam = YamlConfig(config=APPLICATION_CONFIG_FILE).get('email')

    def __init__(self,
                 server=emailParam['server'],
                 port=emailParam['port'],
                 user=emailParam['user'],
                 password=emailParam['password'],
                 title=emailParam['title'],
                 sender=emailParam['sender'],
                 receiver=emailParam['receiver'],
                 ):
        '''
        初始化Email参数
        :param server:  邮件服务器ip或域名
        :param port: 邮件服务器端口号
        :param user: 登录账户
        :param password: 登录密码
        :param title: 邮件标题
        :param sender: 发送邮箱
        :param receiver: 接收邮箱
        '''
        self.server = server
        self.port = port
        self.user = user
        self.password = password
        self.title = title
        self.sender = 'Automation' + '<' + sender + '>'
        self.receiver = receiver
        self.message = None
        self.files = None
        self.msg = MIMEMultipart('related')
        self.msg['From'] = Header(self.sender, 'utf-8')
        self.msg['To'] = Header(self.receiver, 'utf-8')
        self.msg['Subject'] = Header(self.title, 'utf-8')

    def createSession(self):
        '''
        建立SMTP邮件服务连接
        '''
        try:
            self.smtpObj = smtplib.SMTP()
            self.smtpObj.connect(self.server,
                                 self.port)
            # 若开启SSL,则关闭TLS
            # self.smtpObj.starttls()
            self.smtpObj.login(self.user,
                               self.password)
            return self.smtpObj
        except SMTPConnectError:
            logger.exception('邮件SMTPConnectError连接错误, 请检查网络以及邮件配置.')
        except SMTPAuthenticationError:
            logger.exception('邮件SMTPAuthenticationError认证错误, 请检查邮件登录账套.')
        except SMTPException:
            logger.exception('触发SMTPException异常, 当前无适配邮件认证方式, 请确认当前开启的验证方式(SSL或TSL).')

    def checkAtType(self, attype):
        '''
        校验附件类型并自动添加
        :param attype:附件类型
        :return:
        '''
        if isinstance(attype, list):
            for af in attype:
                self.attachFile(af)
        if isinstance(attype, str):
            self.attachFile(attype)

    def attachFile(self, file):
        '''
        构造附件扩展,仅MIMEBase支持中文附件
        :param file: 附件文件
        '''
        # with open(file, 'rb') as f:
        #     att = MIMEText(f.read(), 'plait', 'utf-8')
        # att["Content-Type"] = 'application/octet-stream'
        # filename = re.split(r'[\\|/]', file)[-1]
        # att["Content-Disposition"] = 'attachment; filename={}'.format(filename)
        # self.msg.attach(att)
        # logger.info('邮件已添加附件 {}'.format(filename))
        att = MIMEBase('application', 'octet-stream')
        with open(file, 'rb') as f:
            att.set_payload(f.read())
        filename = re.split(r'[\\|/]', file)[-1]
        att.add_header('Content-Disposition', 'attachment', filename=('gbk', '', filename))
        encoders.encode_base64(att)
        self.msg.attach(att)
        logger.info('邮件已添加附件 {}'.format(filename))

    def attachImage(self, path=os.path.join(RESOURCE_PATH, "Allure")):
        '''
        构造附图扩展
        :param path: 图片路径
        '''
        with open(os.path.join(path, 'Allure.png'), 'rb') as f:
            attimg = MIMEImage(f.read())
        attimg.add_header('Content-ID', '<image1>')
        return attimg

    def attachHtml(self, href="http://10.16.168.70:5000/allure", desc="API功能自动化测试报告"):
        """
        构造文本扩展
        :param href: 链接地址
        :param desc: 链接描述
        :return:
        """
        if self.image_flag:
            img_str = '<p><img src="cid:image1"></p>'
            message = \
                '''
                <h4>Dear All:</h4><br/><p>{}</p>
                <p>【<font size="3" color="gray"><b>测试报告</b></font>】:点击<a href="{}">{}</a>进行查看.</p><br/>
                {}
                '''.format(self.message, href, desc, img_str)
        else:
            message = \
                '''
                <h4>Dear All:</h4><br/><p>{}</p>
                <p>【<font size="3" color="gray"><b>测试报告</b></font>】:点击<a href="{}">{}</a>进行查看.</p><br/>
                '''.format(self.message, href, desc)

        msgalter = MIMEMultipart('alternative')
        msgalter.attach(MIMEText(message, _subtype='html', _charset='utf-8'))
        return msgalter

    def build_all_msg(self):
        '''
        添加所有邮件数据
        '''
        self.msg.attach(self.attachHtml())
        self.msg.attach(self.attachImage())
        return self.msg

    def build_html_msg(self):
        """
        添加文本邮件信息
        :return:
        """
        self.msg.attach(self.attachHtml())
        return self.msg

    def build_image_msg(self):
        """
        添加图片邮件信息
        :return:
        """
        self.msg.attach(self.attachImage())
        return self.msg

    def send(self, message='FYI', image_flag=False, *filepath):
        '''
        触发邮件发送
        :param message: 邮件文本信息
        :param image_flag: 是否发送图片
        :param filepath: 邮件附件元组
        :return:
        '''
        self.message = message
        self.image_flag = image_flag
        for p in filepath:
            if os.path.isdir(p):
                self.files = list()
                for f in os.listdir(p):
                    self.files.append(os.path.join(p, f))
                self.checkAtType(self.files)
            elif os.path.isfile(p):
                self.files = p
                self.checkAtType(self.files)
            else:
                self.files = p
                filename = re.split(r'[\\|/]', str(p))[-1]
                logger.warning('注意! 邮件附件"{0}"的路径"{1}"可能无效, 附件无法上传.'.
                               format(filename, p))
        try:
            logger.info("开始发送测试结果邮件......")
            session = self.createSession()
            session.sendmail(self.sender,
                             self.receiver.split(';'),
                             self.build_all_msg().as_string() if self.image_flag else self.build_html_msg().as_string()
                             )
        except (gaierror and error):
            logger.exception('邮件发送失败! ~ 无法连接到SMTP服务器, 请检查网络以及邮件配置.')
        else:
            logger.info('[Done]:{0}邮件发送成功! 收件人:{1}.'.format(self.title, self.receiver))
            session.quit()
            session.close()
예제 #13
0
 def __init__(self, logger_name='GastepoAutoTest', config=APPLICATION_CONFIG_FILE):
     '''
     通过logging模块配置控制台和间隔文件log
     :param logger_name: 日志名称
     '''
     c = YamlConfig(config=config).get('log')
     self.color = str(c.get("logcolor")).capitalize()
     self.logger = logging.getLogger(logger_name)
     logging.root.setLevel(logging.NOTSET)
     self.log_file_name = c.get('logname') if c and c.get('logname') else 'GastepoAutoTest.log'
     self.when_auto = c.get('when') if c and c.get('when') else 'D'
     self.backup_count = c.get('backup') if c and c.get('backup') else 5
     self.console_output_level = c.get('console_level') if c and c.get('console_level') else 'DEBUG'
     self.file_output_level = c.get('file_level') if c and c.get('file_level') else 'INFO'
     pattern = c.get('pattern') if c and c.get(
         'pattern') else '%(name)s - %(levelname)s - %(asctime)s - %(message)s'
     if self.color == "True":
         LOG_COLORS_CONFIG = {
             'DEBUG': 'white',
             'INFO': 'black',
             'WARNING': 'yellow',
             'ERROR': 'red',
             'CRITICAL': 'bold_red',
         }
         self.formatter = colorlog.ColoredFormatter('%(log_color)s{}'.format(pattern), log_colors=LOG_COLORS_CONFIG)
     else:
         self.formatter = logging.Formatter(pattern)
예제 #14
0
# -*- coding: utf-8 -*-

import os
import shutil
import time
from subprocess import CalledProcessError

from Gastepo.Core.Base.BaseData import APPLICATION_CONFIG_FILE
from Gastepo.Core.Base.BaseData import RESULT_PATH, REPORT_PATH, RESOURCE_PATH
from Gastepo.Core.Util.CommonUtils import run_command
from Gastepo.Core.Util.ConfigUtils import YamlConfig
from Gastepo.Core.Util.LogUtils import logger

ALLURE_RESULT = RESULT_PATH
ALLURE_REPORT = REPORT_PATH
CHECK_COUNT = YamlConfig(config=APPLICATION_CONFIG_FILE).get("allure", 2).get("check_count")

class AllureTools(object):
    """
    Allure测试报告操作类
    """

    @classmethod
    def check_result(cls, check_count=CHECK_COUNT):
        """
        检查Allure测试结果json文件是否生成。
        :param check_count: 检测次数。
        :return:
        """
        check_result = None
        for count in range(check_count):