一、背景
生产环境的文档中心的OpenApi和Kong服务配置的OpenApi可能存在不一致的情况,比如生产环境的文档中心有某个OpenApi,但是Kong服务没有配置到,那客户使用就会有问题。所以,前段时间(M09版本)花了4个人力(2个开发+2个测试)人工排查比对了2个0.5天,比较费时费力。
为了大概了解下存在不一致的原因,梳理了下OpenApi 接口上线流程:
- 公司其他业务线同事开发底层接口,如果需要开放给客户、租户使用,需要申请上线工单;
- 工单申请通过之后,需要上线的接口会通过Excel表格式给到网关开发同事;
- 网关开发同事配置需要上线的接口的路由 - OpenApiPath、Methods;
- 跑自动化连通性脚本,测试是否通过;
- 测试通过,部署到文档中心;
- 把新增到生产的接口添加到自动化连通性脚本里面。
个人觉得可能性比较大的原因有2个:沟通中消息不对称、持续迭代的过程中出现错漏。
二、方案构思
相对于人工巡查比对的方法:文档中心界面的OpenApi → Kong Conf ,总结了一些规律,写了一个自动化巡检工具。
工具代码目录如下:
代码目录分析:
- data-campare-result:工具执行结果存放;
- data-source:存放数据源,其中,docs文件是文档中心的代码文件,kong-configuration是kong服务的 openapi 配置代码文件;
- basic.py:提供公用方法被调用,如,读取docs文件/kong-configuration文件的openapi所在文件路径;
- doc_openapi.py:文档中心代码里面配置的openapi是一个json文件,需要将false,true,null 转化成Python语法的False,True,None,再把 json 里面的openapi和method提取出来,转成规范的统一的格式,组装、返回结果;
- kong_openapi.py:kong服务配置的openapi是一个数组里面存放多个字典,通过读取service-route.js文件的每一行数据,提取openapi和method,转成规范的统一的格式,组装、返回结果;
- main.py:代码执行入口,调用basic.py、doc_openapi.py、kong_openapi.py,对结果进行分析,并把分析结果写入到data-compare-result目录下的compare_result.txt文件存放。
main.py的代码如下:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# author : 枫叶测试
# datetime: 9/30/21 5:30 PM
# filename: main.py
import sys, emoji
from src.doc_openapi import *
from src.kong_openapi import *
from src.basic import *
from src.QyWxApi import *
# kong配置openapi的目录路径
kong_file_dir = "./data-source/kong-configuration/test"
# 定义列表存储kong配置的openapi
compare_kong_openapi = []
# 文档中心配置openapi的目录路径
doc_file_dir = "./data-source/docs/static/swagger-json-build/new/zh-cn"
# 定义列表存储文档中心配置的openapi
compare_doc_openapi = []
# 定义列表手动配置不需要比对的openapi的服务名,比如doc已经下线或废弃的openapi
no_compare_openapi = ['cross-organization-authorization', 'blockchain']
# 获取文档中心配置openapi的所有文件路径名称
doc_file_json = get_file(doc_file_dir, doc_file_json)
# 获取文档中心所有配置文件的openapi,除了all文件外
for i in doc_file_json:
if 'all' not in i:
# print(i)
doc_openapi_dic = process_doc_openapi(i)
paths = jsonpath(doc_openapi_dic, '$..paths')
doc_openapi_list = search_doc_openapi(paths)
compare_doc_openapi.extend(doc_openapi_list)
print("doc_file_openapi: " + "\n", compare_doc_openapi, "\n" + "doc_file_openapi_total:", len(compare_doc_openapi))
# 获取kong服务配置openapi的所有文件路径名称
kong_file_js = get_file(kong_file_dir, kong_file_js)
print(kong_file_js)
# 获取kong服务所有配置文件的openapi
for i in kong_file_js:
compare_kong_openapi = kong_openapi(i, compare_kong_openapi)
print("kong_file_openapi: " + "\n", compare_kong_openapi, "\n" + "kong_file_openapi_total:", len(compare_kong_openapi))
compare_result = []
for i in compare_doc_openapi:
# 文档中心的openapi对比kong服务的openapi,如果前者不在后者里面,即输出为所需结果
if i not in compare_kong_openapi:
if no_compare_openapi[0] not in i and no_compare_openapi[1] not in i:
compare_result.append(i)
with open("./data-compare-result/comapre_result.txt", "a+") as f:
f.write(i + '\n')
print("文档中心已经配置但kong服务没配置的openapi数量:",len(compare_result),"\n"+"详情:",compare_result)
"""
微信机器人发送测试结果的配置
"""
emoji_zan = emoji.emojize(':100:', use_aliases=True)
emoji_wang = emoji.emojize(':globe_with_meridians:', use_aliases=True)
emoji_wen = emoji.emojize(":book:", use_aliases=True)
emoji_fadajing = emoji.emojize(":mag_right:", use_aliases=True)
emoji_paperclip = emoji.emojize(":paperclip:", use_aliases=True)
emoji_X = emoji.emojize(":x:", use_aliases=True)
emoji_right = emoji.emojize(":white_check_mark:", use_aliases=True)
if len(compare_result) == 0:
compare_result_str = "<font color=\"info\">Perfect%s文档中心配置的openapi完全匹配kong-configure配置</font>" % emoji_zan
emoji_result = emoji_right
else:
compare_result_str = "\n".join(compare_result)
emoji_result = emoji_X
docs_branch = sys.argv[1] if len(sys.argv) >= 2 else "NoExit"
kong_config_branch = sys.argv[2] if len(sys.argv) >= 3 else "NoExit"
robot_key = sys.argv[3] if len(sys.argv) >= 4 else "Test"
content = "openapi自动化巡检测试报告" \
"\n" + "【文档中心】" + \
"\n" + "代码分支:" + str(docs_branch) + \
"\n" + "已配置的openapi总数:" + str(len(compare_doc_openapi)) + \
"\n" + "【kong-configure】" + \
"\n" + "代码分支:" + str(kong_config_branch) + \
"\n" + "已配置的openapi总数:" + str(len(compare_kong_openapi)) + \
"\n" + "【文档中心已配置但kong服务未配置的openapi】" + \
"\n" + "总数:" + str(len(compare_result)) + \
"\n" + "详情:" + \
"\n" + compare_result_str
content_markdown = {
"content": f"""`**openApi自动化巡检测试报告**`
>{emoji_wen}**文档中心**
>代码分支:<font color=\"comment\">{docs_branch}</font>
>已配置的openapi总数: <font color=\"info\">{len(compare_doc_openapi)}</font>
>
>{emoji_wang}**kong-configure**
>代码分支:<font color=\"comment\">{kong_config_branch}</font>
>已配置的openapi总数: <font color=\"info\">{len(compare_kong_openapi)}</font>
>
>{emoji_fadajing}**文档中心已配置但kong服务未配置的openapi**
>测试结果:{emoji_result} 总数:<font color=\"warning\">{len(compare_result)}</font>
>详情:{compare_result_str}
>
>{emoji_paperclip}**supplement**
>Developer:枫叶测试
>Tips:Regular inspection tests every Friday at 10 a.m
"""
}
mesg["text"]["content"] = content
mesg_markdown["markdown"] = content_markdown
robot_key_test = "*****" # 调试群
robot_key_openapi = "******" # 网关内部群
# Jenkins执行的命令参数:Test、OpenApi
robot_key = robot_key_openapi if robot_key == "OpenApi" else robot_key_test
robot(robot_key, mesg_markdown)
三、使用方法
- 本地
把下载的代码文件放到data-source文件目录下,文件名指定为:docs、kong_configuration,然后,执行main.py文件
- Jenkins构建(可跳转)
四、效果
自动化巡检执行的结果和人工排查比对的结果做比较,完全一致,都发现了9个缺失的URL
五、发送测试结果
- 巡检测试结果异常报告(测试数据是M09的旧分支,人工排查和自动化结果一致)
- 巡检测试结果正常报告(bug修复后,测试数据是最新master分支)
六、分析总结
最终实现的解决方案:
1.效率
现在自动化巡检一次的程序执行时间在7s左右,对比人力的效率,已经不是一个量级可以比较了。
2.准确性
测试数据使用有问题的旧分支,人工排查发现不匹配接口9个,巡检自动化结果和人工排查结果数量、内容一致。
3.手动巡检/定时监控
可以手动选择不同的环境的不同分支进行构建巡检,如:生产环境用的是release分支,qa环境用的是master分支。
每个sprint版本都会更新OpenApi,但有些紧急的,更新频率是周,所以,设置定时任务每周五早上10点巡检监控,是否有异常。