Ejemplo n.º 1
0
 def prepare(self):
     self.user = UserModule()
     self.project = ProjectModule()
     self.setting = SettingModule()
     self.option = OptionModule()
     self.msg = MessagesModule()
     self.statistics = StatisticsModule()
     self.common_func = CommonFunction()
     self.option_func = OptionsFunction()
     self.thread_func = ThreadFunction()
Ejemplo n.º 2
0
 def __init__(self):
     self.project = ProjectModule()
     self.setting = SettingModule()
     self.option_func = OptionsFunction()
     self.common_func = CommonFunction()
     self.thread_func = ThreadFunction()
     self.jenkins_server = jenkins.Jenkins(url=jenkins_url,
                                           username=jenkins_user,
                                           password=jenkins_password,
                                           timeout=5)
Ejemplo n.º 3
0
 def __init__(self, pid=0, jid=0):
     self.default_headers = {
         'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
         'User-Agent':
         'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
         'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4',
         'Cookie': ''
     }
     self.headers = dict()
     self.setting = SettingModule()
     self.common_func = CommonFunction()
     self.option_func = OptionsFunction()
     self.pid = pid
     self.jid = jid
Ejemplo n.º 4
0
 def prepare(self):
     self.common_func = CommonFunction()
     self.user = UserModule()
     self.project = ProjectModule()
     self.setting = SettingModule()
     self.option = OptionModule()
     self.option_func = OptionsFunction()
     self.company = yield self.option_func.get_option_by_name(name='company')
     self.limit = yield self.option_func.get_option_by_name(name='page_limit')
     self.company = self.company or '开源接口测试平台'
     self.argv = dict(company=self.company)
Ejemplo n.º 5
0
 def __init__(self):
     self.common_func = CommonFunction()
Ejemplo n.º 6
0
class UserModule(object):
    """
    用户表相关操作
    """
    def __init__(self):
        self.common_func = CommonFunction()

    # 获取用户信息
    @gen.coroutine
    def get_user_info(self, email_or_username=None, uid=None, status=None):
        where = []
        params = dict()
        if uid is not None:
            where.append("u.id=%(uid)s")
            params['uid'] = uid
        if email_or_username is not None:
            where.append("(u.email=%(user)s OR u.username=%(user)s)")
            params['user'] = email_or_username
        if status is not None:
            where.append("u.status=%(status)s")
            params['status'] = status
        sql = "SELECT u.*, (SELECT COUNT(IF(m.`type` IN ('notice', 'message') AND m.`status` NOT IN (0, 2), m.`type`, NULL)) + COUNT(IF(m.`type` IN ('todo') AND m.`status` NOT IN (0, 5), m.`type`, NULL)) FROM t_messages m WHERE m.type <> 'active' AND m.userId=u.id AND m.`status` <> 0) as unreadCount FROM t_users u"
        if where:
            sql += ' WHERE {}'.format(' AND '.join(where))
        try:
            cursor = yield pool.execute(sql, params)
            result = cursor.fetchone()
            cursor.close()
            return munchify(result)
        except pymysql.Error as e:
            log.error(e)
            return None

    # 通过user_id获取用户信息
    @gen.coroutine
    def get_users_info_by_id(self, uid, status=None):
        if isinstance(uid, list):
            uid = ','.join([str(u) for u in uid])
        sql = 'SELECT * FROM t_users u WHERE u.id in ({})'.format(uid)
        param = dict()
        if status is not None:
            sql += ' AND status=%(status)s'
            param['status'] = status
        sql += ' ORDER BY u.role'
        try:
            cursor = yield pool.execute(sql, param)
            result = cursor.fetchall()
            cursor.close()
            return munchify(result)
        except pymysql.Error as e:
            log.error(e)
            return []

    # 获取用户列表
    @gen.coroutine
    def get_users_list(self, page=1, limit=None, status=None, name=None):
        sql = 'SELECT * FROM t_users u'
        sql_count = 'SELECT COUNT(*) count FROM t_users u'
        where = []
        params = dict()
        if name is not None:
            where.append(
                "(u.realname like %(name)s OR u.username like %(name)s OR u.email like %(name)s OR u.profile like %(name)s)"
            )
            params['name'] = '%{}%'.format(name)
        if status is not None:
            where.append("u.status=%(status)s")
            params['status'] = status
        if where:
            where = ' WHERE {}'.format(' AND '.join(where))
            sql += where
            sql_count += where
        sql += ' ORDER BY u.role'
        if limit is not None:
            offset = (page - 1) * limit
            sql += ' LIMIT {},{}'.format(offset, limit)
        try:
            cursor = yield pool.execute(sql, params)
            result = cursor.fetchall()
            cursor = yield pool.execute(sql_count, params)
            total = cursor.fetchone()
            cursor.close()
            return munchify(result), munchify(total).count
        except pymysql.Error as e:
            log.error(e)
            return [], 0

    # 注册用户
    @gen.coroutine
    def register_user(self,
                      email,
                      password,
                      username=None,
                      real_name=None,
                      profile=None,
                      role=1,
                      status=1):
        register_time = time.strftime('%Y-%m-%d %H:%M:%S')
        password = self.common_func.encode_password(password)
        try:
            cursor = yield pool.execute('SELECT COUNT(*) count FROM t_users')
            total = munchify(cursor.fetchone())
            if total.count == 0:
                role = 0
                status = 2
        except pymysql.Error as e:
            log.error(e)
        username = username or '{}_{}'.format(
            email.split('@')[0], str(int(time.time() * 1000)))
        sql = """
        INSERT INTO t_users (username, email, password, realname, profile, registerTime, lastLoginTime, role, status)
        VALUE(%(username)s, %(email)s, %(password)s, %(realname)s, %(profile)s, %(registerTime)s, %(lastLoginTime)s, %(role)s, %(status)s)
        """
        user = yield self.get_user_info(email_or_username=email)
        if not user:
            with (yield pool.Connection()) as conn:
                with conn.cursor() as cursor:
                    try:
                        yield cursor.execute(
                            sql,
                            dict(
                                username=username,
                                email=email,
                                password=password,
                                realname=real_name or '',
                                registerTime=register_time,
                                lastLoginTime=register_time,
                                profile=json.dumps(profile, ensure_ascii=False)
                                or '',
                                role=role,
                                status=status))
                    except pymysql.Error as e:
                        yield conn.rollback()
                        log.error('注册用户 {} 失败#{}'.format(email, e))
                        flag, msg = False, '注册用户 {} 失败#{}'.format(email, e)
                    else:
                        yield conn.commit()
                        log.info('注册用户 {} 成功'.format(email))
                        flag, msg = munchify(
                            dict(id=cursor.lastrowid, status=status,
                                 role=role)), '注册用户成功!'
        else:
            log.error('该邮箱已注册!')
            flag, msg = False, '该邮箱已注册!'
        return flag, msg

    # 编辑用户
    @gen.coroutine
    def edit_user(self,
                  email=None,
                  uid=None,
                  password=None,
                  username=None,
                  real_name=None,
                  last_login_time=None,
                  role=None,
                  status=None,
                  profile=None):
        user = yield self.get_user_info(
            email_or_username=None if uid else email, uid=uid)
        if user:
            update = []
            param = dict(email=email if email else user.email)
            if password is not None:
                update.append("password=%(password)s")
                param['password'] = self.common_func.encode_password(password)
            if username is not None:
                sql = "SELECT id, username FROM t_users u WHERE u.email != %(email)s AND u.username = %(username)s"
                param['username'] = username
                try:
                    cursor = yield pool.execute(sql, param)
                    user_info = cursor.fetchone()
                    if (user_info and uid
                            and uid != user_info['id']) or (user_info
                                                            and uid is None):
                        log.error('用户名 {} 已存在'.format(username))
                        return False, '用户名 {} 已存在'.format(username)
                    else:
                        update.append("username=%(username)s")
                except pymysql.Error as e:
                    log.error(e)
                    return False, '编辑用户失败#{}'.format(e)
            if email is not None and uid is not None:
                is_exist_user = yield self.get_user_info(email)
                if is_exist_user and is_exist_user.id != uid:
                    log.error('该邮箱 {} 已注册'.format(email))
                    return False, '该邮箱 {} 已注册'.format(email)
                else:
                    update.append("email=%(email)s")
            if real_name is not None:
                update.append("realname=%(realname)s")
                param['realname'] = real_name
            if last_login_time is not None:
                update.append("lastLoginTime=%(lastLoginTime)s")
                param['lastLoginTime'] = last_login_time
            if role is not None:
                update.append('role=%(role)s')
                param['role'] = role
            if profile is not None:
                update.append('profile=%(profile)s')
                param['profile'] = json.dumps(profile, ensure_ascii=False)
            if status is not None:
                update.append('status=%(status)s')
                param['status'] = status
            if update:
                if uid is not None:
                    param['uid'] = uid
                    sql = "UPDATE t_users SET {} WHERE id=%(uid)s".format(
                        ', '.join(update))
                else:
                    sql = "UPDATE t_users SET {} WHERE email=%(email)s".format(
                        ', '.join(update))
                tx = yield pool.begin()
                try:
                    yield tx.execute(sql, param)
                except pymysql.Error as e:
                    yield tx.rollback()
                    log.error('编辑用户失败#{}'.format(e))
                    flag, msg = False, '用户 {} 资料修改失败'.format(user.email)
                else:
                    yield tx.commit()
                    log.info('用户 {} 资料修改成功'.format(user.email))
                    flag, msg = True, '用户 {} 资料修改成功'.format(user.email)
                return flag, msg
            else:
                log.error('没有可更新的项')
                return False, '没有可更新的项'
        else:
            log.error('用户 {} 不存在!'.format(email))
            return False, '用户 {} 不存在!'.format(email)

    # 删除用户信息
    @gen.coroutine
    def delete_user(self, uid=None, username_or_email=None, status=None):
        user = yield self.get_user_info(uid=uid,
                                        email_or_username=username_or_email,
                                        status=status)
        if user:
            where = []
            params = dict()
            if uid is not None:
                where.append("id=%(uid)s")
                params['uid'] = uid
            if username_or_email is not None:
                where.append("(email=%(user)s OR username=%(user)s)")
                params['user'] = username_or_email
            if status is not None:
                where.append("status=%(status)s")
                params['status'] = status
            sql = 'DELETE FROM t_users'
            if where:
                sql += ' WHERE {}'.format(' AND '.join(where))
            tx = yield pool.begin()
            try:
                yield tx.execute(sql, params)
            except pymysql.Error as e:
                yield tx.rollback()
                log.error('删除用户失败#{}'.format(e))
                flag, msg = False, '删除用户失败'
            else:
                yield tx.commit()
                log.info('删除用户成功')
                flag, msg = True, '删除用户成功'
            return flag, msg
        else:
            log.error('用户不存在!')
            return False, '用户不存在!'
