Arthur-Wu commit

This commit is contained in:
ieemoo
2024-11-11 17:16:31 +08:00
parent 0550884b67
commit fd92879ff1
36 changed files with 1505 additions and 8 deletions

45
commons/AssertLib.py Normal file
View 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

View File

@ -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
View 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
View 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
View 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
View 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
View 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