修复bug: 修复定时任务多个项目共同执行时获取和更新LastResultPool、CookiePool、VariablePool对象存在冲突的问题
This commit is contained in:
parent
3c7667e125
commit
a10d3c0cf4
|
@ -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, # 应答包
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: {}
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue