Arthur-Wu commit
This commit is contained in:
45
commons/AssertLib.py
Normal file
45
commons/AssertLib.py
Normal file
@ -0,0 +1,45 @@
|
||||
# !/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Author:: Arthur Wu
|
||||
# @Date:: 2024/10/24-14:39
|
||||
# @Description::
|
||||
|
||||
|
||||
def _assert_result(RspJson, ExpRespJson_c, LOGGER):
|
||||
try:
|
||||
if RspJson["msg"] == "成功":
|
||||
if ExpRespJson_c["msg"] == "成功":
|
||||
FailedCase = []
|
||||
if ExpRespJson_c["data"] not in ['', None, True, False, "true", "false"]:
|
||||
if type(RspJson["data"]) == dict:
|
||||
# 0302-校验返回体中的修改的参数值是否正确
|
||||
for key, expect_value in ExpRespJson_c['data'].items():
|
||||
return_value = RspJson['data'][key]
|
||||
if expect_value == return_value:
|
||||
LOGGER.info(f"---接口返回体字段校验成功!\n"
|
||||
f"---待校验字段为:{key},预期值为:{expect_value},返回值为:{return_value}\n")
|
||||
else:
|
||||
LOGGER.error(f"---接口返回体字段校验失败!字段值不正确:\n"
|
||||
f"---待校验字段为:{key},预期值为:{expect_value},返回值为:{return_value}\n")
|
||||
FailedCase.append(f"字段-{key}-校验失败!")
|
||||
if FailedCase==[]:
|
||||
return True
|
||||
else: return False
|
||||
elif RspJson["msg"] == "失败":
|
||||
if ExpRespJson_c["msg"] == "失败":
|
||||
return True
|
||||
else:
|
||||
LOGGER.error(f"---接口请求成功! 校验失败!接口返回信息:{RspJson['msg']}")
|
||||
return False
|
||||
elif ExpRespJson_c["msg"] == "请求参数错误":
|
||||
if RspJson["msg"] == "请求参数错误":
|
||||
return True
|
||||
else:
|
||||
LOGGER.error(f"---接口请求成功! 校验失败!接口返回信息:{RspJson['msg']}")
|
||||
return False
|
||||
else:
|
||||
LOGGER.error(f"---接口请求失败! 错误信息:{RspJson['msg']}")
|
||||
return False
|
||||
except AssertionError as e:
|
||||
LOGGER.error(f"---断言失败!错误信息:{e}")
|
||||
return False
|
@ -1,8 +1,27 @@
|
||||
# !/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/10/8
|
||||
import os,sys,random,string
|
||||
import time, datetime
|
||||
|
||||
|
||||
class Common():
|
||||
|
||||
def __init__(self):
|
||||
self.timestamp = int(time.time())
|
||||
self.Datetime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
|
||||
self.today_date = datetime.date.today().strftime('%Y-%m-%d')
|
||||
self.rootpath = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
def return_folder(self):
|
||||
ReportPath = os.path.join(self.rootpath, 'YiMao/reports', str(self.Datetime)).replace("\\", "/")
|
||||
if not os.path.exists(ReportPath):
|
||||
os.makedirs(ReportPath)
|
||||
return ReportPath + '/'
|
||||
|
||||
def delete_txt_files(self):
|
||||
txtPath = os.path.join(self.rootpath, 'YiMao/ProcessData')
|
||||
for root, dirs, files in os.walk(txtPath):
|
||||
for file_name in files:
|
||||
if file_name.endswith('.txt'):
|
||||
file_path = os.path.join(root, file_name)
|
||||
os.remove(file_path)
|
||||
print(f"已删除: {file_path}")
|
107
commons/EngineX.py
Normal file
107
commons/EngineX.py
Normal file
@ -0,0 +1,107 @@
|
||||
# !/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/10/8
|
||||
'''
|
||||
import os,pytest,subprocess,json,shutil,time,requests
|
||||
from configs.globalObj import *
|
||||
from configs.globalParams import *
|
||||
|
||||
class Engine():
|
||||
|
||||
def __init__(self):
|
||||
self.CasesSuite = []
|
||||
self.rootpath = os.path.dirname(os.path.dirname(__file__))
|
||||
self.FolderPath = ReturnFolder
|
||||
self.projectCasesPath = str(os.path.join(GlobalPath['YMCaseScriptsPath']).replace("\\", "/"))
|
||||
self.ReportName = "Reports"
|
||||
|
||||
def __execute(self):
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/5/9
|
||||
:return:
|
||||
'''
|
||||
for dirpath, dirnames, filenames in os.walk(self.projectCasesPath):
|
||||
for fn in filenames:
|
||||
if fn.startswith("test_"):
|
||||
caseScriptPath = os.path.join(dirpath, fn).replace("\\", "/")
|
||||
self.CasesSuite.append(caseScriptPath)
|
||||
if 0 == len(self.CasesSuite):
|
||||
raise ValueError("---[ERROR] the test suite was empty !")
|
||||
else:
|
||||
pytest.main(args=[*self.CasesSuite, '-vsq', '--alluredir', self.FolderPath])
|
||||
subprocess.Popen(
|
||||
"allure generate " + self.FolderPath + ' -o ' + self.FolderPath + "html"
|
||||
+ ' --workers=2 '+'--tests-per-worker=2',
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE).stdout.read()
|
||||
LOGGER.info("---[INFO] Allure html report generate complete !")
|
||||
|
||||
def __move_file(self):
|
||||
rootpath = (os.getcwd()).replace("\\", "/")
|
||||
pathli = rootpath.split("/")
|
||||
LastReportPath = ''
|
||||
PathList = self.FolderPath.split("/")
|
||||
try:
|
||||
LastReportPath = "D:/Program Files/AutoTestReports/"
|
||||
shutil.move(self.FolderPath, LastReportPath)
|
||||
except Exception as e:
|
||||
LOGGER.error(f"---Move the html report file error: {e}")
|
||||
return os.path.join(LastReportPath, PathList[-2]).replace("\\", "/")
|
||||
|
||||
def __delete_pycache_dirs(self, target_dir):
|
||||
for root, dirs, files in os.walk(target_dir):
|
||||
for dir_name in dirs:
|
||||
if dir_name == '__pycache__':
|
||||
dir_path = os.path.join(root, dir_name)
|
||||
shutil.rmtree(dir_path)
|
||||
print(f"已删除: {dir_path}")
|
||||
|
||||
def __delete_txt_files(self, target_dir):
|
||||
for root, dirs, files in os.walk(target_dir):
|
||||
for file_name in files:
|
||||
if file_name.endswith('.txt'):
|
||||
file_path = os.path.join(root, file_name)
|
||||
os.remove(file_path)
|
||||
print(f"已删除: {file_path}")
|
||||
|
||||
def run_test_suite(self):
|
||||
txtPath = os.path.join(self.rootpath, "YiMao/ProcessData")
|
||||
self.__delete_pycache_dirs(self.rootpath)
|
||||
self.__delete_txt_files(txtPath)
|
||||
self.__execute()
|
||||
returnList = []
|
||||
lastReportPath = self.__move_file()
|
||||
returnList.append(lastReportPath)
|
||||
self.__delete_txt_files(txtPath)
|
||||
self.__delete_pycache_dirs(self.rootpath)
|
||||
return returnList
|
||||
|
||||
class NotificationModule():
|
||||
def __init__(self):
|
||||
self.__headers = {'Content-Type': 'application/json;charset=utf-8'}
|
||||
datainfo = {
|
||||
"Debug": "7aedbee7239870e3e653748a2889d8bf063c61efa9213c7099bd57476066dc86",
|
||||
"Formal": "80b026022a28166cfc9eebaf8f6a880cc06f56a14b8803e8d67e7fb3cb05844e"
|
||||
}
|
||||
self.urlInfo = f'https://oapi.dingtalk.com/robot/send?access_token={datainfo["Debug"]}'
|
||||
# self.urlInfo = f'https://oapi.dingtalk.com/robot/send?access_token={datainfo["Formal"]}'
|
||||
self.ReportUrl = ProCfgData["ReportsURL"]
|
||||
self.ExecutionEnvironment = ProCfgData["ExecutionEnv"]
|
||||
|
||||
def send_msg(self, ResultPath):
|
||||
ReportPath = os.path.join(ResultPath[0], 'html', 'index.html').replace('\\', '/')
|
||||
reportUrlpath = self.ReportUrl + ReportPath.split("AutoTestReports")[1]
|
||||
my_data = {
|
||||
"msgtype": "markdown",
|
||||
"markdown": {
|
||||
"title": "亿猫管理后台接口自动化测试",
|
||||
"text": f"#### 亿猫管理后台({self.ExecutionEnvironment})环境自动化测试执行结束: \n"
|
||||
f">#### [自动化测试报告链接(请点击查看)]({reportUrlpath})\n>\n"
|
||||
}
|
||||
}
|
||||
sess = requests.session()
|
||||
sess.keep_alive = False
|
||||
requests.post(url=self.urlInfo, data=json.dumps(my_data), headers=self.__headers, verify=False)
|
||||
sess.close()
|
||||
|
65
commons/FileHandler.py
Normal file
65
commons/FileHandler.py
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import os, xlrd, yaml
|
||||
from openpyxl import load_workbook
|
||||
|
||||
class YamlHandler():
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/5/8
|
||||
@Description::
|
||||
'''
|
||||
def read_yaml(self, YamlFilePath, encoding='utf-8'):
|
||||
try:
|
||||
with open(YamlFilePath, encoding=encoding) as f:
|
||||
return yaml.load(f.read(), Loader=yaml.FullLoader)
|
||||
except Exception as e:
|
||||
print("ERROR: read yaml file error::".format(e))
|
||||
return 'failed to read avata autotest config file.'
|
||||
|
||||
class ReadExcel(object):
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/5/8
|
||||
@Description::
|
||||
'''
|
||||
def get_data(self, FilePath, SheetName="Sheet1"):
|
||||
data = load_workbook(FilePath)
|
||||
table = data[SheetName]
|
||||
nrows = table.max_row
|
||||
ncols = table.max_column
|
||||
if nrows > 1:
|
||||
test_data = []
|
||||
for row in range(2, nrows + 1):
|
||||
sub_data = {}
|
||||
for colum in range(1, ncols + 1):
|
||||
sub_data[table.cell(1, colum).value] = table.cell(row, colum).value
|
||||
test_data.append(sub_data)
|
||||
return test_data
|
||||
|
||||
class Txt():
|
||||
'''@Author:: Arthur Wu
|
||||
@Date:: 2024/5/8
|
||||
@Description::
|
||||
'''
|
||||
def __init__(self):
|
||||
rootpath = os.path.dirname(os.path.dirname(__file__))
|
||||
self.record_files_path = os.path.join(rootpath, 'YiMao/ProcessData').replace("\\", "/")
|
||||
|
||||
def read_txt(self, FileName):
|
||||
filepath = os.path.join(self.record_files_path, FileName)
|
||||
AllLineValue = []
|
||||
if os.path.exists(filepath):
|
||||
with open(filepath, "r", encoding='utf-8') as file:
|
||||
for lineval in file:
|
||||
newlineval = lineval.strip()
|
||||
AllLineValue.append(newlineval)
|
||||
return AllLineValue
|
||||
|
||||
def append_write_txt(self, FileName, Message):
|
||||
try:
|
||||
filepath = os.path.join(self.record_files_path, FileName)
|
||||
with open(filepath, "a", encoding='UTF-8') as f:
|
||||
f.write(Message + '\n')
|
||||
return True
|
||||
except Exception as e:
|
||||
print("Error: append_write_txt error::" + str(e))
|
||||
return False
|
||||
|
32
commons/Logger.py
Normal file
32
commons/Logger.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# @Time :
|
||||
# @Author :
|
||||
# @File : Logger.py
|
||||
# @Software: PyCharm
|
||||
import logging, os, time
|
||||
from time import localtime
|
||||
|
||||
class Singleton:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._instance is None:
|
||||
cls._instance = super(Singleton, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self, LogPath, FileName='YMAutotest'):
|
||||
def __logging(LogPath, FileName):
|
||||
datetime = time.strftime("%Y%m%d%H%M%S", localtime())
|
||||
filepath = f'{LogPath}{FileName}_{datetime}.log'
|
||||
controlshow = logging.StreamHandler()
|
||||
controlshow.setLevel(logging.INFO)
|
||||
logging.basicConfig(
|
||||
filename=filepath,
|
||||
filemode="w",
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s %(filename)s [line:%(lineno)d] %(levelname)s——: %(message)s \n',
|
||||
datefmt='%Y%m%d %H:%M:%S'
|
||||
)
|
||||
return logging
|
||||
self.logging = __logging(LogPath, FileName)
|
97
commons/PgSqlLib.py
Normal file
97
commons/PgSqlLib.py
Normal file
@ -0,0 +1,97 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from sshtunnel import SSHTunnelForwarder
|
||||
import psycopg2
|
||||
|
||||
class PGSQL():
|
||||
def __init__(self):
|
||||
ssh_host = 'ops.yimaogo.com'
|
||||
ssh_username = 'yimaogo_test'
|
||||
ssh_pwd = 'yimaogo!test@1234'
|
||||
ssh_port = 22
|
||||
db_host = '10.0.16.24'
|
||||
db_port = 5432
|
||||
db_dbname = 'yimaogo_test'
|
||||
db_user = 'yimaogo_test'
|
||||
db_password = 'yimaogo!test@1234'
|
||||
self.ssh_server = SSHTunnelForwarder(
|
||||
ssh_address_or_host=(ssh_host, ssh_port),
|
||||
ssh_username=ssh_username,
|
||||
ssh_password=ssh_pwd,
|
||||
remote_bind_address=(db_host, db_port)
|
||||
)
|
||||
self.ssh_server.daemon_forward_servers = False
|
||||
self.ssh_server.start()
|
||||
self.conn = psycopg2.connect(
|
||||
database=db_dbname,
|
||||
user=db_user,
|
||||
password=db_password,
|
||||
host='127.0.0.1',
|
||||
port=self.ssh_server.local_bind_port
|
||||
)
|
||||
self.cursor = self.conn.cursor()
|
||||
|
||||
def close(self):
|
||||
self.cursor.close()
|
||||
self.conn.close()
|
||||
self.ssh_server.close()
|
||||
|
||||
def select_data(self, SQL):
|
||||
self.cursor.execute(SQL)
|
||||
# 获取查询结果
|
||||
# rows = self.cursor.fetchone()
|
||||
# print(rows)
|
||||
rows = self.cursor.fetchall()
|
||||
# print(rows)
|
||||
# for row in rows:
|
||||
# print(row)
|
||||
return rows
|
||||
|
||||
def delete_data(self, SQL):
|
||||
self.cursor.execute(SQL)
|
||||
self.conn.commit()
|
||||
|
||||
def del_sample_activity_data(self, IDList=None):
|
||||
import time
|
||||
print('---开始删除派样活动自动化测试脏数据')
|
||||
for SampActivityID in IDList:
|
||||
# for SampActivityID in range(120, 140):
|
||||
print(f'---待删除ID为:{SampActivityID}')
|
||||
selsqlstr = f'SELECT * FROM public.sample_activity WHERE id={SampActivityID};'
|
||||
delsqlstr = [
|
||||
f"DELETE FROM public.sample_activity_gift WHERE activity_id={SampActivityID};",
|
||||
f"DELETE FROM public.sample_record WHERE activity_id={SampActivityID};",
|
||||
f"DELETE FROM public.sample_activity_store WHERE activity_id={SampActivityID};"
|
||||
f"DELETE FROM public.sample_activity WHERE id={SampActivityID};"
|
||||
]
|
||||
for s in delsqlstr:
|
||||
time.sleep(0.5)
|
||||
self.delete_data(s)
|
||||
time.sleep(0.5)
|
||||
self.select_data(selsqlstr)
|
||||
self.close()
|
||||
print("---删除 派样活动 脏数据结束!\n")
|
||||
|
||||
def del_coupon_activity_data(self, IDList=None):
|
||||
try:
|
||||
import time
|
||||
print('---开始删除 优惠券活动 自动化测试脏数据')
|
||||
for ActivityID in IDList:
|
||||
# for ActivityID in range(251, 264):
|
||||
print(f'---待删除ID为:{ActivityID}')
|
||||
selsqlstr = f'SELECT * FROM public.coupon_setting WHERE id={ActivityID};'
|
||||
delsqlstr = [
|
||||
f"DELETE FROM public.coupon_setting_distribution WHERE coupon_setting_id={ActivityID};",
|
||||
f"DELETE FROM public.coupon_setting WHERE id={ActivityID};",
|
||||
]
|
||||
for s in delsqlstr:
|
||||
time.sleep(0.5)
|
||||
self.delete_data(s)
|
||||
time.sleep(0.5)
|
||||
self.select_data(selsqlstr)
|
||||
self.close()
|
||||
print("---删除派样活动脏数据结束!\n")
|
||||
return "---[Successed]"
|
||||
except Exception as e:
|
||||
print(f"---删除派样活动脏数据失败: {e}\n")
|
||||
return e
|
||||
|
32
commons/SignatureYM.py
Normal file
32
commons/SignatureYM.py
Normal file
@ -0,0 +1,32 @@
|
||||
# !/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
from authlib.integrations.requests_client import OAuth2Session
|
||||
|
||||
|
||||
class SignatureYM():
|
||||
|
||||
def __init__(self):
|
||||
self.client_id = "95579765e4fe91af9962"
|
||||
self.client_secret = "3dcb964ede5d455f1d54623dad5e496bff468f81"
|
||||
self.redirect_uri = 'https://auth.yimaogo.com/api/callback'
|
||||
self.authorization_base_url = 'https://auth.yimaogo.com/api/login/oauth/authorize'
|
||||
self.token_url = 'https://auth.yimaogo.com/api/login/oauth/access_token'
|
||||
|
||||
def __tokens(self):
|
||||
oauth = OAuth2Session(self.client_id, redirect_uri=self.redirect_uri)
|
||||
authorization_url, state = oauth.create_authorization_url(self.authorization_base_url)
|
||||
token_dict = oauth.fetch_token(self.token_url, authorization_response={}, client_secret=self.client_secret)
|
||||
return token_dict["access_token"]
|
||||
|
||||
def return_headers(self):
|
||||
tokens = self.__tokens()
|
||||
headers = {
|
||||
'Authorization': tokens,
|
||||
'User-Agent': 'Apifox/1.0.0 (https://apifox.com)',
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': '*/*',
|
||||
'Host': 'api.test.yimaogo.com',
|
||||
'Connection': 'keep-alive'
|
||||
}
|
||||
return headers
|
||||
|
Reference in New Issue
Block a user