Ejemplo n.º 7
0
class JobsMonitor(object):
    def __init__(self):
        self.project = ProjectModule()
        self.setting = SettingModule()
        self.option_func = OptionsFunction()
        self.common_func = CommonFunction()
        self.thread_func = ThreadFunction()
        self.jenkins_server = jenkins.Jenkins(url=jenkins_url,
                                              username=jenkins_user,
                                              password=jenkins_password,
                                              timeout=5)

    # 监控任务状态
    @gen.coroutine
    def jobs_status(self):
        try:
            job_list, total = yield self.setting.get_settings_list(
                s_type=['job', 'jobG', 'jobA'], status=[0, 2], pj_status=1)
            for job in job_list:
                desc = json.loads(job.value)
                if (desc.get('buildEnv')
                        or desc.get('dayBuild')) and job.status == 0 and int(
                            time.time()) > int(job.createTime.timestamp()):
                    yield self.setting.edit_setting(sid=job.id, status=1)
                    continue
                job_name = desc.get(
                    'jobName') if job.type != 'job' else jenkins_jacoco
                if job_name and job.status == 2:
                    if job.type != 'job':
                        last_build_number = self.jenkins_server.get_job_info(
                            job_name).get('lastBuild').get('number')
                        last_build = self.jenkins_server.get_build_info(
                            job_name, last_build_number)
                        status = None if last_build.get('building') else 0
                    else:
                        status = None
                    if (job.type != 'job' and last_build.get('queueId')
                            == desc.get('queueId')) or (job_name
                                                        == jenkins_jacoco):
                        if (job.type != 'job' and status is None
                                and desc['url'] == last_build.get('url')) or (
                                    job_name == jenkins_jacoco):
                            if desc.get('jacocoId'):
                                jacoco_job = self.jenkins_server.get_job_info(
                                    jenkins_jacoco)
                                first_build_number = jacoco_job.get(
                                    'firstBuild').get('number')
                                last_build_number = jacoco_job.get(
                                    'lastBuild').get('number')
                                for num in range(first_build_number,
                                                 last_build_number + 1):
                                    try:
                                        jacoco = self.jenkins_server.get_build_info(
                                            jenkins_jacoco, num)
                                        if jacoco.get('queueId') != desc.get(
                                                'jacocoId'):
                                            continue
                                        if not jacoco.get(
                                                'building') and jacoco.get(
                                                    'result') == 'FAILURE':
                                            day_build_env = desc.get(
                                                'buildEnv') or desc.get(
                                                    'dayBuild')
                                            apps = yield self.option_func.get_env_info(
                                                eid=day_build_env)
                                            stop_time = time.strftime(
                                                '%Y-%m-%d %H:%M:%S',
                                                time.localtime(time.time() +
                                                               3600 * 24))
                                            parameters = [
                                                ('ACTION', 'Monitoring'),
                                                ('STOPTIME', stop_time),
                                                ('CLEAN', 'No'),
                                                ('JOB_ID', job.name)
                                            ]
                                            for app in [
                                                    a.get('details')
                                                    for a in apps
                                            ]:
                                                for ap in app:
                                                    if ap.get('title').lower(
                                                    ).find('linux_app') != -1:
                                                        parameters.append(
                                                            ('ENV',
                                                             ap.get('ip')))
                                            if len(parameters) > 4:
                                                version_file = os.path.join(
                                                    static_path, 'diffAPP',
                                                    job.name)
                                                if not os.path.isdir(
                                                        version_file):
                                                    os.makedirs(version_file)
                                                version_file = os.path.join(
                                                    version_file,
                                                    'jacoco_app_version.txt')
                                                if os.path.isfile(
                                                        version_file):
                                                    os.remove(version_file)
                                                for app in (desc.get('runApps')
                                                            or []):
                                                    parameters.append(
                                                        ('APP', app))
                                                jacoco_id = self.jenkins_server.build_job(
                                                    jenkins_jacoco,
                                                    parameters=parameters)
                                                desc['jacocoId'] = jacoco_id
                                                yield self.setting.edit_setting(
                                                    sid=job.id, value=desc)
                                    except Exception as e:
                                        log.error(e)
                                        continue
                            continue
                        desc['url'] = last_build.get('url')
                        cycle = desc.get('cycle')
                        if cycle == 'hour':
                            next_time = job.createTime + timedelta(hours=1)
                        elif cycle == 'day':
                            next_time = job.createTime + timedelta(days=1)
                        elif cycle == 'week':
                            next_time = job.createTime + timedelta(weeks=1)
                        elif cycle == 'mouth':
                            next_time = job.createTime + timedelta(days=30)
                        elif cycle == 'year':
                            next_time = job.createTime + timedelta(days=365)
                        else:
                            next_time = job.createTime
                            if status == 0: status = 3
                        if status in [0, 3] and desc.get('jacocoId'):
                            jacoco_job = self.jenkins_server.get_job_info(
                                jenkins_jacoco)
                            first_build_number = jacoco_job.get(
                                'firstBuild').get('number')
                            last_build_number = jacoco_job.get(
                                'lastBuild').get('number')
                            for num in range(first_build_number,
                                             last_build_number + 1):
                                try:
                                    jacoco = self.jenkins_server.get_build_info(
                                        jenkins_jacoco, num)
                                    if jacoco.get('queueId') != desc.get(
                                            'jacocoId'):
                                        continue
                                    self.jenkins_server.stop_build(
                                        jenkins_jacoco, num)
                                except Exception as e:
                                    log.error(e)
                                    continue
                                apps = yield self.option_func.get_env_info(
                                    eid=desc.get('buildEnv')
                                    or desc.get('dayBuild'))
                                desc['buildEnv'] = ''
                                parameters = [('ACTION', 'Reporting'),
                                              ('HIS_BUILD_ID', num),
                                              ('CLEAN', 'Yes'),
                                              ('JOB_ID', job.name)]
                                for app in [a.get('details') for a in apps]:
                                    for ap in app:
                                        if ap.get('title').lower().find(
                                                'linux_app') != -1:
                                            parameters.append(
                                                ('ENV', ap.get('ip')))
                                if len(parameters) > 4:
                                    for app in (desc.get('runApps') or []):
                                        parameters.append(('APP', app))
                                    self.jenkins_server.build_job(
                                        jenkins_jacoco, parameters=parameters)
                        yield self.setting.edit_setting(
                            sid=job.id,
                            value=desc,
                            status=status,
                            create_time=next_time.strftime('%Y-%m-%d %H:%M:%S')
                            if status in [0, 3] else None)
        except Exception as e:
            log.warning(e)

    # 执行定时任务
    @gen.coroutine
    def run_jobs(self):
        try:
            job_list, total = yield self.setting.get_settings_list(
                s_type=['jobG', 'jobA'], status=1, pj_status=1)
            for job in job_list:
                desc = json.loads(job.value)
                job_name = desc.get('jobName')
                day_build_env = desc.get('buildEnv') or desc.get('dayBuild')
                if not job_name or not day_build_env:
                    continue
                data = munchify(
                    dict(env=day_build_env,
                         type='api' if job.type == 'jobA' else 'gui',
                         exec=job_name))
                yield self.option_func.get_hosts_info(data)
                yield self.option_func.get_mysql_jdbc(eid=day_build_env,
                                                      data=data)
                yield self.option_func.get_cases_info(job, data)
                queue_id = self.jenkins_server.build_job(
                    job_name, parameters=dict(JOB_ID=job.name))
                if queue_id:
                    apps = yield self.option_func.get_env_info(
                        eid=day_build_env)
                    stop_time = time.strftime(
                        '%Y-%m-%d %H:%M:%S',
                        time.localtime(time.time() + 3600 * 24))
                    parameters = [('ACTION', 'Monitoring'),
                                  ('STOPTIME', stop_time), ('CLEAN', 'Yes'),
                                  ('JOB_ID', job.name)]
                    for app in [a.get('details') for a in apps]:
                        for ap in app:
                            if ap.get('title').lower().find('linux_app') != -1:
                                parameters.append(('ENV', ap.get('ip')))
                    if len(parameters) > 4:
                        version_file = os.path.join(static_path, 'diffAPP',
                                                    job.name)
                        if not os.path.isdir(version_file):
                            os.makedirs(version_file)
                        version_file = os.path.join(version_file,
                                                    'jacoco_app_version.txt')
                        if os.path.isfile(version_file):
                            os.remove(version_file)
                        for app in (desc.get('runApps') or []):
                            parameters.append(('APP', app))
                        jacoco_id = self.jenkins_server.build_job(
                            jenkins_jacoco, parameters=parameters)
                        desc['jacocoId'] = jacoco_id
                    desc['queueId'] = queue_id
                    desc['url'] = self.jenkins_server.get_job_info(
                        job_name).get('url')
                    yield self.setting.edit_setting(sid=job.id,
                                                    value=desc,
                                                    status=2)
        except Exception as e:
            log.warning(e)

    # 申请关闭外网权限
    @gen.coroutine
    def close_network(self):
        try:
            now_date = time.strftime('%Y-%m-%d')
            now_time = time.strftime('%H:%M:%S')
            if now_time > '08:30:00':
                server, total = yield self.setting.get_settings_list(
                    s_type='env', status=1)
                ips = list()
                for svr in server:
                    desc = json.loads(svr.value)
                    if (svr.createTime.strftime('%Y-%m-%d') < now_date or
                        (svr.createTime.strftime('%Y-%m-%d') == now_date
                         and now_time > svr.createTime.strftime('%H:%M:%S'))
                        ) and desc.get('network') == 'yes' and desc.get('ip'):
                        ips.append(desc.get('ip').strip())
                if set(ips):
                    title = '测试环境申请关闭外网权限'
                    mail_content = '''
                    <p>Hi 你好!</p>
                    <p style="padding-left:30px;">测试人员已完成测试任务,申请关闭以下测试环境服务器外网权限。请帮忙处理一下,3ks~</p>
                    <p style="padding-left:30px;">1、服务器</p>
                    <p style="padding-left:60px;">{}</p>    
                                    '''.format('</br>'.join(set(ips)))
                    res, msg = yield self.common_func.send_email(
                        subject=title,
                        content=mail_content,
                        to=net_mail_to,
                        cc=net_mail_cc)
                    if res:
                        log.info(msg)
                        for svr in server:
                            desc = json.loads(svr.value)
                            if (svr.createTime.strftime('%Y-%m-%d') < now_date
                                    or (svr.createTime.strftime('%Y-%m-%d')
                                        == now_date and now_time >
                                        svr.createTime.strftime('%H:%M:%S'))
                                ) and desc.get(
                                    'network') == 'yes' and desc.get('ip'):
                                desc['network'] = 'no'
                                yield self.setting.edit_setting(sid=svr.id,
                                                                value=desc)
                    else:
                        log.warn(msg)
        except Exception as e:
            log.error(e)

    # 同步准生产数据库表
    @gen.coroutine
    def sync_db_tables(self):
        dumps = dict()
        db_path = os.path.join(static_path, 'syncDB', 'lasTables')
        if not os.path.isdir(db_path):
            os.makedirs(db_path)
        flag_file = os.path.join(db_path, 'TAG')
        old_date = ''
        if os.path.isfile(flag_file):
            with open(flag_file, 'r') as fp:
                old_date = fp.read()
        now_date = time.strftime('%Y%m%d')
        if old_date != now_date:
            env_list, total = yield self.project.get_projects_list(
                p_type='env', status=1, search='准生产')
            for env in env_list:
                details, total = yield self.setting.get_settings_list(
                    s_type='env', name=env.name)
                for detail in details:
                    desc = json.loads(detail.value)
                    if desc.get('type') != 'APPLICATION' and desc.get(
                            'title').upper().find('MYSQL') == -1:
                        continue
                    dumps[detail.id] = dict(
                        ip=desc.get('ip').strip(),
                        port=desc.get('port').strip(),
                        user=desc.get('user').strip(),
                        password=desc.get('password').strip(),
                        dbs=desc.get('description').split(','))
                break
            with open(flag_file, 'w') as fp:
                fp.write(time.strftime('%Y%m%d'))
            for key in dumps:
                for db in dumps[key]['dbs']:
                    tmp_path = os.path.join(db_path, '{}_tmp.txt'.format(db))
                    shell_dump = '''cd {}
                    /opt/lampp/bin/mysqldump -h{} -P{} -u{} -p{} -d {} > {}'''.format(
                        root_160, dumps[key]['ip'], dumps[key]['port'],
                        dumps[key]['user'], dumps[key]['password'], db,
                        'lasTables/{}_tmp.txt'.format(db))
                    res, msg = yield self.thread_func.exec_remote_shell(
                        shell=shell_dump,
                        host=host_160,
                        port=port_160,
                        username=user_160,
                        password=password_160)
                    if res and os.path.isfile(tmp_path):
                        with open(tmp_path, 'r', encoding='utf8') as fp:
                            lines = fp.readlines()
                        tables = list()
                        for line in lines:
                            if line.find('DROP TABLE IF EXISTS') == -1:
                                continue
                            table = re.findall(r'`(\w+)`;', line)
                            table and tables.append('{}\n'.format(table[0]))
                        with open(os.path.join(db_path, '{}.txt'.format(db)),
                                  'w') as fp:
                            fp.writelines(tables)
                        os.remove(tmp_path)
                    else:
                        log.info(msg)
        old_time = time.time() - 30 * 24 * 3600
        old_path = os.path.join(static_path, 'syncDB',
                                time.strftime('%Y%m%d', time.gmtime(old_time)))
        if os.path.isdir(old_path):
            shutil.rmtree(old_path)
