Commit 83955a6d7045b8e741c28de714f92823463d4e5c
0 parents
更新文件
Showing
34 changed files
with
1474 additions
and
0 deletions
README.md
0 → 100644
commons/ConfigDB.py
0 → 100644
1 | +++ a/commons/ConfigDB.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import pymysql | |
4 | +import time | |
5 | +import json | |
6 | +import commons.common as ca | |
7 | +from commons.Logging import log | |
8 | + | |
9 | + | |
10 | +dbhost=ca.get_global_config('global_data','Database','dbhost') | |
11 | +dbport=int(ca.get_global_config('global_data','Database','dbport')) | |
12 | +dbname=ca.get_global_config('global_data','Database','dbname') | |
13 | +dbuser=ca.get_global_config('global_data','Database','dbuser') | |
14 | +dbpassword=ca.get_global_config('global_data','Database','dbpassword') | |
15 | +#dbcharset=get_global_config('Database','dbcharset') | |
16 | + | |
17 | +def mysql_conn_test(): | |
18 | + # 数据库连接重试功能和连接超时功能的DB连接 | |
19 | + _conn_status = True | |
20 | + _max_retries_count = 3 # 设置最大重试次数 | |
21 | + _conn_retries_count = 0 # 初始重试次数 | |
22 | + _conn_timeout = 3 # 连接超时时间为3秒 | |
23 | + while _conn_status and _conn_retries_count < _max_retries_count: | |
24 | + try: | |
25 | + print('连接数据库中..') | |
26 | + db = pymysql.connect(host=dbhost, | |
27 | + port=dbport, | |
28 | + user=dbuser, | |
29 | + passwd=dbpassword, | |
30 | + database=dbname, | |
31 | + charset='utf8', | |
32 | + connect_timeout=_conn_timeout) | |
33 | + _conn_status = False # 如果conn成功则_status为设置为False则退出循环,返回db连接对象 | |
34 | + print("连接结果 ",db) | |
35 | + return db | |
36 | + except: | |
37 | + _conn_retries_count += 1 | |
38 | + print(_conn_retries_count) | |
39 | + print('connect db is error!!') | |
40 | + time.sleep(3) # 此为测试看效果 | |
41 | + continue | |
42 | + raise Exception("pls check your mysql config!") | |
43 | + | |
44 | + | |
45 | +def mysql_selectOne(select_action): | |
46 | + action=select_action | |
47 | + db = pymysql.connect(host=dbhost, | |
48 | + port=dbport, | |
49 | + user=dbuser, | |
50 | + passwd=dbpassword, | |
51 | + database=dbname, | |
52 | + charset='utf8', | |
53 | + connect_timeout=3) | |
54 | + cursor = db.cursor() | |
55 | + try: | |
56 | + # 使用execute方法执行SQL语句 | |
57 | + cursor.execute(action) | |
58 | + data = cursor.fetchone() | |
59 | + return data | |
60 | + except Exception as e: | |
61 | + print("数据库操作异常:%s" % str(e)) | |
62 | + log.error("数据库操作异常:%s" % str(e)) | |
63 | + assert False | |
64 | + finally: | |
65 | + # 关闭数据库连接 | |
66 | + db.close() | |
67 | + | |
68 | +def mysql_selectAll(select_action): | |
69 | + action=select_action | |
70 | + db = pymysql.connect(host=dbhost, | |
71 | + port=dbport, | |
72 | + user=dbuser, | |
73 | + passwd=dbpassword, | |
74 | + database=dbname, | |
75 | + charset='utf8', | |
76 | + connect_timeout=3) | |
77 | + cursor = db.cursor() | |
78 | + try: | |
79 | + # 使用execute方法执行SQL语句 | |
80 | + cursor.execute(action) | |
81 | + # 使用 fetchall() 方法获取所有数据 | |
82 | + data = cursor.fetchall() | |
83 | +# print data | |
84 | + return data | |
85 | + except Exception as e: | |
86 | + print("数据库操作异常:%s" % str(e)) | |
87 | + log.error("数据库操作异常:%s" % str(e)) | |
88 | + assert False | |
89 | + finally: | |
90 | + # 关闭数据库连接 | |
91 | + db.close() | |
92 | + | |
93 | +def mysql_delete(delete_action): | |
94 | + action=delete_action | |
95 | + db = pymysql.connect(host=dbhost, | |
96 | + port=dbport, | |
97 | + user=dbuser, | |
98 | + passwd=dbpassword, | |
99 | + database=dbname, | |
100 | + charset='utf8', | |
101 | + connect_timeout=3) | |
102 | + cursor = db.cursor() | |
103 | + try: | |
104 | + # 使用execute方法执行SQL语句 | |
105 | + cursor.execute(action) | |
106 | + # 提交 | |
107 | + db.commit() | |
108 | + except Exception as e: | |
109 | + print("数据库操作异常:%s" % str(e)) | |
110 | + log.error("数据库操作异常:%s" % str(e)) | |
111 | + # 错误回滚 | |
112 | + db.rollback() | |
113 | + finally: | |
114 | + # 关闭数据库连接 | |
115 | + db.close() | |
116 | + | |
117 | +def mysql_update(update_action): | |
118 | + action=update_action | |
119 | + db = pymysql.connect(host=dbhost, | |
120 | + port=dbport, | |
121 | + user=dbuser, | |
122 | + passwd=dbpassword, | |
123 | + database=dbname, | |
124 | + charset='utf8', | |
125 | + connect_timeout=3) | |
126 | + cursor = db.cursor() | |
127 | + try: | |
128 | + # 使用execute方法执行SQL语句 | |
129 | + cursor.execute(action) | |
130 | + # 提交 | |
131 | + db.commit() | |
132 | + except Exception as e: | |
133 | + print("数据库操作异常:%s" % str(e)) | |
134 | + log.error("数据库操作异常:%s" % str(e)) | |
135 | + # 错误回滚 | |
136 | + db.rollback() | |
137 | + finally: | |
138 | + # 关闭数据库连接 | |
139 | + db.close() | |
140 | + | |
141 | +def mysql_insert(insert_action): | |
142 | + action=insert_action | |
143 | + db = pymysql.connect(host=dbhost, | |
144 | + port=dbport, | |
145 | + user=dbuser, | |
146 | + passwd=dbpassword, | |
147 | + database=dbname, | |
148 | + charset='utf8', | |
149 | + connect_timeout=3) | |
150 | + cursor = db.cursor() | |
151 | + try: | |
152 | + # 使用execute方法执行SQL语句 | |
153 | + cursor.execute(action) | |
154 | + # 提交 | |
155 | + db.commit() | |
156 | + except Exception as e: | |
157 | + print("数据库操作异常:%s" % str(e)) | |
158 | + log.error("数据库操作异常:%s" % str(e)) | |
159 | + # 错误回滚 | |
160 | + db.rollback() | |
161 | + finally: | |
162 | + # 关闭数据库连接 | |
163 | + db.close() | |
164 | + | |
165 | +def mysql_check_insert(api,section,check_sql,delete_sql,insert_sql): | |
166 | + log.info(u"======测试数据准备======") | |
167 | + check=ca.get_api_config(api, section, check_sql) | |
168 | + delete=ca.get_api_config(api, section, delete_sql) | |
169 | + insert=ca.get_api_config(api, section, insert_sql) | |
170 | + | |
171 | + try: | |
172 | + db = pymysql.connect(dbhost, dbuser, dbpassword, dbname, charset='utf8' ) | |
173 | + cursor = db.cursor() | |
174 | + # 使用execute方法执行SQL语句 | |
175 | + cursor.execute(check) | |
176 | + result=cursor.fetchall() | |
177 | + # 提交 | |
178 | + db.commit() | |
179 | + if result: | |
180 | + log.info(u"检查到数据库有重复数据%r"%str(result)) | |
181 | + log.info(u"删除查询到的重复数据%r"%str(delete)) | |
182 | + cursor.execute(delete) | |
183 | + log.info(u"删除数据完成") | |
184 | + log.info(u"向数据库中插入测试数据%r"%str(insert)) | |
185 | + cursor.execute(insert) | |
186 | + log.info(u"插入数据完成") | |
187 | + result=cursor.fetchall() | |
188 | + db.commit() | |
189 | + return result | |
190 | + else: | |
191 | + log.info(u"数据库没有重复数据直接插入自定义数据%r"%str(insert)) | |
192 | + result=cursor.execute(insert) | |
193 | + log.info(u"插入数据完成,返回结果为为%r"%str(result)) | |
194 | +# cursor.fetchall() | |
195 | + db.commit() | |
196 | + return result | |
197 | + | |
198 | + except Exception as e: | |
199 | + print(u"数据库操作异常:%r" % str(e)) | |
200 | + log.error(u"数据库操作异常:%r" % str(e)) | |
201 | + # 错误回滚 | |
202 | + db.rollback() | |
203 | + assert False | |
204 | + finally: | |
205 | + # 关闭数据库连接 | |
206 | + db.close() | |
207 | + | |
208 | +def Check_in_Mysql(in_data,sql_spm): | |
209 | + log.info(u"======从数据库中查询传入数据======") | |
210 | + result=mysql_selectAll(sql_spm) | |
211 | + log.info(u"传入in_data为: %s"%in_data) | |
212 | + log.info(u"数据库查询到的结果为 %s"%result) | |
213 | + | |
214 | + result=str(result) | |
215 | + if len(str(in_data)) == 0 and len(result)!=0: | |
216 | + log.error(u"传入数据为空!!\n") | |
217 | + assert False | |
218 | + return | |
219 | + elif len(str(in_data)) == 0 and len(result)==0: | |
220 | + log.error(u"传入数据与数据库查询结果都为空!!\n") | |
221 | + assert False | |
222 | + return | |
223 | + elif len(str(in_data)) != 0 and len(result)==0: | |
224 | + log.error(u"数据库查询结果为空\n") | |
225 | + assert False | |
226 | + return | |
227 | + elif isinstance(in_data,(list)): | |
228 | + log.info(u'检查的数据格式 为list类型') | |
229 | + for i in range(0,len(in_data)): | |
230 | + in_data[i]=str(in_data[i]).decode("utf-8").encode("unicode-escape") | |
231 | + | |
232 | + if in_data[i] in result: | |
233 | + assert True | |
234 | + log.info(u"遍历list第%d次,插入数据%r与数据库查询结果一致"%(i,in_data[i])) | |
235 | + else: | |
236 | + log.error(u"#########ERROR#########:\n in_data与数据库查询结果不一致%r"%in_data[i]) | |
237 | + assert False | |
238 | + return True | |
239 | + | |
240 | + elif str(in_data).decode("utf-8").encode("unicode-escape") in result: | |
241 | + assert True | |
242 | + log.info(u"in_data与数据库查询结果一致!!%r"%in_data) | |
243 | + return True | |
244 | + else: | |
245 | + log.info(u"#########ERROR#########:\n in_data与数据库查询结果不一致!!%r"%in_data) | |
246 | + assert False | |
247 | + | |
248 | +def Check_in_Response(check_data,src_data): | |
249 | + "check_data必须为列表形式,src_data必须为r.json()的数据类型" | |
250 | + log.info(u"======从响应Body中查询传入数据======") | |
251 | + src_data=json.dumps(src_data) | |
252 | + src_data=src_data.replace(" ","") | |
253 | + log.info(u"传入check_data为: %s"%check_data) | |
254 | + log.info(u"对比的响应数据为 %s"%src_data) | |
255 | + if len(check_data) == 0 or len(src_data)==0: | |
256 | + log.error(u"传入数据为空!!\n") | |
257 | + assert False | |
258 | + return | |
259 | + elif isinstance (check_data,str) : | |
260 | + check_data=check_data.replace(" ","").replace("[","").replace("]","").decode("utf-8").split(",") | |
261 | + for i in range(0,len(check_data)): | |
262 | + #由于数据库查询的数据中,中文的格式为unicode-escape,所以传入的数据需要进行encode | |
263 | + check_data[i]=check_data[i].decode("utf-8").encode("unicode-escape") | |
264 | +# print type(check_data),check_data[i] | |
265 | + if check_data[i] in src_data: | |
266 | + assert True | |
267 | + log.info(u"遍历list第%d次,字段%s在请求响应结果中"%((i+1),check_data[i].decode("unicode-escape"))) | |
268 | + else: | |
269 | + log.error(u"#########ERROR#########:\n check_data不在请求响应结果中%s"%check_data[i].decode("unicode-escape")) | |
270 | + assert False | |
271 | + return True | |
272 | + elif isinstance (check_data,list) and len(check_data) > 0: | |
273 | + for i in range(0,len(check_data)): | |
274 | + check_data[i]=check_data[i].decode("utf-8").encode("unicode-escape") | |
275 | + print(type(check_data),check_data[i],str(check_data[i])) | |
276 | + print(type(src_data),src_data) | |
277 | + if check_data[i] in src_data: | |
278 | + assert True | |
279 | + log.info(u"遍历list第%d次,插入数据%r与数据库查询结果一致"%(i,check_data[i])) | |
280 | + else: | |
281 | + log.error(u"#########ERROR#########:\n check_data数据库查询结果不一致%r"%check_data[i]) | |
282 | + assert False | |
283 | + return True | |
284 | + else: | |
285 | + log.info(u"#########ERROR#########:\n 检查数据有问题,请检查!!!!!%r") | |
286 | + assert False | ... | ... |
commons/Faker.py
0 → 100644
1 | +++ a/commons/Faker.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import random | |
4 | +from faker import Factory | |
5 | + | |
6 | +class random_data(): | |
7 | + | |
8 | + def __init__(self, type='zh_CN'): | |
9 | + self.type = type | |
10 | + self.fake = Factory().create(self.type) | |
11 | + | |
12 | + def date(self): | |
13 | + "随机时间" | |
14 | + return self.fake.date(pattern="%Y-%m-%d") | |
15 | + | |
16 | + def name(self): | |
17 | + "随机姓名" | |
18 | + return self.fake.name() | |
19 | + | |
20 | + def identity_card(self): | |
21 | + "随机证件" | |
22 | + return self.fake.ssn(min_age=18, max_age=90) | |
23 | + | |
24 | + def plate(self): | |
25 | + "随机车牌号" | |
26 | + return self.fake.license_plate() | |
27 | + | |
28 | + def plate_cn(self,plate_len=6): | |
29 | + "随机车牌号" | |
30 | + char0='京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽赣粤青藏川宁琼' | |
31 | + char1='ABCDEFGHJKLMNPQRSTUVWXYZ'#车牌号中没有I和O,可自行百度 | |
32 | + char2='1234567890' | |
33 | + len0=len(char0)-1 | |
34 | + len1 = len(char1) - 1 | |
35 | + len2 = len(char2) - 1 | |
36 | + ######## | |
37 | + code = '' | |
38 | + index0 = random.randint(0,len0 ) | |
39 | + index1 = random.randint(0,len1) | |
40 | + code += char0[index0] | |
41 | + code += char1[index1] | |
42 | + for i in range(0, plate_len-1): | |
43 | + index2 = random.randint(1, len2) | |
44 | + code += char2[index2] | |
45 | + return(code) | |
46 | + | |
47 | + def country(self): | |
48 | + "随机国家代码" | |
49 | + return self.fake.country() | |
50 | + | |
51 | + def province(self): | |
52 | + "随机省份" | |
53 | + return self.fake.province() | |
54 | + | |
55 | + def city(self): | |
56 | + "随机城市" | |
57 | + return self.fake.city_suffix() | |
58 | + | |
59 | + def district(self): | |
60 | + "随机街道" | |
61 | + return self.fake.district() | |
62 | + | |
63 | + def address(self): | |
64 | + "随机地址全称" | |
65 | + return self.fake.address() | |
66 | + | |
67 | + def phone_number(self): | |
68 | + "随机手机号" | |
69 | + return self.fake.phone_number() | |
70 | + | |
71 | + def email(self): | |
72 | + "随机邮件" | |
73 | + return self.fake.email() | |
74 | + | |
75 | + def longitude(self): | |
76 | + "随机经度" | |
77 | + return self.fake.longitude() | |
78 | + | |
79 | + def latitude (self): | |
80 | + "随机维度" | |
81 | + return self.fake.latitude () | |
82 | + | |
83 | + def credit_card_number (self): | |
84 | + "随机卡号" | |
85 | + return self.fake.credit_card_number () | |
86 | + | |
87 | + | |
88 | + | |
89 | +# a=random_data() | |
90 | +# print(a.date()) | |
91 | +# print(a.name()) | |
92 | +# print(a.identity_card()) | |
93 | +# print(a.plate()) | |
94 | +# print(a.plate_cn(6)) | |
95 | +# print(a.country()) | |
96 | +# print(a.province()) | |
97 | +# print(a.city()) | |
98 | +# print(a.district()) | |
99 | +# print(a.address()) | |
100 | +# print(a.phone_number()) | |
101 | +# print(a.email()) | |
102 | +# print(a.longitude()) | |
103 | +# print(a.latitude()) | |
104 | +# print(a.credit_card_number()) | |
105 | + | ... | ... |
commons/Logging.py
0 → 100644
1 | +++ a/commons/Logging.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import logging,os | |
4 | +# from mylog import mylogger,logg | |
5 | + | |
6 | + | |
7 | +class Logger(): | |
8 | + | |
9 | + def __init__(self, path=__name__,clevel = logging.ERROR,Flevel = logging.DEBUG,test = 'w'): | |
10 | + current_path=os.path.dirname(os.path.dirname(__file__)) | |
11 | + path=current_path+"/report"+"/test.log" | |
12 | + # setattr(mylogger, "logpath", path) | |
13 | + # logg.setting() | |
14 | + | |
15 | + self.logger = logging.getLogger(path) | |
16 | + | |
17 | + self.logger.setLevel(logging.DEBUG) | |
18 | + | |
19 | + fmt = logging.Formatter('[%(asctime)s] [%(levelname)s] : %(message)s', '%Y-%m-%d %H:%M:%S') | |
20 | + | |
21 | + sh = logging.StreamHandler() | |
22 | + | |
23 | + sh.setFormatter(fmt) | |
24 | + | |
25 | + sh.setLevel(clevel) | |
26 | + | |
27 | + #设置文件日志 | |
28 | + | |
29 | + fh = logging.FileHandler(path,mode=test,encoding="utf-8") | |
30 | + | |
31 | + fh.setFormatter(fmt) | |
32 | + | |
33 | + fh.setLevel(Flevel) | |
34 | + | |
35 | + self.logger.addHandler(sh) | |
36 | + | |
37 | + self.logger.addHandler(fh) | |
38 | + | |
39 | + | |
40 | + def debug(self,message): | |
41 | + | |
42 | + self.logger.debug(message) | |
43 | + | |
44 | + def info(self,message): | |
45 | + | |
46 | + self.logger.info(message) | |
47 | + | |
48 | + | |
49 | + def warn(self,message): | |
50 | + | |
51 | + self.logger.warn(message) | |
52 | + | |
53 | + | |
54 | + def error(self,message): | |
55 | + | |
56 | + self.logger.error(message) | |
57 | + | |
58 | + | |
59 | + def critical(self,message): | |
60 | + | |
61 | + self.logger.critical(message) | |
62 | + | |
63 | + | |
64 | +log=Logger() | |
0 | 65 | \ No newline at end of file | ... | ... |
commons/MySession.py
0 → 100644
1 | +++ a/commons/MySession.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import requests | |
4 | +from commons import common as com | |
5 | +from commons.Logging import log | |
6 | +from commons.clientSession import cliSession | |
7 | +from commons.scripts.pwdCry import pwdCry | |
8 | + | |
9 | + | |
10 | +class mysession(requests.Session): | |
11 | + "封装了requests的基类,以供后期统一使用" | |
12 | + | |
13 | + url = "http://test.uap.diligrp.com/login/login.action" | |
14 | + url_client = "http://test.uap.diligrp.com/api/authenticationApi/loginWeb" | |
15 | + | |
16 | + header = { | |
17 | + "Host": "test.uap.diligrp.com", | |
18 | + "Connection": "keep-alive", | |
19 | + "Content-Length": "33", | |
20 | + "Cache-Control": "max-age=0", | |
21 | + "Upgrade-Insecure-Requests": "1", | |
22 | + "Origin": "http://test.uap.diligrp.com", | |
23 | + "Content-Type": "application/x-www-form-urlencoded", | |
24 | + "User-Agent": "Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/90.0.4430.212Safari/537.36", | |
25 | + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", | |
26 | + "Referer": "http://test.uap.diligrp.com/login/index.html", | |
27 | + "Accept-Encoding": "gzip,deflate", | |
28 | + "Accept-Language": "zh-CN,zh-TW;q=0.9,zh;q=0.8,en;q=0.7", | |
29 | + "Cookie": "UAP_accessToken=;UAP_refreshToken=;UAP_loginPath="} | |
30 | + header_client = { | |
31 | + "Content-Type": "text/plain;charset=utf-8", | |
32 | + "Host": "test.uap.diligrp.com", | |
33 | + "Content-Length": "209", | |
34 | + "Expect": "100-continue"} | |
35 | + | |
36 | + body = "userName=sg_wenze&password=111111" | |
37 | + body_client= {"userName":"sg_wenze","password":"111111"} | |
38 | + | |
39 | + def __init__(self): | |
40 | + "如下代码,可以通过配置文件来控制测试环境和灰度环境,http和https" | |
41 | + super().__init__() | |
42 | + self.url = mysession.url.replace("http://test.", com.get_global_config("global_data", "environment", "en")) | |
43 | + self.header = mysession.header | |
44 | + self.body = mysession.body | |
45 | + self.url_client = mysession.url_client.replace("http://test.", com.get_global_config("global_data", "environment", "en")) | |
46 | + self.header_client = mysession.header_client | |
47 | + self.body_client = mysession.body_client | |
48 | + self.timeout = (6,6) | |
49 | + self.max_retries = 3 | |
50 | + self.keep_alive = False | |
51 | + self.ssl_verify = False | |
52 | + self.proxies = None | |
53 | + # self.proxies={'http': 'http://localhost:8888', 'https': 'http://localhost:8888'} | |
54 | + self.myproxies={'http': 'http://localhost:8888', 'https': 'http://localhost:8888'} | |
55 | + self.allow_redirects = False | |
56 | + self.firmid={"group":"1","hd":"2","cd":"3","qqhe":"4","mdj":"5","gy":"6","cc":"7","sg":"8","sy":"9"} | |
57 | + self.market={"sy":"沈阳","heb":"哈尔滨","sg":"寿光","gy":"贵阳","cc":"长春","hs":"杭水","hg":"杭果"} | |
58 | + self.user={} | |
59 | + | |
60 | + def cliLogin(self,user="sy_userName_01"): | |
61 | + self.webHeaders, self.clientHeaders, self.userInfo = cliSession().loginUser(user=user) | |
62 | + return self | |
63 | + | |
64 | + def get_session(self, account, **kwargs): | |
65 | + "如下代码,可以通过配置文件来控制登录的账户session" | |
66 | + self.body = self.body.replace("sg_wenze", | |
67 | + com.get_global_config("global_data", "account", account).split("&")[0]) | |
68 | + self.body = self.body.replace("111111", | |
69 | + com.get_global_config("global_data", "account", account).split("&")[1]) | |
70 | + self.se = requests.session() | |
71 | + co = requests.cookies.RequestsCookieJar() | |
72 | + #加入UAP_firmId属性 | |
73 | + firm=account.split("_")[0] | |
74 | + co.set("UAP_firmId", self.firmid[firm]) | |
75 | + self.se.cookies.update(co) | |
76 | + # 进行登录请求 | |
77 | + re = self.se.post(url=self.url, headers=self.header, data=self.body, proxies=self.proxies, **kwargs) | |
78 | + self.UAP_accessToken=self.se.cookies["UAP_accessToken"] | |
79 | + self.UAP_refreshToken=self.se.cookies["UAP_refreshToken"] | |
80 | + return self.se | |
81 | + | |
82 | + def get_login_info(self, account, **kwargs): | |
83 | + "用于获取用户信息" | |
84 | + self.body_client.update({"userName":com.get_global_config("global_data", "account", account).split("&")[0]}) | |
85 | + self.body_client.update({"password":pwdCry(com.get_global_config("global_data", "account", account).split("&")[1])}) | |
86 | + tmp = requests.post(url=self.url_client, headers=self.header_client, json=self.body_client, proxies=self.proxies, **kwargs) | |
87 | + return tmp | |
88 | + | |
89 | + def get_session_client(self, account, **kwargs): | |
90 | + "get_session和get_session_client的方法只能用一个" | |
91 | + self.body_client.update({"userName": com.get_global_config("global_data", "account", account).split("&")[0]}) | |
92 | + self.body_client.update( {"password": pwdCry(com.get_global_config("global_data", "account", account).split("&")[1])}) | |
93 | + # 登录请求 | |
94 | + self.re = super().post(url=self.url_client, headers=self.header_client, json=self.body_client, **kwargs) | |
95 | + #冗余登录账户信息 | |
96 | + self.user[account]=self.re.json()["data"]["user"] | |
97 | + #配置cookie | |
98 | + co = requests.cookies.RequestsCookieJar() | |
99 | + co.set("UAP_firmId", str(self.re.json()["data"]["user"]["firmId"]),domain=".diligrp.com") | |
100 | + co.set("UAP_accessToken", self.re.json()["data"]["accessToken"],domain=".diligrp.com") | |
101 | + co.set("UAP_refreshToken", self.re.json()["data"]["refreshToken"],domain=".diligrp.com") | |
102 | + self.cookies.update(co) | |
103 | + return self | |
104 | + | |
105 | + def close_session(self): | |
106 | + "关闭session" | |
107 | + self.close() | |
108 | + | |
109 | + def check_login(self, account, **kwargs): | |
110 | + "验证登录接口" | |
111 | + self.body = self.body.replace("sg_wenze", | |
112 | + com.get_global_config("global_data", "account", account).split("&")[0]) | |
113 | + self.body = self.body.replace("111111", com.get_global_config("global_data", "account", account).split("&")[1]) | |
114 | + # POST请求 | |
115 | + print(self.body) | |
116 | + re = super().post(url=self.url, headers=self.header, data=self.body.encode('utf-8'), | |
117 | + allow_redirects=False, **kwargs) | |
118 | + # 判断请求 | |
119 | + assert "UAP_accessToken" in re.headers["Set-Cookie"] | |
120 | + assert "UAP_refreshToken" in re.headers["Set-Cookie"] | |
121 | + assert "UAP_loginPath" in re.headers["Set-Cookie"] | |
122 | + print("登录接口验证成功") | |
123 | + return re | |
124 | + | |
125 | + def useHeadersRequests(self, method=None, url=None, headers=None, data=None, **kwargs): | |
126 | + """ | |
127 | + 模拟客户端接口操作,使用headers进行cookies传递,调用requests库进行接口访问 | |
128 | + :param method:接口请求方式,POST,GET等 | |
129 | + :param url:接口路径 | |
130 | + :param data:接口数据 | |
131 | + :kwargs:其他requests.request()支持参数可以直接传递 | |
132 | + """ | |
133 | + print(url) | |
134 | + # print(headers) | |
135 | + print(data) | |
136 | + log.info("{0:=^86}".format('')) | |
137 | + log.info("{}\n{}\n{}\n".format(url, data, kwargs)) | |
138 | + if "gateway" in url: | |
139 | + # 判断接口路径,通过接口路径钟是否包含gateway来判定接口是否是由客户端进行访问,来判定headers使用 | |
140 | + self.clientHeaders = dict(self.clientHeaders, **headers) | |
141 | + res = requests.request(method=method, url=url, data=data, headers=self.clientHeaders, **kwargs) | |
142 | + else: | |
143 | + self.webHeaders = dict(self.webHeaders, **headers) | |
144 | + res = requests.request(method=method, url=url, data=data, headers=self.webHeaders, **kwargs) | |
145 | + return res | |
146 | + | |
147 | + | |
148 | + def request(self, method ,url, **kwargs): | |
149 | + """:param method: method for the new :class:`Request` object: | |
150 | + ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. | |
151 | + """ | |
152 | + # 记录日志 | |
153 | + log.info("{0:=^86}".format('')) | |
154 | + log.info("{}\n{}\n".format(url, kwargs)) | |
155 | + # 进行请求 | |
156 | + re = super().request(method , url, **kwargs,timeout=self.timeout) | |
157 | + return re | |
158 | + | |
159 | + | |
160 | + def get(self, url, **kwargs): | |
161 | + """Sends a GET request. Returns :class:`Response` object. | |
162 | + | |
163 | + :param url: URL for the new :class:`Request` object. | |
164 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
165 | + :rtype: requests.Response | |
166 | + """ | |
167 | + # 进行请求 | |
168 | + re = super().get(url, **kwargs) | |
169 | + return re | |
170 | + | |
171 | + def post(self, url, data=None, json=None, **kwargs): | |
172 | + """Sends a POST request. Returns :class:`Response` object. | |
173 | + :param url: URL for the new :class:`Request` object. | |
174 | + :param data: (optional) Dictionary, list of tuples, bytes, or file-like | |
175 | + object to send in the body of the :class:`Request`. | |
176 | + :param json: (optional) json to send in the body of the :class:`Request`. | |
177 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
178 | + :rtype: requests.Response | |
179 | + """ | |
180 | + # 进行请求 | |
181 | + re = super().post(url, data=data, json=json, **kwargs) | |
182 | + return re | |
183 | + | |
184 | + def options(self, url, **kwargs): | |
185 | + """Sends a OPTIONS request. Returns :class:`Response` object. | |
186 | + :param url: URL for the new :class:`Request` object. | |
187 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
188 | + :rtype: requests.Response | |
189 | + """ | |
190 | + # 记录日志 | |
191 | + log.info(url, kwargs) | |
192 | + # 进行请求 | |
193 | + re = self.se.options(url, **kwargs) | |
194 | + return re | |
195 | + | |
196 | + def head(self, url, **kwargs): | |
197 | + """Sends a HEAD request. Returns :class:`Response` object. | |
198 | + | |
199 | + :param url: URL for the new :class:`Request` object. | |
200 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
201 | + :rtype: requests.Response | |
202 | + """ | |
203 | + # 记录日志 | |
204 | + log.info(url, kwargs) | |
205 | + # 进行请求 | |
206 | + re = self.se.head(url, **kwargs) | |
207 | + return re | |
208 | + | |
209 | + def put(self, url, data=None, **kwargs): | |
210 | + """Sends a PUT request. Returns :class:`Response` object. | |
211 | + :param url: URL for the new :class:`Request` object. | |
212 | + :param data: (optional) Dictionary, list of tuples, bytes, or file-like | |
213 | + object to send in the body of the :class:`Request`. | |
214 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
215 | + :rtype: requests.Response | |
216 | + """ | |
217 | + # 记录日志 | |
218 | + log.info(url, data, kwargs) | |
219 | + # 进行请求 | |
220 | + re = self.se.put(url, data, **kwargs) | |
221 | + return re | |
222 | + | |
223 | + def delete(self, url, **kwargs): | |
224 | + """Sends a DELETE request. Returns :class:`Response` object. | |
225 | + :param url: URL for the new :class:`Request` object. | |
226 | + :param \*\*kwargs: Optional arguments that ``request`` takes. | |
227 | + :rtype: requests.Response | |
228 | + """ | |
229 | + # 记录日志 | |
230 | + log.info(url, kwargs) | |
231 | + # 进行请求 | |
232 | + re = self.se.delete(url, **kwargs) | |
233 | + return re | |
234 | + | |
235 | + def set_mark(self): | |
236 | + "用户自定义优先级方法" | |
237 | + mark_list = eval(com.get_global_config("global_data", "mark", "list")) | |
238 | + print("预设运行标记:", mark_list) | |
239 | + global _global_mark | |
240 | + if type(mark_list) == type([]) and len(mark_list) != 0: | |
241 | + _global_mark = mark_list | |
242 | + return _global_mark | |
243 | + elif type(mark_list) == type([]) and len(mark_list) == 0: | |
244 | + _global_mark = False | |
245 | + return _global_mark | |
246 | + else: | |
247 | + raise Exception("error,pls check mark data") | |
248 | + | |
249 | + def mark(self, m=None): | |
250 | + try: | |
251 | + # 没有输入任何预设值,默认跑全部 | |
252 | + if _global_mark == False: | |
253 | + return True | |
254 | + # 输入预设值且未标记用例,默认跑全部 | |
255 | + elif _global_mark != False and (m in _global_mark) or len([tag for tag in m if tag in _global_mark]) >0: | |
256 | + return True | |
257 | + else: | |
258 | + return False | |
259 | + except Exception as e: | |
260 | + return False | |
261 | + | |
262 | + | |
263 | +my = mysession() | |
264 | +my.set_mark() | |
265 | + | |
266 | +# 沈阳客户端session | |
267 | +sessionSy = mysession().cliLogin("sy_userName_01") | |
268 | +# 哈尔滨客户端session | |
269 | +sessionHeb = mysession().cliLogin("hd_userName_01") | |
270 | +# print(sessionSy.userInfo) | |
271 | +# print(sessionHeb.userInfo) | |
272 | + | |
273 | +sy1=mysession().get_session_client("sy_user01") | |
274 | +heb=mysession().get_session_client("heb_user01") | |
275 | +# sg=mysession().get_session_client("sg_user01") | |
276 | + | ... | ... |
commons/SendEmail.py
0 → 100644
1 | +++ a/commons/SendEmail.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import os | |
4 | +import smtplib | |
5 | +from email.mime.multipart import MIMEMultipart | |
6 | +from email.header import Header | |
7 | +from email.mime.text import MIMEText | |
8 | +from email.mime.image import MIMEImage | |
9 | +from email.mime.application import MIMEApplication | |
10 | +from commons.Logging import log | |
11 | + | |
12 | +def send_email_text(): | |
13 | + # 1. 编写邮件内容(Email邮件需要专门的MIME格式) | |
14 | + msg = MIMEText('this is a test email', 'plain', 'utf-8') | |
15 | + | |
16 | + # 2. 组装Email头(发件人,收件人,主题) | |
17 | + msg['From'] = 'autotest@diligrp.com' # 发件人 | |
18 | + msg['To'] = 'lixi@diligrp.com' # 收件人 | |
19 | + msg['Subject'] = 'Api Test Report' # 邮件主题 | |
20 | + | |
21 | + # 3. 连接smtp服务器并发送邮件 | |
22 | + smtp = smtplib.SMTP_SSL('smtp.exmail.qq.com') | |
23 | + smtp.login('autotest@diligrp.com', 'MvkuGGCfMtAdbJvE') | |
24 | + smtp.sendmail("autotest@diligrp.com", "lixi@diligrp.com", msg.as_string()) | |
25 | + smtp.quit() | |
26 | + | |
27 | + | |
28 | +def send_email(send_file,send_to=["lixi@diligrp.com"],cc_to=["lixi@diligrp.com"]): | |
29 | + | |
30 | + log_path=os.path.dirname(os.path.dirname(__file__)) | |
31 | + log_path=log_path+"/report/test.log" | |
32 | + send_msg=(",".join(str(i) for i in send_to)) | |
33 | + cc_msg = (",".join(str(j) for j in cc_to)) | |
34 | + msg = MIMEMultipart() # 混合MIME格式 | |
35 | + msg['From'] = 'autotest@diligrp.com' # 发件人 | |
36 | + msg['To'] = send_msg # 收件人 | |
37 | + msg['cc'] = cc_msg # 抄送人 | |
38 | + msg['Subject'] = Header('接口测试报告', 'utf-8') # 中文邮件主题,指定utf-8编码 | |
39 | + | |
40 | + text = MIMEText('this is a test email', 'plain', 'utf-8') | |
41 | + msg.attach(MIMEText(open(send_file,'rb' ).read(), 'html', 'utf-8')) | |
42 | + | |
43 | + att1 = MIMEText(open(send_file, 'rb').read(), 'base64', 'utf-8') | |
44 | + att1["Content-Disposition"] = 'attachment; filename="report.html"' | |
45 | + | |
46 | + att2 = MIMEText(open(log_path, 'rb').read(), 'base64', 'utf-8') | |
47 | + att2["Content-Type"] = 'application/octet-stream' | |
48 | + att2["Content-Disposition"] = 'attachment; filename="test.log"' | |
49 | + msg.attach(text) | |
50 | + msg.attach(att1) | |
51 | + msg.attach(att2) | |
52 | + | |
53 | + #一下发送日志不会在test.log上,因为提前msg.attach了 | |
54 | + log.info("发送邮件") | |
55 | + try: | |
56 | + smtp = smtplib.SMTP_SSL('smtp.exmail.qq.com') # smtp服务器地址 使用SSL模式 | |
57 | + re=smtp.login('autotest@diligrp.com', 'MvkuGGCfMtAdbJvE') # 用户名和密码 | |
58 | + smtp.sendmail("autotest@diligrp.com", send_to+cc_to, msg.as_string()) | |
59 | + print(re) | |
60 | + except Exception as e: | |
61 | + log.error(str(e)) | |
62 | + print(e) | |
63 | + finally: | |
64 | + smtp.quit() | |
65 | + log.info("邮件发送完毕") | ... | ... |
commons/__init__.py
0 → 100644
commons/api/__init__.py
0 → 100644
commons/basic/__init__.py
0 → 100644
1 | +++ a/commons/basic/__init__.py | ... | ... |
commons/clientSession.py
0 → 100644
1 | +++ a/commons/clientSession.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/7/16 10:23 | |
4 | +# @Author : Ljq | |
5 | +# @File : clientSession.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | + | |
10 | +""" | |
11 | + | |
12 | +import requests | |
13 | +import json | |
14 | +from commons.scripts.readConf import readConfig | |
15 | +from commons.scripts.pwdCry import pwdCry | |
16 | + | |
17 | +class cliSession(object): | |
18 | + def __init__(self): | |
19 | + self.rC = readConfig() | |
20 | + self.webHeaders = {"X-Requested-With":"XMLHttpRequest", | |
21 | + "Content-Type":"application/x-www-form-urlencoded", | |
22 | + "Cookie":"UAP_accessToken=${UAP_accessToken}; UAP_refreshToken=${UAP_refreshToken};UAP_firmId=${UAP_firmId}"} | |
23 | + self.clientHeaders={"UAP_accessToken":"${UAP_accessToken}", | |
24 | + "UAP_refreshToken":"${UAP_refreshToken}", | |
25 | + "UAP_firmId":"${UAP_firmId}", | |
26 | + "Cookie":"UAP_accessToken=${UAP_accessToken}; UAP_refreshToken=${UAP_refreshToken}", | |
27 | + "Content-Type":"application/json"} | |
28 | + | |
29 | + | |
30 | + def loginUser(self,user="sy_userName_01"): | |
31 | + """ | |
32 | + :return: | |
33 | + """ | |
34 | + # 登录信息准备 | |
35 | + self.userName,self.password = self.rC.returnOptionsItems("loginInfo",user).split(",") | |
36 | + self.password = pwdCry(self.password) | |
37 | + self.loginUrl = self.rC.returnOptionsItems("host","uapHost")+"/api/authenticationApi/loginWeb" | |
38 | + self.loginData = {"userName":self.userName,"password":self.password} | |
39 | + | |
40 | + # 返回登录信息,以及可用headers,clientHeaders用户客户端操作header,webHeaders用于web页面使用headers | |
41 | + res = requests.post(url=self.loginUrl,data=json.dumps(self.loginData)) | |
42 | + # print(res.json()) | |
43 | + UAP_accessToken,UAP_refreshToken,UAP_firmId=res.json()["data"]["accessToken"],res.json()["data"]["refreshToken"],res.json()["data"]["user"]["firmId"] | |
44 | + webHeadersCookie = "UAP_accessToken="+UAP_accessToken+"; UAP_refreshToken="+UAP_refreshToken+";UAP_firmId="+str(UAP_firmId) | |
45 | + clientHeadersCookie = "UAP_accessToken="+UAP_accessToken+"; UAP_refreshToken="+UAP_refreshToken | |
46 | + self.webHeaders["Cookie"] = webHeadersCookie | |
47 | + self.clientHeaders["UAP_accessToken"] = UAP_accessToken | |
48 | + self.clientHeaders["UAP_refreshToken"]= UAP_refreshToken | |
49 | + self.clientHeaders["UAP_firmId"] = str(UAP_firmId) | |
50 | + self.clientHeaders["Cookie"] = clientHeadersCookie | |
51 | + return self.webHeaders,self.clientHeaders,res.json() | |
52 | + | |
53 | +# a,b,c = cliSession().loginUser() | |
54 | +# print(c) | |
0 | 55 | \ No newline at end of file | ... | ... |
commons/common.py
0 → 100644
1 | +++ a/commons/common.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import os | |
4 | +import configparser | |
5 | +import unittest | |
6 | +from discover import DiscoveringTestLoader | |
7 | +from commons.Logging import log | |
8 | + | |
9 | + | |
10 | +def get_global_config(file,section, key): | |
11 | + "object file is *src/config/global_data.conf" | |
12 | + current_path=os.path.dirname(__file__) | |
13 | + src_path=os.path.dirname(current_path) | |
14 | +# global_setting_path=src_path+'/config/global_data.conf' | |
15 | + global_setting_path=src_path+'/config/'+file+".conf" | |
16 | + #验证文件是否存在 | |
17 | + file_path = os.path.exists(global_setting_path) | |
18 | + if file_path: | |
19 | + #获取文件的数据 | |
20 | + if isinstance(key,int): | |
21 | + log.error("key of section cannot be int Type :<%r> "%str(key)) | |
22 | + raise Exception("key of section cannot be int Type :<%r> "%str(key)) | |
23 | + else: | |
24 | + config = configparser.ConfigParser() | |
25 | + config.read(global_setting_path,encoding="utf-8") | |
26 | + return config.get(section, key) | |
27 | + else: | |
28 | + log.error("File Not Exist :<%r> "%str(global_setting_path)) | |
29 | + raise Exception("File Not Exist :<%r> "%str(global_setting_path)) | |
30 | + | |
31 | + | |
32 | +def get_api_config(api,section,key): | |
33 | + "object file is *src/config/api/*.conf" | |
34 | + current_path=os.path.dirname(__file__) | |
35 | + src_path=os.path.dirname(current_path) | |
36 | + api_path=src_path+"/config/api/" | |
37 | + api_config_path=api_path+api+".conf" | |
38 | + #验证文件是否存在 | |
39 | + file_path = os.path.exists(api_config_path) | |
40 | + if file_path: | |
41 | + #获取文件的数据 | |
42 | + if isinstance(key,int): | |
43 | + log.error("key of section cannot be int Type :<%r> "%str(key)) | |
44 | + raise Exception("key of section cannot be int Type :<%r> "%str(key)) | |
45 | + else: | |
46 | + config = configparser.ConfigParser() | |
47 | + config.read(api_config_path,encoding="utf-8") | |
48 | + return config.get(section, key) | |
49 | + else: | |
50 | + log.error("File Not Exist :<%r> "%str(api_config_path)) | |
51 | + raise Exception("File Not Exist :<%r> "%str(api_config_path)) | |
52 | + | |
53 | +def get_market_config(api,section,key): | |
54 | + "object file is *src/config/marketConfig/*.conf" | |
55 | + current_path=os.path.dirname(__file__) | |
56 | + src_path=os.path.dirname(current_path) | |
57 | + api_path=src_path+"/config/marketConfig/" | |
58 | + api_config_path=api_path+api+".conf" | |
59 | + #验证文件是否存在 | |
60 | + file_path = os.path.exists(api_config_path) | |
61 | + if file_path: | |
62 | + #获取文件的数据 | |
63 | + if isinstance(key,int): | |
64 | + log.error("key of section cannot be int Type :<%r> "%str(key)) | |
65 | + raise Exception("key of section cannot be int Type :<%r> "%str(key)) | |
66 | + else: | |
67 | + config = configparser.ConfigParser() | |
68 | + config.read(api_config_path,encoding="utf-8") | |
69 | + return config.get(section, key) | |
70 | + else: | |
71 | + log.error("File Not Exist :<%r> "%str(api_config_path)) | |
72 | + raise Exception("File Not Exist :<%r> "%str(api_config_path)) | |
73 | + | |
74 | + | |
75 | + | |
76 | +def run_one(name): | |
77 | + test_suite = unittest.TestSuite() | |
78 | + #创建测试套 | |
79 | + test_suite.addTest(name) | |
80 | + #显示运行用例 | |
81 | + print("运行用例为{}".format(test_suite)) | |
82 | + runner = unittest.TextTestRunner() | |
83 | + runner.run(test_suite) | |
84 | + | |
85 | + | |
86 | +def run_list(name): | |
87 | + test_suite = unittest.TestSuite() | |
88 | + test_suite.addTests(name) | |
89 | + #显示运行用例 | |
90 | + print("运行用例为{}".format(test_suite)) | |
91 | + # with open(file="E:\\PycharmWorkspace\\jmsf-re-local\\report\\test.log", mode="a", encoding="utf-8") as file: | |
92 | + # runner = unittest.TextTestRunner(stream=file,verbosity=2) | |
93 | + # runner.run(test_suite) | |
94 | + runner = unittest.TextTestRunner() | |
95 | + runner.run(test_suite) | |
96 | + | |
97 | +def run_class(name): | |
98 | + test_cases = unittest.TestLoader().loadTestsFromTestCase(name) | |
99 | + #显示运行用例 | |
100 | + print("运行用例为{}".format(test_cases)) | |
101 | + runner = unittest.TextTestRunner() | |
102 | + runner.run(test_cases) | |
103 | + | |
104 | +def run_Module(name): | |
105 | + test_cases = unittest.TestLoader().loadTestsFromModule(name) | |
106 | + #显示运行用例 | |
107 | + print("运行用例为{}".format(test_cases)) | |
108 | + runner = unittest.TextTestRunner() | |
109 | + runner.run(test_cases) | |
110 | + | |
111 | +def run_Name(name): | |
112 | + test_cases = unittest.TestLoader().loadTestsFromName(name) | |
113 | + #显示运行用例 | |
114 | + print("运行用例为{}".format(test_cases)) | |
115 | + runner = unittest.TextTestRunner() | |
116 | + runner.run(test_cases) | |
117 | + | |
118 | +def mylog(func): | |
119 | + def RebackTest(self): | |
120 | + log.info("{}".format(func.__name__)) | |
121 | + return func(self) | |
122 | + return RebackTest | |
0 | 123 | \ No newline at end of file | ... | ... |
commons/scripts/__init__.py
0 → 100644
commons/scripts/createIdNum.py
0 → 100644
1 | +++ a/commons/scripts/createIdNum.py | |
1 | +#coding=utf-8 | |
2 | + | |
3 | +# @Time : 2021/5/26 11:19 | |
4 | +# @Author : Ljq | |
5 | +# @File : createIdNum.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | + | |
9 | +""" | |
10 | + 生成身份证号 | |
11 | +""" | |
12 | + | |
13 | +import time | |
14 | +import random | |
15 | + | |
16 | + | |
17 | +def cIN(): | |
18 | + """ | |
19 | + 身份证号生成 | |
20 | + :return: | |
21 | + """ | |
22 | + # 拼接备用身份证号 | |
23 | + area,birthday,policeStationCode,sex = 110101,time.strftime("%Y%m%d", time.localtime()),random.randint(10,99),random.randint(0,9) | |
24 | + idNum_str = f"{area}{birthday}{policeStationCode}{sex}" | |
25 | + basecCode = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] | |
26 | + checkCode = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"] | |
27 | + num = 0 | |
28 | + for i in range(17): | |
29 | + num = num + basecCode[i] * int(idNum_str[i]) | |
30 | + return f"{idNum_str}{checkCode[num % 11]}" | |
31 | +# | |
32 | +# print(cIN()) | |
0 | 33 | \ No newline at end of file | ... | ... |
commons/scripts/dealContentType.py
0 → 100644
1 | +++ a/commons/scripts/dealContentType.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/7/16 14:51 | |
4 | +# @Author : Ljq | |
5 | +# @File : dealContentType.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | + 用于hearders中Content-Type格式处理 | |
10 | +""" | |
11 | + | |
12 | +def jsonCode(headers={}): | |
13 | + headers["Content-Type"] = "application/json; charset=UTF-8" | |
14 | + return headers | |
15 | + | |
16 | +def urlCode(headers={}): | |
17 | + headers["Content-Type"] = "application/x-www-form-urlencoded" | |
18 | + return headers | |
0 | 19 | \ No newline at end of file | ... | ... |
commons/scripts/delReport.py
0 → 100644
1 | +++ a/commons/scripts/delReport.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/7/19 14:35 | |
4 | +# @Author : Ljq | |
5 | +# @File : delectReport.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | +用于删除多余的报告文件 | |
10 | +""" | |
11 | + | |
12 | +import os,sys | |
13 | + | |
14 | +def path_route(path): | |
15 | + if "report" not in os.listdir(path): | |
16 | + return path_route(os.path.abspath(os.path.join(path, "../"))) | |
17 | + else: | |
18 | + return path | |
19 | + | |
20 | +def delReport(path,delNum=5): | |
21 | + report_path = path_route(path) + "/report/" | |
22 | + file_list = os.listdir(report_path) | |
23 | + print("befor sort file_lis --- ", file_list) | |
24 | + if len(file_list) > delNum: | |
25 | + file_list.sort(key=lambda file_name: os.path.getmtime(report_path + file_name)) | |
26 | + print("after sort file_lis --- ", file_list) | |
27 | + file_list = file_list[:0-delNum] | |
28 | + # print("if file_lis --- ",file_list) | |
29 | + for i in file_list: | |
30 | + if os.path.isfile(report_path + i) and ".html" in i: | |
31 | + os.remove(report_path + i) | |
32 | + print(f"删除报告 {i} 成功") | |
33 | + # 文件已删除 | |
34 | + print("多余的报告文件已删除") | |
35 | + else: | |
36 | + print("没有需要删除的文件") | |
0 | 37 | \ No newline at end of file | ... | ... |
commons/scripts/jsonToUrlcode.py
0 → 100644
1 | +++ a/commons/scripts/jsonToUrlcode.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/8/4 14:33 | |
4 | +# @Author : Ljq | |
5 | +# @File : jsonToUrlcode.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | + | |
10 | +""" | |
11 | + | |
12 | +import urllib.parse | |
13 | + | |
14 | +def jsonToUrlcode(data_json={}): | |
15 | + """json格式数据转换未urlcode格式数据""" | |
16 | + data_uc = "" | |
17 | + for k, v in data_json.items(): | |
18 | + data_uc = data_uc + str(k) + "=" + urllib.parse.quote(str(v)) + "&" | |
19 | + print(data_uc) | |
20 | + return data_uc | |
21 | + | |
22 | +# data_json = {"a": "a1", "b": "b1"} | |
23 | +# print(jsonToUrlcode(data_json)) | |
0 | 24 | \ No newline at end of file | ... | ... |
commons/scripts/pwdCry.py
0 → 100644
1 | +++ a/commons/scripts/pwdCry.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/7/20 10:36 | |
4 | +# @Author : Ljq | |
5 | +# @File : pwdCry.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | + | |
10 | +""" | |
11 | + | |
12 | +import base64 | |
13 | +from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5 | |
14 | +from Crypto.PublicKey import RSA | |
15 | + | |
16 | +def pwdCry(string): | |
17 | + public_key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgN7kda5L4ztOUquoHjubQIEyqBpjpaYeq+DBKXA3JNOZsMjGwLGVqfCwQg3HHAGTaWnxsp5gjmh0tSziJFgQf2u45TqA2UObOvklRhbWr56QoTNsjm72wZoSOlUzW3xHi/6PocHdy/7bMOiDf6fmYhFBZdRleX6tCAp7w6DsdbQIDAQAB' | |
18 | + key = '-----BEGIN PUBLIC KEY-----\n' + public_key + '\n-----END PUBLIC KEY-----' | |
19 | + rsakey = RSA.importKey(key) | |
20 | + cipher = Cipher_pksc1_v1_5.new(rsakey) | |
21 | + encrypt_text = cipher.encrypt(string.encode("utf-8")) | |
22 | + cipher_text = base64.b64encode(encrypt_text) | |
23 | + return cipher_text.decode() | |
0 | 24 | \ No newline at end of file | ... | ... |
commons/scripts/readConf.py
0 → 100644
1 | +++ a/commons/scripts/readConf.py | |
1 | +# -*- coding: utf-8 -*- | |
2 | + | |
3 | +# @Time : 2021/7/16 10:36 | |
4 | +# @Author : Ljq | |
5 | +# @File : readConf.py | |
6 | +# @Software: PyCharm | |
7 | + | |
8 | +""" | |
9 | +配置文件读取 | |
10 | +""" | |
11 | +import configparser | |
12 | +import os | |
13 | + | |
14 | +class readConfig(object): | |
15 | + ROBOT_LIBRARY_SCOPE = 'TEST CASE' | |
16 | + ROBOT_LIBRARY_VERSION = '0.1' | |
17 | + | |
18 | + def __init__(self): | |
19 | + # 按市场读取配置文件数据 | |
20 | + self.conf = configparser.ConfigParser() | |
21 | + self.evn_name = os.name | |
22 | + self.file_name = r'conf_test.conf' | |
23 | + self.relative_path = r'/config/marketConfig/' | |
24 | + self.file_path = os.path.abspath( | |
25 | + os.path.join(os.path.dirname(__file__), "../../")) + self.relative_path + self.file_name | |
26 | + print(self.file_path) | |
27 | + self.conf.read(self.file_path,encoding="utf-8") | |
28 | + | |
29 | + def returnSections(self): | |
30 | + # 读取所有的options选项 | |
31 | + sections = self.conf.sections() | |
32 | + print(sections) | |
33 | + return sections | |
34 | + | |
35 | + def returnOptions(self,options): | |
36 | + # 通过options读取所有items | |
37 | + options = self.conf.options(options) | |
38 | + print(options) | |
39 | + return options | |
40 | + | |
41 | + def returnOptionsInfo(self,options): | |
42 | + # 通过options读取相关的items和value | |
43 | + items = self.conf.items(options) | |
44 | + print(items) | |
45 | + | |
46 | + def returnOptionsItems(self,options,items): | |
47 | + # 通过options和items的组合关系读取对应的value | |
48 | + value = self.conf.get(options,items) | |
49 | + print(value) | |
50 | + return value | |
51 | + | |
52 | + def ReturnFilePath(self): | |
53 | + print(self.file_path) | |
54 | + return self.file_path | |
55 | + | |
56 | +rC = readConfig() | |
57 | +# rc.returnSections() | |
58 | +# rc.returnOptions("loginInfo") | |
59 | +# rc.returnOptionsInfo("loginInfo") | |
60 | +# rc.returnOptionsItems("loginInfo","username") | |
61 | +# rc.ReturnFilePath() | |
0 | 62 | \ No newline at end of file | ... | ... |
config/__init__.py
0 → 100644
1 | +++ a/config/__init__.py | ... | ... |
config/api/__init__.py
0 → 100644
1 | +++ a/config/api/__init__.py | ... | ... |
config/api/customer.conf
0 → 100644
1 | +++ a/config/api/customer.conf | |
1 | +# -*- coding: UTF-8 -*- | |
2 | +[fieldConfig] | |
3 | +method=post | |
4 | +url=http://test.trace.diligrp.com:8393/fieldConfig/doUpdate.action | |
5 | +body_format=JSON | |
6 | + | |
7 | +header={ | |
8 | + "Host": "test.trace.diligrp.com", | |
9 | + "Connection": "keep-alive", | |
10 | + "Content-Length": "325", | |
11 | + "Accept": "application/json,text/javascript,*/*;q=0.01", | |
12 | + "X-Requested-With": "XMLHttpRequest", | |
13 | + "User-Agent": "Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/90.0.4430.212Safari/537.36", | |
14 | + "Content-Type": "application/json", | |
15 | + "Origin": "http://test.trace.diligrp.com:8393", | |
16 | + "Referer": "http://test.trace.diligrp.com:8393/upStream/index.html", | |
17 | + "Accept-Encoding": "gzip,deflate", | |
18 | + "Accept-Language": "zh-CN,zh-TW;q=0.9,zh;q=0.8,en;q=0.7"} | |
19 | + | |
20 | +[fieldConfig01] | |
21 | +body={"rows":10,"page":1,"sort":"id","order":"desc","metadata":{"created":"{\"provider\":\"datetimeProvider\",\"index\":10,\"field\":\"created\"}","upORdown":"{\"provider\":\"userFlagProvider\",\"index\":20,\"field\":\"upORdown\"}","upstreamType":"{\"provider\":\"upStreamTypeProvider\",\"index\":30,\"field\":\"upstreamType\"}"}} | |
22 | + | |
23 | + | |
24 | +[fieldConfig02] | |
25 | +body={"rows":10,"page":1,"sort":"id","order":"desc","metadata":{"created":"{\"provider\":\"datetimeProvider\",\"index\":10,\"field\":\"created\"}","upORdown":"{\"provider\":\"userFlagProvider\",\"index\":20,\"field\":\"upORdown\"}","upstreamType":"{\"provider\":\"upStreamTypeProvider\",\"index\":30,\"field\":\"upstreamType\"}"}} | |
26 | + | |
27 | + | |
28 | +[fieldConfig03] | |
29 | +body={"rows":10,"page":1,"sort":"id","order":"desc","metadata":{"created":"{\"provider\":\"datetimeProvider\",\"index\":10,\"field\":\"created\"}","upORdown":"{\"provider\":\"userFlagProvider\",\"index\":20,\"field\":\"upORdown\"}","upstreamType":"{\"provider\":\"upStreamTypeProvider\",\"index\":30,\"field\":\"upstreamType\"}"}} | |
30 | + | |
31 | + | |
32 | + | |
33 | + | |
34 | + | ... | ... |
config/api/sy/__init__.py
0 → 100644
1 | +++ a/config/api/sy/__init__.py | ... | ... |
config/global_data.conf
0 → 100644
1 | +++ a/config/global_data.conf | |
1 | +# -*- coding: UTF-8 -*- | |
2 | + | |
3 | +[market] | |
4 | +#该字段存放市场的缩略名称,运行指定市场的用例,目前为着冗余配置 | |
5 | +#list为空时,默认运行所有市场用例,需要指定市场时,参考demo格式 | |
6 | +list=[] | |
7 | +demo=["sy","heb"] | |
8 | + | |
9 | +[account] | |
10 | +#取值字段根据市场拼音首字母缩写组合而成,尾号数字按照01-99叠加 | |
11 | +#账户和密码通过&符号隔开 | |
12 | +sy_user01=sy_chen&123456 | |
13 | +sy_user02=sygangda&111111 | |
14 | +heb_user01=哈尔滨田太子&a123456 | |
15 | +heb_user02=sy_wenze&111111 | |
16 | +sg_user01=sg_wenze&111111 | |
17 | + | |
18 | +[userId] | |
19 | +#冗余配置字段,可不配置 | |
20 | +user01=210 | |
21 | +user02=87 | |
22 | +user03=256 | |
23 | + | |
24 | +[email] | |
25 | +#为空时[]不发邮件,若要发邮件,参考demo | |
26 | +to_list=["lixi@diligrp.com","liujiqiang@diligrp.com","wenleiming@diligrp.com"] | |
27 | +cc_list=["demo@diligrp.com"] | |
28 | +demo=["lixi@diligrp.com","liujiqiang@diligrp.com","wenleiming@diligrp.com","tg@diligrp.com"] | |
29 | + | |
30 | +[mark] | |
31 | +#为空时[]运行所有用例,若要运行指定用例,参考demo | |
32 | +list=[] | |
33 | +demo=["heb1","P3","v1.6","沈阳",None] | |
34 | + | |
35 | + | |
36 | +[environment] | |
37 | +#格式只能为一下几种 | |
38 | +#http://test. | |
39 | +#https://test. | |
40 | +#http:// | |
41 | +#https:// | |
42 | +en=http://test. | |
43 | + | |
44 | + | |
45 | +[Database] | |
46 | +dbhost=10.35.100.34 | |
47 | +dbport=3306 | |
48 | +dbname=dili_jmsf | |
49 | +dbuser=root | |
50 | +dbpassword=123456 | |
51 | +dbcharset=utf8 | |
52 | + | |
53 | + | |
54 | +[host] | |
55 | +gateway=test.gateway.diligrp.com:8285 | |
56 | + | |
57 | + | |
58 | + | |
59 | + | |
60 | + | |
61 | + | |
62 | + | |
63 | + | ... | ... |
config/marketConfig/__init__.py
0 → 100644
config/marketConfig/conf_pre.conf
0 → 100644
1 | +++ a/config/marketConfig/conf_pre.conf | |
1 | +#登录信息 | |
2 | +[loginInfo] | |
3 | +sy_userName_01=scgy,123123 | |
4 | +hd_userName_01=哈尔滨田太子,a123456 | |
5 | + | |
6 | +# 测试依赖信息 | |
7 | +[testInfo] | |
8 | +#sy | |
9 | +sy_cardNumRe_01=888810033081 | |
10 | +#hd | |
11 | +hd_cardNumRe_01=210823173732 | |
12 | + | |
13 | + | |
14 | +[host] | |
15 | +cardHost=http://test.card.diligrp.com:8386 | |
16 | +uapHost=http://test.uap.diligrp.com | |
17 | +gatewayHost=http://test.gateway.diligrp.com:8285 | |
18 | +jmsfHost=http://test.jmsf.diligrp.com:8385 | |
0 | 19 | \ No newline at end of file | ... | ... |
config/marketConfig/conf_test.conf
0 → 100644
1 | +++ a/config/marketConfig/conf_test.conf | |
1 | +#登录信息 | |
2 | +[loginInfo] | |
3 | +sy_userName_01=scgy,123123 | |
4 | +hd_userName_01=哈尔滨田太子,a123456 | |
5 | + | |
6 | +# 测试依赖信息 | |
7 | +[testInfo] | |
8 | +#sy | |
9 | +sy_cardNumRe_01=888810033081 | |
10 | +#hd | |
11 | +hd_cardNumRe_01=210823173732 | |
12 | + | |
13 | + | |
14 | +[host] | |
15 | +cardHost=http://test.card.diligrp.com:8386 | |
16 | +uapHost=http://test.uap.diligrp.com | |
17 | +gatewayHost=http://test.gateway.diligrp.com:8285 | |
18 | +jmsfHost=http://test.jmsf.diligrp.com:8385 | |
0 | 19 | \ No newline at end of file | ... | ... |
config/marketConfig/put_market_config_info_here
0 → 100644
main.py
0 → 100644
1 | +++ a/main.py | |
1 | +#!/usr/bin/python | |
2 | +# -*- coding: UTF-8 -*- | |
3 | +import os,time | |
4 | +import sys | |
5 | +import unittest | |
6 | +import re | |
7 | +import HTMLTestRunner_cn | |
8 | +import commons.ConfigDB as db | |
9 | +from discover import DiscoveringTestLoader | |
10 | +from commons import SendEmail as em | |
11 | +from commons import common as com | |
12 | +from commons.MySession import my | |
13 | +from commons.scripts import delReport | |
14 | + | |
15 | + | |
16 | + | |
17 | +def Create_Testcase_suite(path=""): | |
18 | + '''创建测试套件''' | |
19 | + if path!="": | |
20 | + path+="/" | |
21 | + print(path) | |
22 | + testunit=unittest.TestSuite() | |
23 | + test_Loader = DiscoveringTestLoader() | |
24 | + discover=test_Loader.discover("./testcase/{}".format(path),pattern='test_*.py',top_level_dir=None) | |
25 | + # print(discover) | |
26 | + for test_suite in discover: | |
27 | + testunit.addTests(test_suite) | |
28 | +# print(testunit) | |
29 | + return testunit | |
30 | + | |
31 | + | |
32 | +def Run_Testcase(testsuit,head=""): | |
33 | + '''运行测试用例并生成报告''' | |
34 | + if (head in my.market.keys()): | |
35 | + head="["+ my.market[head] + "]" | |
36 | + now = time.strftime("%Y-%m-%d %H_%M_%S",time.localtime()) | |
37 | + path=os.path.dirname(os.path.abspath(sys.argv[0])) | |
38 | + report_file=path+"/report/"+now+"_result.html" | |
39 | + #创建报告文件 | |
40 | + fp=open(report_file,'wb') | |
41 | + | |
42 | + runner=HTMLTestRunner_cn.HTMLTestRunner( | |
43 | + stream=fp, | |
44 | + title=u'进门收费{}--接口测试报告'.format(head), | |
45 | + description=u'用例简要执行情况如下:(注:报告详细信息需要下载report.html并用浏览器打开)', | |
46 | + verbosity = 2) | |
47 | + #执行用例 | |
48 | + runner.run(testsuit) | |
49 | + #关闭文件 | |
50 | + fp.close() | |
51 | + delReport.delReport(path) | |
52 | + return report_file | |
53 | + | |
54 | +def Send_email(filename): | |
55 | + '''判断邮件发送逻辑''' | |
56 | + l=eval(com.get_global_config("global_data", "email","to_list").lower()) | |
57 | + c=eval(com.get_global_config("global_data", "email","cc_list").lower()) | |
58 | + if type(l)!=type([]): | |
59 | + raise Exception("error,pls input list type send-email address") | |
60 | + elif len(l)==0: | |
61 | + print("\n To_list of send-email is null,won't send email!") | |
62 | + elif len(l)!=0: | |
63 | + for i in l: | |
64 | + print("\n check send-email format : {}".format(i)) | |
65 | + if re.match(r'^[0-9a-zA-Z_]{1,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$',i): | |
66 | + pass | |
67 | + else: | |
68 | + raise Exception("error,pls check your send-email format") | |
69 | + #发送邮件 | |
70 | + em.send_email(filename,send_to=l,cc_to=c) | |
71 | + else: | |
72 | + print("\n Haven't sent the email,pls check send-email address!") | |
73 | + | |
74 | + | |
75 | + | |
76 | +if __name__ == "__main__": | |
77 | + #检测数据库 | |
78 | + db.mysql_conn_test() | |
79 | + #检测登录接口 | |
80 | + my.check_login("sy_user01") | |
81 | + #创建测试套,运行测试用例,生成报告 | |
82 | + report=Run_Testcase(Create_Testcase_suite("sy")) | |
83 | + #发送邮件 | |
84 | + Send_email(report) | ... | ... |
report/__init__.py
0 → 100644
1 | +++ a/report/__init__.py | ... | ... |
report/test.log
0 → 100644
1 | +++ a/report/test.log | |
1 | +[2021-08-27 14:56:04] [INFO] : ====================================================================================== | |
2 | +[2021-08-27 14:56:04] [INFO] : http://test.uap.diligrp.com/api/authenticationApi/loginWeb | |
3 | +{'data': None, 'json': {'userName': 'sy_chen', 'password': 'NxcpSj8I9WK3GY9MlAfHXIQLnAwYsREKkHVx1Z3sBqTdjgk3+/t0aIn/Xpn0DfUsOgwulzZ9XQ5HhEcu+jky7LdPPnNslkyWsXoXQOfWDa39mB2CRzHInV3gNxos3iyqiNCDXy5hTKM1oy7yhE8CfzlqPUcWRDnZ4iGGMhZNpE4='}, 'headers': {'Content-Type': 'text/plain;charset=utf-8', 'Host': 'test.uap.diligrp.com', 'Content-Length': '209', 'Expect': '100-continue'}} | |
4 | + | |
5 | +[2021-08-27 14:56:04] [INFO] : ====================================================================================== | |
6 | +[2021-08-27 14:56:04] [INFO] : http://test.uap.diligrp.com/api/authenticationApi/loginWeb | |
7 | +{'data': None, 'json': {'userName': '哈尔滨田太子', 'password': 'X8+561DIatg517K/JNe3l4hqIjDSq+r7gTsW4xgP4d0ai6N6gjOD0tn1If8rr54HrYZ//XRY3jdL++cIz5z+HyP5eMD+igf6v+a2W4j8p/IRJsP9v6R3q4Rz35gUoOKalURfJdkQFyzZf7E3X3esOiPMR7n927vUdjIJVAYZU10='}, 'headers': {'Content-Type': 'text/plain;charset=utf-8', 'Host': 'test.uap.diligrp.com', 'Content-Length': '209', 'Expect': '100-continue'}} | |
8 | + | |
9 | +[2021-08-27 14:56:05] [INFO] : ====================================================================================== | |
10 | +[2021-08-27 14:56:05] [INFO] : http://test.uap.diligrp.com/login/login.action | |
11 | +{'data': b'userName=sy_chen&password=123456', 'json': None, 'headers': {'Host': 'test.uap.diligrp.com', 'Connection': 'keep-alive', 'Content-Length': '33', 'Cache-Control': 'max-age=0', 'Upgrade-Insecure-Requests': '1', 'Origin': 'http://test.uap.diligrp.com', 'Content-Type': 'application/x-www-form-urlencoded', 'User-Agent': 'Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/90.0.4430.212Safari/537.36', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Referer': 'http://test.uap.diligrp.com/login/index.html', 'Accept-Encoding': 'gzip,deflate', 'Accept-Language': 'zh-CN,zh-TW;q=0.9,zh;q=0.8,en;q=0.7', 'Cookie': 'UAP_accessToken=;UAP_refreshToken=;UAP_loginPath='}, 'allow_redirects': False} | |
12 | + | |
13 | +[2021-08-27 14:56:05] [INFO] : 发送邮件 | |
14 | +[2021-08-27 14:56:08] [INFO] : 邮件发送完毕 | ... | ... |
testcase/__init__.py
0 → 100644
testcase/heb/__init__.py
0 → 100644
1 | +++ a/testcase/heb/__init__.py | ... | ... |
testcase/hg/__init__.py
0 → 100644
1 | +++ a/testcase/hg/__init__.py | ... | ... |
testcase/sy/__init__.py
0 → 100644
1 | +++ a/testcase/sy/__init__.py | ... | ... |