Skip to content

Commit 84bafc4

Browse files
authored
api coverage add category (#67)
* fix(rxl): api-coverage add prodcutattributes * fix(rxl): 增加{num}类型匹配 * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Save local changes * fix(rxl): Delete unnecessary modifications * fix(rxl): Modify report modules * fix(rxl): report file modifyy method * fix(rxl): Delete unnecessary changes
1 parent beb9f06 commit 84bafc4

File tree

10 files changed

+178
-75
lines changed

10 files changed

+178
-75
lines changed

frontend/src/components/apiList.vue

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
<template>
22
<div id="tab" class="box box-solid">
3-
<div class="box-body" style="max-height:calc(100vh - 100px); overflow:auto">
4-
<i-table stripe :columns="columns" :data="showedAPIData" ></i-table>
3+
<div class="box-body" style="max-height:calc(100vh - 100px) overflow:auto">
4+
<i-table stripe :columns="columns" :data="showedAPIData">
5+
<template #category="{ row }">
6+
<span v-if="row.category.length !== 0">
7+
<span v-for="(item, index) in row.category" :key="index">
8+
<Tag v-if="item.status == 1" color="green">{{item.label}}</Tag>
9+
</span>
10+
</span>
11+
</template>
12+
</i-table>
513
<Modal
614
v-model="isApiDetailModalShow"
715
title="Flow Detail"
@@ -38,19 +46,16 @@ export default {
3846
title: 'Priority',
3947
key: 'priority',
4048
sortable: true,
41-
width: 110,
4249
},
4350
{
4451
title: 'API',
4552
key: 'url',
4653
sortable: true,
47-
width: 380,
4854
},
4955
{
5056
title: 'Description',
5157
key: 'desc',
5258
sortable: true,
53-
width: 200,
5459
},
5560
{
5661
title: 'Count',
@@ -97,6 +102,12 @@ export default {
97102
return row.status === null
98103
},
99104
},
105+
{
106+
title: 'Category',
107+
key: 'category',
108+
slot: 'category',
109+
sortable: true,
110+
},
100111
{
101112
title: 'Detail',
102113
key: 'id',

frontend/src/store/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default new Vuex.Store({
3939
apis
4040
.getCoverage()
4141
.then((response) => {
42-
context.commit('setCoverageData', response.data)
42+
context.commit('setCoverageData', response.data.coverage)
4343
})
4444
.catch(() => {
4545
this.$Notice.open({ title: 'loadCoverageData error!' })

lyrebird_api_coverage/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ def generate(data):
1717
# 获取内存里保存的测试结果API
1818
# /getTest
1919
def get_test_data():
20-
return Response(stream_with_context(generate({'test_data': app_context.merge_list})), content_type='application/json')
20+
return context.make_ok_response(test_data=app_context.merge_list)
2121

2222
# 获取内存里保存的测试覆盖率信息
2323
# /getCoverage
2424
def get_coverage():
25-
return Response(stream_with_context(generate(app_context.coverage)), content_type='application/json')
25+
return context.make_ok_response(coverage = app_context.coverage)
2626

2727
# 保存测试数据在本地
2828
# /saveResult

lyrebird_api_coverage/client/context.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ def __init__(self):
3737
self.covtime = 0
3838
# 时间间隔,每隔指定时间触发1次socket io消息,防止刷新频繁
3939
self.SOCKET_PUSH_INTERVAL = 1
40+
# 是否使用接口请求实时base数据
41+
self.is_api_base_data = False
42+
# category信息
43+
self.category = ''
4044

4145

4246
# 单例模式

lyrebird_api_coverage/client/load_base.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22
import hashlib
33
import json
44
import lyrebird
5+
from pathlib import Path
56
from lyrebird.log import get_logger
67
import os
8+
import imp
9+
import traceback
710

811
from lyrebird_api_coverage.client.context import app_context
912

1013
PLUGINS_CONF_DIR = lyrebird.get_plugin_storage()
1114
DEFAULT_BASE = os.path.join(PLUGINS_CONF_DIR, 'base.json')
1215
CURRENT_DIR = os.path.dirname(__file__)
1316

17+
logger = get_logger()
18+
1419

1520
def get_file_sha1(path):
1621
with open(path, 'rb') as f:
@@ -25,12 +30,31 @@ def auto_load_base():
2530
# 读取指定base文件,写入到base.json
2631
if lyrebird_conf.get('hunter.base'):
2732
base_path = lyrebird_conf.get('hunter.base')
28-
base = codecs.open(base_path, 'r', 'utf-8').read()
29-
f = codecs.open(DEFAULT_BASE, 'w', 'utf-8')
30-
f.write(base)
31-
f.close()
32-
app_context.base_sha1 = get_file_sha1(DEFAULT_BASE)
33-
return json.loads(base)
33+
base_path_obj = Path(base_path)
34+
if not base_path_obj.is_file():
35+
return
36+
# 判断是否需要实时获取接口数据
37+
if base_path_obj.suffix == '.py':
38+
try:
39+
init_base_file = imp.load_source('load_base', str(base_path_obj))
40+
except Exception:
41+
logger.warning(f'Failed to load the file, {traceback.format_exc()}')
42+
return
43+
if not hasattr(init_base_file, 'load_api_base'):
44+
logger.warning(f'load_api_base does not exist')
45+
return
46+
if not callable(init_base_file.load_api_base):
47+
logger.warning(f'The method does not exist')
48+
return
49+
app_context.is_api_base_data = True
50+
return init_base_file.load_api_base()
51+
else:
52+
base = codecs.open(base_path, 'r', 'utf-8').read()
53+
f = codecs.open(DEFAULT_BASE, 'w', 'utf-8')
54+
f.write(base)
55+
f.close()
56+
app_context.base_sha1 = get_file_sha1(DEFAULT_BASE)
57+
return json.loads(base)
3458
# 通过本地默认base文件获取base
3559
elif not os.path.exists(DEFAULT_BASE):
3660
copy_file(DEFAULT_BASE)

lyrebird_api_coverage/client/merge_algorithm.py

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -35,33 +35,36 @@ def init_basedata_handler(self, dic):
3535
# url_dic = {'url': k, 'desc': v.get('desc'), 'priority': v.get('priority'), 'count': 0, 'status': 0,
3636
# 'org': []}
3737
# app_context.merge_list.append(url_dic)
38-
dict2 = {'count': 0, 'status': 0, 'id': ''}
39-
for item in dic.get('api_list'):
40-
# 处理带参数的情况
41-
if '?' in item['url']:
42-
path = item['url'].split('?')[0].lower()
43-
params = item['url'].split('?')[1].split('&')
44-
param_dic = {}
45-
for i in params:
46-
key = i.split('=')[0]
47-
val = i.split('=')[1]
48-
param_dic[key] = val
49-
50-
if app_context.path_param_dic.get(path):
51-
app_context.path_param_dic[path].append({'url': item['url'], 'params': param_dic,
52-
'url_base': format_url.format_api_source(
53-
item.get('url')).lower()})
54-
else:
55-
app_context.path_param_dic[path] = [{'url': item['url'], 'params': param_dic,
56-
'url_base': format_url.format_api_source(
57-
item.get('url')).lower()}]
58-
59-
# format base源 同时变成大小写归一化,变小写
60-
item['url'] = format_url.format_api_source(item.get('url')).lower()
61-
item.update(dict2)
62-
app_context.merge_list.append(item)
63-
64-
def merge_handler_new(self, user_url, path_id):
38+
if app_context.is_api_base_data:
39+
# 如果接口获取base数据,同步merge_list内容
40+
app_context.merge_list = dic.get('api_list')
41+
else:
42+
dict2 = {'count': 0, 'status': 0, 'id': ''}
43+
for item in dic.get('api_list'):
44+
# 处理带参数的情况
45+
if '?' in item['url']:
46+
path = item['url'].split('?')[0].lower()
47+
params = item['url'].split('?')[1].split('&')
48+
param_dic = {}
49+
for i in params:
50+
key = i.split('=')[0]
51+
val = i.split('=')[1]
52+
param_dic[key] = val
53+
54+
if app_context.path_param_dic.get(path):
55+
app_context.path_param_dic[path].append({'url': item['url'], 'params': param_dic,
56+
'url_base': format_url.format_api_source(
57+
item.get('url')).lower()})
58+
else:
59+
app_context.path_param_dic[path] = [{'url': item['url'], 'params': param_dic,
60+
'url_base': format_url.format_api_source(
61+
item.get('url')).lower()}]
62+
# format base源 同时变成大小写归一化,变小写
63+
item['url'] = format_url.format_api_source(item.get('url')).lower()
64+
item.update(dict2)
65+
app_context.merge_list.append(item)
66+
67+
def merge_handler_new(self, user_url, path_id, category):
6568
"""
6669
status=0 base中包含未覆盖,status=1 base中包含已覆盖,status=2 base中不包含且覆盖到的;
6770
path_id表示URL的handler_context的唯一标识,查看详情用
@@ -75,17 +78,45 @@ def merge_handler_new(self, user_url, path_id):
7578
specific_dic = specific_filter_list[0]
7679
# 移除掉对应的数据为插入index0的位置做前置处理
7780
app_context.merge_list.remove(specific_dic)
78-
# 做业务处理
79-
if specific_dic['status'] == 0:
80-
specific_dic['status'] = 1
81-
# 把首次覆盖到的API,放入user_list里面
82-
app_context.user_list.append(user_url)
81+
# 根据数据源,进行业务处理
82+
if app_context.is_api_base_data:
83+
category_dic = specific_dic.get('category')
84+
for p in category_dic:
85+
if category == p['name'] and p['status'] == 0:
86+
p['status'] = 1
87+
p['count'] += 1
88+
p['id'] = path_id
89+
if specific_dic['status'] == 0:
90+
specific_dic['status'] = 1
91+
# 把首次覆盖到的API,放入user_list里面
92+
app_context.user_list.append(user_url)
93+
else:
94+
# 非接口获取base数据
95+
if specific_dic['status'] == 0:
96+
specific_dic['status'] = 1
97+
# 把首次覆盖到的API,放入user_list里面
98+
app_context.user_list.append(user_url)
8399
# count +1
84100
specific_dic['count'] += 1 # 插入原始url # specific_dic['org'].append(org_url)
85101
specific_dic['id'] = path_id
86102
else:
87-
# specific_dic = {'url': user_url, 'desc': '', 'priority': '', 'count': 1, 'status': 2, 'org': [org_url]}
88-
specific_dic = {'url': user_url, 'desc': '', 'priority': None, 'count': 1, 'status': 2, 'id': path_id}
103+
if app_context.is_api_base_data:
104+
specific_dic = {
105+
'url': user_url,
106+
'desc': '',
107+
'priority': None,
108+
'status': 2,
109+
'count': 1,
110+
'category': []
111+
}
112+
specific_dic['category'].append({
113+
'id': None,
114+
'name': category,
115+
'status': 2,
116+
'count': 1
117+
})
118+
else:
119+
specific_dic = {'url': user_url, 'desc': '', 'priority': None, 'count': 1, 'status': 2, 'id': path_id}
89120
# 插入到 index=0 的位置
90121
app_context.merge_list.insert(0, specific_dic)
91122

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from lyrebird_api_coverage.client.context import app_context
2-
from lyrebird import report
2+
from lyrebird import publish
33

44
"""
55
上报处理器,用户请求行为上报到ELK中
66
ps:需要在lyrebird中设定reporter相关配置
77
"""
88

99
class ReportHandler:
10-
def check_url_info(self, url, device_ip):
10+
def check_url_info(self, url, device_ip, category):
1111
specific_list = list(filter(lambda x: x.get('url') == url, app_context.merge_list))
1212
if specific_list and specific_list[0].get('status') == 1:
1313
desc = specific_list[0].get('desc')
@@ -17,19 +17,26 @@ def check_url_info(self, url, device_ip):
1717
desc = 'N/A'
1818
count_flag = -1
1919
priority = -1
20-
info_dict = {'url': url, 'desc': desc, 'priority': priority, 'count_flag': count_flag,
21-
'business': app_context.business, 'version_name': app_context.version_name,
22-
'version_code': app_context.version_code}
20+
info_dict = {
21+
'coverage':{
22+
'url': url,
23+
'desc': desc,
24+
'priority': priority,
25+
'count_flag': count_flag,
26+
'version_name': app_context.version_name,
27+
'version_code': app_context.version_code,
28+
'category': category
29+
}
30+
}
2331
if app_context.info.get(device_ip):
2432
# 如果有Device信息,就上报device相关的信息
25-
info_dict.update(app_context.info.get(device_ip))
33+
info_dict['coverage'].update(app_context.info.get(device_ip))
2634
return info_dict
2735

2836

2937
report_handler = ReportHandler()
3038

3139

32-
def report_worker(url, device_ip):
33-
update_data = report_handler.check_url_info(url, device_ip)
34-
update_data.update({"action": "api-coverage", "user_info": app_context.user_info})
35-
report(update_data)
40+
def report_worker(url, device_ip, category):
41+
update_data = report_handler.check_url_info(url, device_ip, category)
42+
publish('coverage', update_data)

lyrebird_api_coverage/handlers/base_source_handler.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ def get_base_source(self):
4646
def check_base(self, obj):
4747
try:
4848
# 检查base schema
49-
check_schema(obj)
49+
if not app_context.is_api_base_data:
50+
check_schema(obj)
5051
# 检查url是否有重复项存在
5152
redundant_items = check_url_redundant(obj)
5253
if redundant_items:
@@ -59,12 +60,12 @@ def check_base(self, obj):
5960
resp = context.make_fail_response('导入API有重复项' + str(redundant_items))
6061
lyrebird.publish('api_coverage', 'error', name='import_base')
6162
return resp
62-
# 获取base内容,解析出base的business等字段
63-
filename = obj.get('business') + obj.get('version_name') + '.' + str(obj.get('version_code'))
63+
# 获取base内容,解析出base的business等字段
64+
filename = f'''{obj.get('business','')}{obj.get('version_name','')}{obj.get('version_code','')}'''
6465
app_context.filename = filename
65-
app_context.business = obj.get('business')
66-
app_context.version_name = obj.get('version_name')
67-
app_context.version_code = obj.get('version_code')
66+
app_context.business = obj.get('business', '')
67+
app_context.version_name = obj.get('version_name', '--')
68+
app_context.version_code = obj.get('version_code', '--')
6869
return
6970
except Exception as e:
7071
resp = context.make_fail_response(f'导入文件有误: {e}\n请重新import base')

0 commit comments

Comments
 (0)