Ejemplo n.º 8
0
class TestRunner(object):
    Resolver.configure('tornado.netutil.ThreadedResolver')

    def __init__(self, pid=0, jid=0):
        self.default_headers = {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'User-Agent':
            'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36',
            'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4',
            'Cookie': ''
        }
        self.headers = dict()
        self.setting = SettingModule()
        self.common_func = CommonFunction()
        self.option_func = OptionsFunction()
        self.pid = pid
        self.jid = jid

    # 获取请求头
    def get_headers(self, headers=''):
        flag, headers = self.common_func.convert_to_list_or_dict(
            string=headers, s_type='dict')
        self.headers = dict()
        for key in self.default_headers:
            self.headers[key] = self.default_headers[key]
        if flag:
            for key in headers.keys():
                self.headers[key] = headers[key]
        else:
            headers = headers.splitlines()
            for header in headers:
                header = header.strip().split(sep=':', maxsplit=1)
                if len(header) == 2:
                    name = header[0].strip()
                    value = header[1].strip()
                    self.headers[name] = value
        return self.headers

    # 加解密操作
    @gen.coroutine
    def __do_crypt(self, do='encrypt', body=None, crypt_key=''):
        crypt_info = yield self.option_func.get_crypt_info(pid=self.pid, do=do)
        if not crypt_info:
            return body
        func = crypt_info.function
        try:
            if func:
                if crypt_key:
                    flag, body = self.common_func.convert_to_list_or_dict(
                        string=body, s_type='dict')
                    if not flag and isinstance(body, str) and re.match(
                            r'^.*=.*(&.*=.*)*$', body) is not None:
                        body = self.common_func.url_query_decode(body)
                        if isinstance(body, dict):
                            flag = True
                    if flag:
                        source = body[crypt_key]
                        if not isinstance(source, str):
                            try:
                                source = json.dumps(source, ensure_ascii=False)
                            except Exception as e:
                                log.warning(e)
                                if isinstance(source, bytes):
                                    source = source.decode('utf8',
                                                           errors='ignore')
                                else:
                                    source = str(source)
                        body[crypt_key] = func(source, crypt_info['key'],
                                               crypt_info['iv'],
                                               crypt_info['mode'])
                else:
                    if not isinstance(body, str):
                        try:
                            body = json.dumps(body, ensure_ascii=False)
                        except Exception as e:
                            log.warning(e)
                            if isinstance(body, bytes):
                                body = body.decode('utf8', errors='ignore')
                            else:
                                body = str(body)
                    body = func(body, crypt_info['key'], crypt_info['iv'],
                                crypt_info['mode'])
        except Exception as e:
            log.warning(e)
        return body

    # 尝试将请求数据转换成字典
    def __parse_body_arguments(self, body):
        flag, body = self.common_func.convert_to_list_or_dict(string=body,
                                                              s_type='dict')
        if not flag and isinstance(body, str) and re.match(
                r'^.*=.*(&.*=.*)*$', body) is not None:
            body = self.common_func.url_query_decode(body)
            if isinstance(body, dict):
                flag = True
        if not flag:
            self.headers = self.headers if len(
                self.headers) != 0 else self.default_headers
            try:
                request_body = dict()
                if re.match(r'^.*=.*(&.*=.*)*$', body) is not None:
                    parse_body_arguments(
                        content_type=self.headers['Content-Type'],
                        body=body,
                        arguments=request_body,
                        files=request_body,
                        headers=self.headers)
                if len(request_body) > 0:
                    body = request_body
                for key in body:
                    if isinstance(body[key], list):
                        body[key] = body[key][0]
                        body[key] = body[key].decode('utf8', errors='ignore')
                flag = True
            except Exception as e:
                log.warning(e)
                flag = False
        return flag, body

    # 获取请求响应数据
    @gen.coroutine
    def __get_body(self, body='', do='encrypt', name='', crypt_key=''):
        try:
            body = ast.literal_eval(body)
        except Exception as e:
            log.warning(e)
            if do == 'encrypt' and crypt_key != '':
                flag, body = self.__parse_body_arguments(body)
        if isinstance(body, dict):
            if name != 'none':
                if do == 'encrypt' and crypt_key == '':
                    body = urlencode(body, encoding='utf8', quote_via=quote)
                body = yield self.__do_crypt(do=do,
                                             body=body,
                                             crypt_key=crypt_key)
            if isinstance(body, dict):
                if do == 'encrypt' and self.headers['Content-Type'].find(
                        'x-www-form-urlencoded') != -1:
                    body = urlencode(body, encoding='utf8', quote_via=quote)
                else:
                    body = json.dumps(body, ensure_ascii=False)
        else:
            if name != 'none':
                body = yield self.__do_crypt(do=do, body=body, crypt_key='')
            if isinstance(body, dict):
                body = json.dumps(body, ensure_ascii=False)
        return body

    # 解析Host配置
    @gen.coroutine
    def __parse_host(self, url='', env='none'):
        urls = self.common_func.url_split(url=url)
        host = urls.host
        ips, total = yield self.setting.get_settings_list(pid=self.pid,
                                                          s_type='host',
                                                          name=host,
                                                          pj_status=1,
                                                          limit=None)
        for row in ips:
            if env != 'none':
                url = '{}://{}:{}{}'.format(urls.scheme, env, urls.port,
                                            urls.path)
                break
            elif row.status == 1:
                url = '{}://{}:{}{}'.format(urls.scheme, row.value, urls.port,
                                            urls.path)
                break
        self.headers['Host'] = urls.netloc
        return url

    # 解析接口返回值全字段检查配置
    def __parse_check_key(self, check_key):
        keys = []
        top = []
        rex = re.compile(
            r'^\[\w+=\d\|(int|float|num|str|/.*/|date|time|datetime|list|dict)('
            r',\w+=\d\|(int|float|num|str|/.*/|date|time|datetime|list|dict))*\]$'
        )
        for row in check_key.splitlines():
            row = row.strip().split(sep='.', maxsplit=1)
            if len(row) == 2:
                if re.match(rex, row[1]) is not None:
                    deeps = [row[1]]
                else:
                    deeps = row[1].split(sep='.', maxsplit=1)
                if re.match(r'^\[\d+\]$', deeps[0]) is None:
                    top.append('{}=1|dict'.format(row[0]))
                else:
                    top.append('{}=1|list'.format(row[0]))
                deep = '{}.'.format(row[0])
                tmp_key = []
                for i in range(len(row[1].split('.'))):
                    if len(deeps) == 2 and re.match(rex, deeps[1]) is not None:
                        deep += '{}.'.format(deeps[0])
                        for j in deeps[1][1:-1].split(','):
                            tmp_key.append(j)
                        break
                    elif re.match(rex, deeps[0]) is not None:
                        for j in deeps[0][1:-1].split(','):
                            tmp_key.append(j)
                        break
                    deep += '{}.'.format(deeps[0])
                    if len(deeps) == 2:
                        if re.match(rex, deeps[1]) is not None:
                            deeps = deeps[1]
                        else:
                            deeps = deeps[1].split(sep='.', maxsplit=1)
                keys.append(dict(deep=deep[:-1], keys=tmp_key, result=dict()))
            else:
                top.append(row[0])
        keys.append(dict(deep='top', keys=list(set(top)), result=dict()))
        return keys

    # 返回值全字段检查结果判断
    def __check_key_result(self, body, check_key, key, k):
        check_key[k]['result'][key[0]] = True
        key[1] = key[1].split(sep='|', maxsplit=1)
        require = key[1][0]
        key_type = key[1][1]
        if isinstance(body[key[0]], str):
            body[key[0]] = body[key[0]].strip()
        if require == '1' and (body[key[0]] == '' or body[key[0]] is None):
            check_key[k]['result'][key[0]] = False
        elif body[key[0]] != '' and body[key[0]] is not None:
            if re.match(r'^/.*/$', key_type):
                rex = re.compile(key_type[1:-1])
                if re.match(rex, body[key[0]]) is None:
                    check_key[k]['result'][key[0]] = False
            elif key_type == 'int' and not isinstance(body[key[0]], int):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'float' and not isinstance(body[key[0]], float):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'num' and not isinstance(
                    body[key[0]], int) and not isinstance(body[key[0]], float):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'str' and not isinstance(body[key[0]], str):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'list' and not isinstance(body[key[0]], list):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'dict' and not isinstance(body[key[0]], dict):
                check_key[k]['result'][key[0]] = False
            elif key_type == 'date' and re.match(r'^\d{4}-\d{2}-\d{2}$',
                                                 body[key[0]]) is None:
                check_key[k]['result'][key[0]] = False
            elif key_type == 'time' and re.match(r'^\d{2}:\d{2}:\d{2}$',
                                                 body[key[0]]) is None:
                check_key[k]['result'][key[0]] = False
            elif key_type == 'datetime' and re.match(
                    r'^\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}$',
                    body[key[0]]) is None:
                check_key[k]['result'][key[0]] = False
        if not check_key[k]['result'][key[0]]:
            check_key[k]['result']['key_result'] = False
        return body, check_key

    # 解析响应内容
    @gen.coroutine
    def __parse_response(self,
                         response,
                         name='',
                         crypt_key='',
                         checkpoint='',
                         check_key='',
                         correlation='',
                         method='GET',
                         url=''):
        body = response.body if response else ''
        request_body = response.request.body if response else ''
        if isinstance(body, bytes):
            body = body.decode('utf8', errors='ignore')
        if isinstance(request_body, bytes):
            request_body = request_body.decode('utf8', errors='ignore')
        headers_dict = dict(response.headers if response else '')
        headers = ''
        for key in headers_dict:
            headers += '{}: {}\r\n'.format(key, headers_dict[key])
        request_headers_dict = dict(
            response.request.headers if response else '')
        request_headers = ''
        for key in request_headers_dict:
            request_headers += '{}: {}\r\n'.format(key,
                                                   request_headers_dict[key])
        if response:
            error = response.error if not response.error else str(
                response.error)
        else:
            error = str(httpclient.HTTPError(599, 'Timeout while connecting'))
        resp = dict(
            body=body,
            code=response.code if response else 599,
            effective_url=response.effective_url if response else '',
            error=error,
            headers=headers,
            request_headers=request_headers,
            request_body=request_body,
            reason=response.reason if response else 'Timeout while connecting',
            request_time=response.request_time if response else '',
            time_info=response.time_info if response else '',
            method=method,
            url=url)
        resp['body_decrypt'] = yield self.__get_body(body,
                                                     do='decrypt',
                                                     name=name,
                                                     crypt_key=crypt_key)
        resp['checkpoint'] = []
        if checkpoint != '':
            if re.match(r'^/.*/$', checkpoint) is not None:
                rex = re.compile(checkpoint[1:-1])
                if re.findall(rex, resp['body_decrypt']):
                    resp['checkpoint'].append(
                        dict(result=True, checkpoint=checkpoint))
                else:
                    log.warning('检查点 {} 检查不通过'.format(checkpoint))
                    resp['checkpoint'].append(
                        dict(result=False, checkpoint=checkpoint))
            else:
                for check in checkpoint.split('|'):
                    check = check.strip()
                    if resp['body_decrypt'].find(check) != -1:
                        resp['checkpoint'].append(
                            dict(result=True, checkpoint=check))
                    else:
                        log.warning('检查点 {} 检查不通过'.format(check))
                        resp['checkpoint'].append(
                            dict(result=False, checkpoint=check))
        resp['check_key'] = []
        if check_key != '':
            check_key = self.__parse_check_key(check_key)
            for k in range(len(check_key)):
                body = resp['body_decrypt']
                check_key[k]['result']['key_result'] = True
                if check_key[k]['deep'] == 'top':
                    for key in check_key[k]['keys']:
                        if re.match(r'^\[\d+\]$', key) is not None:
                            key = int(key[1:-1])
                            flag, body = self.common_func.convert_to_list_or_dict(
                                body, 'list')
                            if not flag:
                                log.warning('返回值全字段检查 被检查数据格式不是List, 无法继续')
                                if body in ['', '[]', '{}', [], {}]:
                                    check_key[k]['result']['ERROR'] = '被检查数据为空'
                                else:
                                    check_key[k]['result'][
                                        'ERROR'] = '被检查数据类型不是List'
                                check_key[k]['result']['key_result'] = False
                                continue
                            try:
                                body[key]
                            except Exception as e:
                                log.warning(e)
                                check_key[k]['result'][
                                    'ERROR'] = '被检查数据格式不包含List类型'
                                check_key[k]['result']['key_result'] = False
                                continue
                        else:
                            flag, body = self.common_func.convert_to_list_or_dict(
                                body, 'dict')
                            if not flag and isinstance(body, str) and re.match(
                                    r'^.*=.*(&.*=.*)*$', body) is not None:
                                body = self.common_func.url_query_decode(body)
                                if isinstance(body, dict):
                                    flag = True
                            if not flag:
                                log.warning('返回值全字段检查 被检查数据格式不是Dict, 无法继续')
                                if body in ['', '[]', '{}', [], {}]:
                                    check_key[k]['result']['ERROR'] = '被检查数据为空'
                                else:
                                    check_key[k]['result'][
                                        'ERROR'] = '被检查数据类型不是Dict'
                                check_key[k]['result']['key_result'] = False
                                continue
                            key = key.split(sep='=', maxsplit=1)
                            if key[0] not in body.keys():
                                log.warning('返回值全字段检查 {} 检查不通过'.format(
                                    check_key[k]['keys']))
                                check_key[k]['result'][key[0]] = '字段不存在'
                                check_key[k]['result']['key_result'] = False
                                continue
                            else:
                                body, check_key = self.__check_key_result(
                                    body=body,
                                    check_key=check_key,
                                    key=key,
                                    k=k)
                else:
                    keys = check_key[k]['keys']
                    flag, keys = self.common_func.convert_to_list_or_dict(
                        keys, 'list')
                    for key in check_key[k]['deep'].split('.'):
                        if re.match(r'^\[\d+\]$', key) is not None:
                            key = int(key[1:-1])
                            flag, body = self.common_func.convert_to_list_or_dict(
                                body, 'list')
                            if not flag:
                                log.warning('返回值全字段检查 被检查数据格式不是List, 无法继续')
                                if body in ['', '[]', '{}', [], {}]:
                                    check_key[k]['result']['ERROR'] = '被检查数据为空'
                                else:
                                    check_key[k]['result'][
                                        'ERROR'] = '被检查数据类型不是List'
                                check_key[k]['result']['key_result'] = False
                                continue
                        elif not isinstance(body, dict):
                            flag, body = self.common_func.convert_to_list_or_dict(
                                body, 'dict')
                            if not flag and isinstance(body, str) and re.match(
                                    r'^.*=.*(&.*=.*)*$', body) is not None:
                                body = self.common_func.url_query_decode(body)
                                if isinstance(body, dict):
                                    flag = True
                            if not flag:
                                log.warning('返回值全字段检查 被检查数据格式不是Dict, 无法继续')
                                if body in ['', '[]', '{}', [], {}]:
                                    check_key[k]['result']['ERROR'] = '被检查数据为空'
                                else:
                                    check_key[k]['result'][
                                        'ERROR'] = '被检查数据类型不是Dict'
                                check_key[k]['result']['key_result'] = False
                                continue
                        try:
                            body = body[key]
                        except Exception as e:
                            log.warning(e)
                            check_key[k]['result'][
                                'ERROR'] = '被检查数据格式不包含List类型'
                            check_key[k]['result']['key_result'] = False
                            continue
                    flag, body = self.common_func.convert_to_list_or_dict(
                        body, 'dict')
                    if not flag and isinstance(body, str) and re.match(
                            r'^.*=.*(&.*=.*)*$', body) is not None:
                        body = self.common_func.url_query_decode(body)
                        if isinstance(body, dict):
                            flag = True
                    if not flag:
                        log.warning('返回值全字段检查 被检查数据格式不是Dict, 无法继续')
                        if body in ['', '[]', '{}', [], {}]:
                            check_key[k]['result']['ERROR'] = '被检查数据为空'
                        else:
                            check_key[k]['result']['ERROR'] = '被检查数据类型不是Dict'
                        check_key[k]['result']['key_result'] = False
                        continue
                    for key in keys:
                        key = key.split(sep='=', maxsplit=1)
                        if key[0] not in body.keys():
                            log.warning('返回值全字段检查 {} 检查不通过'.format(
                                check_key[k]['keys']))
                            check_key[k]['result'][key[0]] = '字段不存在'
                            check_key[k]['result']['key_result'] = False
                            continue
                        else:
                            body, check_key = self.__check_key_result(
                                body=body, check_key=check_key, key=key, k=k)
            resp['check_key'] = check_key
        resp['correlation'] = dict()
        if response and correlation != '':
            correlations = correlation.split('|')
            correlation = dict()
            for corr in correlations:
                body = resp['body_decrypt']
                cor = corr.split(sep='=', maxsplit=1)
                key = cor[0].strip()
                c_type = 'string'
                words = cor[1].strip()
                if re.match(r'^int\(.+\)$', words) is not None:
                    c_type = 1
                    words = words[4:-1]
                elif re.match(r'^float\(.+\)$', words) is not None:
                    c_type = 1.00
                    words = words[6:-1]
                word = words.split('.')
                correlation[key] = word
                for k in word:
                    if k == 'response_headers' and len(word) != 1:
                        header = words.split(sep='.', maxsplit=1)
                        if len(header) == 2:
                            header_key = header[1]
                            if re.match(r'^/.*/$', header_key) is not None:
                                rex = re.compile(header_key[1:-1])
                                if isinstance(resp['headers'], bytes):
                                    resp['headers'] = resp['headers'].decode(
                                        'utf8', errors='ignore')
                                result = re.findall(rex, resp['headers'])
                                if result:
                                    if isinstance(result[0], tuple):
                                        body = result[0][0]
                                    else:
                                        body = ''
                                        for row in result:
                                            row = row if row != '' else '\n'
                                            body += row
                                else:
                                    body = ''
                            else:
                                body = response.headers.get(header_key)
                            break
                    if k == 'response_body' and len(word) == 1:
                        if isinstance(resp['body'], bytes):
                            resp['body'] = resp['body'].decode('utf8',
                                                               errors='ignore')
                        body = escape.xhtml_escape(resp['body'])
                        break
                    if re.match(r'^/.*/$', words) is not None:
                        rex = re.compile(words[1:-1])
                        if isinstance(resp['body'], bytes):
                            resp['body'] = resp['body'].decode('utf8',
                                                               errors='ignore')
                        result = re.findall(rex, resp['body'])
                        if result:
                            if isinstance(result[0], tuple):
                                body = escape.xhtml_escape(result[0][0])
                            else:
                                body = escape.xhtml_escape(result[0])
                        else:
                            body = ''
                        break
                    if re.match(r'^\[\d+\]$', k) is not None:
                        k = int(k[1:-1])
                        flag, body = self.common_func.convert_to_list_or_dict(
                            body, 'list')
                        if not flag:
                            log.warning('响应数据格式不是List, 无法继续')
                            body = ''
                            break
                    elif not isinstance(body, dict):
                        flag, body = self.common_func.convert_to_list_or_dict(
                            body, 'dict')
                        if not flag and isinstance(body, str) and re.match(
                                r'^.*=.*(&.*=.*)*$', body) is not None:
                            body = self.common_func.url_query_decode(body)
                            if isinstance(body, dict):
                                flag = True
                        if not flag:
                            log.warning('响应数据格式不是Dict, 无法继续')
                            body = ''
                            break
                    try:
                        body = body[k]
                    except Exception as e:
                        log.warning(e)
                        body = ''
                        break
                correlation[key] = body
                try:
                    if isinstance(c_type, int):
                        correlation[key] = int(
                            float(re.sub(r'[^\d+\.]', '', body)))
                    elif isinstance(c_type, float):
                        correlation[key] = float(re.sub(r'[^\d+\.]', '', body))
                except Exception as e:
                    log.warning(e)
            resp['correlation'] = correlation
        flag = True
        if resp['error'] is not None and resp['code'] != 302 and resp[
                'code'] != 301:
            flag = False
        if resp['check_key']:
            for line in resp['check_key']:
                if not line['result']['key_result']:
                    flag = False
                    break
        if resp['checkpoint']:
            for line in resp['checkpoint']:
                if not line['result']:
                    flag = False
                    break
        resp['test_result'] = flag
        return resp

    # 解析自定义参数配置
    @gen.coroutine
    def __parse_custom_param(self, headers, body, correlation_result={}):
        correlation_result = dict(self.common_func.default_param(),
                                  **correlation_result)
        params = yield self.option_func.get_custom_param(
            pid=self.pid, correlation=correlation_result)
        if isinstance(headers, bytes):
            headers = headers.decode('utf8', errors='ignore')
        if isinstance(body, bytes):
            body = body.decode('utf8', errors='ignore')
        for key in correlation_result:
            if not isinstance(correlation_result[key], str):
                correlation_result[key] = str(correlation_result[key])
            if headers.find(key) != -1:
                headers = headers.replace(key, correlation_result[key])
            if body.find(key) != -1:
                body = body.replace(key, correlation_result[key])
        for param in params:
            if headers.find('{%s}' % param['name']) != -1:
                if param['type'] == 'Function':
                    func = param['function']
                    flag, body_dict = self.__parse_body_arguments(body)
                    encrypt = yield self.option_func.get_crypt_info(self.pid)
                    headers = headers.replace('{%s}' % param['name'],
                                              func(body_dict, params, encrypt))
                else:
                    headers = headers.replace('{%s}' % param['name'],
                                              param['value'])
            if body.find('{%s}' % param['name']) != -1:
                if param['type'] == 'Function':
                    func = param['function']
                    flag, body_dict = self.__parse_body_arguments(body)
                    encrypt = yield self.option_func.get_crypt_info(self.pid)
                    body = body.replace('{%s}' % param['name'],
                                        func(body_dict, params, encrypt))
                else:
                    body = body.replace('{%s}' % param['name'], param['value'])
        return headers, body

    # 请求操作
    @gen.coroutine
    def __request_url(self,
                      url='',
                      env='none',
                      method='GET',
                      body='',
                      follow_redirects=True):
        test_client = httpclient.AsyncHTTPClient(max_clients=100)
        argv = dict(method=method,
                    headers=self.headers,
                    follow_redirects=False,
                    request_timeout=600,
                    validate_cert=False,
                    raise_error=False)
        url = yield self.__parse_host(url=url, env=env)
        if method == 'GET':
            url = '{}?{}'.format(url, body)
        elif method == 'POST':
            argv['body'] = body
        try:
            log.info('开始请求接口 {}'.format(url))
            response = yield test_client.fetch(url, **argv)
        except httpclient.HTTPError as e:
            response = e.response
            log.warning('请求接口 {} 异常# {}'.format(
                url, str(response.error if response else e)))
        # test_client.close()
        if response and response.code in [301, 302]:
            for cookie in response.headers.get_list('Set-Cookie'):
                self.headers['Cookie'] += '{};'.format(cookie)
            url = response.headers.get('Location')
            log.info('{} {} {}'.format(response.code, response.reason, url))
            if response.reason.find('Moved') >= 0:
                response = yield self.__request_url(
                    url=url,
                    env=env,
                    method=method,
                    body=body,
                    follow_redirects=follow_redirects)
            elif follow_redirects:
                response = yield self.__request_url(
                    url=url,
                    env=env,
                    method='GET',
                    follow_redirects=follow_redirects)
        log.info('结束请求接口 {}'.format(url))
        return response

    # 生成测试报告
    @gen.coroutine
    def __gen_report(self, job_name, test_suites, start_time, end_time):
        setting = yield self.setting.get_settings_by_range(pid=self.pid,
                                                           s_type='log',
                                                           start=start_time,
                                                           end=end_time,
                                                           sort=self.jid)
        if setting:
            elapsed_time = end_time - start_time
            start_time = time.strftime(
                '%Y-%m-%d %H:%M:%S', time.gmtime(float(start_time) + 3600 * 8))
            end_time = time.strftime('%Y-%m-%d %H:%M:%S',
                                     time.gmtime(float(end_time) + 3600 * 8))
            url, total = yield self.setting.get_settings_list(pid=self.pid,
                                                              s_type='url',
                                                              limit=None)
            overview = dict(name=job_name,
                            start_time=start_time,
                            end_time=end_time,
                            elapsed_time=elapsed_time,
                            total=total,
                            total_test=len(test_suites),
                            success_test=0,
                            fail_test=0,
                            success_rate='0.0 %',
                            report_time=time.strftime('%Y-%m-%d %H:%M:%S'))
            for suite in test_suites:
                suite['total_test'] = len(suite['cases'])
                suite['success_test'] = 0
                suite['fail_test'] = 0
                suite['report'] = []
                suite['result'] = True
            for row in setting:
                res = json.loads(row.value)
                for suite in test_suites:
                    if suite['suite_id'] == row.status:
                        if res['test_result']:
                            suite['success_test'] += 1
                        else:
                            suite['fail_test'] += 1
                            suite['result'] = False
                        suite['report'].append(res)
            for suite in test_suites:
                suite['result'] = suite['result'] if suite[
                    'success_test'] + suite['fail_test'] == suite[
                        'total_test'] else False
                if suite['result']:
                    overview['success_test'] += 1
                else:
                    overview['fail_test'] += 1
            overview['success_rate'] = '{:.2f} %'.format(
                overview['success_test'] / overview['total_test'] * 100)
            result = dict(overview=overview, report=test_suites)
            report_id, msg = yield self.setting.add_setting(
                pid=self.pid,
                s_type='report',
                sort=self.jid,
                name=time.time(),
                value=json.dumps(result, ensure_ascii=False))
            return report_id
        else:
            return False

    # 执行单接口测试
    @gen.coroutine
    def run_test(self,
                 url='',
                 label='',
                 comment='',
                 method='GET',
                 headers='',
                 body='',
                 crypt='none',
                 encrypt_content='',
                 no_test=False,
                 check_key='',
                 decrypt_content='',
                 checkpoint='',
                 env='none',
                 correlation='',
                 correlation_result={},
                 follow_redirects=True):
        headers, body = yield self.__parse_custom_param(
            headers=headers, body=body, correlation_result=correlation_result)
        self.get_headers(headers)
        request_body = yield self.__get_body(body=body,
                                             do='encrypt',
                                             name=crypt,
                                             crypt_key=encrypt_content)
        if no_test:
            return request_body
        resp = yield self.__request_url(url=url,
                                        env=env,
                                        method=method,
                                        body=request_body,
                                        follow_redirects=follow_redirects)
        response = yield self.__parse_response(response=resp,
                                               name=crypt,
                                               crypt_key=decrypt_content,
                                               checkpoint=checkpoint,
                                               check_key=check_key,
                                               correlation=correlation,
                                               method=method,
                                               url=url)
        response['label'] = label
        response['comment'] = comment
        if not resp:
            response['request_body'] = request_body
            for key in self.headers:
                response['request_headers'] += '{}: {}\r\n'.format(
                    key, self.headers[key])
        elif method == 'GET':
            response['request_body'] = request_body
        log.info('响应返回 {}'.format(json.dumps(response, ensure_ascii=False)))
        return response

    # 执行多接口测试
    @gen.coroutine
    def __run_all_test(self, job_name, test_suites):
        if not test_suites:
            return False
        start_time = time.time()
        correlation_result = dict()
        for test in test_suites:
            cases = yield self.setting.get_settings_by_ids(test['cases'])
            for url_info in cases:
                try:
                    url_info = json.loads(url_info.value)
                    resp = yield self.run_test(
                        correlation_result=correlation_result, **url_info)
                    yield self.setting.add_setting(pid=self.pid,
                                                   s_type='log',
                                                   name=time.time(),
                                                   sort=self.jid,
                                                   value=json.dumps(
                                                       resp,
                                                       ensure_ascii=False),
                                                   status=test['suite_id'])
                    correlation_result = dict(correlation_result,
                                              **resp['correlation'])
                except Exception as e:
                    log.error(e)
        end_time = time.time()
        report_id = yield self.__gen_report(job_name, test_suites, start_time,
                                            end_time)
        return report_id

    # 执行排队任务
    @gen.coroutine
    def run_job(self):
        job = yield self.setting.get_setting_by_id(sid=self.jid)
        if job:
            start_time = time.time()
            job_value = json.loads(job.value)
            start_strftime = time.strftime(
                '%Y-%m-%d %H:%M:%S', time.gmtime(float(start_time) + 3600 * 8))
            job_value['overview']['start_time'] = start_strftime
            yield self.setting.edit_setting(sid=job.id,
                                            status=2,
                                            value=json.dumps(
                                                job_value, ensure_ascii=False))
            test_suites = []
            suites = yield self.setting.get_settings_by_ids(
                job_value['testsuite'])
            for suite in suites:
                tests = dict(suite_id=suite.id,
                             suite_name=suite.name,
                             cases=json.loads(suite.value)['cases'])
                test_suites.append(tests)
            result = yield self.__run_all_test(job_value['name'], test_suites)
            if result:
                status = 3
                job_value['lastreport'] = result
            else:
                status = 5
            end_time = time.time()
            elapsed_time = end_time - start_time
            end_time = time.strftime('%Y-%m-%d %H:%M:%S',
                                     time.gmtime(float(end_time) + 3600 * 8))
            job_value['overview']['end_time'] = end_time
            job_value['overview']['elapsed_time'] = elapsed_time
            name = float(job.name)
            if job_value['overview']['cycle_time'] != 0:
                while name < time.time():
                    name += job_value['overview']['cycle_time']
                job_value['overview']['plan_time'] = time.strftime(
                    '%Y-%m-%d %H:%M:%S', time.gmtime(name + 3600 * 8))
                status = 0
            yield self.setting.edit_setting(sid=job.id,
                                            status=status,
                                            name=name,
                                            value=json.dumps(
                                                job_value, ensure_ascii=False))
            yield Mail().send_html_report(result)
