smartpush 1.3.4__tar.gz → 1.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {smartpush-1.3.4 → smartpush-1.3.7}/PKG-INFO +1 -1
- {smartpush-1.3.4 → smartpush-1.3.7}/setup.py +1 -1
- smartpush-1.3.7/smartpush/flow/MockFlow.py +100 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/get_jira_info.py +6 -5
- smartpush-1.3.7/smartpush/test.py +90 -0
- smartpush-1.3.7/smartpush/utils/ListDictUtils.py +30 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush.egg-info/PKG-INFO +1 -1
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush.egg-info/SOURCES.txt +3 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/README.md +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/setup.cfg +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/__init__.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/export/__init__.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/export/basic/ExcelExportChecker.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/export/basic/GetOssUrl.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/export/basic/ReadExcel.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/export/basic/__init__.py +0 -0
- {smartpush-1.3.4/smartpush/utils → smartpush-1.3.7/smartpush/flow}/__init__.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/utils/DataTypeUtils.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush/utils/StringUtils.py +0 -0
- /smartpush-1.3.4/smartpush/test.py → /smartpush-1.3.7/smartpush/utils/__init__.py +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush.egg-info/dependency_links.txt +0 -0
- {smartpush-1.3.4 → smartpush-1.3.7}/smartpush.egg-info/top_level.txt +0 -0
@@ -0,0 +1,100 @@
|
|
1
|
+
import json
|
2
|
+
import random
|
3
|
+
import time
|
4
|
+
import requests
|
5
|
+
from smartpush.utils import ListDictUtils
|
6
|
+
|
7
|
+
|
8
|
+
def get_current_flow(host_domain, cookies, flow_id, oppor="forward"):
|
9
|
+
# 提取flow所有节点数据
|
10
|
+
_url = host_domain + "/flow/getFlowDetail"
|
11
|
+
headers = {
|
12
|
+
"cookie": cookies
|
13
|
+
}
|
14
|
+
params = {
|
15
|
+
"flowId": flow_id,
|
16
|
+
"active": True,
|
17
|
+
"includeActivityDetail": True
|
18
|
+
}
|
19
|
+
result = json.loads(requests.request(method="get", url=_url, headers=headers, params=params).text)
|
20
|
+
|
21
|
+
# 按节点id存储
|
22
|
+
node_counts = []
|
23
|
+
for node in result["resultData"]["nodes"]:
|
24
|
+
node_counts.append({node["id"]: {"completedCount": node["data"]["completedCount"],
|
25
|
+
"skippedCount": node["data"]["skippedCount"],
|
26
|
+
"openUserCount": node["data"]["openUserCount"],
|
27
|
+
"clickUserCount": node["data"]["clickUserCount"],
|
28
|
+
"waitingCount": node["data"]["waitingCount"]}
|
29
|
+
}
|
30
|
+
)
|
31
|
+
return {oppor: node_counts}, result["resultData"]["version"]
|
32
|
+
|
33
|
+
|
34
|
+
def start_flow(host_domain, cookies, flow_id, version):
|
35
|
+
# 开启flow
|
36
|
+
_url = host_domain + "/flow/publishFlow"
|
37
|
+
headers = {
|
38
|
+
"cookie": cookies,
|
39
|
+
"Content-Type": "application/json"
|
40
|
+
}
|
41
|
+
params = {
|
42
|
+
"flowId": flow_id,
|
43
|
+
"version": str(version)
|
44
|
+
}
|
45
|
+
result = requests.request(method="post", url=_url, headers=headers, json=params).text
|
46
|
+
|
47
|
+
|
48
|
+
def mock_pulsar(mock_domain, pulsar, limit=1):
|
49
|
+
# post请求
|
50
|
+
# times:为触发次数,默认1次即可
|
51
|
+
# 第三步提取的content直接替换mq的值即可
|
52
|
+
# 需参数化字段:
|
53
|
+
# abandonedOrderId、checkoutId、controlObjectId取第一步control_object_id做参数化
|
54
|
+
# platform为平台字段,枚举: 1:SF 2:ec1 4:ec2 8:domain
|
55
|
+
# messageId:需更改,保证不是之前使用过的
|
56
|
+
# userId:需参数化,兼容不同平台和环境
|
57
|
+
# handle、storeId:兼容不同店铺
|
58
|
+
#
|
59
|
+
# 备注:
|
60
|
+
# 可通过弃单id、userId字段测异常场景:如无联系人时,能触发但不发送,记录跳过数等;
|
61
|
+
_url = mock_domain + "/flow/testEventMulti"
|
62
|
+
headers = {
|
63
|
+
"Content-Type": "application/json"
|
64
|
+
}
|
65
|
+
# 生成随机message_id
|
66
|
+
prefix = 179
|
67
|
+
pulsar["messageId"] = f"{prefix}{random.randint(10 ** 15, 10 ** 16 - 1)}"
|
68
|
+
params = {
|
69
|
+
"times": limit,
|
70
|
+
"mq": pulsar
|
71
|
+
}
|
72
|
+
result = requests.request(method="post", url=_url, headers=headers, json=params).text
|
73
|
+
return json.loads(result)
|
74
|
+
|
75
|
+
|
76
|
+
def check_flow(mock_domain, host_domain, cookies, **kwargs):
|
77
|
+
"""
|
78
|
+
params
|
79
|
+
mock_domain:必填,触发接口域名
|
80
|
+
host_domain:必填,spflow接口域名
|
81
|
+
cookies:必填,sp登录态
|
82
|
+
flow_id:必填
|
83
|
+
pulsar:必填,模拟的触发数据
|
84
|
+
limit:非必填,默认为1 - mock_pulsar函数用于控制模拟触发的次数
|
85
|
+
num:非必填,默认为1 - compare_lists函数用于断言方法做差值计算
|
86
|
+
"""
|
87
|
+
# 触发前提取flow数据,后续做对比
|
88
|
+
old_flow_counts, old_versions = get_current_flow(host_domain=host_domain, cookies=cookies,
|
89
|
+
flow_id=kwargs["flow_id"])
|
90
|
+
# 启动flow
|
91
|
+
start_flow(host_domain=host_domain, cookies=cookies, flow_id=kwargs["flow_id"], version=old_versions)
|
92
|
+
# 触发flow
|
93
|
+
mock_pulsar(mock_domain=mock_domain, pulsar=kwargs["pulsar"], limit=kwargs.get("limit", 1))
|
94
|
+
# 触发后提取flow数据,做断言
|
95
|
+
time.sleep(30)
|
96
|
+
new_flow_counts, new_versions = get_current_flow(host_domain=host_domain, cookies=cookies,
|
97
|
+
flow_id=kwargs["flow_id"])
|
98
|
+
# 断言
|
99
|
+
result = ListDictUtils.compare_lists(temp1=old_flow_counts, temp2=new_flow_counts, num=kwargs.get("num", 1))
|
100
|
+
return [True, "断言成功"] if len(result) == 0 else [False, result]
|
@@ -2,7 +2,6 @@ import datetime
|
|
2
2
|
import json
|
3
3
|
import requests
|
4
4
|
from jira import JIRA
|
5
|
-
from datetime import datetime
|
6
5
|
from smartpush.utils.StringUtils import StringUtils
|
7
6
|
|
8
7
|
test_user = {
|
@@ -201,6 +200,7 @@ class JiraInfo:
|
|
201
200
|
else:
|
202
201
|
print(f"{new_jql} 更新失败!")
|
203
202
|
except Exception as e:
|
203
|
+
# raise e
|
204
204
|
print(f"更新过滤器 JQL 时出错: {e}")
|
205
205
|
|
206
206
|
def product_and_ui_acceptance_notice(self, webhook, datas):
|
@@ -250,12 +250,12 @@ class JiraInfo:
|
|
250
250
|
:return:
|
251
251
|
"""
|
252
252
|
content = ""
|
253
|
-
today = datetime.today().strftime('%Y-%m-%d')
|
253
|
+
today = datetime.date.today().strftime('%Y-%m-%d')
|
254
254
|
for key, value in datas.items():
|
255
255
|
adjusted_test_completion_time = value.get("调整后测试完成时间(测试环境)")
|
256
256
|
test_end_time = value.get("测试完成时间(测试环境)") if adjusted_test_completion_time is None else adjusted_test_completion_time
|
257
257
|
test_end_text = '测试完成时间(测试环境)' if adjusted_test_completion_time is None else '调整后测试完成时间(测试环境)'
|
258
|
-
test_end_time_new = datetime.strptime(test_end_time, "%Y-%m-%d").strftime('%Y-%m-%d') if test_end_time is not None else None
|
258
|
+
test_end_time_new = datetime.datetime.strptime(test_end_time, "%Y-%m-%d").strftime('%Y-%m-%d') if test_end_time is not None else None
|
259
259
|
summary = value.get("summary")
|
260
260
|
url = value.get("url")
|
261
261
|
backend_workload = value.get("后端工作量")
|
@@ -266,6 +266,7 @@ class JiraInfo:
|
|
266
266
|
print(f"*** {today} 无涉及覆盖率登记需求,不发送通知 ***")
|
267
267
|
return
|
268
268
|
content = f"### <font color=\"warning\"> 涉及后端需求,测试完成后,请分析并登记覆盖率报告</font> \n" + content
|
269
|
+
# print(content)
|
269
270
|
self.send_wecom_robot_message(webhook, content)
|
270
271
|
|
271
272
|
def bug_not_closed_notice(self, webhook, datas):
|
@@ -310,8 +311,8 @@ class JiraInfo:
|
|
310
311
|
automation_saves_labor_time = value.get("自动化节省工时")
|
311
312
|
fixVersions = value.get("fixVersions")
|
312
313
|
content += f"> [{key + '-' + summary}]({url}) \n状态:{status}\n实际上线时间:{actually_online_time}\n自动化测试工作量:{automated_testing_workload}\n自动节省工时:{automation_saves_labor_time}\n" \
|
313
|
-
f"测试:{tester_user_id} \n\n "
|
314
|
-
content = f"### <font color=\"warning\">
|
314
|
+
f"测试:{tester_user_id}\n版本号:{fixVersions} \n\n "
|
315
|
+
content = f"### <font color=\"warning\"> 本周版本需求已上线,请检查并更新jira数据,进行版本收尾</font> \n" + content
|
315
316
|
self.send_wecom_robot_message(webhook, content)
|
316
317
|
|
317
318
|
def get_tester_wecom_userid(self, tester, user_data):
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- codeing = utf-8 -*-
|
2
|
+
# @Time :2025/2/20 00:27
|
3
|
+
# @Author :luzebin
|
4
|
+
import pandas as pd
|
5
|
+
|
6
|
+
from smartpush.export.basic import ExcelExportChecker
|
7
|
+
from smartpush.export.basic.ReadExcel import read_excel_from_oss
|
8
|
+
from smartpush.export.basic.ReadExcel import read_excel_and_write_to_dict
|
9
|
+
from smartpush.export.basic.GetOssUrl import get_oss_address_with_retry
|
10
|
+
from smartpush.utils.DataTypeUtils import DataTypeUtils
|
11
|
+
from smartpush.flow import MockFlow
|
12
|
+
|
13
|
+
if __name__ == '__main__':
|
14
|
+
oss1 = "https://cdn.smartpushedm.com/material_ec2/2025-02-26/31c1a577af244c65ab9f9a984c64f3d9/ab%E5%BC%B9%E7%AA%97%E6%B5%8B%E8%AF%952.10%E5%88%9B%E5%BB%BA-%E6%9C%89%E5%85%A8%E9%83%A8%E6%95%B0%E6%8D%AE%E9%94%80%E5%94%AE%E9%A2%9D%E6%98%8E%E7%BB%86%E6%95%B0%E6%8D%AE.xlsx"
|
15
|
+
oss2 = "https://cdn.smartpushedm.com/material_ec2/2025-02-26/31c1a577af244c65ab9f9a984c64f3d9/ab%E5%BC%B9%E7%AA%97%E6%B5%8B%E8%AF%952.10%E5%88%9B%E5%BB%BA-%E6%9C%89%E5%85%A8%E9%83%A8%E6%95%B0%E6%8D%AE%E9%94%80%E5%94%AE%E9%A2%9D%E6%98%8E%E7%BB%86%E6%95%B0%E6%8D%AE.xlsx"
|
16
|
+
# # print(check_excel_all(oss1, oss1))
|
17
|
+
oss3 = "https://cdn.smartpushedm.com/material_ec2/2025-03-07/dca03e35cb074ac2a46935c85de9f510/导出全部客户.csv"
|
18
|
+
oss4 = "https://cdn.smartpushedm.com/material_ec2/2025-03-07/c5fa0cc24d05416e93579266910fbd3e/%E5%AF%BC%E5%87%BA%E5%85%A8%E9%83%A8%E5%AE%A2%E6%88%B7.csv"
|
19
|
+
expected_oss = "https://cdn.smartpushedm.com/material_ec2/2025-02-26/757df7e77ce544e193257c0da35a4983/%E3%80%90%E8%87%AA%E5%8A%A8%E5%8C%96%E5%AF%BC%E5%87%BA%E3%80%91%E8%90%A5%E9%94%80%E6%B4%BB%E5%8A%A8%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
|
20
|
+
# actual_oss = "https://cdn.smartpushedm.com/material_ec2/2025-02-26/757df7e77ce544e193257c0da35a4983/%E3%80%90%E8%87%AA%E5%8A%A8%E5%8C%96%E5%AF%BC%E5%87%BA%E3%80%91%E8%90%A5%E9%94%80%E6%B4%BB%E5%8A%A8%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx"
|
21
|
+
url = "https://cdn.smartpushedm.com/material_ec2_prod/2025-03-06/fe6f042f50884466979155c5ef825736/copy%20of%202025-01-16%20%E5%88%9B%E5%BB%BA%E7%9A%84%20A%2FB%20%E6%B5%8B%E8%AF%95%20copy%20of%202025-01-16%20app-%E6%99%AE%E9%80%9A%E6%A8%A1%E6%9D%BF%201%E6%95%B0%E6%8D%AE%E6%80%BB%E8%A7%88.xlsx"
|
22
|
+
|
23
|
+
# e_person_oss1 = "https://cdn.smartpushedm.com/material_ec2/2025-02-27/b48f34b3e88045d189631ec1f0f23d51/%E5%AF%BC%E5%87%BA%E5%85%A8%E9%83%A8%E5%AE%A2%E6%88%B7.csv"
|
24
|
+
# a_person_oss2 = "https://cdn.smartpushedm.com/material_ec2/2025-02-27/c50519d803c04e3b9b52d9f625fed413/%E5%AF%BC%E5%87%BA%E5%85%A8%E9%83%A8%E5%AE%A2%E6%88%B7.csv"
|
25
|
+
|
26
|
+
# # #actual_oss= get_oss_address_with_retry("23161","https://cdn.smartpushedm.com/material_ec2_prod/2025-02-20/dae941ec20964ca5b106407858676f89/%E7%BE%A4%E7%BB%84%E6%95%B0%E6%8D%AE%E6%A6%82%E8%A7%88.xlsx","",'{"page":1,"pageSize":10,"type":null,"status":null,"startTime":null,"endTime":null}')
|
27
|
+
# # res=read_excel_and_write_to_dict(read_excel_from_oss(actual_oss))
|
28
|
+
# # print(res)
|
29
|
+
# # print(read_excel_and_write_to_dict(read_excel_from_oss(oss1), type=".xlsx"))
|
30
|
+
# print(check_excel(check_type="all", actual_oss=actual_oss, expected_oss=expected_oss))
|
31
|
+
# print(check_excel_all(actual_oss=oss1, expected_oss=oss2,skiprows =1))
|
32
|
+
# print(check_excel_all(actual_oss=oss1, expected_oss=oss2,ignore_sort=True))
|
33
|
+
# print(check_excel_all(actual_oss=a_person_oss2, expected_oss=e_person_oss1, check_type="including"))
|
34
|
+
print(ExcelExportChecker.check_excel_all(actual_oss=oss3, expected_oss=oss4, check_type="including"))
|
35
|
+
# read_excel_csv_data(type=)
|
36
|
+
# print(DataTypeUtils().check_email_format())
|
37
|
+
# errors = ExcelExportChecker.check_field_format(actual_oss=oss1, fileds={0: {5: "time"}}, skiprows=1)
|
38
|
+
# ExcelExportChecker.check_excel_name(actual_oss=oss1, expected_oss=url)
|
39
|
+
|
40
|
+
_url = "http://sp-go-flow-test.inshopline.com"
|
41
|
+
params = {
|
42
|
+
"abandonedOrderId": "c2c4a695a36373f56899b370d0f1b6f2",
|
43
|
+
"areaCode": "",
|
44
|
+
"context": {
|
45
|
+
"order": {
|
46
|
+
"buyerSubscribeEmail": True,
|
47
|
+
"checkoutId": "c2c4a695a36373f56899b370d0f1b6f2",
|
48
|
+
"discountCodes": [],
|
49
|
+
"orderAmountSet": {
|
50
|
+
"amount": 3,
|
51
|
+
"currency": "JPY"
|
52
|
+
},
|
53
|
+
"orderDetails": [
|
54
|
+
{
|
55
|
+
"productId": "16060724900402692190790343",
|
56
|
+
"title": "测试2.0-商品同步AutoSync-2023-08-17 20:52:00",
|
57
|
+
"titleTranslations": []
|
58
|
+
}
|
59
|
+
],
|
60
|
+
"receiverCountryCode": "HK"
|
61
|
+
},
|
62
|
+
"user": {
|
63
|
+
"addresses": [],
|
64
|
+
"areaCode": "",
|
65
|
+
"email": "testsmart200+10@gmail.com",
|
66
|
+
"firstName": "testsmart200+10",
|
67
|
+
"gender": "others",
|
68
|
+
"id": "1911625831177650177",
|
69
|
+
"lastName": "",
|
70
|
+
"phone": "",
|
71
|
+
"tags": [],
|
72
|
+
"uid": "4603296300",
|
73
|
+
"userName": "testsmart200+10"
|
74
|
+
}
|
75
|
+
},
|
76
|
+
"controlObjectId": "c2c4a695a36373f56899b370d0f1b6f2",
|
77
|
+
"controlObjectType": 4,
|
78
|
+
"email": "testsmart200+10@gmail.com",
|
79
|
+
"handle": "smartpush4",
|
80
|
+
"language": "en",
|
81
|
+
"messageId": "1911625832100397058",
|
82
|
+
"phone": "",
|
83
|
+
"platform": 4,
|
84
|
+
"storeId": "1644395920444",
|
85
|
+
"timezone": "Asia/Macao",
|
86
|
+
"triggerId": "c1001",
|
87
|
+
"uid": "4603296300",
|
88
|
+
"userId": "1911625831177650177"
|
89
|
+
}
|
90
|
+
mock_pulsar = MockFlow.mock_pulsar(_url, params)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
def compare_lists(temp1, temp2, num=1):
|
2
|
+
"""对比两个list中字典,a中字典对应的键值+num等于b字典中键值
|
3
|
+
ab值示例:
|
4
|
+
a = [{"123": {"a": 1, "b": 2}}, {"456": {"a": 5, "b": 6}}]
|
5
|
+
b = [{"123": {"a": 2, "b": 2}}, {"456": {"a": 6, "b": 6}}]
|
6
|
+
"""
|
7
|
+
error = []
|
8
|
+
# 同时遍历两个列表中的字典
|
9
|
+
for temp1_a, temp2_b in zip(temp1, temp2):
|
10
|
+
# 遍历每个字典的键
|
11
|
+
for outer_key in temp1_a:
|
12
|
+
# 确保 temp2 对应的字典中也有相同的外层键
|
13
|
+
if outer_key in temp2_b:
|
14
|
+
# 获取内层字典
|
15
|
+
inner_dict_a = temp1_a[outer_key]
|
16
|
+
inner_dict_b = temp2_b[outer_key]
|
17
|
+
# 遍历内层字典的键
|
18
|
+
for inner_key in inner_dict_a:
|
19
|
+
# 确保 temp2 对应的内层字典中也有相同的键
|
20
|
+
if inner_key in inner_dict_b:
|
21
|
+
# 检查是否满足条件
|
22
|
+
if inner_dict_a[inner_key] + num != inner_dict_b[inner_key]:
|
23
|
+
error.append({
|
24
|
+
outer_key: {
|
25
|
+
|
26
|
+
f"{inner_key}_in_a": inner_dict_a[inner_key],
|
27
|
+
f"{inner_key}_in_b": inner_dict_b[inner_key]
|
28
|
+
}
|
29
|
+
})
|
30
|
+
return error
|
@@ -12,6 +12,9 @@ smartpush/export/basic/ExcelExportChecker.py
|
|
12
12
|
smartpush/export/basic/GetOssUrl.py
|
13
13
|
smartpush/export/basic/ReadExcel.py
|
14
14
|
smartpush/export/basic/__init__.py
|
15
|
+
smartpush/flow/MockFlow.py
|
16
|
+
smartpush/flow/__init__.py
|
15
17
|
smartpush/utils/DataTypeUtils.py
|
18
|
+
smartpush/utils/ListDictUtils.py
|
16
19
|
smartpush/utils/StringUtils.py
|
17
20
|
smartpush/utils/__init__.py
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|