From a10d3c0cf477d4e60bc131e7a8ea0f210cc894df Mon Sep 17 00:00:00 2001 From: azhengzz <820108271@qq.com> Date: Thu, 11 Mar 2021 20:22:19 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dbug:=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E5=A4=9A=E4=B8=AA=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=85=B1=E5=90=8C=E6=89=A7=E8=A1=8C=E6=97=B6=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=92=8C=E6=9B=B4=E6=96=B0LastResultPool=E3=80=81Cook?= =?UTF-8?q?iePool=E3=80=81VariablePool=E5=AF=B9=E8=B1=A1=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E5=86=B2=E7=AA=81=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/cores/case/base/last_result.py | 158 ++++++++++++++---- .../cores/case/http/http_cookie_manager.py | 134 ++++++++++----- ApiAutomationTest/app/cores/variable.py | 84 +++++++--- 3 files changed, 280 insertions(+), 96 deletions(-) diff --git a/ApiAutomationTest/app/cores/case/base/last_result.py b/ApiAutomationTest/app/cores/case/base/last_result.py index 000b0e6..d695080 100644 --- a/ApiAutomationTest/app/cores/case/base/last_result.py +++ b/ApiAutomationTest/app/cores/case/base/last_result.py @@ -3,64 +3,158 @@ # 记录最近一次测试结果 from copy import deepcopy +from flask import session from app.extensions import session_id_manager +from app.cores.dictionaries import DISPATCHER_TRIGGER_TYPE class LastResult: + """ + LastResultPool = { + session_id1: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + ... + }, + session_id2: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + ... + }, + ... + } + + ScheduleLastResultPool = { + project_id1: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + ... + }, + project_id2: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + ... + }, + ... + } + """ + + # 上次执行结果 LastResultPool = {} + # 定时任务项目-上次执行结果 + ScheduleLastResultPool = {} + @classmethod def get_last_result(cls) -> dict: - session_id = session_id_manager.get_session_id() - return cls.LastResultPool.get(session_id) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + return cls.ScheduleLastResultPool.get(project_id) + else: + session_id = session_id_manager.get_session_id() + return cls.LastResultPool.get(session_id) @classmethod def update_last_result(cls, result, request_headers, request_body, response_headers, response_body): """更新所有字段""" cls._check_current_session_id_last_result_exist() - session_id = session_id_manager.get_session_id() - cls.LastResultPool.get(session_id).update({ - 'result': deepcopy(result), - 'request_headers': deepcopy(request_headers), - 'request_body': deepcopy(request_body), - 'response_headers': deepcopy(response_headers), - 'response_body': deepcopy(response_body), - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + cls.ScheduleLastResultPool.get(project_id).update({ + 'result': deepcopy(result), + 'request_headers': deepcopy(request_headers), + 'request_body': deepcopy(request_body), + 'response_headers': deepcopy(response_headers), + 'response_body': deepcopy(response_body), + }) + else: + session_id = session_id_manager.get_session_id() + cls.LastResultPool.get(session_id).update({ + 'result': deepcopy(result), + 'request_headers': deepcopy(request_headers), + 'request_body': deepcopy(request_body), + 'response_headers': deepcopy(response_headers), + 'response_body': deepcopy(response_body), + }) @classmethod def update_request_and_response_to_last_result(cls, request_headers, request_body, response_headers, response_body): """更新请求和应答数据""" cls._check_current_session_id_last_result_exist() - session_id = session_id_manager.get_session_id() - cls.LastResultPool.get(session_id).update({ - 'request_headers': deepcopy(request_headers), - 'request_body': deepcopy(request_body), - 'response_headers': deepcopy(response_headers), - 'response_body': deepcopy(response_body), - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + cls.ScheduleLastResultPool.get(project_id).update({ + 'request_headers': deepcopy(request_headers), + 'request_body': deepcopy(request_body), + 'response_headers': deepcopy(response_headers), + 'response_body': deepcopy(response_body), + }) + else: + session_id = session_id_manager.get_session_id() + cls.LastResultPool.get(session_id).update({ + 'request_headers': deepcopy(request_headers), + 'request_body': deepcopy(request_body), + 'response_headers': deepcopy(response_headers), + 'response_body': deepcopy(response_body), + }) @classmethod def update_result_to_last_result(cls, result): """更新最近一次执行结果""" cls._check_current_session_id_last_result_exist() - session_id = session_id_manager.get_session_id() - cls.LastResultPool.get(session_id).update({ - 'result': deepcopy(result), - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + cls.ScheduleLastResultPool.get(project_id).update({ + 'result': deepcopy(result), + }) + else: + session_id = session_id_manager.get_session_id() + cls.LastResultPool.get(session_id).update({ + 'result': deepcopy(result), + }) @classmethod def _check_current_session_id_last_result_exist(cls): """检查当前session_id是否在LastResultPool中,如果没有则新增一个空字典""" - session_id = session_id_manager.get_session_id() - if session_id not in cls.LastResultPool: - cls.LastResultPool.update({ - session_id: { - 'result': None, # 上次执行结果 - 'request_headers': None, # 请求头 - 'request_body': None, # 请求包 - 'response_headers': None, # 应答头 - 'response_body': None, # 应答包 - } - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id not in cls.ScheduleLastResultPool: + cls.ScheduleLastResultPool.update({ + project_id: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + } + }) + else: + session_id = session_id_manager.get_session_id() + if session_id not in cls.LastResultPool: + cls.LastResultPool.update({ + session_id: { + 'result': None, # 上次执行结果 + 'request_headers': None, # 请求头 + 'request_body': None, # 请求包 + 'response_headers': None, # 应答头 + 'response_body': None, # 应答包 + } + }) diff --git a/ApiAutomationTest/app/cores/case/http/http_cookie_manager.py b/ApiAutomationTest/app/cores/case/http/http_cookie_manager.py index 6d8c165..b5b8406 100644 --- a/ApiAutomationTest/app/cores/case/http/http_cookie_manager.py +++ b/ApiAutomationTest/app/cores/case/http/http_cookie_manager.py @@ -1,23 +1,46 @@ # coding=utf-8 -from flask import request +from flask import request, session from requests.cookies import RequestsCookieJar from datetime import timedelta, datetime import uuid from typing import Optional, List, Mapping -from app.cores.dictionaries import DISPATCHER_TYPE +from app.cores.dictionaries import DISPATCHER_TYPE, DISPATCHER_TRIGGER_TYPE # requests库会在发起请求时根据请求服务器的domain选择合适的cookie作为请求头中的cookie数据发出 # 可参考代码 requests.models.prepare_cookies() class HTTPCookieManager: - """管理自动化测试中请求头Cookie数据""" + """ + 管理自动化测试中请求头Cookie数据 + + CookiePool = { + http_cookie_manager_id1: { + DISPATCHER_TYPE.DEBUG: RequestsCookieJar(), + DISPATCHER_TYPE.BUILD: RequestsCookieJar(), + }, + http_cookie_manager_id1: { + DISPATCHER_TYPE.DEBUG: RequestsCookieJar(), + DISPATCHER_TYPE.BUILD: RequestsCookieJar(), + }, + ... + } + + ScheduleCookiePool = { + project_id1: RequestsCookieJar(), + project_id2: RequestsCookieJar(), + ... + } + """ # cookie池,不同的会话放到不同的字典中,key为区分会话唯一编号放入cookie中 CookiePool = {} + # 对于定时构建的项目,使用另一个Cookie池保存,key为项目id + ScheduleCookiePool = {} + def __init__(self, app=None): if app is not None: self.init_app(app) @@ -26,65 +49,86 @@ class HTTPCookieManager: app.http_cookie_manager = self app.after_request(self._update_cookie) - def update_cookie_pool(self, http_cookie_manager_id: str = None, rcj: RequestsCookieJar = None, type: str = None): + def update_cookie_pool(self, rcj: RequestsCookieJar = None, type: str = None): """ - :param http_cookie_manager_id: 标识当前会话cookie编号 :param rcj: RequestsCookieJar对象,一般由应答头获得 response.cookies :param type: 需要更新到的cookie类型 DISPATCHER_TYPE.BUILD或DISPATCHER_TYPE.DEBUG :return: None """ - if http_cookie_manager_id is None: - try: - http_cookie_manager_id = request.cookies.get(HTTPCookieManagerConfig.COOKIE_NAME) - except KeyError: - raise KeyError('在请求上下文cookies中未找到名为%s的cookie' % HTTPCookieManagerConfig.COOKIE_NAME) - - if rcj is None or type is None: - self._add_empty_to_cookie_pool(http_cookie_manager_id) + # 如果cookie池没有的话先创建默认值 + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + if project_id not in __class__.ScheduleCookiePool: + self._add_empty_to_cookie_pool() else: + http_cookie_manager_id = self._get_http_cookie_manager_id() if http_cookie_manager_id not in __class__.CookiePool: - self._add_empty_to_cookie_pool(http_cookie_manager_id) - if len(rcj) == 0: # 空的RequestsCookieJar - return - if type in [DISPATCHER_TYPE.DEBUG, DISPATCHER_TYPE.BUILD]: + self._add_empty_to_cookie_pool() + # 如果入参rcj为空的RequestsCookieJar则不更新直接返回 + if len(rcj) == 0: + return + # 根据type和dispatcher_trigger_type进行cookie更新 + if type in [DISPATCHER_TYPE.DEBUG, DISPATCHER_TYPE.BUILD]: + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + old_rcj = __class__.ScheduleCookiePool[project_id] + if old_rcj is None: + __class__.ScheduleCookiePool[project_id] = rcj + else: + self._update_request_cookie_jar(old_rcj=old_rcj, new_rcj=rcj) + else: + http_cookie_manager_id = self._get_http_cookie_manager_id() old_rcj = __class__.CookiePool[http_cookie_manager_id][type] if old_rcj is None: __class__.CookiePool[http_cookie_manager_id][type] = rcj else: self._update_request_cookie_jar(old_rcj=old_rcj, new_rcj=rcj) - else: - raise ValueError('不支持传入type值为%s,只支持type=single_case 或 type=build_case' % type) + else: + raise ValueError('不支持传入type值为%s,只支持type=single_case 或 type=build_case' % type) def _update_request_cookie_jar(self, old_rcj: RequestsCookieJar, new_rcj: RequestsCookieJar): """将新的rcj更新到老的rcj上""" old_rcj.update(other=new_rcj) - def _add_empty_to_cookie_pool(self, http_cookie_manager_id: str): + def _add_empty_to_cookie_pool(self): """ 为当前会话在cookie pool中添加一个新的,默认值为RequestsCookieJar() - :param http_cookie_manager_id: 标识当前会话cookie编号 :return: None """ - __class__.CookiePool.update({ - http_cookie_manager_id: { - DISPATCHER_TYPE.DEBUG: RequestsCookieJar(), - DISPATCHER_TYPE.BUILD: RequestsCookieJar(), - } - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + __class__.ScheduleCookiePool.update({ + project_id: RequestsCookieJar(), + }) + else: + http_cookie_manager_id = self._get_http_cookie_manager_id() + __class__.CookiePool.update({ + http_cookie_manager_id: { + DISPATCHER_TYPE.DEBUG: RequestsCookieJar(), + DISPATCHER_TYPE.BUILD: RequestsCookieJar(), + } + }) def get_request_cookie_jar(self, type: str) -> Optional[RequestsCookieJar]: """ 获取当前会话中指定类型的cookie数据 - :param type: cookie类型 single_case或build_case + :param type: cookie类型 DISPATCHER_TYPE.BUILD或DISPATCHER_TYPE.DEBUG :return: RequestsCookieJar """ - try: - http_cookie_manager_id = request.cookies.get(HTTPCookieManagerConfig.COOKIE_NAME) - except KeyError: - raise KeyError('在请求上下文cookies中未找到名为%s的cookie' % HTTPCookieManagerConfig.COOKIE_NAME) - if http_cookie_manager_id not in __class__.CookiePool: - return - return __class__.CookiePool[http_cookie_manager_id][type] + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + if project_id not in __class__.ScheduleCookiePool: + return + return __class__.ScheduleCookiePool[project_id] + else: + http_cookie_manager_id = self._get_http_cookie_manager_id() + if http_cookie_manager_id not in __class__.CookiePool: + return + return __class__.CookiePool[http_cookie_manager_id][type] def clear_and_reset(self, rcj: RequestsCookieJar, cookies: List[Mapping]): """ @@ -120,7 +164,6 @@ class HTTPCookieManager: path='/', secure=HTTPCookieManagerConfig.COOKIE_SECURE, httponly=HTTPCookieManagerConfig.COOKIE_HTTPONLY) - self._add_empty_to_cookie_pool(uuid_) else: pass return response @@ -132,15 +175,24 @@ class HTTPCookieManager: :return: """ if self.get_request_cookie_jar(type=type) is not None: - try: - http_cookie_manager_id = request.cookies.get(HTTPCookieManagerConfig.COOKIE_NAME) - except KeyError: - raise KeyError('在请求上下文cookies中未找到名为%s的cookie' % HTTPCookieManagerConfig.COOKIE_NAME) if type in [DISPATCHER_TYPE.DEBUG, DISPATCHER_TYPE.BUILD]: - __class__.CookiePool[http_cookie_manager_id][type] = RequestsCookieJar() + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + __class__.ScheduleCookiePool[project_id] = RequestsCookieJar() + else: + http_cookie_manager_id = self._get_http_cookie_manager_id() + __class__.CookiePool[http_cookie_manager_id][type] = RequestsCookieJar() else: raise ValueError('不支持传入type值为%s,只支持type=single_case 或 type=build_case' % type) + def _get_http_cookie_manager_id(self): + """获取请求上下文中的http_cookie_manager_id""" + try: + return request.cookies.get(HTTPCookieManagerConfig.COOKIE_NAME) + except KeyError: + raise KeyError('在请求上下文cookies中未找到名为%s的cookie' % HTTPCookieManagerConfig.COOKIE_NAME) + class HTTPCookieManagerConfig: # 标识HTTPCookieManager在当前浏览器客户端对应id的cookie diff --git a/ApiAutomationTest/app/cores/variable.py b/ApiAutomationTest/app/cores/variable.py index 6ed7431..76aeb7b 100644 --- a/ApiAutomationTest/app/cores/variable.py +++ b/ApiAutomationTest/app/cores/variable.py @@ -1,8 +1,10 @@ # coding=utf-8 from typing import Dict +from flask import session from app.extensions import session_id_manager +from app.cores.dictionaries import DISPATCHER_TRIGGER_TYPE class Variable: @@ -21,12 +23,28 @@ class Variable: }, session_id2:{ ... - } + }, + ... + } + + ScheduleVariablePool = { + project_id: { + key: value, + key1: value1, + ... + }, + project_id2: { + ... + }, + ... } """ - + # 变量池 VariablePool = {} + # 定时任务变量池 + ScheduleVariablePool = {} + @classmethod def get_project_variable(cls, project_id): """ @@ -36,9 +54,14 @@ class Variable: :return: 项目级所有变量 :rtype: Dict """ - session_id = session_id_manager.get_session_id() cls._set_default_project_variable(project_id=project_id) - return cls.VariablePool.get(session_id).get(project_id) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + return cls.ScheduleVariablePool.get(project_id) + else: + session_id = session_id_manager.get_session_id() + return cls.VariablePool.get(session_id).get(project_id) @classmethod def set_project_variable(cls, project_id, key, value): @@ -51,27 +74,42 @@ class Variable: :param value: 变量值 :type value: str """ - session_id = session_id_manager.get_session_id() cls._set_default_project_variable(project_id=project_id) - cls.VariablePool.get(session_id).get(project_id).update({ - key: value - }) + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + cls.ScheduleVariablePool.get(project_id).update({ + key: value + }) + else: + session_id = session_id_manager.get_session_id() + cls.VariablePool.get(session_id).get(project_id).update({ + key: value + }) @classmethod def _set_default_project_variable(cls, project_id): """当VariablePool为空时,为其设置默认值,避免取出值为None的项目级变量池""" - session_id = session_id_manager.get_session_id() - session_var = cls.VariablePool.get(session_id) - if session_var is None: - cls.VariablePool.update({ - session_id: { - project_id: {} - } - }) - return - project_var = cls.VariablePool.get(session_id).get(project_id) - if project_var is None: - cls.VariablePool.get(session_id).update({ - project_id: {} - }) - return + if session.get('dispatcher_trigger_type') == DISPATCHER_TRIGGER_TYPE.BY_SCHEDULE: + project_id = session.get('project_id') + if project_id: + project_var = cls.ScheduleVariablePool.get(project_id) + if project_var is None: + cls.ScheduleVariablePool.update({ + project_id: {} + }) + else: + session_id = session_id_manager.get_session_id() + session_var = cls.VariablePool.get(session_id) + if session_var is None: + cls.VariablePool.update({ + session_id: { + project_id: {} + } + }) + else: + project_var = cls.VariablePool.get(session_id).get(project_id) + if project_var is None: + cls.VariablePool.get(session_id).update({ + project_id: {} + })