Ejemplo n.º 9
0
 def __get_links(self, url, user_agent='', cookie='', check_all=False):
     response = yield self.__request_url(url, user_agent, cookie)
     common_func = CommonFunction()
     url_split = common_func.url_split(url)
     host = url_split.host
     scheme = url_split.scheme
     netloc = '{}://{}'.format(scheme, url_split.netloc)
     links = []
     if response and response.body:
         body = response.body if not isinstance(
             response.body, bytes) else response.body.decode(
                 'utf8', errors='ignore')
         body = body if isinstance(body, str) else str(body)
         link_a = re.findall(
             r'<a.*?href=[\'"](.*?)[\'"].*?title=[\'"](.*?)[\'"].*?>(.*?)</a>',
             body)
         link_b = re.findall(
             r'<a.*?title=[\'"](.*?)[\'"].*?href=[\'"](.*?)[\'"].*?>(.*?)</a>',
             body)
         link_c = re.findall(r'<a.*?href=[\'"](.*?)[\'"].*?>(.*?)</a>',
                             body)
         link_d = re.findall(r'data-href=[\'"](.*?)[\'"]', body)
         link_e = re.findall(r'data-url=[\'"](.*?)[\'"]', body)
         for link in link_a:
             href = link[0].strip()
             if re.match(r'^(http|https):', href) is not None:
                 pass
             elif re.match(r'^//', href) is not None:
                 href = scheme + href
             elif re.match(r'^/', href) is not None:
                 href = netloc + href
             elif re.match(r'^(javascript|#)', href.lower()) is not None:
                 continue
             else:
                 href = '{}/{}'.format(url, href)
             title = link[1]
             text = link[2] if link[2] != '' else link[1]
             log.info('获取到链接: {} {}'.format(text, href))
             link = dict(href=href, title=title, text=text)
             if link not in links:
                 links.append(link)
         for link in link_b:
             href = link[1].strip()
             if re.match(r'^(http|https):', href) is not None:
                 pass
             elif re.match(r'^//', href) is not None:
                 href = scheme + href
             elif re.match(r'^/', href) is not None:
                 href = netloc + href
             elif re.match(r'^(javascript|#)', href.lower()) is not None:
                 continue
             else:
                 href = '{}/{}'.format(url, href)
             title = link[0]
             text = link[2] if link[2] != '' else link[0]
             log.info('获取到链接: {} {}'.format(text, href))
             link = dict(href=href, title=title, text=text)
             if link not in links:
                 links.append(link)
         for link in link_c:
             href = link[0].strip()
             if re.match(r'^(http|https):', href) is not None:
                 pass
             elif re.match(r'^//', href) is not None:
                 href = scheme + href
             elif re.match(r'^/', href) is not None:
                 href = netloc + href
             elif re.match(r'^(javascript|#)', href.lower()) is not None:
                 continue
             else:
                 href = '{}/{}'.format(url, href)
             title = ''
             text = link[1]
             log.info('获取到链接: {} {}'.format(text, href))
             link = dict(href=href, title=title, text=text)
             if link not in links:
                 links.append(link)
         for link in link_d + link_e:
             href = link[0].strip()
             if re.match(r'^(http|https):', href) is not None:
                 pass
             elif re.match(r'^//', href) is not None:
                 href = scheme + href
             elif re.match(r'^/', href) is not None:
                 href = netloc + href
             elif re.match(r'^(javascript|#)', href.lower()) is not None:
                 continue
             else:
                 href = '{}/{}'.format(url, href)
             title = ''
             text = ''
             log.info('获取到链接: {} {}'.format(text, href))
             link = dict(href=href, title=title, text=text)
             if link not in links:
                 links.append(link)
     next_links = []
     if check_all:
         for link in links:
             cur_host = common_func.url_split(link['href']).host
             if cur_host == host and link['href'] not in next_links:
                 next_links.append(link['href'])
     return links, next_links, response
Ejemplo n.º 10
0
class BaseHandler(RequestHandler):
    """
    后台管理父类,后台相关handlers继承本类
    """
    current_user = None

    # 初始化方法
    @gen.coroutine
    def prepare(self):
        self.user = UserModule()
        self.project = ProjectModule()
        self.setting = SettingModule()
        self.option = OptionModule()
        self.msg = MessagesModule()
        self.statistics = StatisticsModule()
        self.common_func = CommonFunction()
        self.option_func = OptionsFunction()
        self.thread_func = ThreadFunction()

    # 获取当前用户信息
    @gen.coroutine
    def get_current_user_async(self):
        user = self.get_secure_cookie('OSTSESSION', None)
        try:
            token = self.request.headers.get('Token')
            if token and not user:
                user = base64.b64decode(
                    base64.b16decode(
                        token.strip().encode('utf8'))).decode('utf8')
        except Exception as e:
            log.error(e)
        if user is not None:
            if isinstance(user, bytes):
                user = user.decode('utf8', errors='ignore')
            user = yield self.user.get_user_info(email_or_username=user)
            if not user:
                self.clear_cookie('OSTSESSION')
            else:
                self.set_secure_cookie('OSTSESSION',
                                       user.email,
                                       expires=time.time() + 1800)
        return user

    # 返回json格式字符串
    @gen.coroutine
    def write_json(self, msg):
        if isinstance(msg, dict):
            msg = json.dumps(msg, ensure_ascii=False)
        self.set_header("Content-Type", "application/json; charset=UTF-8")
        self.finish(msg)

    # 获取json格式请求参数
    @gen.coroutine
    def get_request_body_to_json(self):
        params = self.request.body
        if isinstance(params, bytes):
            params = params.decode('utf8')
        try:
            params = munchify(json.loads(params))
        except Exception as e:
            log.error(e)
            params = None
        return params

    # 登录或注册
    @gen.coroutine
    def _login_or_register(self,
                           username='',
                           email='',
                           name='',
                           department='',
                           password='******'):
        self.clear_cookie('OSTSESSION')
        if (username == '' and email
                == '') or password == '' or name == '' or department == '':
            return False, '[自动登录]请求参数不对!'
        username = email if email != '' else username
        user = yield self.user.get_user_info(username)
        if not user:
            if not self.common_func.check_string(
                    username, 'email') and not self.common_func.check_string(
                        password, 'password'):
                return False, '[自动注册]邮箱或密码格式不对!'
            else:
                user, msg = yield self.user.register_user(
                    email=email,
                    password=password,
                    real_name=name,
                    status=2,
                    profile=dict(
                        department=department,
                        avatar=
                        'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
                        position=''))
                if user:
                    self.set_secure_cookie('OSTSESSION',
                                           email,
                                           expires=time.time() + 1800)
                    content = dict(group=dict(name='', link=''),
                                   project=dict(name='', link=''),
                                   template='同学, 欢迎加入组织!')
                    self.msg.add_message(user_id=user.id,
                                         m_type='active',
                                         content=content)
                return user, '[自动注册]{}'.format(msg)
        elif user.password == self.common_func.encode_password(
                password) and user.status != 0:
            self.user.edit_user(
                username, last_login_time=time.strftime('%Y-%m-%d %H:%M:%S'))
            self.set_secure_cookie('OSTSESSION',
                                   email,
                                   expires=time.time() + 1800)
            content = dict(group=dict(name='', link=''),
                           project=dict(name='', link=''),
                           template='同学, 欢迎回来!')
            self.msg.add_message(user_id=user.id,
                                 m_type='active',
                                 content=content)
            return user, '[自动登录]操作成功!'
        else:
            return False, '[自动登录]登录密码不对或账户被禁用!'
Ejemplo n.º 11
0
class UserModule(object):
    """
    用户表相关操作
    """
    def __init__(self):
        self.common_func = CommonFunction()

    # 获取用户信息
    @gen.coroutine
    def get_user_info(self, email_or_username, status=None):
        sql = "SELECT * FROM t_users u WHERE (u.email=%(user)s OR u.username=%(user)s)"
        param = dict(user=email_or_username)
        if status is not None:
            sql += ' AND u.status=%(status)s'
            param['status'] = status
        cursor = yield pool.execute(sql, param)
        result = cursor.fetchone()
        cursor.close()
        return munchify(result)

    # 通过user_id获取用户信息
    @gen.coroutine
    def get_users_info_by_ids(self, ids, status=None):
        if ids and isinstance(ids, list):
            param = dict()
            ins = ''
            for i in range(len(ids)):
                param['id{}'.format(i)] = ids[i]
                ins += '%(id{})s,'.format(i)
            sql = 'SELECT * FROM t_users u WHERE u.id in ({})'.format(ins[:-1])
            if status is not None:
                sql += ' AND status=%(status)s'
                param['status'] = status
            sql += ' ORDER BY u.role'
            cursor = yield pool.execute(sql, param)
            result = cursor.fetchall()
            cursor.close()
            return munchify(result)
        else:
            return []

    # 获取用户列表
    @gen.coroutine
    def get_users_list(self, page=1, limit=10, status=None):
        sql = 'SELECT * FROM t_users u'
        sql_count = 'SELECT COUNT(*) count FROM t_users u'
        if status is not None:
            sql += ' WHERE u.status=%(status)s'
            sql_count += ' WHERE u.status=%(status)s'
        sql += ' ORDER BY u.role'
        if limit is not None:
            offset = (page - 1) * limit
            sql += ' LIMIT {},{}'.format(offset, limit)
        cursor = yield pool.execute(sql, dict(status=status))
        result = cursor.fetchall()
        cursor = yield pool.execute(sql_count, dict(status=status))
        total = cursor.fetchone()
        cursor.close()
        return munchify(result), munchify(total).count

    # 注册用户
    @gen.coroutine
    def register_user(self, email, password):
        register_time = time.strftime('%Y-%m-%d %H:%M:%S')
        password = self.common_func.encode_password(password)
        cursor = yield pool.execute('SELECT COUNT(*) count FROM t_users')
        total = munchify(cursor.fetchone())
        if total.count == 0:
            role = 0
        else:
            role = 2
        username = '******'.format(
            email.split('@')[0], str(int(time.time() * 1000)))
        sql = """
        INSERT INTO t_users (username, email, password, registerTime, lastLoginTime, role)
        VALUE(%(username)s, %(email)s, %(password)s, %(registerTime)s, %(lastLoginTime)s, %(role)s)
        """
        user = yield self.get_user_info(email_or_username=email)
        if not user:
            with (yield pool.Connection()) as conn:
                with conn.cursor() as cursor:
                    try:
                        yield cursor.execute(
                            sql,
                            dict(username=username,
                                 email=email,
                                 password=password,
                                 registerTime=register_time,
                                 lastLoginTime=register_time,
                                 role=role))
                    except pymysql.Error as e:
                        yield conn.rollback()
                        log.error('注册用户失败#{}'.format(e))
                        flag, msg = False, '注册用户失败#{}'.format(e)
                    else:
                        yield conn.commit()
                        log.info('注册用户成功')
                        flag, msg = cursor.lastrowid, '注册用户成功'
        else:
            log.error('该用户已存在, 请更换注册邮箱')
            flag, msg = False, '该用户已存在, 请更换注册邮箱'
        return flag, msg

    # 编辑用户
    @gen.coroutine
    def edit_user(self,
                  email,
                  password=None,
                  username=None,
                  realname=None,
                  last_login_time=None,
                  role=None,
                  status=None):
        user = yield self.get_user_info(email)
        if user:
            update = []
            param = dict(email=user.email)
            if password is not None:
                update.append("password=%(password)s")
                param['password'] = self.common_func.encode_password(password)
            if username is not None:
                sql = "SELECT username FROM t_users u WHERE u.email != %(email)s AND u.username = %(username)s"
                param['username'] = username
                cursor = yield pool.execute(sql, param)
                user_info = cursor.fetchone()
                if user_info:
                    log.error('用户名 {} 已存在'.format(username))
                    return False, '用户名 {} 已存在'.format(username)
                else:
                    update.append("username=%(username)s")
            if realname is not None:
                update.append("realname=%(realname)s")
                param['realname'] = realname
            if last_login_time is not None:
                update.append("lastLoginTime=%(lastLoginTime)s")
                param['lastLoginTime'] = last_login_time
            if role is not None:
                update.append('role=%(role)s')
                param['role'] = role
            if status is not None:
                update.append('status=%(status)s')
                param['status'] = status
            if update:
                sql = "UPDATE t_users SET {} WHERE email=%(email)s".format(
                    ', '.join(update))
                tx = yield pool.begin()
                try:
                    yield tx.execute(sql, param)
                except pymysql.Error as e:
                    yield tx.rollback()
                    log.error('编辑用户失败#{}'.format(e))
                    flag, msg = False, '用户 {} 资料修改失败'.format(email)
                else:
                    yield tx.commit()
                    log.info('用户 {} 资料修改成功'.format(email))
                    flag, msg = True, '用户 {} 资料修改成功'.format(email)
                return flag, msg
            else:
                log.error('没有可更新的项')
                return False, '没有可更新的项'
        else:
            log.error('没有可编辑的用户#{}'.format(email))
            return False, '没有可编辑的用户#{}'.format(email)
Ejemplo n.º 12
0
 def post(self, op='option', do='save'):
     if self.current_user.role == 2:
         msg = dict(result=False, msg='请使用管理员登录后再进行操作!')
         yield self.return_json(msg)
         return
     if op == 'option':
         company = self.get_argument('company', default='')
         page_limit = self.get_argument('page_limit', default='')
         email_ext = self.get_argument('email_ext', default='')
         smtp_host = self.get_argument('smtp_host', default='')
         smtp_port = self.get_argument('smtp_port', default='')
         use_ssl = self.get_argument('use_ssl', default='off')
         smtp_user = self.get_argument('smtp_user', default='')
         smtp_password = self.get_argument('smtp_password', default='')
         mail_from = self.get_argument('mail_from', default='')
         report_url = self.get_argument('report_url', default='')
         mail_report = self.get_argument('mail_report', default='off')
         common_func = CommonFunction()
         if smtp_user != '' and not common_func.check_string(
                 smtp_user, 'email'):
             msg = dict(result=False, msg='【SMTP 登录用户】必须是Email格式')
             yield self.return_json(msg)
             return
         if mail_from != '' and not common_func.check_string(
                 mail_from, 'email'):
             msg = dict(result=False, msg='【发件人显示为】必须是Email格式')
             yield self.return_json(msg)
             return
         if do == 'test':
             send_to = self.get_argument('send_to', default='')
             if '' in (send_to, smtp_port, smtp_host, smtp_user,
                       smtp_password):
                 msg = dict(result=False, msg='所有配置不能为空, 请检查配置是否正确')
                 yield self.return_json(msg)
                 return
             if not common_func.check_string(send_to, 'email'):
                 msg = dict(result=False, msg='【配置测试】地址必须是Email格式')
                 yield self.return_json(msg)
                 return
             mail = Mail(smtp_server=smtp_host,
                         smtp_port=smtp_port,
                         use_ssl=use_ssl,
                         smtp_user=smtp_user,
                         smtp_password=smtp_password,
                         mail_from=mail_from)
             message = '<p>[{}]邮件配置测试, 收到此邮件说明配置正确。</p>'.format(
                 self.company)
             result, msg = yield mail.send_mail(
                 subject='[{}][系统测试邮件]'.format(self.company),
                 message=message,
                 to=[send_to])
             if result:
                 msg = dict(result=True, msg='邮件发送成功')
             else:
                 msg = dict(result=False, msg='邮件发送失败, {}'.format(msg))
         else:
             if page_limit == '':
                 page_limit = 0
             else:
                 page_limit = int(page_limit)
             if len(company) < 2 or len(company) > 60:
                 msg = dict(result=False, msg='【公司名称】格式不正确')
                 yield self.return_json(msg)
                 return
             if page_limit < 10 or page_limit > 100 or page_limit % 10 != 0:
                 msg = dict(result=False, msg='【分页数目】必须为10的倍数且是10与100之间的整数')
                 yield self.return_json(msg)
                 return
             if report_url != '' and not common_func.check_string(
                     report_url, 'url'):
                 msg = dict(result=False, msg='【邮件报告链接域名】格式不对, 请检查')
                 yield self.return_json(msg)
                 return
             edit_options = dict(company=company,
                                 page_limit=page_limit,
                                 email_ext=email_ext,
                                 report_url=report_url,
                                 smtp_host=smtp_host,
                                 smtp_port=smtp_port,
                                 smtp_user=smtp_user,
                                 mail_report=mail_report,
                                 smtp_password=smtp_password,
                                 use_ssl=use_ssl,
                                 mail_from=mail_from)
             options = yield self.option.get_options_list()
             flag = True
             msg = ''
             options_name = []
             for option in options:
                 options_name.append(option.name)
             if options_name:
                 for option in edit_options:
                     if option in options_name:
                         result, msg = yield self.option.edit_option(
                             name=option, value=edit_options[option])
                     else:
                         result, msg = yield self.option.add_option(
                             name=option, value=edit_options[option])
                     if not result:
                         flag = False
                         break
             else:
                 for option in edit_options:
                     result, msg = yield self.option.add_option(
                         name=option, value=edit_options[option])
                     if not result:
                         flag = False
                         break
             if flag:
                 msg = dict(result=True, msg='更新系统配置成功')
             else:
                 msg = dict(result=False, msg=msg)
         yield self.return_json(msg)
     elif op == 'users':
         if do == 'add':
             email = self.get_argument('email', default='')
             if self.common_func.check_string(email, 'email'):
                 user = yield self.user.get_user_info(email)
                 if user is None:
                     self.user.register_user(email, '123456')
             self.redirect('/admin/manage/users')
             return
         uid = self.get_argument('id', default='')
         user = yield self.user.get_users_info_by_ids(ids=[uid])
         if not user:
             msg = dict(result=False, msg='所编辑的用户不存在')
             yield self.return_json(msg)
             return
         if do == 'status':
             status = int(self.get_argument('status', default=0))
             result, msg = yield self.user.edit_user(email=user[0].email,
                                                     status=status)
             if result:
                 msg = dict(result=True, msg=msg)
             else:
                 msg = dict(result=False, msg=msg)
             yield self.return_json(msg)
             return
         elif do == 'role':
             role = int(self.get_argument('role', default=0))
             result, msg = yield self.user.edit_user(email=user[0].email,
                                                     role=role)
             if result:
                 msg = dict(result=True, msg=msg)
             else:
                 msg = dict(result=False, msg=msg)
             yield self.return_json(msg)
             return
         elif do == 'reset':
             result, msg = yield self.user.edit_user(email=user[0].email,
                                                     password='******')
             if result:
                 msg = dict(result=True,
                            msg='用户 {} 的密码已重置为 123456'.format(
                                user[0].email))
             else:
                 msg = dict(result=False, msg=msg)
             yield self.return_json(msg)
             return
     elif op == 'logs':
         yield self.setting.delete_settings_list(s_type='log')
         self.redirect('/admin/manage/logs')