From 22eb0cad59fa1484226b39b90ae0590816753654 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Wed, 20 Nov 2019 15:50:15 +0800 Subject: [PATCH 01/18] =?UTF-8?q?=E5=A2=9E=E5=8A=A0xss=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../java/yi/master/util/xss/XssFilter.java | 46 ++++ .../xss/XssHttpServletRequestWrapper.java | 124 ++++++++++ .../java/yi/master/util/xss/XssUtils.java | 70 ++++++ src/main/webapp/WEB-INF/web.xml | 213 ++++++++++-------- update.md | 22 ++ 6 files changed, 385 insertions(+), 96 deletions(-) create mode 100644 src/main/java/yi/master/util/xss/XssFilter.java create mode 100644 src/main/java/yi/master/util/xss/XssHttpServletRequestWrapper.java create mode 100644 src/main/java/yi/master/util/xss/XssUtils.java diff --git a/pom.xml b/pom.xml index fd7182c..f8c8367 100644 --- a/pom.xml +++ b/pom.xml @@ -444,6 +444,12 @@ + + org.jsoup + jsoup + 1.11.3 + + - - - org.springframework.web.util.Log4jConfigListener - - - - contextConfigLocation - classpath:applicationContext.xml - - - org.springframework.web.context.ContextLoaderListener - - - yi.master.listener.InitWebListener - - - - - DruidWebStatFilter - com.alibaba.druid.support.http.WebStatFilter - - exclusions - *.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/* - - - + + yi + + login.html + + + 180 + + + log4jConfigLocation + classpath:log4j.properties + + + log4jRefreshInterval + 60000 + + + contextConfigLocation + classpath:applicationContext.xml + + + + + org.springframework.web.util.Log4jConfigListener + + + + + org.springframework.web.context.ContextLoaderListener + + + + yi.master.listener.InitWebListener + + + + + + + DruidWebStatFilter + com.alibaba.druid.support.http.WebStatFilter + + exclusions + *.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/* + + + + + DruidWebStatFilter + /* + + + + + DruidStatView + com.alibaba.druid.support.http.StatViewServlet + + + + DruidStatView + /druid/* + + + + + encodingFilter + org.springframework.web.filter.CharacterEncodingFilter + + encoding + UTF-8 + + + forceEncoding + true + + - DruidWebStatFilter - /* - - - - - DruidStatView - com.alibaba.druid.support.http.StatViewServlet - + encodingFilter + /* + + + + + XssEscape + yi.master.util.xss.XssFilter + + + XssEscape + /* + REQUEST + + + + + openSessionInView + org.springframework.orm.hibernate4.support.OpenSessionInViewFilter + + sessionFactoryBeanName + sessionFactory + + + + openSessionInView + /* + + + + + struts2 + org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter + + + struts2 + /* + + - - DruidStatView - /druid/* - - - - - encodingFilter - org.springframework.web.filter.CharacterEncodingFilter - - encoding - UTF-8 - - - forceEncoding - true - - - - encodingFilter - /* - - - openSessionInView - org.springframework.orm.hibernate4.support.OpenSessionInViewFilter - - sessionFactoryBeanName - sessionFactory - - - - openSessionInView - /* - - - struts2 - org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter - - - struts2 - /* - - - - \ No newline at end of file diff --git a/update.md b/update.md index 9c17ede..e78353a 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,25 @@ +1、增加websocket接口mock; +2、默认不展示web自动化测试模块; +3、增加初级的测试数据池功能; +4、增加历史数据报表功能。 +5、优化数据验证、数据库验证等功能; +6、支持对数组的取值,设定值; +7、增加测试集全局配置:头信息、验证规则、测试集变量等功能; +8、完善操作说明手册, +9、支持从yapi/rap/postman/swagger/各种规范的日志文件中导入接口; +10、一键安装包 for linux; +11、更加方便安全的版本更新方案; +12、主页和论坛。 + + + + +### v1.0.0正式版 +#### 2019 +- 新增:xss过滤器; + + + ### v0.2.1beta #### 2019.11.17 - 修复:HTTP协议使用GET请求如果参数值为空的情况会导致无法正确的拼接查询参数到URL后面的问题; -- Gitee From c4c4a4d5fac73fb89d9575531eb59d1bbcc841b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E5=87=B0=E9=99=A2=E5=A4=A7=E7=99=BD?= Date: Wed, 20 Nov 2019 17:23:14 +0800 Subject: [PATCH 02/18] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 666ca9f..3a455fb 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,14 @@ QQ群交流:468324085,加群验证:易大师 [演示地址](http://www.xuwangcheng.com/yi)(账号 tester/11111111) -#### 一键安装包 +#### 一键安装 for windows 百度云: https://pan.baidu.com/s/1i8siuIuPXsjlnawYFc4c6A **账号 admin/q708162543** **安装完成进入安装根目录,双击执行start.bat,弹出两个cmd窗口不要关闭,打开浏览器输入http://localhost:8080** +#### Linux安装教程 +https://gitee.com/xuwangcheng/masteryi-automated-testing/wikis/pages?sort_id=1736227&doc_id=196989 + #### 主要功能 - 接口、报文、场景三层分离,接口测试更加灵活多变; - 支持Http/Https/Socket/WebService/WebSocket/Dubbo协议接口,后续支持更多; -- Gitee From 2636f17288dd44648e43fdcfb8e1f1310ce5b09b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=87=A4=E5=87=B0=E9=99=A2=E5=A4=A7=E7=99=BD?= Date: Wed, 20 Nov 2019 17:30:50 +0800 Subject: [PATCH 03/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a455fb..db2b364 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ QQ群交流:468324085,加群验证:易大师 **安装完成进入安装根目录,双击执行start.bat,弹出两个cmd窗口不要关闭,打开浏览器输入http://localhost:8080** #### Linux安装教程 -https://gitee.com/xuwangcheng/masteryi-automated-testing/wikis/pages?sort_id=1736227&doc_id=196989 +https://www.xuwangcheng.com/articles/2019/11/20/1574239339298.html #### 主要功能 - 接口、报文、场景三层分离,接口测试更加灵活多变; -- Gitee From ff248a1fc6f3229c869176b981b0f1abc5a32d64 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Fri, 22 Nov 2019 17:00:34 +0800 Subject: [PATCH 04/18] =?UTF-8?q?=E5=A2=9E=E5=8A=A0WebSockets=E7=9A=84?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3Mock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advanced/action/InterfaceMockAction.java | 29 +-- .../business/advanced/bean/InterfaceMock.java | 17 +- .../config/mock/MockGenerateRuleConfig.java | 11 +- .../advanced/dao/InterfaceMockDao.java | 11 +- .../dao/impl/InterfaceMockDaoImpl.java | 11 +- .../advanced/enums/InterfaceProbeStatus.java | 2 +- .../advanced/enums/MockConfigSettingType.java | 12 + .../service/InterfaceMockService.java | 13 +- .../impl/InterfaceMockServiceImpl.java | 9 +- .../business/message/bean/Parameter.java | 43 ++-- .../java/yi/master/constant/MessageKeys.java | 41 ++-- .../entity/ClientTestResponseObject.java | 2 +- .../message/test/mock/MockServer.java | 219 ++++++++++++++++++ .../message/test/mock/MockSocketServer.java | 210 ++++++----------- .../test/mock/MockWebSocketServer.java | 100 ++++++++ .../yi/master/listener/InitWebListener.java | 9 +- .../java/yi/master/util/PracticalUtils.java | 4 +- .../java/yi/master/util/cache/CacheUtil.java | 51 ++-- src/main/webapp/WEB-INF/web.xml | 18 +- src/main/webapp/js/globalConstant.js | 9 +- src/main/webapp/resource/advanced/mockTest.js | 39 ++-- 21 files changed, 583 insertions(+), 277 deletions(-) create mode 100644 src/main/java/yi/master/business/advanced/enums/MockConfigSettingType.java create mode 100644 src/main/java/yi/master/coretest/message/test/mock/MockServer.java create mode 100644 src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java diff --git a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java index 7af4127..7c2e24e 100644 --- a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java +++ b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java @@ -14,6 +14,7 @@ import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; import yi.master.business.advanced.bean.config.mock.MockResponseConfig; import yi.master.business.advanced.bean.config.mock.MockValidateRuleConfig; import yi.master.business.advanced.enums.InterfaceMockStatus; +import yi.master.business.advanced.enums.MockConfigSettingType; import yi.master.business.base.dto.ParseMessageToNodesOutDTO; import yi.master.business.advanced.service.InterfaceMockService; import yi.master.business.base.action.BaseAction; @@ -21,6 +22,7 @@ import yi.master.business.message.bean.Parameter; import yi.master.business.user.bean.User; import yi.master.constant.MessageKeys; import yi.master.coretest.message.parse.MessageParse; +import yi.master.coretest.message.test.mock.MockServer; import yi.master.coretest.message.test.mock.MockSocketServer; import yi.master.exception.AppErrorCode; import yi.master.exception.YiException; @@ -62,6 +64,7 @@ public class InterfaceMockAction extends BaseAction { public String updateStatus() { interfaceMockService.updateStatus(model.getMockId(), model.getStatus()); + MockServer.handleMockServer(model.getMockId()); return SUCCESS; } @@ -75,24 +78,8 @@ public class InterfaceMockAction extends BaseAction { } else { interfaceMockService.edit(model); } - - //开启Socket模拟服务 - MockSocketServer server = CacheUtil.getSocketServers().get(model.getMockId()); - - if (server != null && (InterfaceMockStatus.DISABLED.getStatus().equals(model.getStatus()) - || !MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(model.getProtocolType()))) { - server.stop(); - } - - if (server == null && InterfaceMockStatus.ENABLED.getStatus().equals(model.getStatus()) - && MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(model.getProtocolType())) { - try { - new MockSocketServer(model.getMockId()); - } catch (Exception e) { - LOGGER.warn(e.getMessage(), e); - } - } - + + MockServer.handleMockServer(model.getMockId()); setData(model); return SUCCESS; } @@ -105,15 +92,15 @@ public class InterfaceMockAction extends BaseAction { String settingType = ""; String settingValue = ""; if (StringUtils.isNotBlank(model.getResponseMock())) { - settingType = "responseMock"; + settingType = MockConfigSettingType.responseMock.name(); settingValue = model.getResponseMock(); } if (StringUtils.isNotBlank(model.getRequestValidate())) { - settingType = "requestValidate"; + settingType = MockConfigSettingType.requestValidate.name(); settingValue = model.getRequestValidate(); } interfaceMockService.updateSetting(model.getMockId(), settingType, settingValue); - MockSocketServer thisSocket = CacheUtil.getSocketServers().get(model.getMockId()); + MockServer thisSocket = CacheUtil.getMockServers().get(model.getMockId()); if (thisSocket != null) { thisSocket.updateConfig(settingType, settingValue); } diff --git a/src/main/java/yi/master/business/advanced/bean/InterfaceMock.java b/src/main/java/yi/master/business/advanced/bean/InterfaceMock.java index c4eb09b..257b3b6 100644 --- a/src/main/java/yi/master/business/advanced/bean/InterfaceMock.java +++ b/src/main/java/yi/master/business/advanced/bean/InterfaceMock.java @@ -3,6 +3,7 @@ package yi.master.business.advanced.bean; import java.io.Serializable; import java.sql.Timestamp; +import org.apache.commons.lang3.StringUtils; import org.apache.struts2.json.annotations.JSON; import yi.master.annotation.FieldNameMapper; @@ -10,6 +11,7 @@ import yi.master.annotation.FieldRealSearch; import yi.master.business.user.bean.User; import yi.master.constant.MessageKeys; import yi.master.constant.SystemConsts; +import yi.master.coretest.message.test.mock.MockServer; import yi.master.coretest.message.test.mock.MockSocketServer; import yi.master.util.cache.CacheUtil; @@ -129,15 +131,12 @@ public class InterfaceMock implements Serializable { if (MessageKeys.ProtocolType.http.name().equalsIgnoreCase(this.protocolType)) { return CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_HOME) + "/mock" + this.mockUrl; } - - if (MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(this.protocolType)) { - MockSocketServer mockServer = CacheUtil.getSocketServers().get(this.mockId); - - if (mockServer != null) { - return mockServer.getMockUrl(); - } - } - + + MockServer mockServer = CacheUtil.getMockServers().get(this.mockId); + if (mockServer != null) { + return mockServer.getMockUrl() + (StringUtils.isNotBlank(this.mockUrl) ? this.mockUrl : ""); + } + return "未启用"; } diff --git a/src/main/java/yi/master/business/advanced/bean/config/mock/MockGenerateRuleConfig.java b/src/main/java/yi/master/business/advanced/bean/config/mock/MockGenerateRuleConfig.java index bee07c2..0ce036c 100644 --- a/src/main/java/yi/master/business/advanced/bean/config/mock/MockGenerateRuleConfig.java +++ b/src/main/java/yi/master/business/advanced/bean/config/mock/MockGenerateRuleConfig.java @@ -49,11 +49,18 @@ public class MockGenerateRuleConfig implements Serializable { public MockGenerateRuleConfig() { super(); } - + + /** + * 生成指定的内容 + * @param requestMsg + * @return + */ public String generateValue(String requestMsg) { switch (this.generateType) { case "node": - if (StringUtils.isBlank(requestMsg)) return this.generateValue; + if (StringUtils.isBlank(requestMsg)) { + return this.generateValue; + } MessageParse parseUtil = MessageParse.getParseInstance(MessageParse.judgeType(requestMsg)); return parseUtil.getObjectByPath(requestMsg, this.generateValue); case "variable": diff --git a/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java b/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java index c14e8ba..cdebed9 100644 --- a/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java +++ b/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java @@ -30,5 +30,14 @@ public interface InterfaceMockDao extends BaseDao{ * 获取所有启用状态的Socket Mock服务 * @return */ - List getEnableSocketMock(); + List getEnableMockServer(); + + /** + * 更新调用次数:包含成功和失败的 + * @author xuwangcheng + * @date 2019/11/22 16:11 + * @param mockId mockId + * @return + */ + void updateCallCount(Integer mockId); } diff --git a/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java b/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java index 032e442..736a21e 100644 --- a/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java +++ b/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java @@ -34,10 +34,15 @@ public class InterfaceMockDaoImpl extends BaseDaoImpl implements } @Override - public List getEnableSocketMock() { - - String hql = "From InterfaceMock m where m.protocolType='Socket' and m.status='0'"; + public List getEnableMockServer() { + String hql = "From InterfaceMock m where m.protocolType in ('WebSocket', 'Socket') and m.status='0'"; return getSession().createQuery(hql).list(); } + @Override + public void updateCallCount(Integer mockId) { + String hql = "update InterfaceMock m set m.callCount=m.callCount + 1 where m.mockId=:mockId"; + getSession().createQuery(hql).setInteger("mockId", mockId).executeUpdate(); + } + } diff --git a/src/main/java/yi/master/business/advanced/enums/InterfaceProbeStatus.java b/src/main/java/yi/master/business/advanced/enums/InterfaceProbeStatus.java index 8a46a2a..aa18f76 100644 --- a/src/main/java/yi/master/business/advanced/enums/InterfaceProbeStatus.java +++ b/src/main/java/yi/master/business/advanced/enums/InterfaceProbeStatus.java @@ -25,7 +25,7 @@ public enum InterfaceProbeStatus { private String status; - private InterfaceProbeStatus (String status) { + InterfaceProbeStatus (String status) { this.status = status; } diff --git a/src/main/java/yi/master/business/advanced/enums/MockConfigSettingType.java b/src/main/java/yi/master/business/advanced/enums/MockConfigSettingType.java new file mode 100644 index 0000000..39d9f65 --- /dev/null +++ b/src/main/java/yi/master/business/advanced/enums/MockConfigSettingType.java @@ -0,0 +1,12 @@ +package yi.master.business.advanced.enums; + +/** + * mock配置的种类 + * @author xuwangcheng + * @version 1.0.0 + * @description + * @date 2019/11/22 10:26 + */ +public enum MockConfigSettingType { + responseMock,requestValidate +} diff --git a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java index f8535bd..ef12d8b 100644 --- a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java +++ b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java @@ -29,8 +29,17 @@ public interface InterfaceMockService extends BaseService { void updateSetting(Integer mockId, String settingType, String configJson); /** - * 获取所有启用状态的Socket Mock服务 + * 获取所有启用状态的 Mock服务 * @return */ - List getEnableSocketMock(); + List getEnableMockServer(); + + /** + * 更新调用次数:包含成功和失败的 + * @author xuwangcheng + * @date 2019/11/22 16:11 + * @param mockId mockId + * @return + */ + void updateCallCount(Integer mockId); } diff --git a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java index 5cf4102..46d9a23 100644 --- a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java +++ b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java @@ -43,8 +43,13 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp } @Override - public List getEnableSocketMock() { + public List getEnableMockServer() { - return interfaceMockDao.getEnableSocketMock(); + return interfaceMockDao.getEnableMockServer(); } + + @Override + public void updateCallCount(Integer mockId) { + interfaceMockDao.updateCallCount(mockId); + } } diff --git a/src/main/java/yi/master/business/message/bean/Parameter.java b/src/main/java/yi/master/business/message/bean/Parameter.java index 0551fc2..54be029 100644 --- a/src/main/java/yi/master/business/message/bean/Parameter.java +++ b/src/main/java/yi/master/business/message/bean/Parameter.java @@ -104,8 +104,10 @@ public class Parameter implements Serializable { * @return */ public static Integer getParentId (String path, Set parameters) { - if (MessageKeys.MESSAGE_PARAMETER_DEFAULT_ROOT_PATH.equals(path)) { - return 0; //根节点 + if (MessageKeys.MESSAGE_PARAMETER_DEFAULT_ROOT_PATH.equalsIgnoreCase(path) + || MessageKeys.MESSAGE_PARAMETER_CUSTOM_PATH_NAME.equalsIgnoreCase(path)) { + //根节点 + return 0; } String parentIdentify = path.substring(path.lastIndexOf(".") + 1); @@ -114,7 +116,8 @@ public class Parameter implements Serializable { if (p != null) { return p.getParameterId(); } - return null; //找不到父节点 + //找不到父节点 + return null; } private static Parameter findParam (String identify, String path, Set parameters) { @@ -241,23 +244,37 @@ public class Parameter implements Serializable { @Override public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; + if (this == obj) { + return true; + } + + if (obj == null){ + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + Parameter other = (Parameter) obj; if (parameterIdentify == null) { if (other.parameterIdentify != null) - return false; + { + return false; + } } else if (!parameterIdentify.equals(other.parameterIdentify)) - return false; + { + return false; + } if (path == null) { if (other.path != null) - return false; + { + return false; + } } else if (!path.equals(other.path)) - return false; + { + return false; + } return true; } diff --git a/src/main/java/yi/master/constant/MessageKeys.java b/src/main/java/yi/master/constant/MessageKeys.java index 735f6b8..47fdd4d 100644 --- a/src/main/java/yi/master/constant/MessageKeys.java +++ b/src/main/java/yi/master/constant/MessageKeys.java @@ -167,7 +167,7 @@ public interface MessageKeys { private TestClient client; - private ProtocolType(TestClient client) { + ProtocolType(TestClient client) { this.client = client; } @@ -209,7 +209,7 @@ public interface MessageKeys { private String code; - private TestRunStatus (String code) { + TestRunStatus (String code) { this.code = code; } @@ -256,48 +256,49 @@ public interface MessageKeys { /**协议公共调用参数*/ - public static final String PUBLIC_PARAMETER_CONNECT_TIMEOUT = "ConnectTimeOut"; - public static final String PUBLIC_PARAMETER_READ_TIMEOUT = "ReadTimeOut"; - public static final String PUBLIC_PARAMETER_USERNAME = "Username"; - public static final String PUBLIC_PARAMETER_PASSWORD = "Password"; - public static final String PUBLIC_PARAMETER_METHOD = "Method"; + String PUBLIC_PARAMETER_CONNECT_TIMEOUT = "ConnectTimeOut"; + String PUBLIC_PARAMETER_READ_TIMEOUT = "ReadTimeOut"; + String PUBLIC_PARAMETER_USERNAME = "Username"; + String PUBLIC_PARAMETER_PASSWORD = "Password"; + String PUBLIC_PARAMETER_METHOD = "Method"; /**HTTP协议调用参数*/ - public static final String HTTP_PARAMETER_HEADER = "Headers"; - public static final String HTTP_PARAMETER_QUERYS = "Querys"; - public static final String HTTP_PARAMETER_AUTHORIZATION = "Authorization"; - public static final String HTTP_PARAMETER_ENC_TYPE = "EncType"; - public static final String HTTP_PARAMETER_REC_ENC_TYPE = "RecEncType"; + String HTTP_PARAMETER_HEADER = "Headers"; + String HTTP_PARAMETER_QUERYS = "Querys"; + String HTTP_PARAMETER_AUTHORIZATION = "Authorization"; + String HTTP_PARAMETER_ENC_TYPE = "EncType"; + String HTTP_PARAMETER_REC_ENC_TYPE = "RecEncType"; /**webservice协议调用参数*/ - public static final String WEB_SERVICE_PARAMETER_NAMESPACE = "Namespace"; + String WEB_SERVICE_PARAMETER_NAMESPACE = "Namespace"; /**默认path路径根节点*/ - public static final String MESSAGE_PARAMETER_DEFAULT_ROOT_PATH = "TopRoot"; + String MESSAGE_PARAMETER_DEFAULT_ROOT_PATH = "TopRoot"; + String MESSAGE_PARAMETER_CUSTOM_PATH_NAME = "path"; /**测试环境中默认路径中的替换变量*/ - public static final String BUSINESS_SYSTEM_DEFAULTPATH_NAME_ATTRIBUTE = "\\$\\{name\\}"; - public static final String BUSINESS_SYSTEM_DEFAULTPATH_PATH_ATTRIBUTE = "\\$\\{path\\}"; + String BUSINESS_SYSTEM_DEFAULTPATH_NAME_ATTRIBUTE = "\\$\\{name\\}"; + String BUSINESS_SYSTEM_DEFAULTPATH_PATH_ATTRIBUTE = "\\$\\{path\\}"; /** * 使用节点参数时需要再参数路径左右加上以下左右边界 */ - public static final String CUSTOM_PARAMETER_BOUNDARY_SYMBOL_LEFT = "#"; - public static final String CUSTOM_PARAMETER_BOUNDARY_SYMBOL_RIGHT = "#"; + String CUSTOM_PARAMETER_BOUNDARY_SYMBOL_LEFT = "#"; + String CUSTOM_PARAMETER_BOUNDARY_SYMBOL_RIGHT = "#"; /** * quartz定时任务执行的测试将会在对应的测试报告添加下面的备注 */ - public static final String QUARTZ_AUTO_TEST_REPORT_MARK = "自动化定时任务"; + String QUARTZ_AUTO_TEST_REPORT_MARK = "自动化定时任务"; /** * 缺少测试数据时测试详情中的备注 */ - public static final String NO_ENOUGH_TEST_DATA_RESULT_MARK = "缺少测试数据"; + String NO_ENOUGH_TEST_DATA_RESULT_MARK = "缺少测试数据"; } diff --git a/src/main/java/yi/master/coretest/message/protocol/entity/ClientTestResponseObject.java b/src/main/java/yi/master/coretest/message/protocol/entity/ClientTestResponseObject.java index 95ec84e..925592a 100644 --- a/src/main/java/yi/master/coretest/message/protocol/entity/ClientTestResponseObject.java +++ b/src/main/java/yi/master/coretest/message/protocol/entity/ClientTestResponseObject.java @@ -30,7 +30,7 @@ public class ClientTestResponseObject { /** * 一般是测试失败时的备注 */ - private String mark; + private String mark = ""; public String getResponseMessage() { return responseMessage; diff --git a/src/main/java/yi/master/coretest/message/test/mock/MockServer.java b/src/main/java/yi/master/coretest/message/test/mock/MockServer.java new file mode 100644 index 0000000..2697679 --- /dev/null +++ b/src/main/java/yi/master/coretest/message/test/mock/MockServer.java @@ -0,0 +1,219 @@ +package yi.master.coretest.message.test.mock; + +import cn.hutool.core.thread.ThreadUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import yi.master.business.advanced.bean.InterfaceMock; +import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; +import yi.master.business.advanced.bean.config.mock.MockResponseConfig; +import yi.master.business.advanced.enums.InterfaceMockStatus; +import yi.master.business.advanced.enums.MockConfigSettingType; +import yi.master.business.advanced.service.InterfaceMockService; +import yi.master.constant.MessageKeys; +import yi.master.constant.SystemConsts; +import yi.master.util.FrameworkUtil; +import yi.master.util.cache.CacheUtil; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +/** + * mock服务抽象类 + * @author xuwangcheng + * @version 1.0.0 + * @description + * @date 2019/11/21 19:02 + */ +public abstract class MockServer { + private static final Logger logger = LoggerFactory.getLogger(MockServer.class); + + protected static final InterfaceMockService mockService = (InterfaceMockService) FrameworkUtil.getSpringBean(InterfaceMockService.class); + protected Integer mockId; + protected MockRequestValidateConfig validateConfig; + protected MockResponseConfig mockConfig; + protected String errorMsg; + protected String mockUrl; + + protected MockServer(Integer mockId) throws Exception { + this.mockId = mockId; + InterfaceMock interfaceMock = mockService.get(mockId); + if (interfaceMock == null) { + throw new Exception("Mock信息不存在!"); + } + + validateConfig = MockRequestValidateConfig.getInstance(interfaceMock.getRequestValidate()); + mockConfig = MockResponseConfig.getInstance(interfaceMock.getResponseMock()); + } + + /** + * 实例化Mock服务 + * @author xuwangcheng + * @date 2019/11/22 10:02 + * @param protocolType protocolType + * @param mockId mockId + * @return {@link MockServer} + */ + public static MockServer getMockServerInstance (String protocolType, Integer mockId) throws Exception { + if (MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(protocolType)) { + return new MockSocketServer(mockId); + } + if (MessageKeys.ProtocolType.websocket.name().equalsIgnoreCase(protocolType)) { + return new MockWebSocketServer(mockId); + } + + + return null; + } + + /** + * 通过mockId开启或者关闭mock服务 + * @author xuwangcheng + * @date 2019/11/22 16:38 + * @param mockId mockId + * @return + */ + public static void handleMockServer (Integer mockId) { + InterfaceMock model = mockService.get(mockId); + if (model == null) { + return; + } + + MockServer server = CacheUtil.getMockServers().get(model.getMockId()); + //关闭 + if (server != null && (InterfaceMockStatus.DISABLED.getStatus().equals(model.getStatus()))) { + server.stop(); + } + //开启 + if (server == null && InterfaceMockStatus.ENABLED.getStatus().equals(model.getStatus())) { + try { + MockServer mockServer = MockServer.getMockServerInstance(model.getProtocolType(), model.getMockId()); + if (mockServer != null) { + mockServer.start(); + } + } catch (Exception e) { + logger.warn(e.getMessage(), e); + } + } + } + + /** + * 是否已经开启运行 + * @author xuwangcheng + * @date 2019/11/22 16:51 + * @param mockId mockId + * @return {@link boolean} + */ + public static boolean isOpen (Integer mockId) { + return CacheUtil.getMockServers().get(mockId) != null; + } + + /** + * 启动Mock服务 + * @author xuwangcheng + * @date 2019/11/22 10:22 + * @param + * @return + */ + public abstract void start(); + /** + * 停止Mock服务 + * @author xuwangcheng + * @date 2019/11/22 10:23 + * @param + * @return + */ + public abstract void stop(); + /** + * 获取请求地址,不包含路径 + * @author xuwangcheng + * @date 2019/11/22 10:23 + * @param + * @return {@link String} + */ + public abstract String getMockUrl(); + + /** + * 更新Mock配置 + * @author xuwangcheng + * @date 2019/11/22 10:25 + * @param settingType settingType + * @param settingValue settingValue + * @return + */ + public void updateConfig(String settingType, String settingValue) { + if (MockConfigSettingType.responseMock.name().equals(settingType)) { + this.mockConfig = MockResponseConfig.getInstance(settingValue); + } + if (MockConfigSettingType.requestValidate.name().equals(settingType)) { + this.validateConfig = MockRequestValidateConfig.getInstance(settingValue); + } + } + + protected String getHost () { + String ip = ""; + try { + InetAddress addr = InetAddress.getLocalHost(); + ip = addr.getHostAddress().toString(); + } catch (Exception e) { + logger.error("获取服务器本地地址失败,使用配置选项!", e); + String homeUrl = CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_HOME); + ip = homeUrl.substring(homeUrl.indexOf("/") + 2, homeUrl.lastIndexOf(":")); + } + + return ip; + } + + /** + * 测试本机端口是否被使用 + * @param port + * @return + */ + protected boolean isLocalPortUsing(int port){ + boolean flag = true; + try { + //如果该端口还在使用则返回true,否则返回false,127.0.0.1代表本机 + flag = isPortUsing("127.0.0.1", port); + } catch (Exception e) { + } + return flag; + } + /*** + * 测试主机Host的port端口是否被使用 + * @param host + * @param port + * @throws UnknownHostException + */ + private boolean isPortUsing(String host, int port) throws UnknownHostException { + boolean flag = false; + InetAddress Address = InetAddress.getByName(host); + try { + //建立一个Socket连接 + Socket socket = new Socket(Address, port); + if (socket != null) { + socket.close(); + } + flag = true; + } catch (IOException e) {} + return flag; + } + + + /** + * 更新调用次数 + * @author xuwangcheng + * @date 2019/11/22 16:16 + * @param + * @return + */ + protected void updateCallCount () { + ThreadUtil.execute(new Runnable() { + @Override + public void run() { + mockService.updateCallCount(mockId); + } + }); + } + +} diff --git a/src/main/java/yi/master/coretest/message/test/mock/MockSocketServer.java b/src/main/java/yi/master/coretest/message/test/mock/MockSocketServer.java index e780ca4..5ae85fc 100644 --- a/src/main/java/yi/master/coretest/message/test/mock/MockSocketServer.java +++ b/src/main/java/yi/master/coretest/message/test/mock/MockSocketServer.java @@ -1,127 +1,98 @@ package yi.master.coretest.message.test.mock; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.io.Writer; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; - +import cn.hutool.core.thread.ThreadUtil; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - -import yi.master.business.advanced.bean.InterfaceMock; -import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; -import yi.master.business.advanced.bean.config.mock.MockResponseConfig; -import yi.master.business.advanced.service.InterfaceMockService; import yi.master.constant.SystemConsts; -import yi.master.util.FrameworkUtil; import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; +import java.io.*; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + /** * socket类型的mock服务 * @author xuwangcheng * @version 20180731 * */ -public class MockSocketServer { +public class MockSocketServer extends MockServer { private static final Logger logger = Logger.getLogger(MockSocketServer.class); - private static final InterfaceMockService mockService = (InterfaceMockService) FrameworkUtil.getSpringBean(InterfaceMockService.class); - - private Integer mockId; - - private MockRequestValidateConfig validateConfig; - - private MockResponseConfig mockConfig; - private ServerSocket socket; - - private String errorMsg; - public MockSocketServer(Integer mockId) throws Exception { - super(); - this.mockId = mockId; - - InterfaceMock interfaceMock = mockService.get(mockId); - if (interfaceMock == null) { - throw new Exception("Mock信息不存在!"); - } - - validateConfig = MockRequestValidateConfig.getInstance(interfaceMock.getRequestValidate()); - mockConfig = MockResponseConfig.getInstance(interfaceMock.getResponseMock()); - - boolean flag = true; - while (flag) { - try { - socket = new ServerSocket(PracticalUtils.getRandomNum(65535, 10025)); - flag = false; - } catch (Exception e) { - - logger.error("创建Socket server 出错, 等待重新创建!", e); - } - } - new Thread(new Runnable() { - @Override - public void run() { - - start(); - } - }).start(); - - CacheUtil.getSocketServers().put(mockId, this); + protected MockSocketServer(Integer mockId) throws Exception { + super(mockId); } - public MockSocketServer() { - super(); + @Override + public void start() { + boolean flag = true; + while (flag) { + try { + socket = new ServerSocket(PracticalUtils.getRandomNum(65535, 10025)); + flag = false; + } catch (Exception e) { + logger.error("创建Socket server 出错, 等待重新创建!", e); + } + } + + ThreadUtil.execute(new Runnable() { + @Override + public void run() { + while (!socket.isClosed()) { + Socket connection =null; + try { + connection = socket.accept(); + updateCallCount(); + String requestMessage = readMessageFromClient(connection.getInputStream()); + logger.debug("MockSocketServer " + getMockUrl() + " 接收到数据:" + requestMessage); + String responseMsg = validateConfig.validate(null, requestMessage); + if (SystemConsts.DefaultBooleanIdentify.TRUE.getString().equals(responseMsg)) { + responseMsg = mockConfig.generate(null, requestMessage); + } else if (StringUtils.isNotBlank(mockConfig.getExampleErrorMsg())) { + responseMsg = PracticalUtils.replaceGlobalVariable(mockConfig.getExampleErrorMsg().replace("${errorMsg}", responseMsg), null); + } + + writeMsgToClient(connection.getOutputStream(), responseMsg); + logger.debug("MockSocketServer " + getMockUrl() + " 回复数据:" + responseMsg); + connection.close(); + } catch (Exception e) { + logger.error("Socket Server " + getMockUrl() + " 处理socket请求出错!", e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (IOException e) { + logger.warn("IOException", e); + } + } + } + } + } + }); + + CacheUtil.getMockServers().put(mockId, this); } - - private void start() { - while (!socket.isClosed()) { - Socket connection =null; - - try { - connection = socket.accept(); - - String requestMessage = readMessageFromClient(connection.getInputStream()); - logger.debug("MockSocketServer " + getMockUrl() + " 接收到数据:" + requestMessage); - String responseMsg = validateConfig.validate(null, requestMessage); - if (SystemConsts.DefaultBooleanIdentify.TRUE.getString().equals(responseMsg)) { - responseMsg = mockConfig.generate(null, requestMessage); - } else if (StringUtils.isNotBlank(mockConfig.getExampleErrorMsg())) { - responseMsg = PracticalUtils.replaceGlobalVariable(mockConfig.getExampleErrorMsg().replace("${errorMsg}", responseMsg), null); - } - - writeMsgToClient(connection.getOutputStream(), responseMsg); - logger.debug("MockSocketServer " + getMockUrl() + " 回复数据:" + responseMsg); - connection.close(); - } catch (Exception e) { - logger.error("Socket Server " + getMockUrl() + " 处理socket请求出错!", e); - } finally { - if (connection != null) { - try { - connection.close(); - } catch (IOException e) { - logger.warn("IOException", e); - } - } - } - } - } - + + @Override + public String getMockUrl() { + if (StringUtils.isBlank(mockUrl)) { + mockUrl = getHost() + ":" + socket.getLocalPort(); + } + return mockUrl; + } + + @Override public void stop() { try { if (socket != null) { socket.close(); } - CacheUtil.getSocketServers().remove(mockId); + CacheUtil.getMockServers().remove(mockId); } catch (IOException e) { logger.error("关闭Socket server 失败!", e); } @@ -155,49 +126,4 @@ public class MockSocketServer { writer.flush(); writer.close(); } - - public void updateConfig(String settingType, String settingValue) { - if ("responseMock".equals(settingType)) { - this.mockConfig = MockResponseConfig.getInstance(settingValue); - } - if ("requestValidate".equals(settingType)) { - this.validateConfig = MockRequestValidateConfig.getInstance(settingValue); - } - } - - public void setMockId(Integer mockId) { - this.mockId = mockId; - } - - public Integer getMockId() { - return mockId; - } - - public ServerSocket getSocket() { - return socket; - } - - public void setErrorMsg(String errorMsg) { - this.errorMsg = errorMsg; - } - - public String getErrorMsg() { - return errorMsg; - } - - public String getMockUrl() { - String ip = ""; - - try { - InetAddress addr = InetAddress.getLocalHost(); - ip = addr.getHostAddress().toString(); - } catch (Exception e) { - logger.error("获取服务器本地地址失败,使用配置选项!", e); - String homeUrl = CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_HOME); - ip = homeUrl.substring(homeUrl.indexOf("/") + 2, homeUrl.lastIndexOf(":")); - } - - return ip + ":" + socket.getLocalPort(); - } - } diff --git a/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java b/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java new file mode 100644 index 0000000..9744f24 --- /dev/null +++ b/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java @@ -0,0 +1,100 @@ +package yi.master.coretest.message.test.mock; + +import cn.hutool.core.util.StrUtil; +import org.apache.commons.lang.StringUtils; +import org.apache.log4j.Logger; +import org.java_websocket.WebSocket; +import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.server.WebSocketServer; +import yi.master.constant.SystemConsts; +import yi.master.util.PracticalUtils; +import yi.master.util.cache.CacheUtil; + +import java.net.InetSocketAddress; + +/** + * + * webSocketMock服务 + * @author xuwangcheng + * @version 1.0.0 + * @description + * @date 2019/11/22 8:52 + */ +public class MockWebSocketServer extends MockServer { + private static final Logger logger = Logger.getLogger(MockWebSocketServer.class); + private WebSocketServer webSocketServer; + + protected MockWebSocketServer(Integer mockId) throws Exception { + super(mockId); + } + + @Override + public void start() { + int randomPort = PracticalUtils.getRandomNum(65535, 1024); + while (isLocalPortUsing(randomPort)) { + randomPort = PracticalUtils.getRandomNum(65535, 1024); + } + + webSocketServer = new WebSocketServer(new InetSocketAddress(randomPort)) { + @Override + public void onOpen(WebSocket conn, ClientHandshake handshake) { + logger.debug(StrUtil.format("WebSocketMockServer {} on Open...", getMockUrl())); + } + + @Override + public void onClose(WebSocket conn, int code, String reason, boolean remote) { + logger.debug(StrUtil.format("WebSocketMockServer {} on Close:\ncode={}", getMockUrl(), code)); + } + + @Override + public void onMessage(WebSocket conn, String message) { + logger.info(StrUtil.format("WebSocketMockServer {} on Message:\n{}", getMockUrl(), message)); + updateCallCount(); + //处理消息 + String responseMsg = validateConfig.validate(null, message); + if (SystemConsts.DefaultBooleanIdentify.TRUE.getString().equals(responseMsg)) { + responseMsg = mockConfig.generate(null, message); + } else if (StringUtils.isNotBlank(mockConfig.getExampleErrorMsg())) { + responseMsg = PracticalUtils.replaceGlobalVariable(mockConfig.getExampleErrorMsg().replace("${errorMsg}", responseMsg), null); + } + //回复消息 + conn.send(responseMsg); + logger.info(StrUtil.format("WebSocketMockServer {} Response :\n{}", getMockUrl(), responseMsg)); + } + + @Override + public void onError(WebSocket conn, Exception ex) { + logger.debug(StrUtil.format("WebSocketMockServer {} on Error...", getMockUrl())); + } + + @Override + public void onStart() { + logger.debug(StrUtil.format("WebSocketMockServer {} Start...", getMockUrl())); + } + }; + + webSocketServer.start(); + CacheUtil.getMockServers().put(mockId, this); + } + + @Override + public void stop() { + try { + if (webSocketServer != null) { + webSocketServer.stop(); + } + CacheUtil.getMockServers().remove(mockId); + } catch (Exception e) { + logger.error("关闭WebSocket server 失败!", e); + } + } + + @Override + public String getMockUrl() { + if (StringUtils.isBlank(mockUrl)) { + mockUrl = "ws://" + getHost() + ":" + this.webSocketServer.getPort(); + } + return mockUrl; + } + +} diff --git a/src/main/java/yi/master/listener/InitWebListener.java b/src/main/java/yi/master/listener/InitWebListener.java index 1ac3091..1eefa7d 100644 --- a/src/main/java/yi/master/listener/InitWebListener.java +++ b/src/main/java/yi/master/listener/InitWebListener.java @@ -24,6 +24,7 @@ import yi.master.business.system.service.OperationInterfaceService; import yi.master.business.testconfig.bean.DataDB; import yi.master.business.testconfig.service.DataDBService; import yi.master.constant.SystemConsts; +import yi.master.coretest.message.test.mock.MockServer; import yi.master.coretest.message.test.mock.MockSocketServer; import yi.master.coretest.task.JobManager; import yi.master.util.FrameworkUtil; @@ -46,7 +47,7 @@ public class InitWebListener implements ServletContextListener { while (CacheUtil.saveRecord()) {} //关闭Mock Socket Server - for (MockSocketServer server:CacheUtil.getSocketServers().values()) { + for (MockServer server:CacheUtil.getMockServers().values()) { server.stop(); } @@ -120,10 +121,10 @@ public class InitWebListener implements ServletContextListener { new Timer().schedule(new LogRecordStorageTimeTask(), 5000, 60000); //启动所有的Socket Mock服务 - List socketMocks = ((InterfaceMockService) FrameworkUtil.getSpringBean(InterfaceMockService.class)).getEnableSocketMock(); - for (InterfaceMock mock:socketMocks) { + List mocks = ((InterfaceMockService) FrameworkUtil.getSpringBean(InterfaceMockService.class)).getEnableMockServer(); + for (InterfaceMock mock:mocks) { try { - new MockSocketServer(mock.getMockId()); + MockServer.getMockServerInstance(mock.getProtocolType(), mock.getMockId()).start(); } catch (Exception e) { LOGGER.error("Mock Socket服务失败:mockName=" + mock.getMockName() + ",mockId=" + mock.getMockId(), e); } diff --git a/src/main/java/yi/master/util/PracticalUtils.java b/src/main/java/yi/master/util/PracticalUtils.java index b488ed7..be63c1b 100644 --- a/src/main/java/yi/master/util/PracticalUtils.java +++ b/src/main/java/yi/master/util/PracticalUtils.java @@ -730,14 +730,14 @@ public class PracticalUtils { */ @SuppressWarnings({ "static-access", "unchecked", "rawtypes" }) public static Map getComplexSceneConfigs (String configJson) { - JSONObject obj = new JSONObject().fromObject(configJson); + JSONObject obj = JSONObject.fromObject(configJson); Map configs = new HashMap(); Map classMap = new HashMap(); classMap.put("useVariables", Map.class); classMap.put("saveVariables", Map.class); - Map objs = (Map) obj.toBean(obj, Map.class); + Map objs = (Map) JSONObject.toBean(obj, Map.class); for (String key:objs.keySet()) { JSONObject o = obj.getJSONObject(key); configs.put(key, (ComplexSceneConfig) JSONObject.toBean(o, ComplexSceneConfig.class, classMap)); diff --git a/src/main/java/yi/master/util/cache/CacheUtil.java b/src/main/java/yi/master/util/cache/CacheUtil.java index 0d0d8f7..5e8caed 100644 --- a/src/main/java/yi/master/util/cache/CacheUtil.java +++ b/src/main/java/yi/master/util/cache/CacheUtil.java @@ -13,6 +13,7 @@ import yi.master.business.log.bean.LogRecord; import yi.master.business.log.service.LogRecordService; import yi.master.business.system.bean.GlobalSetting; import yi.master.business.testconfig.bean.DataDB; +import yi.master.coretest.message.test.mock.MockServer; import yi.master.coretest.message.test.mock.MockSocketServer; import yi.master.coretest.message.test.performance.PerformanceTestObject; import yi.master.util.FrameworkUtil; @@ -51,11 +52,11 @@ public class CacheUtil { * 性能测试对象 */ private static Map> ptObjects = new HashMap>(); - - /** - * socket类型mock服务,key值为对应的mock对象的mockId - */ - private static Map socketServers = new HashMap(); + + /** + * mock相关服务,key值为对应的mock对象的mockId + */ + private static Map mockServers = new HashMap<>(); public static void setQueryDBMap(Map queryDBMap) { @@ -232,25 +233,25 @@ public class CacheUtil { pts.put(ptObject.getObjectId(), ptObject); } - /** - * 设置SocketMock服务集合 - * @author xuwangcheng - * @date 2019/8/30 15:54 - * @param socketServers socketServers - */ - public static void setSocketServers( - Map socketServers) { - CacheUtil.socketServers = socketServers; - } + /** + * 设置Mock服务集合 + * @author xuwangcheng + * @date 2019/11/22 9:49 + * @param mockServers mockServers + * @return + */ + public static void setMockServers (Map mockServers) { + CacheUtil.mockServers = mockServers; + } - /** - * 获取SocketMock服务集合 - * @author xuwangcheng - * @date 2019/8/30 15:54 - * @param - * @return {@link Map} - */ - public static Map getSocketServers() { - return socketServers; - } + /** + * 获取Mock服务集合 + * @author xuwangcheng + * @date 2019/11/22 9:49 + * @param + * @return {@link Map} + */ + public static Map getMockServers () { + return mockServers; + } } diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 0ce004d..ed91172 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -83,15 +83,15 @@ - - XssEscape - yi.master.util.xss.XssFilter - - - XssEscape - /* - REQUEST - + + + + + + + + + diff --git a/src/main/webapp/js/globalConstant.js b/src/main/webapp/js/globalConstant.js index 918ab84..b88f5d5 100644 --- a/src/main/webapp/js/globalConstant.js +++ b/src/main/webapp/js/globalConstant.js @@ -397,7 +397,7 @@ var EXPLANATION_MARK = { //接口自动化相关 -//报文处理类型参数设置 +//报文处理器参数设置 var MESSAGE_PROCESS = { "ShanXiOpenApi":{ "pemFilePath":"" @@ -410,6 +410,13 @@ var MESSAGE_PROCESS = { } } +//接口可Mock类型 +var MESSAGE_MOCK_TYPE = { + "HTTP":"HTTP", + "Socket": "Socket", + "WebSocket": "WebSocket" +} + //接口协议-调用参数配置信息 var MESSAGE_PROTOCOL = { "HTTP":{ diff --git a/src/main/webapp/resource/advanced/mockTest.js b/src/main/webapp/resource/advanced/mockTest.js index f216c36..ace417c 100644 --- a/src/main/webapp/resource/advanced/mockTest.js +++ b/src/main/webapp/resource/advanced/mockTest.js @@ -34,14 +34,16 @@ var templateParams = { label:"协议", select:[{ name:"protocolType", - option:[{ - value:"HTTP", - text:"HTTP" - }, - { - value:"Socket", - text:"Socket" - }] + option:function(){ + let arr = []; + $.each(MESSAGE_MOCK_TYPE, function(i, n){ + arr.push({ + value:n, + text: i + }); + }); + return arr; + }() }] }, { @@ -112,17 +114,16 @@ var columnsSetting = [ { "data":"protocolType", "render":function(data) { - var option = { - "HTTP":{ - btnStyle:"success", - status:"HTTP" - }, - "Socket":{ - btnStyle:"primary", - status:"Socket" - } - }; - return labelCreate(data, option); + var option = {}; + + $.each(MESSAGE_MOCK_TYPE, function(i, n) { + option[i] = { + btnStyle:"success", + status:n + } + }); + + return labelCreate(data, option); }}, { "data":null, -- Gitee From 7eac6f15a65b3368e0cc0f0411f8f981cc10765b Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Fri, 22 Nov 2019 18:16:31 +0800 Subject: [PATCH 05/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/webapp/js/dcits.js | 4 ++-- src/main/webapp/resource/message/complexScene.js | 6 +++--- src/main/webapp/resource/message/setScene.js | 13 ++++++------- update.md | 9 ++++++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/webapp/js/dcits.js b/src/main/webapp/js/dcits.js index dcd5395..53c349a 100644 --- a/src/main/webapp/js/dcits.js +++ b/src/main/webapp/js/dcits.js @@ -1058,10 +1058,10 @@ function layer_show (title, url, w, h, type, success, cancel, end, other) { url="/404.html"; }; if (w == null || w == '' || w >= maxWidth) { - w = maxWidth * 0.8 + w = maxWidth * 0.86 }; if (h == null || h == '' || h >= maxHeight) { - h= (maxHeight * 0.86) ; + h= (maxHeight * 0.9) ; }; if (type == null || type == '') { type = 2; diff --git a/src/main/webapp/resource/message/complexScene.js b/src/main/webapp/resource/message/complexScene.js index 46fbaa0..2d22c95 100644 --- a/src/main/webapp/resource/message/complexScene.js +++ b/src/main/webapp/resource/message/complexScene.js @@ -232,9 +232,9 @@ var eventList = { }, ".show-scenes":function() { //管理组合中的测试场景 - if (setId != null) {//测试集中展示组合场景不能管理 - return false; - } + // if (setId != null) {//测试集中展示组合场景不能管理 + // return false; + // } var data = table.row( $(this).parents('tr') ).data(); layer_show(data.complexSceneName + "-组合场景设定", "messageScene.html?complexSceneId=" + data.id, null, null, 2, null, null, function() { refreshTable(); diff --git a/src/main/webapp/resource/message/setScene.js b/src/main/webapp/resource/message/setScene.js index 00a8eb0..351d95c 100644 --- a/src/main/webapp/resource/message/setScene.js +++ b/src/main/webapp/resource/message/setScene.js @@ -22,18 +22,17 @@ var templateParams = { id:"batch-op", iMarkClass:"Hui-iconfont-del3", name:"批量操作" - },{ + }, { + size:"M", + id:"show-complex-set-scene", + iconFont:"", + name:"组合场景" + }, { type:"success", size:"M", id:"setting-set-config", iconFont:"", name:"运行时设置" - },{ - type:"success", - size:"M", - id:"show-complex-set-scene", - iconFont:"", - name:"组合场景" },{ type:"success", size:"M", diff --git a/update.md b/update.md index e78353a..752970e 100644 --- a/update.md +++ b/update.md @@ -1,4 +1,4 @@ -1、增加websocket接口mock; +~~1、增加websocket接口mock;~~ 2、默认不展示web自动化测试模块; 3、增加初级的测试数据池功能; 4、增加历史数据报表功能。 @@ -9,14 +9,17 @@ 9、支持从yapi/rap/postman/swagger/各种规范的日志文件中导入接口; 10、一键安装包 for linux; 11、更加方便安全的版本更新方案; -12、主页和论坛。 - +12、主页和论坛; +13、支持直接从接口的报文列表中新增Mock接口; +~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ +15、权限控制可以显示隐藏按钮。 ### v1.0.0正式版 #### 2019 - 新增:xss过滤器; +- 新增:webSocket接口Mock; -- Gitee From e319fa9b61d85d628866dbc4ab0488229f4cd04f Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Sun, 24 Nov 2019 03:46:47 +0800 Subject: [PATCH 06/18] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=8C=96=E6=9B=B4=E6=96=B0=E7=9A=84=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yi/master/exception/AppErrorCode.java | 2 + .../interceptor/CallMethodInterceptor.java | 34 +++-- .../interceptor/InterfaceMockInterceptor.java | 3 - .../yi/master/listener/InitWebListener.java | 13 +- .../yi/master/listener/VersionUpdateUtil.java | 132 ++++++++++++++++++ src/main/resources/update/0.2.0beta | 1 + src/main/webapp/index.html | 3 +- src/main/webapp/js/ajaxErrorHandler.js | 20 +++ src/main/webapp/js/globalConstant.js | 1 - src/main/webapp/login.html | 4 +- src/main/webapp/welcome.html | 3 +- update.md | 5 +- 12 files changed, 191 insertions(+), 30 deletions(-) create mode 100644 src/main/java/yi/master/listener/VersionUpdateUtil.java create mode 100644 src/main/resources/update/0.2.0beta create mode 100644 src/main/webapp/js/ajaxErrorHandler.js diff --git a/src/main/java/yi/master/exception/AppErrorCode.java b/src/main/java/yi/master/exception/AppErrorCode.java index cea8399..3098816 100644 --- a/src/main/java/yi/master/exception/AppErrorCode.java +++ b/src/main/java/yi/master/exception/AppErrorCode.java @@ -26,6 +26,8 @@ public enum AppErrorCode { MOCK_INTERFACE_DISABLED(9997, "mock接口被禁止调用"), MOCK_INTERFACE_NOT_EXIST(9996, "未定义的mock接口"), MOCK_ERROR(9995, "接口mock出错,请联系接口自动化测试平台"), + SYSTEM_IS_UPDATING(9994, "系统正在系统,请稍后刷新访问..."), + SYSTEM_IS_NEED_RESTART(9993, "系统刚刚升级完成,请联系管理员重启服务器..."), //自动化测试 diff --git a/src/main/java/yi/master/interceptor/CallMethodInterceptor.java b/src/main/java/yi/master/interceptor/CallMethodInterceptor.java index 605a397..c467da4 100644 --- a/src/main/java/yi/master/interceptor/CallMethodInterceptor.java +++ b/src/main/java/yi/master/interceptor/CallMethodInterceptor.java @@ -1,18 +1,14 @@ package yi.master.interceptor; -import java.util.List; -import java.util.Map; -import java.util.Random; - -import javax.servlet.http.HttpServletRequest; - +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import net.sf.json.JSONObject; - +import org.apache.commons.httpclient.HttpStatus; import org.apache.log4j.Logger; import org.apache.struts2.StrutsStatics; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; - import yi.master.business.base.action.BaseAction; import yi.master.business.log.enums.LogCallType; import yi.master.business.log.enums.LogInterceptStatus; @@ -23,12 +19,16 @@ import yi.master.business.user.bean.User; import yi.master.constant.SystemConsts; import yi.master.exception.AppErrorCode; import yi.master.exception.YiException; +import yi.master.listener.VersionUpdateUtil; import yi.master.util.FrameworkUtil; import yi.master.util.MD5Util; import yi.master.util.PracticalUtils; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.interceptor.AbstractInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; +import java.util.Map; +import java.util.Random; /** * 每个用户调用任何一个操作接口都必须经过本拦截器 @@ -59,6 +59,16 @@ public class CallMethodInterceptor extends AbstractInterceptor { @SuppressWarnings("unchecked") @Override public String intercept(ActionInvocation arg0) throws Exception { + ActionContext actionContext = arg0.getInvocationContext(); + HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE); + //判断当前系统是否需要重启 + if (VersionUpdateUtil.getIsNeedRestart()) { + response.setHeader("needrestart", "true"); + response.setStatus(HttpStatus.SC_FORBIDDEN); + throw new YiException(AppErrorCode.SYSTEM_IS_NEED_RESTART); + } + + User user = null; OperationInterface opInterface = null; String callUrl = null; @@ -72,7 +82,7 @@ public class CallMethodInterceptor extends AbstractInterceptor { String responseParams = null; String mark = null; - ActionContext actionContext = arg0.getInvocationContext(); + HttpServletRequest request= (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); browserAgent = request.getHeader("User-Agent"); userHost = PracticalUtils.getIpAddr(request); diff --git a/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java b/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java index 62deb6c..582e0df 100644 --- a/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java +++ b/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java @@ -26,9 +26,6 @@ import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class InterfaceMockInterceptor extends AbstractInterceptor { - /** - * - */ private static final long serialVersionUID = 1L; private static Logger logger = Logger.getLogger(InterfaceMockInterceptor.class.getName()); diff --git a/src/main/java/yi/master/listener/InitWebListener.java b/src/main/java/yi/master/listener/InitWebListener.java index 1eefa7d..26c5af1 100644 --- a/src/main/java/yi/master/listener/InitWebListener.java +++ b/src/main/java/yi/master/listener/InitWebListener.java @@ -73,7 +73,7 @@ public class InitWebListener implements ServletContextListener { //获取当前系统的所有接口信息 - LOGGER.info("获取当前系统的所有接口信息!"); + LOGGER.info("获取系统接口信息!"); List ops = opService.findAll(); //放置到全局context中 context.setAttribute(SystemConsts.APPLICATION_ATTRIBUTE_OPERATION_INTERFACE, ops); @@ -91,12 +91,7 @@ public class InitWebListener implements ServletContextListener { //获取系统版本号,如果与数据库中的版本号不一致则更新 String version = CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_VERSION); - if (StringUtils.isBlank(version)|| !version.equals(SystemConsts.VERSION)) { - LOGGER.warn("当前代码版本号为:v" + SystemConsts.VERSION + ",与数据库版本v" + version + "不一致!"); - - settingService.updateSetting(SystemConsts.GLOBAL_SETTING_VERSION, SystemConsts.VERSION); - CacheUtil.updateGlobalSettingValue(SystemConsts.GLOBAL_SETTING_VERSION, SystemConsts.VERSION); - } + VersionUpdateUtil.updateVersion(version); //获取查询数据库信息 LOGGER.info("获取测试数据源信息!"); @@ -115,12 +110,12 @@ public class InitWebListener implements ServletContextListener { jobManager.startTasks(); context.setAttribute(SystemConsts.QUARTZ_SCHEDULER_START_FLAG, SystemConsts.QUARTZ_SCHEDULER_IS_START); - //启动操作日志异步入库线程 //日志信息异步入库 new Timer().schedule(new LogRecordStorageTimeTask(), 5000, 60000); - //启动所有的Socket Mock服务 + //启动所有的Mock服务 + LOGGER.info("启动所有当前可用的Mock服务!"); List mocks = ((InterfaceMockService) FrameworkUtil.getSpringBean(InterfaceMockService.class)).getEnableMockServer(); for (InterfaceMock mock:mocks) { try { diff --git a/src/main/java/yi/master/listener/VersionUpdateUtil.java b/src/main/java/yi/master/listener/VersionUpdateUtil.java new file mode 100644 index 0000000..11d4892 --- /dev/null +++ b/src/main/java/yi/master/listener/VersionUpdateUtil.java @@ -0,0 +1,132 @@ +package yi.master.listener; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.io.resource.ClassPathResource; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.DefaultTransactionDefinition; +import yi.master.business.system.dao.GlobalSettingDao; +import yi.master.business.system.service.GlobalSettingService; +import yi.master.constant.SystemConsts; +import yi.master.util.FrameworkUtil; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * 系统升级 + * @author xuwangcheng14@163.com + * @date 2019/11/24 1:34 + */ + +public class VersionUpdateUtil { + private static final Logger logger = LoggerFactory.getLogger(VersionUpdateUtil.class); + /** + * 所有版本列表 + */ + private static final List ALL_VERSION_LIST = new ArrayList<>(); + + /** + * 是否需要重启 + */ + private static Boolean isNeedRestart = false; + static { + ALL_VERSION_LIST.add("0.1.1beta"); + ALL_VERSION_LIST.add("0.1.2beta"); + ALL_VERSION_LIST.add("0.1.3beta"); + ALL_VERSION_LIST.add("0.1.4beta"); + ALL_VERSION_LIST.add("0.1.5beta"); + ALL_VERSION_LIST.add("0.2.0beta"); + ALL_VERSION_LIST.add("0.2.1beta"); + } + + /** + * 升级系统 + * @author xuwangcheng + * @date 2019/11/24 1:49 + * @param databaseVersion databaseVersion + * @return + */ + public static void updateVersion (String databaseVersion) { + if (StringUtils.isBlank(databaseVersion) || SystemConsts.VERSION.equals(databaseVersion)) { + return; + } + + logger.info("当前代码版本为v" + SystemConsts.VERSION + ",当前数据库版本为v" + databaseVersion); + logger.info("开始升级系统..."); + + PlatformTransactionManager dstManager = (PlatformTransactionManager) FrameworkUtil.getSpringBean(PlatformTransactionManager.class); + DefaultTransactionDefinition def = new DefaultTransactionDefinition(); + def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + TransactionStatus transaction = dstManager.getTransaction(def); + + try { + boolean isBegin = false; + GlobalSettingDao settingDao = (GlobalSettingDao) FrameworkUtil.getSpringBean("globalSettingDao"); + for (String version:ALL_VERSION_LIST) { + if (isBegin) { + updateSql(version, settingDao); + logger.info("成功升级到版本v" + version + "!"); + } + if (version.equals(databaseVersion)) { + isBegin = true; + } + } + settingDao.updateSetting(SystemConsts.GLOBAL_SETTING_VERSION, SystemConsts.VERSION); + dstManager.commit(transaction); + } catch (Exception e) { + logger.error("版本升级出错,请联系作者xuwangcheng14@163.com寻求帮助!", e); + dstManager.rollback(transaction); + + throw new RuntimeException(e); + } + + if (isNeedRestart) { + logger.info("版本升级成功!请重启Tomcat服务器..."); + } + } + + /** + * 更新升级SQL + * @author xuwangcheng + * @date 2019/11/24 2:18 + * @param version version + * @param settingDao settingDao + * @return + */ + private static void updateSql (String version, GlobalSettingDao settingDao) { + File file = null; + try { + ClassPathResource classPathResource = new ClassPathResource("update/" + version); + file = classPathResource.getFile(); + } catch (Exception e) {} + + if (file != null && file.exists()) { + logger.info("正在升级到版本v" + version + "..."); + List sqls = FileUtil.readLines(file, "utf-8"); + if (CollUtil.isNotEmpty(sqls)) { + for (String sql:sqls) { + if (StringUtils.isNotBlank(sql)) { + isNeedRestart = true; + + logger.info("Update System execute SQL:" + sql); + settingDao.getSession().createSQLQuery(sql).executeUpdate(); + } + } + } + } + + } + + public static Boolean getIsNeedRestart() { + return isNeedRestart; + } +} diff --git a/src/main/resources/update/0.2.0beta b/src/main/resources/update/0.2.0beta new file mode 100644 index 0000000..58fb992 --- /dev/null +++ b/src/main/resources/update/0.2.0beta @@ -0,0 +1 @@ +update at_global_setting set setting_value='易大师接口自动化测试平台' where setting_name='siteName'; \ No newline at end of file diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html index 31a217c..5e6db5e 100644 --- a/src/main/webapp/index.html +++ b/src/main/webapp/index.html @@ -103,13 +103,14 @@ - + + - + + + + + - + + \ No newline at end of file diff --git a/src/main/webapp/index.js b/src/main/webapp/index.js new file mode 100644 index 0000000..54e62b9 --- /dev/null +++ b/src/main/webapp/index.js @@ -0,0 +1,271 @@ +//方便子页面调用 +var loadMenuFun; + +//菜单信息 +var menuJson; + +//////////////////////////////////可全局用到的信息 +//当前登陆用户的权限信息列表 +var currentUserPermissionList; +//首页地址 +var homeUrl; +//用户id +var userId; +//第三方token登陆 +var token; +//退出时返回的页面 +var backUrl; + +//全部的handlebars模版,子页面调用 +var templates; +//全部的html模板,子页面调用 +var htmls; +////////////////////////////////// +$(document).ready(function() { + //打开welcome页面 + $('iframe').attr("src", "welcome.html"); + + /***********通过外部token登录的方式打开首页****************/ + token = GetQueryString("token"); + backUrl = GetQueryString("backUrl"); + backUrl = (backUrl == null ? "login.html" : "http://" + backUrl); + if (token != null && token != "") { + $(".redirect-to-page").hide(); + } + /******************************************************/ + + $(".openIframeNew").on("click",function(){ + Hui_admin_tab(this); + }); + + + /*******************初始化子iFrame中的模板和远程子页面html代码***************************/ + //模板id + templates = initHandlebarsTemplate(); + + + //页面名 + htmls = loadChildrenHtml(["interfaceParameter-viewTree", + "messageScene-test", + "messageScene-validateFullJson", + "messageScene-validateKeyword", + "role-power", + "viewWindow"]); + /*****************************************************/ +}); + + +/*************预先编译子iframe中的模板***************/ +function initHandlebarsTemplate () { + var loadingIndex = layer.msg('正在初始化系统...', {icon:16, shade:0.45, time:999999999}); + var templates = {}; + $("#templates-page").load("./resource/template/customTemplate.htm", function() { + $("#templates-page > script").each(function(i, n){ + templates[$(n).attr('id')] = Handlebars.compile($(n).html()); + }); + layer.close(loadingIndex); + }); + return templates; +} + +/*****加载子页面代码到内存*******/ +function loadChildrenHtml (options) { + if (options == null || typeof options != 'object') { + return false; + } + var htmls = {}; + $.each(options, function (i, n) { + $("#children-page").append('
'); + $("#" + n).load("./resource/template/" + n + ".htm", function() { + htmls[n] = $("#" + n).html(); + $("#" + n).html(''); + }); + }); + return htmls; +} + +/********************加载菜单***************************/ +loadMenuFun = function() { + $.get(REQUEST_URL.MENU.GET_USER_MENUS, function(data){ + if (data.returnCode == 0) { + menuJson = data.data; + var systemSwitchDom = $('#system-type-name').siblings('ul'); + var defaultTypeKey = null; + $.each(menuJson, function(systemKey, content){ + defaultTypeKey == null && (defaultTypeKey = systemKey); + systemSwitchDom.append('
  • ' + content.name + '
  • '); + }); + + $("#menu-page").load("./resource/template/menuTemplate.htm", function(){ + templates['menu-template'] = Handlebars.compile($("#menu-page > script").html()); + switchMenu(getCookie('menuType') == null ? defaultTypeKey : getCookie('menuType'), true, defaultTypeKey); + $(".switch-system").click(function(){ + var name = switchMenu($(this).attr('system-type')); + name && (layer.msg('已切换至系统:' + name, {time:2000})); + }); + }) + } + }); +} +/** + * 根据配置切换菜单显示 + * @param menuType + * @param init + * @param defaultTypeKey + * @returns {*} + */ +function switchMenu(menuType, init, defaultTypeKey) { + if (menuType == null) { + menuType = "interface"; + } + if (menuType == getCookie('menuType') && !init) { + return null; + } + if (menuJson[menuType] == null) { + menuType = defaultTypeKey; + } + $("#menu").html(templates['menu-template'](menuJson[menuType]['menu'])); + //重新初始化菜单效果 + $.Huifold(".menu_dropdown dl dt",".menu_dropdown dl dd","fast",3,"click"); + //第一个菜单为打开状态 + $("#menu dt:eq(0)").click(); + //如果切换的是其他的系统菜单,则关闭全部的Tab选项卡 + //$("#min_title_list li i").trigger("click"); + setCookie("menuType", menuType); + $("#system-type-name").html(menuJson[menuType]['name'] + ''); + return menuJson[menuType]['name']; +} + + + +/***********修改密码*********/ +function to_changePasswd() { + layer.prompt({ + formType: 1, + value: '', + title: '验证旧密码' + }, function(value, index, elem){ + layer.close(index); + $.post(REQUEST_URL.USER.VERIFY_PASSWORD, {password: value}, function (data) { + if (data.returnCode == 0) { + layer.prompt({ + formType: 1, + value: '', + title: '请输入新密码' + }, function(value1, index1, elem){ + layer.close(index1); + layer.confirm('确定要将密码修改为"' + value1 + '"吗?', {icon:0, title:'警告'}, function(index2) { + layer.close(index2); + $.get(REQUEST_URL.USER.MODIFY_PASSWORD,{password:value1}, function(data) { + if (data.returnCode == 0) { + layer.msg('密码修改成功,设置自动登录的需要重新输入密码!', {icon:1, time:1500}); + } else { + layer.alert(data.msg, {icon: 5}); + } + }); + + }); + }); + }else{ + layer.alert(data.msg, {icon:5}); + } + }); + }); +} + +/***********手动点击logout会清除登录信息cookie*********/ +function to_logout(){ + $.get(REQUEST_URL.LOGIN.LOGOUT,function(data){ + if(data.returnCode==0){ + clearCookie("username"); + clearCookie("password"); + window.location.href = backUrl; + } + }); +} + +/***********切换用户*********/ +function to_changeUser(){ + var loginHtml ='
    '+ + '
    '+ + ''+ + '
    '+ + ''+ + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    '+ + ''+ + '
    '+ + '
    '+ + '
    ' + + '' + + '
    ' + + ' ' + + '' + + '
    ' + + '
    ' + + '
    '+ + '
    '+ + ' '+ + ''+ + '

    '+ + '
    '+ + '
    '+ + '
    '; + + var index = layer.open({ + title:'切换用户', + type: 1, + area: ['569px', '317px'], + content: loginHtml, + success:function(layero, index){ + $("#loginBtn").click(userLogin); + //监听键盘回车事件 + $(layero).keyup(function (event) { + var keyCode = event.which; + if(keyCode == 13){ + $("#loginBtn").click(); + } + }); + + $("#verifyCode").siblings('img').click(function(){ + var that = this; + $.get(REQUEST_URL.LOGIN.CREATE_VERIFY_CODE, function(data){ + if (data.returnCode == 0) { + $(that).attr('src', 'data:image/png;base64,' + data.data); + } + }); + }); + + $("#username").trigger("focus").trigger("select"); + $("#verifyCode").siblings('img').click(); + } + }); +} + +/**切换用户时的登录页面*/ +function userLogin(){ + var username = $("#username").val(); + var password = $("#password").val(); + var verifyCode = $("#verifyCode").val(); + var tipMsg = $("#loginTip"); + if(username != "" && username != null && password != "" && password != null && verifyCode != "" && verifyCode != null){ + $.post(REQUEST_URL.LOGIN.LOGIN,{ + username:username, + password:password, + verifyCode: verifyCode + },function(data){ + if(data.returnCode==0){ + location.reload(); + }else if (data.returnCode==2){ + layer.alert(data.msg, {icon: 4}); + }else { + tipMsg.text(data.msg); + } + }); + }else{ + tipMsg.text("请填写完整再提交登录"); + } +} \ No newline at end of file diff --git a/src/main/webapp/js/bak/explanationMarks.json b/src/main/webapp/js/bak/explanationMarks.json deleted file mode 100644 index c4c9100..0000000 --- a/src/main/webapp/js/bak/explanationMarks.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "parameterizedFilePath":{ - "title":"关于参数化文件的说明", - "content":"上传的参数化文件需为 txt 格式。
    第一行为参数化节点路径(路径名称大小写敏感,请与参数标识符保持一致),从第二列开始为参数化数据,默认数据分隔符为英文下逗号,你可以自行设定不同的分隔符。" - }, - "mock-validate-path":{ - "title":"Mock入参验证节点路径的填写说明", - "content":"根据入参报文的格式不同,该项需要填写不同的内容:
    JSON、XML: 完整的入参节点路径,例如ROOT.INFO.USERNAME;
    URL: 留空;
    不限格式: 例如Socket报文,可使用关联规则来获取。
    对于URL参数和请求头,此处可忽略。" - }, - "settingMailStyle":{ - "title":"自定义推送邮件的模板", - "content":"你可以自定义设定定时任务和探测任务的推送的邮件模板,模板类型为Html,同时可以在模板中插入相关测试结果变量。" - }, - "webStepConfig":{ - "title":"测试步骤配置", - "html":true, - "content":"explanation-mark-webstep-config", - "width":915, - "height":500 - }, - "webTestConfig":{ - "title":"Web自动化运行时配置说明", - "content":"1、如果你的浏览器driver文件路径没有放置到环境变量下,请在此配置, 请填写全路径,注意填写的是自动化执行客户端所在机器上的driver路径 .
    2、如何你的浏览器不是安装在默认路径或者安装的是绿色版,请指定各浏览器的执行bin文件的绝对路径(其他同上)。" - }, - "webCustomVariableSetting":{ - "title":"Web自动化自定义变量说明", - "content":"在测试用例、测试用例集、用例与用例集的关联对象中可以配置自定义的变量,变量以key-value形式保存(其中value可以使用全局变量),自定义的变量可以在下属的测试步骤中使用:
    优先级 用例集自定义变量 > 用例与用例集关联对象自定义变量 > 用例自定义变量" - }, - "webSuiteCaseSetting":{ - "title":"测试集用例自定义 配置说明", - "content":"执行顺序:默认按照设定的数字大小来排序,数字越小的先执行,越大的后执行。
    分组名:在进行分布式执行时,会将组名相同的用例分配到同一个远程执行机执行。
    跳过标记:方便在不需要执行某个用例时排除而不是删除掉。" - } -} \ No newline at end of file diff --git a/src/main/webapp/js/bak/messageProcess.json b/src/main/webapp/js/bak/messageProcess.json deleted file mode 100644 index 33c7cbe..0000000 --- a/src/main/webapp/js/bak/messageProcess.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ShanXiOpenApi":{ - }, - "AnhuiApp":{ - } -} \ No newline at end of file diff --git a/src/main/webapp/js/bak/protocol.json b/src/main/webapp/js/bak/protocol.json deleted file mode 100644 index c0492a0..0000000 --- a/src/main/webapp/js/bak/protocol.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "HTTP":{ - "Headers":{ - }, - "Querys":{ - }, - "Authorization":{ - }, - "Method":"POST", - "ConnectTimeOut":"", - "ReadTimeOut":"", - "RecEncType":"UTF-8", - "EncType":"UTF-8" - }, - "HTTPS":{ - "Headers":{ - }, - "Authorization":{ - }, - "Method":"POST", - "ConnectTimeOut":"", - "ReadTimeOut":"", - "RecEncType":"UTF-8", - "EncType":"UTF-8" - }, - "Socket":{ - "ConnectTimeOut":"", - "ReadTimeOut":"" - }, - "WebService":{ - "ConnectTimeOut":"", - "Namespace":"", - "Method":"", - "Username":"", - "Password":"" - } -} diff --git a/src/main/webapp/js/bak/readme.txt b/src/main/webapp/js/bak/readme.txt deleted file mode 100644 index 03a5bc7..0000000 --- a/src/main/webapp/js/bak/readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -explanationMarks.json 页面表单的说明文档 -HttpRequestHeader.json http常用的请求头说明 -HttpResponseHeader.json http常用的响应头说明 -menu.json 首页菜单数据 -messageProcess.json 接口报文后置处理器参数定义 -protocol.json 接口报文的格式定义 -webStepParameter.json Web自动化测试步骤的一些选择参数说明 -zh_CN.txt Datatables的本地化文件-中文 \ No newline at end of file diff --git a/src/main/webapp/js/bak/requestUrls.js b/src/main/webapp/js/bak/requestUrls.js deleted file mode 100644 index 148f714..0000000 --- a/src/main/webapp/js/bak/requestUrls.js +++ /dev/null @@ -1,297 +0,0 @@ -var BATCH_AUTO_TEST_URL = "test-scenesTest"; //批量测试 测试集或者全量 -var GET_TEST_CONFIG_URL = "test-getConfig";//获取当前用户的测试配置 -var UPDATE_TEST_CONFIG_URL = "test-updateConfig";//更新指定测试配置 -var CHECK_DATA_URL = "test-checkHasData";//测试之前检查指定的测试集中所有的测试场景是否有足够的测试数据 -var TEST_SCENE_URL = "test-sceneTest";//单场景测试 -var TEST_COMPLEX_SCENE_URL = "test-complexSceneTest";//测试组合场景 - -var PARAMS_GET_URL = "param-getParams"; //根据interfaceId来 获取parameters -var PARAM_SAVE_URL = "param-save"; //保存新增的接口参数 -var PARAM_DEL_URL = "param-del"; //删除指定参数 -var PARAM_GET_URL = "param-get"; -var PARAM_EDIT_URL = "param-edit"; //编辑参数的指定属性 -var PARAM_JSON_IMPORT_URL = "param-batchImportParams"; //导入json串 -var PARAM_DEL_ALL_URL = "param-delInterfaceParams";//删除指定接口下的所有参数 - - -var INTERFACE_LIST_URL = "interface-list"; //获取接口列表 -var INTERFACE_CHECK_NAME_URL = "interface-checkName"; //检查新增接口名是否重复 -var INTERFACE_EDIT_URL = "interface-edit"; //接口编辑 -var INTERFACE_GET_URL = "interface-get"; //获取指定接口信息 -var INTERFACE_DEL_URL = "interface-del"; //删除指定接口 -var INTERFACE_IMPORT_FROM_EXCEL_URL = "interface-importFromExcel";//从已经上传完成的excel中导入接口数据 -var INTERFACE_EXPORT_DOCUMENT_EXCEL_URL = "interface-exportInterfaceDocument";//批量导出接口文档 -var INTERFACE_GET_PARAMETERS_JSON_TREE_URL = "interface-getParametersJsonTree";//获取jsonTree数据 -var INTERFACE_UPDATE_CHILDREN_BUSINESS_SYSTEMS_URL = "interface-updateChildrenBusinessSystems";//更新接口下属报文场景等的测试环境信息 - - - -var MESSAGE_LIST_URL = "message-list"; //获取报文列表 -var MESSAGE_EDIT_URL = "message-edit"; //报文信息编辑 -var MESSAGE_GET_URL = "message-get"; //获取指定报文信息 -var MESSAGE_DEL_URL = "message-del"; //删除指定报文 -var MESSAGE_FORMAT_URL = "message-format";//格式化报文串 -var MESSAGE_VALIDATE_JSON_URL = "message-validateJson";//报文串验证 -var MESSAGE_IMPORT_FROM_EXCEL = "message-importFromExcel";//从已经上传完成的excel中导入接口数据 -var MESSAGE_CREATE_MESSAE_BY_NODES_URL = "message-createMessage"; - - -var SCENE_LIST_URL = "scene-list"; //获取场景列表 -var SCENE_EDIT_URL = "scene-edit"; //场景编辑 -var SCENE_GET_URL = "scene-get"; //获取指定场景信息 -var SCENE_DEL_URL = "scene-del"; //删除指定场景 -var SCENE_GET_TEST_OBJECT_URL = "scene-getTestObject"; //获取场景的测试数据和测试地址 -var SCENE_LIST_NO_DATA_SCENES_URL = "scene-listNoDataScenes"; //获取指定测试集中没有测试数据的测试场景列表 -var SCENE_IMPORT_FROM_EXCEL = "scene-importFromExcel";//从已经上传完成的excel中导入场景数据 -var SCENE_UPDATE_RESPONSE_EXAMPLE = "scene-updateResponseExample";//更新返回示例 -var SCENE_GET_REQUEST_MSG_JSON_TREE_URL = "scene-getRequestMsgJsonTree";//获取请求入参节点树信息 -var SCENE_GET_RESPONSE_MSG_JSON_TREE_URL = "scene-getResponseMsgJsonTree";//获取请求入参节点树信息 - - -var GET_SETTING_DATA_URL = "data-getSettingData"; //获取当前场景所属报文的所有可编辑入参节点 包含其他信息 -var IMPORT_DATA_VALUES_URL = "data-importDatas";//批量导入测试数据 -var DATA_LIST_URL = "data-list"; //获取指定测试场景数据列表 -var DATA_EDIT_URL = "data-edit"; //测试数据编辑 -var DATA_GET_URL = "data-get"; //获取指定测试数据信息 -var DATA_DEL_URL = "data-del"; //删除指定测试数据 -var DATA_CHECK_NAME_URL = "data-checkName"; //验证数据标记是否重复 -var GET_SETTING_DATA_URL = "data-getSettingData";//获取设置参数数据时需要用到的相关数据 -var CREATE_NEW_DATA_MSG_URL = "data-createDataMsg";//根据传入的json数据字符串和场景id生成新得带有数据的报文 -var DATA_CHANGE_STATUS_URL = "data-changeStatus";//修改指定数据状态 -var DATA_UPDATE_PARAMS_DATA_URL = "data-updateParamsData";//修改设置数据内容 - -var REPORT_LIST_URL = "report-list";//测试报告列表 -var REPORT_GET_URL = "report-get";//获取指定测试报告信息 -var REPORT_DEL_URL = "report-del";//删除指定测试报告 -var REPORT_DOWNLOAD_STATIS_HTML = "report-generateStaticReportHtml";//获取静态测试报告路径(不存在就后台执行生成) -var REPORT_GET_DETAILS_URL = "report-getReportDetail";//获取生成完整测试报告所需数据 -var REPORT_SEND_MAIL_URL = "report-sendMail";//将生成的离线报告进行邮件推送 - -var RESULT_LIST_URL = "result-list";//获取测试结果列表 -var RESULT_GET_URL = "result-get";//获取指定测试结果详情信息 - - -var SET_OP_SCENE_URL = "set-opScene";//操作测试场景,添加到测试集或者从测试集删除 -var LIST_MY_SETS_URL = "set-getMySet";//获取测试集列表 -var SET_SCENE_LIST_URL = "set-listScenes";//展示存在测试集或者不存在于测试集的测试场景 -var SET_LIST_URL = "set-list"; //获取测试集列表 -var SET_EDIT_URL = "set-edit"; //测试集信息编辑 -var SET_GET_URL = "set-get"; //获取指定测试集信息 -var SET_DEL_URL = "set-del"; //删除指定测试集 -var SET_NAME_CHECK_URL = "set-checkName"; //验证测试集名称是否重复 -var SET_RUN_SETTING_CONFIG_URL = "set-settingConfig";//配置测试集运行时配置 -var SET_GET_CATEGORY_NODES_URL = "set-getCategoryNodes";//获取测试集目录树 -var SET_MOVE_TO_FOLDER = "set-moveFolder"; //将指定测试集移动到指定的目录文件夹下 - -//组合场景信息 -var COMPLEX_SCENE_LIST_URL = "complexScene-list"; -var COMPLEX_SCENE_GET_URL = "complexScene-get"; -var COMPLEX_SCENE_EDIT_URL = "complexScene-edit"; -var COMPLEX_SCENE_DEL_URL = "complexScene-del"; -var COMPLEX_SCENE_LIST_SET_SCENES_URL="complexScene-listSetScenes";//获取指定测试集的组合场景 -var COMPLEX_SCENE_ADD_TO_SET_URL = "complexScene-addToSet";//添加组合场景到指定测试集 -var COMPLEX_SCENE_DEL_FROM_SET_URL = "complexScene-delFromSet";//从测试集中删除组合场景 -var COMPLEX_SCENE_LIST_SCENES_URL = "complexScene-listScenes";//获取组合场景中的所有测试场景 -var COMPLEX_SCENE_UPDATE_CONFIG_INFO_URL = "complexScene-updateConfigInfo";//更新配置信息 -var COMPLEX_SCENE_ADD_SCENE_URL = "complexScene-addScene";//添加测试场景到组合场景 -var COMPLEX_SCENE_DEL_SCENE_URL = "complexScene-delScene";//从组合场景中删除测试场景 -var COMPLEX_SCENE_SORT_SCENES_URL = "complexScene-sortScenes";//测试场景执行顺序排序 -var COMPLEX_SCENE_UPDATE_SCENE_CONFIG_URL = "complexScene-updateSceneConfig";//更新指定测试场景的配置信息 -var COMPLEX_SCENE_LIST_SAVE_VARIABLES_URL = "complexScene-getSaveVariables";//获取组合场景中指定的保存变量名称 - -//场景验证 -var VALIDATE_GET_URL = "validate-getValidate";//获取指定测试场景的验证规则(只限全文验证和边界验证) -var VALIDATE_FULL_EDIT_URL = "validate-validateFullEdit";//全文验证规则更新 -var VALIDATE_RULE_LIST_URL = "validate-getValidates"; //获取验证规则列表 -var VALIDATE_RULE_EDIT_URL = "validate-edit";//新增或者编辑验证规则 -var VALIDATE_RULE_GET_URL = "validate-get";//获取指定验证规则信息 -var VALIDATE_RULE_DEL_URL = "validate-del";//删除指定验证规则 -var VALIDATE_FULL_RULE_GET_URL = "validate-getValidate";//获取全文验证规则 -var VALIDATE_RULE_UPDATE_STATUS = "validate-updateValidateStatus";//更新验证规则状态 - -//定时任务 -var TASK_CHECK_NAME_URL = "task-checkName";//验证测试任务是否重名 -var TASK_EDIT_URL = "task-edit";//编辑定时任务 -var TASK_DEL_URL = "task-del";//删除指定定时任务 -var TASK_LIST_URL = "task-list";//定时任务列表 -var TASK_GET_URL = "task-get";//获取指定定时任务列表 -var TASK_STOP_TASK_URL = "task-stopRunningTask";//停止运行中的定时任务 -var TASK_ADD_RUNABLE_TASK_URL = "task-startRunableTask";//运行可运行的定时任务 -var TASK_START_QUARTZ_URL = "task-startQuartz";//开启quartz定时器 -var TASK_STOP_QUARTZ_URL = "task-stopQuartz";//停止quartz定时器 -var TASK_GET_QUARTZ_STATUS_URL = "task-getQuartzStatus";//获取quartz定时器当前的状态 -var TASK_UPDATE_CRON_EXPRESSION_URL = "task-updateCronExpression";//更新定时规则 - -var GLOBAL_SETTING_EDIT_URL = "global-edit";//全局配置编辑 -var GLOBAL_SETTING_LIST_ALL_URL = "global-listAll";//获取全部的全局配置 - -var OP_INTERFACE_LIST_URL = "op-listOp"; //操作接口列表 -var OP_INTERFACE_DEL_URL = "op-del"; //删除操作接口 -var OP_INTERFACE_GET_URL = "op-get"; //获取操作接口详细信息 -var OP_INTERFACE_EDIT_URL = "op-edit"; //编辑操作接口 -var OP_INTERFACE_DEIT_GET_NODE_TREE_URL = "op-getNodeTree";//获取节点树数据 -var OP_INTERFACE_LIST_ALL_URL = "op-listAll"; //获取全部的操作接口 - -var QUERY_DB_LINK_TEST_URL = "db-testDB";//测试指定查询数据库是否可连接 -var QUERY_DB_DEL_URL = "db-del";//删除指定查询数据库信息 -var QUERY_DB_LIST_URL = "db-list"//查询数据库列表 -var QUERY_DB_EDIT_URL = "db-edit"//编辑指定查询数据库信息 -var QUERY_DB_GET_URL = "db-get";//获取指定查询数据库信息 -var QUERY_DB_LIST_ALL_URL = "db-listAll";//获取所有当前可用的查询数据数据信息 - - -var MAIL_LIST_URL = "mail-list";//信息列表 -var MAIL_DEL_URL = "mail-del";//删除信息 -var MAIL_CHANGE_STATUS = "mail-changeStatus";//改变已读状态 - -var ROLE_DEL_URL = "role-del";//删除指定角色信息 -var ROLE_GET_NODES_INTERFACE_URL = "role-getInterfaceNodes";//获取当前所有操作接口,并标记哪些是当前角色拥有的 -var ROLE_GET_NODES_MENU_URL = "role-getMenuNodes"; //获取当前所有菜单,并标记哪些是当前角色拥有的 -var ROLE_EDIT_URL = "role-edit";//编辑指定角色信息 -var ROLE_LIST_URL = "role-list";//角色信息列表 -var ROLE_GET_URL = "role-get";//指定角色信息 -var ROLE_UPDATE_POWER_URL = "role-updateRolePower";//更新操作接口与角色之间的关系(角色的权限信息) -var ROLE_UPDATE_MENU_URL = "role-updateRoleMenu";//更新菜单与角色之间的关系 -var ROLE_LIST_ALL_URL = "role-listAll";//展示所有角色 - -var USER_LIST_URL = "user-list";//用户列表 -var USER_LOCK_URL = "user-lock";//锁定用户或者解锁用户 -var USER_GET_URL = "user-get";//获取用户信息 -var USER_EDIT_URL = "user-edit";//编辑用户信息 -var USER_RESET_PASSWD_URL = "user-resetPwd";//重置指定用户的密码为111111 - - -var GLOBAL_VARIABLE_LIST_URL = "variable-listAll"; -var GLOBAL_VARIABLE_EDIT_URL = "variable-edit"; -var GLOBAL_VARIABLE_DEL_URL = "variable-del"; -var GLOBAL_VARIABLE_GET_URL = "variable-get"; -var GLOBAL_VARIABLE_CHECK_NAME_URL = "variable-checkName";//检查key是否重复 -var GLOBAL_VARIABLE_UPDATE_VALUE_URL = "variable-updateValue";//更新指定变量模板的value值 -var GLOBAL_VARIABLE_CREATE_VARIABLE_URL = "variable-createVariable";//生成变量结果 - -var BUSINESS_SYSTEM_EDIT_URL = "system-edit";//编辑或者新增测试环境信息 -var BUSINESS_SYSTEM_GET_URL = "system-get";//获取测试环境信息 -var BUSINESS_SYSTEM_LIST_URL = "system-list";//查询测试环境列表 -var BUSINESS_SYSTEM_LIST_ALL_URL = "system-listAll";//查询所有测试环境列表 -var BUSINESS_SYSTEM_DEL_URL = "system-del";//删除测试环境信息 - -var BUSINESS_SYSTEM_INTERFACE_LIST_URL = "system-listInterface";//根据mode来查询当前测试环境包含的或者不包含的接口信息 -var BUSINESS_SYSTEM_OP_INTERFACE_URL = "system-opInterface";//从指定的测试环境中删除或者增加接口信息 - -var PROBE_TASK_GET_URL = "probe-get"; -var PROBE_TASK_EDIT_URL = "probe-edit"; -var PROBE_TASK_DEL_URL = "probe-del"; -var PROBE_TASK_LIST_ALL_URL = "probe-listAll"; -var PROBE_TASK_LIST_URL = "probe-list"; -var PROBE_TASK_UPDATE_CONFIG = "probe-updateConfig"//更新探测配置 -var PROBE_TASK_START_URL = "probe-startTask";//开启任务 -var PROBE_TASK_STOP_URL = "probe-stopTask";//停止任务 -var PROBE_TASK_GET_SINGLE_REPORT_DATA_URL = "probe-getProbeResultReportData"; -var PROBE_TASK_GET_PROBE_RESULT_SYSNOPSIS_VIEW_DATA_URL = "probe-getProbeResultSynopsisViewData"; -var PROBE_TASK_BATCH_ADD_URL = "probe-batchAdd"; - -var UPLOAD_FILE_URL = "file-upload";//上传文件 -var DOWNLOAD_FILE_URL = "file-download";//下载文件 - - -//系统日志记录 -var LOG_RECORD_LIST_URL = "log-list"; -var LOG_RECORD_GET_URL = "log-get"; -var LOG_RECORD_DEL_URL = "log-del"; - -//接口mock功能 -var INTERFACE_MOCK_LIST_URL = "mock-list"; -var INTERFACE_MOCK_EDIT_URL = "mock-edit"; -var INTERFACE_MOCK_GET_URL = "mock-get"; -var INTERFACE_MOCK_DEL_URL = "mock-del"; -var INTERFACE_MOCK_CHECK_NAME_URL = "mock-checkName"; -var INTERFACE_MOCK_UPDATE_STATUS_URL = "mock-updateStatus"; -var INTERFACE_MOCK_UPDATE_SETTING_URL = "mock-updateSetting"; -var INTERFACE_MOCK_PARSE_MESSAGE_TO_CONFIG_URL = "mock-parseMessageToConfig"; -var INTERFACE_MOCK_PARSE_MESSAGE_TO_NODES_URL = "mock-parseMessageToNodes"; - - -//性能测试配置 -var PERFORMANCE_TEST_CONFIG_EDIT_URL = "ptc-edit"; -var PERFORMANCE_TEST_CONFIG_LIST_URL = "ptc-list"; -var PERFORMANCE_TEST_CONFIG_DEL_URL = "ptc-del"; -var PERFORMANCE_TEST_CONFIG_GET_URL = "ptc-get"; - -var PERFORMANCE_TEST_TASK_LIST_URL = "ptc-listTest" //获取当前用户的性能测试任务列表 -var PERFORMANCE_TEST_TASK_STOP_URL = "ptc-stopTest";//停止指定性能测试任务 -var PERFORMANCE_TEST_TASK_DEL_URL = "ptc-delTest";//删除指定性能测试任务-并且不会保存测试结果 -var PERFORMANCE_TEST_TASK_INIT_URL = "ptc-initTest";//初始化性能测试任务 -var PERFORMANCE_TEST_TASK_ACTION_URL = "ptc-actionTest";//开始执行性能测试任务 -var PERFORMANCE_TEST_TASK_VIEW_URL = "ptc-viewTest";//查看性能测试任务的实时状态 - -//性能测试结果 -var PERFORMANCE_TEST_RESULT_LIST_URL = "ptr-list"; -var PERFORMANCE_TEST_RESULT_GET_URL = "ptr-get"; -var PERFORMANCE_TEST_RESULT_DEL_URL = "ptr-del"; -var PERFORMANCE_TEST_RESULT_ANAYLZE_URL = "ptr-anaylzeView";//分析结果 -var PERFORMANCE_TEST_RESULT_SUMMARIZED_URL = "ptr-summarizedView";//汇总结果到excel -var PERFORMANCE_TEST_RESULT_DETAILS_LIST_ALL_URL = "ptr-detailsList";//详细结果查看 - - -/*************************************WEB自动化**************************************************************/ -//web自动化-山西-模块管理 -var WEB_SCRIPT_MODULE_LIST_URL = "webModule-list"; -var WEB_SCRIPT_MODULE_GET_URL = "webModule-get"; -var WEB_SCRIPT_MODULE_DEL_URL = "webModule-del"; -var WEB_SCRIPT_MODULE_EDIT_URL = "webModule-edit"; -var WEB_SCRIPT_MODULE_CHECK_NAME_URL = "webModule-checkName"; //检查moduleCode是否重复 - -//web自动化-山西-任务管理 -var WEB_SCRIPT_TASK_LIST_URL = "webTask-list"; -var WEB_SCRIPT_TASK_DEL_URL = "webTask-del"; - - -//元素对象管理 -var WEB_ELEMENT_LIST_ALL_URL = "element-listAll"; -var WEB_ELEMENT_LIST_URL = "element-list"; -var WEB_ELEMENT_GET_URL = "element-get"; -var WEB_ELEMENT_DEL_URL = "element-del"; -var WEB_ELEMENT_EDIT_URL = "element-edit"; -var WEB_ELEMENT_MOVE_URL = "element-move"; -var WEB_ELEMENT_COPY_URL = "element-copy"; - - -//测试用例 -var WEB_CASE_LIST_ALL_URL = "webcase-listAll"; -var WEB_CASE_LIST_URL = "webcase-list"; -var WEB_CASE_GET_URL = "webcase-get"; -var WEB_CASE_DEL_URL = "webcase-del"; -var WEB_CASE_EDIT_URL = "webcase-edit"; -var WEB_CASE_CHANGE_BROSWER_TYPE_URL = "webcase-changeBroswerType"; -var WEB_CASE_UPDATE_CONFIG_JSON_URL = "webcase-updateConfig"; - -//测试步骤 -var WEB_STEP_LIST_ALL_URL = "webstep-listAll"; -var WEB_STEP_LIST_URL = "webstep-list"; -var WEB_STEP_GET_URL = "webstep-get"; -var WEB_STEP_DEL_URL = "webstep-del"; -var WEB_STEP_EDIT_URL = "webstep-edit"; -var WEB_STEP_UPDATE_CONFIG_URL = "webstep-updateConfig"; - -//测试用例集 -var WEB_SUITE_LIST_ALL_URL = "websuite-listAll"; -var WEB_SUITE_LIST_URL = "websuite-list"; -var WEB_SUITE_GET_URL = "websuite-get"; -var WEB_SUITE_DEL_URL = "websuite-del"; -var WEB_SUITE_EDIT_URL = "websuite-edit"; -var WEB_SUITE_CHANGE_BROSWER_TYPE_URL = "websuite-changeBroswerType"; -var WEB_SUITE_UPDATE_CONFIG_JSON_URL = "websuite-updateConfig"; -var WEB_SUITE_LIST_CASE_URL = "websuite-listCase"; -var WEB_SUITE_OP_CASE_URL = "websuite-opCase"; -var WEB_SUITE_CASE_UPDATE_SETTING_URL = "websuite-updateCaseSetting"; - -//运行时配置 -var WEB_CONFIG_GET_URL = "webconfig-get"; -var WEB_CONFIG_EDIT_URL = "webconfig-edit"; - -//菜单相关 -var BUSI_MENU_EDIT_URL = "menu-edit"; -var BUSI_MENU_GET_URL = "menu-get"; -var BUSI_MENU_LIST_ALL_URL = "menu-listAll"; -var BUSI_MENU_DEL_URL = "menu-del"; -var BUSI_MENU_GET_USER_MENUS_URL = "menu-getUserMenus"; diff --git a/src/main/webapp/js/bak/webStepParameter.json b/src/main/webapp/js/bak/webStepParameter.json deleted file mode 100644 index 4ff1859..0000000 --- a/src/main/webapp/js/bak/webStepParameter.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "dataType":{ - "string":{ - "dataType":true, - "text":"字符串常量", - "example":"xuwangcheng14@163.com", - "mark":"普通的字符串,根据操作类型不同可能代表不同含义,请根据操作类型的说明来填写." - }, - "keyboard":{ - "dataType":true, - "text":"键盘组合按键", - "example":"Keys.ENTER 模拟键盘Enter按键", - "mark":"模拟键盘按键,支持组合按键,常用键如下:
    回车键 Keys.ENTER
    删除键 Keys.BACK_SPACE
    空格键 Keys.SPACE
    制表键 Keys.TAB
    回退键 Keys.ESCAPE
    刷新键 Keys.F5
    更多按键说明请参考说明文档!" - }, - "gloablVariable":{ - "dataType":true, - "text":"全局变量", - "example":"${__current_timestamp}", - "mark":"等同于字符串常量,但是需要在 全局变量 模块中提前定义." - }, - "regexp":{ - "dataType":true, - "text":"正则表达式", - "example":"[0-9]{1,3}", - "mark":"根据正则表达式来生成指定的字符串." - }, - "attribute":{ - "dataType":true, - "text":"元素属性/文本值", - "example":"name", - "mark":"获取选择的指定元素上的指定属性的值,其中text表示该元素的文本值." - }, - "saveVariable":{ - "dataType":true, - "text":"测试变量", - "example":"order_id", - "mark":"在本次测试中定义的、保存的上下文变量,如果有同名的变量,取值优先级如下:
    同个测试用例中不同步骤保存的变量 > 不同测试用例中步骤保存的值 > 测试集中定义的变量 > 测试用例中定义的变量." - }, - "dbSql":{ - "dataType":true, - "text":"数据库取值", - "example":"select order_id from order_info where order_type='0' and user_id=<user_id> and op_time>${__current_date};", - "mark":"可选择指定的数据源执行指定的SQL查询,如果返回多条记录,则只会取第一条内容,如果一条结果中包含多列也只会去第一列内容.
    同时在SQL语句你可以使用 <user_id> 格式来表示测试变量,同时可以使用全局变量." - } - - }, - "opType":{ - "open":{ - "opType":true, - "text":"打开", - "mark":"打开一个正确的浏览器地址", - "requiredData":"可选 如果填入该值,则会使用该处地址", - "validateData":"不需要" - }, - "check":{ - "opType":true, - "text":"检查", - "mark":"判断获取到的内容和预期值是否匹配", - "requiredData":"需要 该值可以为任何类型", - "validateData":"需要 该值可以为任何类型,如果该值类型为正则表达式,则会进行正则匹配来验证" - }, - "action":{ - "opType":true, - "text":"执行用例片段", - "mark":"执行一个用例片段", - "requiredData":"不需要", - "validateData":"不需要" - }, - "script":{ - "opType":true, - "text":"执行js脚本", - "mark":"执行一段JS脚本", - "requiredData":"不需要", - "validateData":"不需要" - }, - "input":{ - "opType":true, - "text":"输入", - "mark":"向输入框输入文本内容", - "requiredData":"需要 该值可为任何类型", - "validateData":"不需要" - }, - "save":{ - "opType":true, - "text":"保存值", - "mark":"获取内容并保存,可以获取窗口标题、当前浏览器地址、元素文本、元素属性等", - "requiredData":"可选 当元素类型为TAG时,如果该值为空,默认取元素的文本内容;如果该值不为空,则该值为元素的属性名称", - "validateData":"不需要" - }, - "click":{ - "opType":true, - "text":"点击", - "mark":"点击元素", - "requiredData":"不需要", - "validateData":"不需要" - }, - "hover":{ - "opType":true, - "text":"鼠标悬停", - "mark":"将鼠标移动到某个元素上", - "requiredData":"不需要", - "validateData":"不需要" - }, - "alertCancel":{ - "opType":true, - "text":"弹出框-取消", - "mark":"对于系统级(非页面元素)的弹出框(包含警告框、确认框、对话框),进行取消操作", - "requiredData":"不需要", - "validateData":"不需要" - }, - "alertConfirm":{ - "opType":true, - "text":"弹出框-确认", - "mark":"对于系统级(非页面元素)的弹出框(包含确认框、对话框),进行确认操作", - "requiredData":"不需要", - "validateData":"不需要" - }, - "alertClose":{ - "opType":true, - "text":"弹出框-关闭", - "mark":"对于系统级(非页面元素)的弹出框(包含警告框、确认框、对话框),进行关闭操作", - "requiredData":"不需要", - "validateData":"不需要" - }, - "alertInput":{ - "opType":true, - "text":"对话框-输入", - "mark":"对于系统级(非页面元素)的对话框,进行输入操作,默认自动点击确认按钮", - "requiredData":"需要", - "validateData":"不需要" - }, - "upload":{ - "opType":true, - "text":"上传文件", - "mark":"进行文件上传操作", - "requiredData":"需要 该值为文件的绝对路径(文件应该位于执行机中而不是服务器上)", - "validateData":"不需要" - }, - "slide":{ - "opType":true, - "text":"滑动", - "mark":"拖动元素在 x,y 方向上移动移动一段距离", - "requiredData":"需要 例如:x=500,y=100,代表在x/y轴上个拖动500px的距离", - "validateData":"不需要" - } - } -} \ No newline at end of file diff --git a/src/main/webapp/js/dcits.js b/src/main/webapp/js/dcits.js index 34d6732..00c1465 100644 --- a/src/main/webapp/js/dcits.js +++ b/src/main/webapp/js/dcits.js @@ -409,7 +409,7 @@ var publish = { */ function controlButtonShowByPermission (domObj) { //跳过超级管理员用户 - if (parent.$("#user_id").val() == SUPER_ADMIN_USER_ID) { + if (top.userId == SUPER_ADMIN_USER_ID) { return; } if (thisPagePermissionList == null) { diff --git a/src/main/webapp/js/globalConstant.js b/src/main/webapp/js/globalConstant.js index 3eb67be..a1ad0a3 100644 --- a/src/main/webapp/js/globalConstant.js +++ b/src/main/webapp/js/globalConstant.js @@ -9,6 +9,9 @@ var SUPER_ADMIN_USER_ID = 1; //请求路径 var REQUEST_URL = { + WEB_SOCKET: { + PUSH_MAIL_NUM: "/push/mail", + }, //登陆相关 LOGIN: { LOGOUT: "user-logout", @@ -619,3 +622,24 @@ var WEB_STEP_PARAMETER = { } } } + + +function createWebSocket (path) { + if (top.homeUrl == null || top.homeUrl == '') { + return null; + } + let url = (top.homeUrl).replace('https', 'ws').replace('http', 'ws'); + let ws; + if ('WebSocket' in window){ + ws = new WebSocket(url + path); + } + else if ('MozWebSocket' in window){ + ws = new MozWebSocket(url + path); + } + else{ + console.error("该浏览器不支持websocket"); + return null; + } + + return ws; +} \ No newline at end of file diff --git a/src/main/webapp/js/handlebarsHelpers.js b/src/main/webapp/js/handlebarsHelpers.js new file mode 100644 index 0000000..3ac2827 --- /dev/null +++ b/src/main/webapp/js/handlebarsHelpers.js @@ -0,0 +1,84 @@ +/*****************************Handlebars预定义helper***********************************/ +/**null转换空字符串**/ +Handlebars.registerHelper('inputValue', function(value, defaultValue){ + if (value == null || value.length == 0) { + value = defaultValue; + } + + return value; +}); + +/**结果标签展示**/ +Handlebars.registerHelper('resultLabelView', function(status){ + var color = ""; + var flag = ""; + if (status == "0") { + color = "success"; + flag = "SUCCESS"; + } else if (status == "1") { + color = "danger"; + flag = "FAIL"; + } else { + color = "default"; + flag = "STOP"; + } + + return '' + flag + ''; +}); + +/** + * 比对实现 + */ +Handlebars.registerHelper('if_eq', function(v1, v2, opts) { + if(v1 == v2) + return opts.fn(this); + else + return opts.inverse(this); +}); + + +/** + * 验证路径 + */ +Handlebars.registerHelper('validate_path', function(v1) { + if (v1 && !isJSON('{' + v1 + '}')) { + return v1 + "."; + } + + return ""; +}); + +/** + * 获取地址栏参数 + * @param name + * @returns + */ +function GetQueryString(name) { + var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + var r = window.location.search.substr(1).match(reg); + if (r != null) + return decodeURIComponent(r[2]); + return null; +} + +/** + * 判断是否为json格式字符串 + * @param str + */ +function isJSON(str) { + if (typeof str == 'string') { + try { + var obj=JSON.parse(str); + if(typeof obj == 'object' && obj ){ + return true; + }else{ + return false; + } + + } catch(e) { + console.log('error:'+str+'!!!'+e); + return false; + } + } + console.log('It is not a string!') +} \ No newline at end of file diff --git a/src/main/webapp/resource/advanced/mockTest.js b/src/main/webapp/resource/advanced/mockTest.js index ace417c..e963f27 100644 --- a/src/main/webapp/resource/advanced/mockTest.js +++ b/src/main/webapp/resource/advanced/mockTest.js @@ -1,99 +1,100 @@ var templateParams = { - tableTheads:["名称", "mock地址", "协议", "入参验证", "出参设定", "已请求次数", "当前状态", "创建时间", "创建用户", "备注","操作"], - btnTools:[{ - type:"primary", - size:"M", - id:"add-object", - iconFont:"", - name:"添加Mock接口" - },{ - type:"danger", - size:"M", - id:"batch-op", - iconFont:"", - name:"批量操作" - }], - formControls:[{ - edit:true, - label:"ID", - objText:"mockIdText", - input:[{ - hidden:true, - name:"mockId" - }] - }, - { - required:true, - label:"名称", - input:[{ - name:"mockName" - }] - }, - { - required:true, - label:"协议", - select:[{ - name:"protocolType", - option:function(){ - let arr = []; - $.each(MESSAGE_MOCK_TYPE, function(i, n){ - arr.push({ - value:n, - text: i - }); - }); - return arr; - }() - }] - }, - { - label:"mock路径", - input:[{ - name:"mockUrl", - placeholder:"只在协议为HTTP时有效,请以斜杠/起始" - }] - }, - { - label:"当前状态", - select:[{ - name:"status", - option:[{ - value:"0", - text:"启用" - }, - { - value:"1", - text:"禁用" - }] - }] - }, - { - name:"createTime", - value:new Date().Format("yyyy-MM-dd hh:mm:ss") - - }, - { - name:"user.userId" - - }, - { - name:"callCount", - value:"0" - }, - { - name:"requestValidate" - }, - { - name:"responseMock" - }, - { - label:"备注", - textarea:[{ - name:"mark" - }] - }, - -]}; + tableTheads: ["名称", "mock地址", "协议", "入参验证", "出参设定", "已请求次数", "当前状态", "创建时间", "创建用户", "备注", "操作"], + btnTools: [{ + type: "primary", + size: "M", + id: "add-object", + iconFont: "", + name: "添加Mock接口" + }, { + type: "danger", + size: "M", + id: "batch-op", + iconFont: "", + name: "批量操作" + }], + formControls: [{ + edit: true, + label: "ID", + objText: "mockIdText", + input: [{ + hidden: true, + name: "mockId" + }] + }, + { + required: true, + label: "名称", + input: [{ + name: "mockName" + }] + }, + { + required: true, + label: "协议", + select: [{ + name: "protocolType", + option: function () { + let arr = []; + $.each(MESSAGE_MOCK_TYPE, function (i, n) { + arr.push({ + value: n, + text: i + }); + }); + return arr; + }() + }] + }, + { + label: "mock路径", + input: [{ + name: "mockUrl", + placeholder: "只在协议为HTTP/WebSocket时有效,请以斜杠/起始" + }] + }, + { + label: "当前状态", + select: [{ + name: "status", + option: [{ + value: "0", + text: "启用" + }, + { + value: "1", + text: "禁用" + }] + }] + }, + { + name: "createTime", + value: new Date().Format("yyyy-MM-dd hh:mm:ss") + + }, + { + name: "user.userId" + + }, + { + name: "callCount", + value: "0" + }, + { + name: "requestValidate" + }, + { + name: "responseMock" + }, + { + label: "备注", + textarea: [{ + name: "mark" + }] + }, + + ] +}; var columnsSetting = [ { diff --git a/src/main/webapp/resource/message/autoTest.html b/src/main/webapp/resource/message/autoTest.html index b30c284..3a660f6 100644 --- a/src/main/webapp/resource/message/autoTest.html +++ b/src/main/webapp/resource/message/autoTest.html @@ -49,7 +49,7 @@

    当前测试完成数:

    当前成功数:

    当前失败数:

    -

    当前停止数:

    +

    异常中止数:




    diff --git a/src/main/webapp/resource/user/mail.js b/src/main/webapp/resource/user/mail.js index 394782c..bcafa14 100644 --- a/src/main/webapp/resource/user/mail.js +++ b/src/main/webapp/resource/user/mail.js @@ -67,11 +67,15 @@ var columnsSetting = [ var eventList = { "#batch-del-object":function(){ var checkboxList = $(".selectMail:checked"); - batchDelObjs(checkboxList, REQUEST_URL.MAIL.GET); + batchDelObjs(checkboxList, REQUEST_URL.MAIL.GET, null, null, function() { + (top['welcome']).getMailNum(); + }); }, "#batch-setting-read":function(){ var checkboxList = $(".selectMail:checked"); - batchOp (checkboxList, REQUEST_URL.MAIL.CHANGE_STATUS, "处理", null, "mailId", {statusName:"readStatus", status:"0"}) + batchOp(checkboxList, REQUEST_URL.MAIL.CHANGE_STATUS, "处理", null, "mailId", {statusName:"readStatus", status:"0"}, function() { + (top['welcome']).getMailNum(); + }); }, ".object-del":function(){ var data = table.row( $(this).parents('tr') ).data(); diff --git a/src/main/webapp/welcome.html b/src/main/webapp/welcome.html index 81f5bf5..7c68ff5 100644 --- a/src/main/webapp/welcome.html +++ b/src/main/webapp/welcome.html @@ -95,134 +95,6 @@ - + \ No newline at end of file diff --git a/src/main/webapp/welcome.js b/src/main/webapp/welcome.js new file mode 100644 index 0000000..36cb71f --- /dev/null +++ b/src/main/webapp/welcome.js @@ -0,0 +1,165 @@ +$(document).ready(function(){ + //获取登陆之后的相关信息 + queryLoginInfo(); + + //获取权限列表 + $.get(REQUEST_URL.ROLE.GET_USER_PERMISSION_LIST, function (json) { + if (json.returnCode == RETURN_CODE.SUCCESS) { + top.currentUserPermissionList = json.data; + } else { + layer.alert('获取用户权限信息出错,请重新登陆!'); + } + }); + + //检查系统版本 + $.get(REQUEST_URL.GLOBAL_SETTING.CHECK_SYSTEM_VERSION, function(json){ + if (json.returnCode == 0) { + if (json.data.newVersion != null && json.data.newVersion != json.data.version) { + $("#version").html('有新版本可以升级'); + } + } else { + console.error("检查系统版本失败:" + json.msg); + } + }); +}); + +/** + * 获取登陆之好的相关信息:包括用户信息,全局配置,测试统计数据等 + */ +function queryLoginInfo(){ + var userInfo = {}; + var lastLoginTime = ""; + var df = $.Deferred(); + df.done(function(){ + if (!($.isEmptyObject(userInfo))) { + //加载目录信息 + parent.loadMenuFun(); + //获取配置 + getSetting(); + //获取统计信息 + getStatisticalQuantity(); + //获取未读邮件信息 + queryMailNum(); + + //填充页面基本信息 + $("#group_name").text(userInfo.role.roleGroup); + $("#real_name").text(userInfo.realName); + $("#last_login_time").text(lastLoginTime); + parent.$("#role_name").text(userInfo.role.roleName); + parent.$("#real_name").text(userInfo.realName); + if (userInfo.role.roleName != "admin") { + parent.$(".adminPower").css("display","none"); + } + + + } + }); + + //获取登陆用户信息 + $.post(REQUEST_URL.LOGIN.GET_LOGIN_USER_INFO, {token:parent.token}, function(data) { + if (data.returnCode == RETURN_CODE.SUCCESS) { + userInfo = data.data.user; + lastLoginTime = data.data.lastLoginTime; + parent.homeUrl = data.data.homeUrl; + parent.userId = userInfo.userId; + df.resolve(); + } else if (data.returnCode == RETURN_CODE.NO_LOGIN) { + var username = getCookie("username"); + var password = getCookie("password"); + if (username != null && password != null && parent.token == null) { + $.post(REQUEST_URL.LOGIN.LOGIN,{ + username:username, + password:password + }, function(data) { + if (data.returnCode == RETURN_CODE.SUCCESS) { + userInfo = data.data.user; + lastLoginTime = data.data.lastLoginTime; + parent.homeUrl = data.data.homeUrl; + parent.userId = userInfo.userId; + df.resolve(); + } else { + parent.window.location.href = parent.backUrl; + } + }); + } else { + parent.window.location.href = parent.backUrl; + } + }else{ + parent.window.location.href = parent.backUrl; + } + }); +} + +/** + * 获取全局配置并设置到页面 + */ +function getSetting() { + $.get(REQUEST_URL.GLOBAL_SETTING.GET_WEB_SETTINGS, function(data) { + if(data.returnCode == 0){ + data = data.data; + $("#notice").html(data.notice); + $("#copyright").html(data.copyright); + $("#siteName").html(data.siteName); + parent.$("#siteName").html(data.siteName); + parent.$("#version").text("V" + data.version); + } + }); +} + +/** + * ajax请求查询用户未读邮件数量 + */ +function getMailNum(){ + $.get(REQUEST_URL.MAIL.GET_NO_READ_MAIL_NUM, function(data) { + if (data.returnCode === RETURN_CODE.SUCCESS && data.data !== 0) { + parent.$(".noReadMailNum").text(data.data); + } else { + parent.$(".noReadMailNum").text(""); + } + }); +} + +/** + * 查询未读邮件数量,默认使用webSocket,否则使用ajax轮询 + */ +function queryMailNum () { + //第一次获取 + getMailNum(); + + let userId = parent.userId; + let ws = createWebSocket('/push/mail/' + userId); + + if (ws == null) { + setInterval(getMailNum, 90000); + return; + } + + ws.onmessage = function(event) { + if (event.data !== 0) { + parent.$(".noReadMailNum").text(event.data); + } + } + + parent.window.onbeforeunload = function(event) { + ws.close(); + } +} + + + +/** + * 获取测试统计数据 + */ +function getStatisticalQuantity() { + $.get(REQUEST_URL.GLOBAL_SETTING.GET_STATISTICAL_QUANTITY, function(data) { + if(data.returnCode == 0){ + $.each(data.data, function(itemName, countInfo) { + $("td[count-type='" + itemName + "']").eq(0).text(countInfo.totalCount); + $("td[count-type='" + itemName + "']").eq(1).text(countInfo.todayCount); + $("td[count-type='" + itemName + "']").eq(2).text(countInfo.yesterdayCount); + $("td[count-type='" + itemName + "']").eq(3).text(countInfo.thisWeekCount); + $("td[count-type='" + itemName + "']").eq(4).text(countInfo.thisMonthCount); + }); + } + }); +} \ No newline at end of file diff --git a/update.md b/update.md index e16e75e..368b236 100644 --- a/update.md +++ b/update.md @@ -13,7 +13,7 @@ 13、支持直接从接口的报文列表中新增Mock接口; ~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ ~~15、权限控制可以显示隐藏按钮。~~ -16、重写部分功能,使用websocket交互。 +~~16、重写部分功能,使用websocket交互。~~ -- Gitee From eed8ae3a89860d8a129276aa8ad1caebc76c1d51 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Mon, 25 Nov 2019 18:18:37 +0800 Subject: [PATCH 10/18] =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=8D=E5=B1=95?= =?UTF-8?q?=E7=A4=BAWeb=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/update/1.0.0 | 3 ++- src/main/webapp/js/ajaxErrorHandler.js | 2 +- update.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/resources/update/1.0.0 b/src/main/resources/update/1.0.0 index 84df0ea..e36b60e 100644 --- a/src/main/resources/update/1.0.0 +++ b/src/main/resources/update/1.0.0 @@ -1,2 +1,3 @@ ALTER TABLE `at_operation_interface` ADD COLUMN `permission_mark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'jquery选择器标识' AFTER `parent_op_id`; -ALTER TABLE `at_operation_interface` ADD COLUMN `page_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '所属页面' AFTER `permission_mark`; \ No newline at end of file +ALTER TABLE `at_operation_interface` ADD COLUMN `page_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '所属页面' AFTER `permission_mark`; +UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; \ No newline at end of file diff --git a/src/main/webapp/js/ajaxErrorHandler.js b/src/main/webapp/js/ajaxErrorHandler.js index 3045450..2954415 100644 --- a/src/main/webapp/js/ajaxErrorHandler.js +++ b/src/main/webapp/js/ajaxErrorHandler.js @@ -14,7 +14,7 @@ $.ajaxSetup({ break; default: - top.layer.alert("AJAX调用失败", {icon:5}); + break; } } }); \ No newline at end of file diff --git a/update.md b/update.md index 368b236..e206266 100644 --- a/update.md +++ b/update.md @@ -1,5 +1,5 @@ ~~1、增加websocket接口mock;~~ -2、默认不展示web自动化测试模块; +~~2、默认不展示web自动化测试模块;~~ 3、增加初级的测试数据池功能; 4、增加历史数据报表功能。 5、优化数据验证、数据库验证等功能; -- Gitee From 26ac6bc84108027da7a1820c11d27d14e93b4c06 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Mon, 25 Nov 2019 18:46:25 +0800 Subject: [PATCH 11/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/InterfaceMockService.java | 13 ++++++-- .../impl/InterfaceMockServiceImpl.java | 33 +++++++++++++++---- .../java/yi/master/constant/SystemConsts.java | 3 -- src/main/webapp/resource/message/message.js | 3 +- update.md | 1 + 5 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java index ef12d8b..991731e 100644 --- a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java +++ b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java @@ -1,10 +1,10 @@ package yi.master.business.advanced.service; -import java.util.List; - import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.base.service.BaseService; +import java.util.List; + public interface InterfaceMockService extends BaseService { /** * 根据mockUrl查找指定的mock信息 @@ -42,4 +42,13 @@ public interface InterfaceMockService extends BaseService { * @return */ void updateCallCount(Integer mockId); + + /** + * 场景转换为Mock + * @author xuwangcheng + * @date 2019/11/25 18:34 + * @param sceneId sceneId + * @return {@link boolean} + */ + boolean parseSceneToMock (Integer sceneId); } diff --git a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java index 46d9a23..e3fc073 100644 --- a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java +++ b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java @@ -1,21 +1,26 @@ package yi.master.business.advanced.service.impl; -import java.util.List; - import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.advanced.dao.InterfaceMockDao; import yi.master.business.advanced.service.InterfaceMockService; import yi.master.business.base.service.impl.BaseServiceImpl; +import yi.master.business.message.bean.MessageScene; +import yi.master.business.message.dao.MessageSceneDao; +import yi.master.exception.AppErrorCode; +import yi.master.exception.YiException; + +import java.util.List; @Service("interfaceMockService") public class InterfaceMockServiceImpl extends BaseServiceImpl implements InterfaceMockService { - - private InterfaceMockDao interfaceMockDao; - + private InterfaceMockDao interfaceMockDao; + + @Autowired + private MessageSceneDao messageSceneDao; + @Autowired public void setInterfaceMockDao(InterfaceMockDao interfaceMockDao) { super.setBaseDao(interfaceMockDao); @@ -38,7 +43,9 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp public void updateSetting(Integer mockId, String settingType, String configJson) { - if (StringUtils.isBlank(settingType) || StringUtils.isBlank(configJson)) return; + if (StringUtils.isBlank(settingType) || StringUtils.isBlank(configJson)) { + return; + } interfaceMockDao.updateSetting(mockId, settingType, configJson); } @@ -52,4 +59,16 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp public void updateCallCount(Integer mockId) { interfaceMockDao.updateCallCount(mockId); } + + @Override + public boolean parseSceneToMock(Integer sceneId) { + MessageScene messageScene = messageSceneDao.get(sceneId); + if (messageScene == null) { + throw new YiException(AppErrorCode.MESSAGE_INFO_NOT_EXITS); + } + + + + return false; + } } diff --git a/src/main/java/yi/master/constant/SystemConsts.java b/src/main/java/yi/master/constant/SystemConsts.java index ce65807..18dc245 100644 --- a/src/main/java/yi/master/constant/SystemConsts.java +++ b/src/main/java/yi/master/constant/SystemConsts.java @@ -149,9 +149,6 @@ public interface SystemConsts { * sessionMap中登录用户key值 */ String SESSION_ATTRIBUTE_LOGIN_USER = "user"; - - //ApplicationMap中指定属性名 - String APPLICATION_ATTRIBUTE_OPERATION_INTERFACE = "ops"; //SessionMap中指定属性名 String SESSION_ATTRIBUTE_VERIFY_CODE = "verifyCode"; diff --git a/src/main/webapp/resource/message/message.js b/src/main/webapp/resource/message/message.js index 6adad07..9b0b6d1 100644 --- a/src/main/webapp/resource/message/message.js +++ b/src/main/webapp/resource/message/message.js @@ -284,7 +284,7 @@ var columnsSetting = [ { "data":null, "render":function(data, type, full, meta){ - var context = [{ + var context = [{ title:"报文编辑", markClass:"object-edit", iconFont:"" @@ -293,6 +293,7 @@ var columnsSetting = [ markClass:"object-del", iconFont:"" }]; + return btnIconTemplate(context); }} ]; diff --git a/update.md b/update.md index e206266..cff4825 100644 --- a/update.md +++ b/update.md @@ -14,6 +14,7 @@ ~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ ~~15、权限控制可以显示隐藏按钮。~~ ~~16、重写部分功能,使用websocket交互。~~ +17、对文件上传类接口的支持。 -- Gitee From 7ab460760b4ccfb7c06dc92c96d348739e78748d Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Mon, 25 Nov 2019 21:35:00 +0800 Subject: [PATCH 12/18] =?UTF-8?q?=E4=BB=8E=E5=9C=BA=E6=99=AF=E4=B8=AD?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8E=A5=E5=8F=A3Mock(=E5=BE=85=E9=AA=8C?= =?UTF-8?q?=E8=AF=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advanced/action/InterfaceMockAction.java | 57 +++++----- .../config/mock/MockValidateRuleConfig.java | 47 +++++++- .../service/InterfaceMockService.java | 2 +- .../impl/InterfaceMockServiceImpl.java | 102 +++++++++++++++++- .../yi/master/exception/AppErrorCode.java | 7 ++ src/main/resources/update/1.0.0 | 77 +++++++++++++ src/main/webapp/js/dcits.js | 4 +- src/main/webapp/js/globalConstant.js | 3 +- src/main/webapp/resource/advanced/mockTest.js | 49 ++++++++- .../resource/advanced/performanceTest.js | 2 +- update.md | 2 +- 11 files changed, 308 insertions(+), 44 deletions(-) diff --git a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java index 7c2e24e..bb3132b 100644 --- a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java +++ b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java @@ -1,37 +1,32 @@ package yi.master.business.advanced.action; -import java.util.HashSet; -import java.util.Set; - +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; - import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; import yi.master.business.advanced.bean.config.mock.MockResponseConfig; import yi.master.business.advanced.bean.config.mock.MockValidateRuleConfig; -import yi.master.business.advanced.enums.InterfaceMockStatus; import yi.master.business.advanced.enums.MockConfigSettingType; -import yi.master.business.base.dto.ParseMessageToNodesOutDTO; import yi.master.business.advanced.service.InterfaceMockService; import yi.master.business.base.action.BaseAction; +import yi.master.business.base.dto.ParseMessageToNodesOutDTO; import yi.master.business.message.bean.Parameter; -import yi.master.business.user.bean.User; -import yi.master.constant.MessageKeys; import yi.master.coretest.message.parse.MessageParse; import yi.master.coretest.message.test.mock.MockServer; -import yi.master.coretest.message.test.mock.MockSocketServer; import yi.master.exception.AppErrorCode; import yi.master.exception.YiException; import yi.master.util.FrameworkUtil; import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; -import net.sf.json.JSONArray; -import net.sf.json.JSONObject; +import java.util.HashSet; +import java.util.List; +import java.util.Set; /** * 接口mock相关接口 @@ -53,6 +48,8 @@ public class InterfaceMockAction extends BaseAction { private InterfaceMockService interfaceMockService; private String message; + + private Integer messageSceneId; @Autowired public void setInterfaceMockService( @@ -83,7 +80,20 @@ public class InterfaceMockAction extends BaseAction { setData(model); return SUCCESS; } - + + + /** + * 解析接口场景为Mock规则 + * @author xuwangcheng + * @date 2019/11/25 20:56 + * @param + * @return {@link String} + */ + public String parseSceneToMockInfo () { + interfaceMockService.parseSceneToMock(messageSceneId); + return SUCCESS; + } + /** * 更新配置内容 * @return @@ -114,20 +124,8 @@ public class InterfaceMockAction extends BaseAction { * @return */ public String parseMessageToConfig() { - MessageParse parseUtil = MessageParse.getParseInstance(MessageParse.judgeType(message)); - Set parameters = parseUtil.importMessageToParameter(message, null); - JSONArray rules = new JSONArray(); - for (Parameter param:parameters) { - if (MessageKeys.MessageParameterType.isStringOrNumberType(param.getType())) { - MockValidateRuleConfig rule = new MockValidateRuleConfig(); - rule.setName(param.getParameterIdentify()); - rule.setPath(param.getPath().replaceAll(MessageKeys.MESSAGE_PARAMETER_DEFAULT_ROOT_PATH + "\\.*", "")); - rule.setType(param.getType()); - rule.setValidateValue(param.getDefaultValue()); - rules.add(rule); - } - } - setData(rules.toString()); + List rules = MockValidateRuleConfig.parseValidateRuleList(message, null); + setData(JSONArray.fromObject(rules).toString()); return SUCCESS; } @@ -171,5 +169,8 @@ public class InterfaceMockAction extends BaseAction { public void setMessage(String message) { this.message = message; } - -} + + public void setMessageSceneId(Integer messageSceneId) { + this.messageSceneId = messageSceneId; + } +} diff --git a/src/main/java/yi/master/business/advanced/bean/config/mock/MockValidateRuleConfig.java b/src/main/java/yi/master/business/advanced/bean/config/mock/MockValidateRuleConfig.java index 06551ec..e04c0ed 100644 --- a/src/main/java/yi/master/business/advanced/bean/config/mock/MockValidateRuleConfig.java +++ b/src/main/java/yi/master/business/advanced/bean/config/mock/MockValidateRuleConfig.java @@ -1,14 +1,18 @@ package yi.master.business.advanced.bean.config.mock; -import java.io.Serializable; -import java.util.Map; -import java.util.regex.Pattern; - import org.apache.commons.lang3.StringUtils; - import yi.master.business.message.bean.Parameter; +import yi.master.constant.MessageKeys; +import yi.master.coretest.message.parse.MessageParse; import yi.master.util.PracticalUtils; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + public class MockValidateRuleConfig implements Serializable { /** * @@ -79,6 +83,39 @@ public class MockValidateRuleConfig implements Serializable { public MockValidateRuleConfig() { super(); } + + + /** + * 根据报文解析验证参数 + * @author xuwangcheng + * @date 2019/11/25 20:29 + * @param msg msg + * @param msgType msgType + * @return {@link List} + */ + public static List parseValidateRuleList (String msg, String msgType) { + List rules = new ArrayList<>(); + if (StringUtils.isBlank(msgType)) { + msgType = MessageParse.judgeType(msg); + } + + MessageParse parseUtil = MessageParse.getParseInstance(msgType); + if (parseUtil != null && StringUtils.isNotBlank(msg)) { + Set parameters = parseUtil.importMessageToParameter(msg, null); + for (Parameter param:parameters) { + if (MessageKeys.MessageParameterType.isStringOrNumberType(param.getType())) { + MockValidateRuleConfig rule = new MockValidateRuleConfig(); + rule.setName(param.getParameterIdentify()); + rule.setPath(param.getPath().replaceAll(MessageKeys.MESSAGE_PARAMETER_DEFAULT_ROOT_PATH + "\\.*", "")); + rule.setType(param.getType()); + rule.setValidateValue(param.getDefaultValue()); + rules.add(rule); + } + } + } + + return rules; + } /** * 对参数做验证:header或者入参节点或者查询参数 diff --git a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java index 991731e..8f83608 100644 --- a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java +++ b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java @@ -44,7 +44,7 @@ public interface InterfaceMockService extends BaseService { void updateCallCount(Integer mockId); /** - * 场景转换为Mock + * 接口场景转换为Mock规则 * @author xuwangcheng * @date 2019/11/25 18:34 * @param sceneId sceneId diff --git a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java index e3fc073..052be8c 100644 --- a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java +++ b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java @@ -1,18 +1,31 @@ package yi.master.business.advanced.service.impl; +import net.sf.json.JSONObject; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import yi.master.business.advanced.bean.InterfaceMock; +import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; +import yi.master.business.advanced.bean.config.mock.MockResponseConfig; +import yi.master.business.advanced.bean.config.mock.MockValidateRuleConfig; import yi.master.business.advanced.dao.InterfaceMockDao; +import yi.master.business.advanced.enums.InterfaceMockStatus; import yi.master.business.advanced.service.InterfaceMockService; import yi.master.business.base.service.impl.BaseServiceImpl; +import yi.master.business.message.bean.InterfaceInfo; +import yi.master.business.message.bean.Message; import yi.master.business.message.bean.MessageScene; import yi.master.business.message.dao.MessageSceneDao; +import yi.master.constant.MessageKeys; +import yi.master.coretest.message.parse.MessageParse; import yi.master.exception.AppErrorCode; import yi.master.exception.YiException; +import yi.master.util.FrameworkUtil; +import yi.master.util.PracticalUtils; +import java.sql.Timestamp; import java.util.List; +import java.util.Map; @Service("interfaceMockService") public class InterfaceMockServiceImpl extends BaseServiceImpl implements InterfaceMockService { @@ -51,7 +64,6 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp @Override public List getEnableMockServer() { - return interfaceMockDao.getEnableMockServer(); } @@ -64,11 +76,95 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp public boolean parseSceneToMock(Integer sceneId) { MessageScene messageScene = messageSceneDao.get(sceneId); if (messageScene == null) { - throw new YiException(AppErrorCode.MESSAGE_INFO_NOT_EXITS); + throw new YiException(AppErrorCode.SCENE_INFO_NOT_EXIST); } + Message message = messageScene.getMessage(); + if (message == null) { + throw new YiException(AppErrorCode.MESSAGE_INFO_NOT_EXITS); + } + + InterfaceInfo interfaceInfo = message.getInterfaceInfo(); + if (interfaceInfo == null) { + throw new YiException(AppErrorCode.INTERFACE_INFO_NOT_EXIST); + } + + boolean flag = !MessageKeys.ProtocolType.http.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()) + && !MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()) + && !MessageKeys.ProtocolType.websocket.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()); + if (flag) { + throw new YiException(AppErrorCode.MOCK_PROTOCOL_NOT_SUPPORT); + } + + + InterfaceMock mockInfo = new InterfaceMock(); + mockInfo.setCallCount(0); + mockInfo.setCreateTime(new Timestamp(System.currentTimeMillis())); + mockInfo.setMark("由接口场景自动生成"); + mockInfo.setMockName(interfaceInfo.getInterfaceName()); + + //获取测试地址 + String requestUrl = ""; + if (StringUtils.isNotBlank(messageScene.getRequestUrl())) { + requestUrl = messageScene.getRequestUrl(); + } + if (StringUtils.isBlank(requestUrl) && StringUtils.isNotBlank(message.getRequestUrl())) { + requestUrl = message.getRequestUrl(); + } + if (StringUtils.isBlank(requestUrl)) { + requestUrl = interfaceInfo.getRequestUrlReal(); + } + + mockInfo.setMockUrl(requestUrl); + mockInfo.setProtocolType(interfaceInfo.getInterfaceProtocol()); + mockInfo.setStatus(InterfaceMockStatus.DISABLED.getStatus()); + mockInfo.setUser(FrameworkUtil.getLoginUser()); + + MockRequestValidateConfig requestValidateConfig = new MockRequestValidateConfig(); + requestValidateConfig.setMessageType(message.getMessageType()); + + MessageParse parseUtil = MessageParse.getParseInstance(message.getMessageType()); + String requestMsg = parseUtil.depacketizeMessageToString(message.getComplexParameter(), null); + + if (StringUtils.isNotBlank(requestMsg)) { + requestValidateConfig.setParameters(MockValidateRuleConfig.parseValidateRuleList(requestMsg, message.getMessageType())); + } + if (MessageKeys.ProtocolType.http.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol())) { + String callParameter = message.getCallParameter(); + Map parameters = PracticalUtils.jsonToMap(callParameter); + if (parameters != null) { + Object headers = parameters.get(MessageKeys.HTTP_PARAMETER_HEADER); + Object querys = parameters.get(MessageKeys.HTTP_PARAMETER_QUERYS); + Object method = parameters.get(MessageKeys.PUBLIC_PARAMETER_METHOD); + + if (headers != null) { + requestValidateConfig.setHeaders(MockValidateRuleConfig.parseValidateRuleList(JSONObject.fromObject(headers).toString() + , MessageKeys.MessageType.JSON.name())); + } + + if (querys != null) { + requestValidateConfig.setQuerys(MockValidateRuleConfig.parseValidateRuleList(JSONObject.fromObject(querys).toString() + , MessageKeys.MessageType.JSON.name())); + } + + if (method != null) { + requestValidateConfig.setMethod(method.toString()); + } + + } + } + + mockInfo.setRequestValidate(JSONObject.fromObject(requestValidateConfig).toString()); + + String responseMsg = messageScene.getResponseExample(); + MockResponseConfig responseConfig = new MockResponseConfig(); + if (StringUtils.isNotBlank(responseMsg)) { + responseConfig.setExampleResponseMsg(responseMsg); + } + mockInfo.setResponseMock(JSONObject.fromObject(responseConfig).toString()); - return false; + edit(mockInfo); + return true; } } diff --git a/src/main/java/yi/master/exception/AppErrorCode.java b/src/main/java/yi/master/exception/AppErrorCode.java index 3098816..5677df2 100644 --- a/src/main/java/yi/master/exception/AppErrorCode.java +++ b/src/main/java/yi/master/exception/AppErrorCode.java @@ -69,6 +69,13 @@ public enum AppErrorCode { //测试报告 REPORT_INFO_NOT_EXIST(350001, "测试报告信息不存在"), REPORT_TEST_NO_DATA(350002, "该项测试还未完成或者没有任何测试结果"), + + + //高级测试相关 + MOCK_PROTOCOL_NOT_SUPPORT(360001, "不支持该协议接口的Mock"), + + //场景相关 + SCENE_INFO_NOT_EXIST(370001, "测试场景不存在") ; private Integer code; diff --git a/src/main/resources/update/1.0.0 b/src/main/resources/update/1.0.0 index e36b60e..69ef962 100644 --- a/src/main/resources/update/1.0.0 +++ b/src/main/resources/update/1.0.0 @@ -1,3 +1,80 @@ ALTER TABLE `at_operation_interface` ADD COLUMN `permission_mark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'jquery选择器标识' AFTER `parent_op_id`; ALTER TABLE `at_operation_interface` ADD COLUMN `page_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '所属页面' AFTER `permission_mark`; +UPDATE `at_operation_interface` SET `op_name` = '接口信息编辑', `call_name` = 'interface-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑指定接口信息', `status` = '0', `parent_op_id` = 3, `permission_mark` = '.object-edit', `page_name` = 'interface' WHERE `op_id` = 25; +UPDATE `at_operation_interface` SET `op_name` = '删除接口', `call_name` = 'interface-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定接口', `status` = '0', `parent_op_id` = 3, `permission_mark` = '.object-del', `page_name` = 'interface' WHERE `op_id` = 27; +UPDATE `at_operation_interface` SET `op_name` = '获取接口的参数', `call_name` = 'param-getParams', `is_parent` = 'false', `op_type` = NULL, `mark` = '获取指定接口的所有入参节点信息', `status` = '0', `parent_op_id` = 5, `permission_mark` = '.edit-params', `page_name` = 'interface' WHERE `op_id` = 33; +UPDATE `at_operation_interface` SET `op_name` = '保存参数', `call_name` = 'param-save', `is_parent` = 'false', `op_type` = NULL, `mark` = '保存单个接口入参信息', `status` = '0', `parent_op_id` = 5, `permission_mark` = '#add-object', `page_name` = 'interfaceParameter' WHERE `op_id` = 34; +UPDATE `at_operation_interface` SET `op_name` = '删除参数', `call_name` = 'param-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定参数', `status` = '0', `parent_op_id` = 5, `permission_mark` = '.object-del', `page_name` = 'interfaceParameter' WHERE `op_id` = 35; +UPDATE `at_operation_interface` SET `op_name` = '编辑参数', `call_name` = 'param-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑指定参数信息', `status` = '0', `parent_op_id` = 5, `permission_mark` = '.object-edit', `page_name` = 'interfaceParameter' WHERE `op_id` = 36; +UPDATE `at_operation_interface` SET `op_name` = '导入报文串入参', `call_name` = 'param-batchImportParams', `is_parent` = 'false', `op_type` = NULL, `mark` = '根据报文串批量导入入参', `status` = '0', `parent_op_id` = 5, `permission_mark` = '#batch-add-object', `page_name` = 'interfaceParameter' WHERE `op_id` = 37; +UPDATE `at_operation_interface` SET `op_name` = '批量删除', `call_name` = 'param-delInterfaceParams', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定接口下的所有入参', `status` = '0', `parent_op_id` = 5, `permission_mark` = '#batch-del-object', `page_name` = 'interfaceParameter' WHERE `op_id` = 38; +UPDATE `at_operation_interface` SET `op_name` = '编辑报文信息', `call_name` = 'message-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑报文信息', `status` = '0', `parent_op_id` = 6, `permission_mark` = '.object-edit', `page_name` = 'message' WHERE `op_id` = 40; +UPDATE `at_operation_interface` SET `op_name` = '删除报文', `call_name` = 'message-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定报文', `status` = '0', `parent_op_id` = 6, `permission_mark` = '.object-del', `page_name` = 'message' WHERE `op_id` = 42; +UPDATE `at_operation_interface` SET `op_name` = '场景信息编辑', `call_name` = 'scene-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑指定测试场景', `status` = '0', `parent_op_id` = 7, `permission_mark` = '.object-edit', `page_name` = 'messageScene' WHERE `op_id` = 46; +UPDATE `at_operation_interface` SET `op_name` = '删除测试场景', `call_name` = 'scene-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定测试场景', `status` = '0', `parent_op_id` = 7, `permission_mark` = '.object-del', `page_name` = 'messageScene' WHERE `op_id` = 48; +UPDATE `at_operation_interface` SET `op_name` = '删除指定测试数据', `call_name` = 'data-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定测试数据', `status` = '0', `parent_op_id` = 8, `permission_mark` = '.object-del', `page_name` = 'testData' WHERE `op_id` = 55; +UPDATE `at_operation_interface` SET `op_name` = '编辑测试数据信息', `call_name` = 'data-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑测试数据信息', `status` = '0', `parent_op_id` = 8, `permission_mark` = '.object-edit', `page_name` = 'testData' WHERE `op_id` = 59; +UPDATE `at_operation_interface` SET `op_name` = '删除测试报告', `call_name` = 'report-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定测试报告', `status` = '0', `parent_op_id` = 9, `permission_mark` = '.object-del', `page_name` = 'report' WHERE `op_id` = 62; +UPDATE `at_operation_interface` SET `op_name` = '查看离线测试报告', `call_name` = 'report-generateStaticReportHtml', `is_parent` = 'false', `op_type` = NULL, `mark` = '查看离线测试报告', `status` = '0', `parent_op_id` = 9, `permission_mark` = '.download-report', `page_name` = 'report' WHERE `op_id` = 63; +UPDATE `at_operation_interface` SET `op_name` = '查看在线测试报告', `call_name` = 'report-getReportDetail', `is_parent` = 'false', `op_type` = NULL, `mark` = '查看动态生成的在线测试报告', `status` = '0', `parent_op_id` = 9, `permission_mark` = '.view-report', `page_name` = 'report' WHERE `op_id` = 64; +UPDATE `at_operation_interface` SET `op_name` = '操作测试集场景', `call_name` = 'set-opScene', `is_parent` = 'false', `op_type` = NULL, `mark` = '添加到测试集或者从测试集删除', `status` = '0', `parent_op_id` = 11, `permission_mark` = '.op-scene,#batch-op', `page_name` = 'setScene' WHERE `op_id` = 67; +UPDATE `at_operation_interface` SET `op_name` = '编辑测试集信息', `call_name` = 'set-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑指定测试集信息', `status` = '0', `parent_op_id` = 11, `permission_mark` = '#edit-set-info', `page_name` = 'setScene' WHERE `op_id` = 71; +UPDATE `at_operation_interface` SET `op_name` = '删除测试集', `call_name` = 'set-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定测试集', `status` = '0', `parent_op_id` = 11, `permission_mark` = '#del-this-set', `page_name` = 'setScene' WHERE `op_id` = 73; +UPDATE `at_operation_interface` SET `op_name` = '设定测试集运行时配置', `call_name` = 'set-settingConfig', `is_parent` = 'false', `op_type` = NULL, `mark` = '设定指定测试集的运行时配置(默认还是自定义)', `status` = '0', `parent_op_id` = 11, `permission_mark` = '#setting-set-config', `page_name` = 'setScene' WHERE `op_id` = 75; +UPDATE `at_operation_interface` SET `op_name` = '编辑验证规则信息', `call_name` = 'validate-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑验证规则信息', `status` = '0', `parent_op_id` = 12, `permission_mark` = '.object-edit', `page_name` = 'validateParameters' WHERE `op_id` = 84; +UPDATE `at_operation_interface` SET `op_name` = '删除验证规则信息', `call_name` = 'validate-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定验证规则信息', `status` = '0', `parent_op_id` = 12, `permission_mark` = '.object-del', `page_name` = 'validateParameters' WHERE `op_id` = 86; +UPDATE `at_operation_interface` SET `op_name` = '编辑定时任务', `call_name` = 'task-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑定时任务', `status` = '0', `parent_op_id` = 14, `permission_mark` = '.object-edit', `page_name` = 'autoTask' WHERE `op_id` = 89; +UPDATE `at_operation_interface` SET `op_name` = '删除指定定时任务', `call_name` = 'task-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定定时任务', `status` = '0', `parent_op_id` = 14, `permission_mark` = '.object-del', `page_name` = 'autoTask' WHERE `op_id` = 90; +UPDATE `at_operation_interface` SET `op_name` = '停止运行中的定时任务', `call_name` = 'task-stopRunningTask', `is_parent` = 'false', `op_type` = NULL, `mark` = '停止运行中的定时任务', `status` = '0', `parent_op_id` = 14, `permission_mark` = '.start-stop-task', `page_name` = 'autoTask' WHERE `op_id` = 93; +UPDATE `at_operation_interface` SET `op_name` = '运行可运行的定时任务', `call_name` = 'task-startRunableTask', `is_parent` = 'false', `op_type` = NULL, `mark` = '运行可运行的定时任务', `status` = '0', `parent_op_id` = 14, `permission_mark` = '.start-stop-task', `page_name` = 'autoTask' WHERE `op_id` = 94; +UPDATE `at_operation_interface` SET `op_name` = '更新定时规则', `call_name` = 'task-updateCronExpression', `is_parent` = 'false', `op_type` = NULL, `mark` = '更新定时规则', `status` = '0', `parent_op_id` = 14, `permission_mark` = '.setting-cron-expression', `page_name` = 'autoTask' WHERE `op_id` = 98; +UPDATE `at_operation_interface` SET `op_name` = '更新全局配置信息', `call_name` = 'global-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '更新全局配置信息', `status` = '0', `parent_op_id` = 15, `permission_mark` = '.save-setting', `page_name` = 'globalSetting' WHERE `op_id` = 99; +UPDATE `at_operation_interface` SET `op_name` = '测试指定数据源是否可连接', `call_name` = 'db-testDB', `is_parent` = 'false', `op_type` = NULL, `mark` = '测试指定数据源是否可连接', `status` = '0', `parent_op_id` = 17, `permission_mark` = '.db-test', `page_name` = 'queryDbList' WHERE `op_id` = 102; +UPDATE `at_operation_interface` SET `op_name` = '删除指定查询数据库信息', `call_name` = 'db-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定查询数据库信息', `status` = '0', `parent_op_id` = 17, `permission_mark` = '.object-del', `page_name` = 'queryDbList' WHERE `op_id` = 103; +UPDATE `at_operation_interface` SET `op_name` = '编辑指定查询数据库信息', `call_name` = 'db-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑指定查询数据库信息', `status` = '0', `parent_op_id` = 17, `permission_mark` = '.object-edit', `page_name` = 'queryDbList' WHERE `op_id` = 105; +UPDATE `at_operation_interface` SET `op_name` = '编辑变量信息', `call_name` = 'variable-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑变量模板信息', `status` = '0', `parent_op_id` = 18, `permission_mark` = '.object-edit', `page_name` = 'variable' WHERE `op_id` = 109; +UPDATE `at_operation_interface` SET `op_name` = '删除变量信息', `call_name` = 'variable-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定变量模板信息', `status` = '0', `parent_op_id` = 18, `permission_mark` = '.object-del', `page_name` = 'variable' WHERE `op_id` = 110; +UPDATE `at_operation_interface` SET `op_name` = '删除站内信', `call_name` = 'mail-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除信息', `status` = '0', `parent_op_id` = 20, `permission_mark` = '.object-del', `page_name` = 'mail' WHERE `op_id` = 116; +UPDATE `at_operation_interface` SET `op_name` = '删除指定角色信息', `call_name` = 'role-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除指定角色信息', `status` = '0', `parent_op_id` = 21, `permission_mark` = '.object-del', `page_name` = 'role' WHERE `op_id` = 118; +UPDATE `at_operation_interface` SET `op_name` = '编辑指定角色信息', `call_name` = 'role-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑指定角色信息', `status` = '0', `parent_op_id` = 21, `permission_mark` = '.object-edit', `page_name` = 'role' WHERE `op_id` = 120; +UPDATE `at_operation_interface` SET `op_name` = '锁定用户或者解锁用户', `call_name` = 'user-lock', `is_parent` = 'false', `op_type` = NULL, `mark` = '锁定用户或者解锁用户', `status` = '0', `parent_op_id` = 22, `permission_mark` = '.user-lock', `page_name` = 'user' WHERE `op_id` = 126; +UPDATE `at_operation_interface` SET `op_name` = '编辑用户信息', `call_name` = 'user-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '新增或者编辑用户信息', `status` = '0', `parent_op_id` = 22, `permission_mark` = '.object-edit', `page_name` = 'user' WHERE `op_id` = 128; +UPDATE `at_operation_interface` SET `op_name` = '重置用户密码', `call_name` = 'user-resetPwd', `is_parent` = 'false', `op_type` = NULL, `mark` = '重置指定用户的密码为111111', `status` = '0', `parent_op_id` = 22, `permission_mark` = '.reset-pass', `page_name` = 'user' WHERE `op_id` = 129; +UPDATE `at_operation_interface` SET `op_name` = '从excel导入数据', `call_name` = 'interface-importFromExcel', `is_parent` = 'false', `op_type` = NULL, `mark` = '从上传的Excel中导入接口信息数据', `status` = '0', `parent_op_id` = 3, `permission_mark` = '#import-data-from-excel', `page_name` = 'interface' WHERE `op_id` = 130; +UPDATE `at_operation_interface` SET `op_name` = '从excel导入数据', `call_name` = 'message-importFromExcel', `is_parent` = 'false', `op_type` = NULL, `mark` = '从上传的Excel中导入报文信息数据', `status` = '0', `parent_op_id` = 6, `permission_mark` = '#import-data-from-excel', `page_name` = 'message' WHERE `op_id` = 131; +UPDATE `at_operation_interface` SET `op_name` = '从excel导入数据', `call_name` = 'scene-importFromExcel', `is_parent` = 'false', `op_type` = NULL, `mark` = '从上传的Excel中导入测试场景信息数据', `status` = '0', `parent_op_id` = 7, `permission_mark` = '#import-data-from-excel', `page_name` = 'messageScene' WHERE `op_id` = 132; +UPDATE `at_operation_interface` SET `op_name` = '移动测试集', `call_name` = 'set-moveFolder', `is_parent` = 'false', `op_type` = NULL, `mark` = '将指定测试集移动到指定的目录文件夹下', `status` = '0', `parent_op_id` = 11, `permission_mark` = '#batch-move-folder', `page_name` = 'testSet' WHERE `op_id` = 135; +UPDATE `at_operation_interface` SET `op_name` = '导出接口文档', `call_name` = 'interface-exportInterfaceDocument', `is_parent` = 'false', `op_type` = NULL, `mark` = '批量导出接口文档', `status` = '0', `parent_op_id` = 3, `permission_mark` = '#export-interface-document', `page_name` = 'interface' WHERE `op_id` = 136; +UPDATE `at_operation_interface` SET `op_name` = '编辑或新增组合场景', `call_name` = 'complexScene-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑或新增组合场景', `status` = '0', `parent_op_id` = 998, `permission_mark` = '.object-edit', `page_name` = 'complexScene' WHERE `op_id` = 1001; +UPDATE `at_operation_interface` SET `op_name` = '删除组合场景', `call_name` = 'complexScene-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除组合场景', `status` = '0', `parent_op_id` = 998, `permission_mark` = '.object-del', `page_name` = 'complexScene' WHERE `op_id` = 1002; +UPDATE `at_operation_interface` SET `op_name` = '测试环境', `call_name` = 'system', `is_parent` = 'true', `op_type` = NULL, `mark` = '测试环境、业务系统', `status` = '0', `parent_op_id` = 13, `permission_mark` = '', `page_name` = '' WHERE `op_id` = 1019; +UPDATE `at_operation_interface` SET `op_name` = '编辑或者新增测试环境', `call_name` = 'system-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '.object-edit', `page_name` = 'businessSystem' WHERE `op_id` = 1020; +UPDATE `at_operation_interface` SET `op_name` = '获取测试环境信息', `call_name` = 'system-get', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '', `page_name` = '' WHERE `op_id` = 1022; +UPDATE `at_operation_interface` SET `op_name` = '查询测试环境列表', `call_name` = 'system-list', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '', `page_name` = '' WHERE `op_id` = 1023; +UPDATE `at_operation_interface` SET `op_name` = '删除测试环境信息', `call_name` = 'system-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '.object-del', `page_name` = 'businessSystem' WHERE `op_id` = 1024; +UPDATE `at_operation_interface` SET `op_name` = '查询所有测试环境列表', `call_name` = 'system-listAll', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '', `page_name` = '' WHERE `op_id` = 1025; +UPDATE `at_operation_interface` SET `op_name` = '删除操作接口', `call_name` = 'op-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 16, `permission_mark` = '.object-del', `page_name` = 'opInterface' WHERE `op_id` = 1027; +UPDATE `at_operation_interface` SET `op_name` = '编辑操作接口', `call_name` = 'op-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 16, `permission_mark` = '.object-edit', `page_name` = 'opInterface' WHERE `op_id` = 1029; +UPDATE `at_operation_interface` SET `op_name` = '编辑或者新增探测任务', `call_name` = 'probe-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '编辑或者新增探测任务', `status` = '0', `parent_op_id` = 1032, `permission_mark` = '.object-edit', `page_name` = 'interfaceProbe' WHERE `op_id` = 1034; +UPDATE `at_operation_interface` SET `op_name` = '删除探测任务信息', `call_name` = 'probe-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '删除探测任务信息', `status` = '0', `parent_op_id` = 1032, `permission_mark` = '.object-del', `page_name` = 'interfaceProbe' WHERE `op_id` = 1035; +UPDATE `at_operation_interface` SET `op_name` = '开启探测任务', `call_name` = 'probe-startTask', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1032, `permission_mark` = '.start-probe-task', `page_name` = 'interfaceProbe' WHERE `op_id` = 1039; +UPDATE `at_operation_interface` SET `op_name` = '停止探测任务', `call_name` = 'probe-stopTask', `is_parent` = 'false', `op_type` = NULL, `mark` = '停止探测任务', `status` = '0', `parent_op_id` = 1032, `permission_mark` = '.stop-probe-task', `page_name` = 'interfaceProbe' WHERE `op_id` = 1040; +UPDATE `at_operation_interface` SET `op_name` = '组合场景单个测试', `call_name` = 'test-complexSceneTest', `is_parent` = 'false', `op_type` = NULL, `mark` = '组合场景单个测试', `status` = '0', `parent_op_id` = 4, `permission_mark` = '.object-test', `page_name` = 'complexScene' WHERE `op_id` = 1044; +UPDATE `at_operation_interface` SET `op_name` = '业务系统删除或者增加接口信息', `call_name` = 'system-opInterface', `is_parent` = 'false', `op_type` = NULL, `mark` = '从指定的业务系统中删除或者增加接口信息', `status` = '0', `parent_op_id` = 1019, `permission_mark` = '#batch-op,.op-interface', `page_name` = 'manageSystemInterface' WHERE `op_id` = 1058; +UPDATE `at_operation_interface` SET `op_name` = '删除指定操作日志信息', `call_name` = 'log-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1059, `permission_mark` = '.object-del,#batch-del-object', `page_name` = 'logRecord' WHERE `op_id` = 1062; +UPDATE `at_operation_interface` SET `op_name` = '编辑mock接口基本信息', `call_name` = 'mock-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1064, `permission_mark` = '.object-edit', `page_name` = 'mockTest' WHERE `op_id` = 1066; +UPDATE `at_operation_interface` SET `op_name` = '删除指定mock接口信息', `call_name` = 'mock-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1064, `permission_mark` = '.object-del', `page_name` = 'mockTest' WHERE `op_id` = 1068; +UPDATE `at_operation_interface` SET `op_name` = '更新mock规则', `call_name` = 'mock-updateSetting', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1064, `permission_mark` = '#save-setting-mock-validate', `page_name` = 'mockTest' WHERE `op_id` = 1070; +UPDATE `at_operation_interface` SET `op_name` = '删除性能测试配置', `call_name` = 'ptc-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1073, `permission_mark` = '.object-del', `page_name` = 'performanceTest' WHERE `op_id` = 1075; +UPDATE `at_operation_interface` SET `op_name` = '编辑性能测试配置信息', `call_name` = 'ptc-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1073, `permission_mark` = '.object-edit', `page_name` = 'performanceTest' WHERE `op_id` = 1076; +UPDATE `at_operation_interface` SET `op_name` = '删除性能测试结果', `call_name` = 'ptr-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1078, `permission_mark` = '.object-del,#batch-del', `page_name` = 'performanceTestResult' WHERE `op_id` = 1082; +UPDATE `at_operation_interface` SET `op_name` = '停止指定性能测试任务', `call_name` = 'ptc-stopTest', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1084, `permission_mark` = '.stop-test', `page_name` = 'performanceTestTaskList' WHERE `op_id` = 1086; +UPDATE `at_operation_interface` SET `op_name` = '删除指定性能测试任务', `call_name` = 'ptc-delTest', `is_parent` = 'false', `op_type` = NULL, `mark` = '被删除的性能测试任务不会保存本次测试结果', `status` = '0', `parent_op_id` = 1084, `permission_mark` = '.del-test', `page_name` = 'performanceTestTaskList' WHERE `op_id` = 1087; +UPDATE `at_operation_interface` SET `op_name` = '初始化性能测试任务', `call_name` = 'ptc-initTest', `is_parent` = 'false', `op_type` = NULL, `mark` = '包括初始化配置、加载配置文件、预加载请求报文等', `status` = '0', `parent_op_id` = 1084, `permission_mark` = '.object-test', `page_name` = 'performanceTest' WHERE `op_id` = 1088; +UPDATE `at_operation_interface` SET `op_name` = '邮件推送离线报告', `call_name` = 'report-sendMail', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 9, `permission_mark` = '.send-mail', `page_name` = 'report' WHERE `op_id` = 1093; +UPDATE `at_operation_interface` SET `op_name` = '更新菜单与角色之间的关系', `call_name` = 'role-updateRoleMenu', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 21, `permission_mark` = '.show-role-menu', `page_name` = 'role' WHERE `op_id` = 1133; +UPDATE `at_operation_interface` SET `op_name` = '编辑或新增菜单信息', `call_name` = 'menu-edit', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1134, `permission_mark` = '.object-edit', `page_name` = 'menu' WHERE `op_id` = 1135; +UPDATE `at_operation_interface` SET `op_name` = '删除指定菜单信息', `call_name` = 'menu-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1134, `permission_mark` = '.object-del', `page_name` = 'menu' WHERE `op_id` = 1138; +DELETE FROM `at_operation_interface` WHERE `op_id` = 81; +DELETE FROM `at_operation_interface` WHERE `op_id` = 82; UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; \ No newline at end of file diff --git a/src/main/webapp/js/dcits.js b/src/main/webapp/js/dcits.js index 00c1465..21d0262 100644 --- a/src/main/webapp/js/dcits.js +++ b/src/main/webapp/js/dcits.js @@ -460,9 +460,11 @@ function controlButtonShowByPermission (domObj) { //设置jQuery Ajax全局的参数 $.ajaxSetup({ - error: function (jqXHR, textStatus, errorThrown) { + error: function (jqXHR, textStatus, errorThrown) { + //关闭所有弹窗/loading等 layer.closeAll('dialog'); $(".page-container").spinModal(false); + loading(false); switch (jqXHR.status) { case(500): layer.alert("服务器系统内部错误", {icon:5}); diff --git a/src/main/webapp/js/globalConstant.js b/src/main/webapp/js/globalConstant.js index a1ad0a3..a973d26 100644 --- a/src/main/webapp/js/globalConstant.js +++ b/src/main/webapp/js/globalConstant.js @@ -270,7 +270,8 @@ var REQUEST_URL = { UPDATE_STATUS: "mock-updateStatus", UPDATE_SETTING: "mock-updateSetting", PARSE_MESSAGE_TO_CONFIG: "mock-parseMessageToConfig", - PARSE_MESSAGE_TO_NODES: "mock-parseMessageToNodes" + PARSE_MESSAGE_TO_NODES: "mock-parseMessageToNodes", + PARSE_SCENE_TO_MOCK_INFO: "mock-parseSceneToMockInfo" }, //性能测试 PERFORMANCE_TEST: { diff --git a/src/main/webapp/resource/advanced/mockTest.js b/src/main/webapp/resource/advanced/mockTest.js index e963f27..0ff275c 100644 --- a/src/main/webapp/resource/advanced/mockTest.js +++ b/src/main/webapp/resource/advanced/mockTest.js @@ -366,9 +366,21 @@ var eventList = { }); }, "#add-object":function(){ - publish.renderParams.editPage.modeFlag = 0; - layer_show("添加Mock接口", editHtml, editPageWidth, editPageHeight.add, 1); - publish.init(); + layer.confirm( + '请选择你需要进行的批量操作:', + { + title:'添加Mock接口', + btn:['从场景导入','手动添加'], + shadeClose:true, + },function(index){ + layer.close(index); + layer_show("选择需要Mock的场景", "chooseMessageScene.html?callbackFun=chooseScene¬Multiple=true", null, null, 2); + },function(index){ + layer.close(index); + publish.renderParams.editPage.modeFlag = 0; + layer_show("添加Mock接口", editHtml, editPageWidth, editPageHeight.add, 1); + publish.init(); + }); }, "#batch-op":function(){ layer.confirm( @@ -460,3 +472,34 @@ $(function(){ publish.renderParams = $.extend(true,publish.renderParams,mySetting); publish.init(); }); + + + +function chooseScene (obj) { + if (obj == null) { + return false; + } + + if (Object.prototype.toString.call(obj) === '[object Array]' ) {//可能是多选的数组 + layer.alert('暂时不能使用多选功能,请选择单个场景!', {title:"提示", icon:5}); + return false; + } + + if (MESSAGE_MOCK_TYPE[obj.protocolType] == null) { + layer.alert('目前只支持HTTP/Socket/WebSocket类型的接口MOCK,请重新选择!'); + return false; + } + + loading(true, '正在添加...'); + $.get(REQUEST_URL.INTERFACE_MOCK.PARSE_SCENE_TO_MOCK_INFO, {messageSceneId: obj.messageSceneId}, function(json){ + loading(false); + if (json.returnCode == RETURN_CODE.SUCCESS) { + layer.msg('添加成功!', {icon: 1, time: 1500}) + refreshTable(); + } else { + layer.alert(json.msg, {icon:5}); + } + }); + + +} \ No newline at end of file diff --git a/src/main/webapp/resource/advanced/performanceTest.js b/src/main/webapp/resource/advanced/performanceTest.js index aeeb660..c5e24b2 100644 --- a/src/main/webapp/resource/advanced/performanceTest.js +++ b/src/main/webapp/resource/advanced/performanceTest.js @@ -220,7 +220,7 @@ var eventList = { opObj("确认要删除此配置信息吗?", REQUEST_URL.PERFORMANCE_TEST.DEL, {id:data.ptId}, this, "删除成功!"); }, "#choose-message-scene":function(){ //选择测试场景 - layer_show("选择测试接口场景", "chooseMessageScene.html?callbackFun=chooseScene", null, null, 2); + layer_show("选择测试接口场景", "chooseMessageScene.html?callbackFun=chooseScene¬Multiple=true", null, null, 2); }, "#choose-business-system":function(){//选择业务系统 if (!strIsNotEmpty($("#protocolType").val())) { diff --git a/update.md b/update.md index cff4825..e547e5b 100644 --- a/update.md +++ b/update.md @@ -10,7 +10,7 @@ ~~10、一键安装包 for linux;~~ ~~11、更加方便安全的版本更新方案;~~ 12、主页和论坛; -13、支持直接从接口的报文列表中新增Mock接口; +~~13、支持直接从接口的报文列表中新增Mock接口;~~(待验证) ~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ ~~15、权限控制可以显示隐藏按钮。~~ ~~16、重写部分功能,使用websocket交互。~~ -- Gitee From 40ee43408f4eea3ed05455298e70ed51f84c6371 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Tue, 26 Nov 2019 16:02:36 +0800 Subject: [PATCH 13/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=8E=A5=E5=8F=A3Mock?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advanced/action/InterfaceMockAction.java | 8 +- .../business/advanced/action/MockAction.java | 21 ++-- .../advanced/dao/InterfaceMockDao.java | 7 +- .../dao/impl/InterfaceMockDaoImpl.java | 9 +- .../service/InterfaceMockService.java | 3 +- .../impl/InterfaceMockServiceImpl.java | 16 ++- .../business/message/bean/MessageScene.java | 19 ++- .../java/yi/master/constant/MessageKeys.java | 30 +++-- .../message/test/mock/MockServer.java | 34 +++++- .../test/mock/MockWebSocketServer.java | 7 +- .../yi/master/exception/AppErrorCode.java | 1 + .../interceptor/InterfaceMockInterceptor.java | 14 +-- src/main/webapp/js/dcits.js | 9 +- .../resource/advanced/chooseMessageScene.js | 27 ++++- .../webapp/resource/advanced/mockTest.html | 6 +- src/main/webapp/resource/advanced/mockTest.js | 109 +++++++++++++----- .../resource/message/validateParameters.js | 32 +++-- 17 files changed, 233 insertions(+), 119 deletions(-) diff --git a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java index bb3132b..2a1dcd1 100644 --- a/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java +++ b/src/main/java/yi/master/business/advanced/action/InterfaceMockAction.java @@ -62,6 +62,7 @@ public class InterfaceMockAction extends BaseAction { public String updateStatus() { interfaceMockService.updateStatus(model.getMockId(), model.getStatus()); MockServer.handleMockServer(model.getMockId()); + setData(interfaceMockService.get(model.getMockId())); return SUCCESS; } @@ -157,7 +158,12 @@ public class InterfaceMockAction extends BaseAction { @Override public void checkObjectName() { - InterfaceMock mock = interfaceMockService.findByMockUrl(model.getMockUrl()); + //为空时不验证 + if (StringUtils.isBlank(model.getMockUrl())) { + checkNameFlag = "true"; + return; + } + InterfaceMock mock = interfaceMockService.findByMockUrl(model.getMockUrl(), model.getProtocolType()); checkNameFlag = (mock != null && !mock.getMockId().equals(model.getMockId())) ? "请求路径重复" : "true"; if (model.getMockId() == null) { diff --git a/src/main/java/yi/master/business/advanced/action/MockAction.java b/src/main/java/yi/master/business/advanced/action/MockAction.java index ace67a4..b8c3f3d 100644 --- a/src/main/java/yi/master/business/advanced/action/MockAction.java +++ b/src/main/java/yi/master/business/advanced/action/MockAction.java @@ -1,28 +1,27 @@ package yi.master.business.advanced.action; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Reader; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import com.opensymphony.xwork2.ActionSupport; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts2.ServletActionContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; - import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.advanced.bean.config.mock.MockRequestValidateConfig; import yi.master.business.advanced.bean.config.mock.MockResponseConfig; import yi.master.business.advanced.service.InterfaceMockService; +import yi.master.constant.MessageKeys; import yi.master.constant.SystemConsts; import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; -import com.opensymphony.xwork2.ActionSupport; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Reader; /** * 接口mock处理类
    @@ -54,7 +53,7 @@ public class MockAction extends ActionSupport { HttpServletRequest request = ServletActionContext.getRequest(); String homeUrl = CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_HOME); String uri = request.getRequestURI().replace(homeUrl.substring(homeUrl.lastIndexOf("/")), "").substring(5); - InterfaceMock mock = interfaceMockService.findByMockUrl(uri); + InterfaceMock mock = interfaceMockService.findByMockUrl(uri, MessageKeys.ProtocolType.http.name().toUpperCase()); MockRequestValidateConfig config = MockRequestValidateConfig.getInstance(mock.getRequestValidate()); diff --git a/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java b/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java index cdebed9..5d23d65 100644 --- a/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java +++ b/src/main/java/yi/master/business/advanced/dao/InterfaceMockDao.java @@ -1,17 +1,18 @@ package yi.master.business.advanced.dao; -import java.util.List; - import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.base.dao.BaseDao; +import java.util.List; + public interface InterfaceMockDao extends BaseDao{ /** * 根据mockUrl查找指定的mock信息 * @param mockUrl + * @param protocolType * @return */ - InterfaceMock findByMockUrl(String mockUrl); + InterfaceMock findByMockUrl(String mockUrl, String protocolType); /** * 更新状态 * @param mockId diff --git a/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java b/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java index 736a21e..ff412ba 100644 --- a/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java +++ b/src/main/java/yi/master/business/advanced/dao/impl/InterfaceMockDaoImpl.java @@ -12,10 +12,11 @@ import yi.master.business.base.dao.impl.BaseDaoImpl; public class InterfaceMockDaoImpl extends BaseDaoImpl implements InterfaceMockDao { @Override - public InterfaceMock findByMockUrl(String mockUrl) { - - String hql = "From InterfaceMock m where m.mockUrl=:mockUrl"; - return (InterfaceMock) getSession().createQuery(hql).setString("mockUrl", mockUrl).uniqueResult(); + public InterfaceMock findByMockUrl(String mockUrl, String protocolType) { + String hql = "From InterfaceMock m where m.mockUrl=:mockUrl and m.protocolType=:protocolType"; + return (InterfaceMock) getSession().createQuery(hql) + .setString("mockUrl", mockUrl) + .setString("protocolType", protocolType).uniqueResult(); } @Override diff --git a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java index 8f83608..47da077 100644 --- a/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java +++ b/src/main/java/yi/master/business/advanced/service/InterfaceMockService.java @@ -9,9 +9,10 @@ public interface InterfaceMockService extends BaseService { /** * 根据mockUrl查找指定的mock信息 * @param mockUrl + * @param protocolType * @return */ - InterfaceMock findByMockUrl(String mockUrl); + InterfaceMock findByMockUrl(String mockUrl, String protocolType); /** * 更新状态 diff --git a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java index 052be8c..ba8f298 100644 --- a/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java +++ b/src/main/java/yi/master/business/advanced/service/impl/InterfaceMockServiceImpl.java @@ -41,9 +41,8 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp } @Override - public InterfaceMock findByMockUrl(String mockUrl) { - - return interfaceMockDao.findByMockUrl(mockUrl); + public InterfaceMock findByMockUrl(String mockUrl, String protocolType) { + return interfaceMockDao.findByMockUrl(mockUrl, protocolType); } @Override @@ -89,6 +88,7 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp throw new YiException(AppErrorCode.INTERFACE_INFO_NOT_EXIST); } + //http/socket/websocket才支持场景转mock boolean flag = !MessageKeys.ProtocolType.http.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()) && !MessageKeys.ProtocolType.socket.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()) && !MessageKeys.ProtocolType.websocket.name().equalsIgnoreCase(interfaceInfo.getInterfaceProtocol()); @@ -103,7 +103,7 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp mockInfo.setMark("由接口场景自动生成"); mockInfo.setMockName(interfaceInfo.getInterfaceName()); - //获取测试地址 + //获取mockUrl地址,按照优先级获取 String requestUrl = ""; if (StringUtils.isNotBlank(messageScene.getRequestUrl())) { requestUrl = messageScene.getRequestUrl(); @@ -115,6 +115,14 @@ public class InterfaceMockServiceImpl extends BaseServiceImpl imp requestUrl = interfaceInfo.getRequestUrlReal(); } + //判断url是否重复 + if (StringUtils.isNotBlank(requestUrl)) { + InterfaceMock im = findByMockUrl(requestUrl, interfaceInfo.getInterfaceProtocol()); + if (im != null) { + throw new YiException(AppErrorCode.MOCK_URL_EXIST, requestUrl); + } + } + mockInfo.setMockUrl(requestUrl); mockInfo.setProtocolType(interfaceInfo.getInterfaceProtocol()); mockInfo.setStatus(InterfaceMockStatus.DISABLED.getStatus()); diff --git a/src/main/java/yi/master/business/message/bean/MessageScene.java b/src/main/java/yi/master/business/message/bean/MessageScene.java index 382ff13..5dc40e5 100644 --- a/src/main/java/yi/master/business/message/bean/MessageScene.java +++ b/src/main/java/yi/master/business/message/bean/MessageScene.java @@ -1,17 +1,9 @@ package yi.master.business.message.bean; // default package -import java.io.Serializable; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.struts2.json.annotations.JSON; - import yi.master.annotation.FieldNameMapper; import yi.master.business.advanced.bean.InterfaceProbe; import yi.master.business.advanced.bean.PerformanceTestConfig; @@ -21,6 +13,13 @@ import yi.master.constant.MessageKeys; import yi.master.util.FrameworkUtil; import yi.master.util.PracticalUtils; +import java.io.Serializable; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** * 接口自动化测试场景 @@ -94,10 +93,10 @@ public class MessageScene implements Serializable, Cloneable { */ private String requestUrl; - @FieldNameMapper(fieldPath="size(testDatas)",ifSearch=false) + @FieldNameMapper(fieldPath="size(testDatas)", ifSearch=false) private Integer testDataNum = getTestDataNum(); - @FieldNameMapper(fieldPath="size(rules)",ifSearch=false) + @FieldNameMapper(fieldPath="size(rules)", ifSearch=false) private Integer rulesNum; @FieldNameMapper(fieldPath="message.messageName") diff --git a/src/main/java/yi/master/constant/MessageKeys.java b/src/main/java/yi/master/constant/MessageKeys.java index 47fdd4d..face91c 100644 --- a/src/main/java/yi/master/constant/MessageKeys.java +++ b/src/main/java/yi/master/constant/MessageKeys.java @@ -143,43 +143,51 @@ public interface MessageKeys { /** * http测试 */ - http(HTTPTestClient.getInstance()), + http(HTTPTestClient.getInstance(), "HTTP"), /** * webservice测试 */ - webservice(WebserviceTestClient.getInstance()), + webservice(WebserviceTestClient.getInstance(), "WebService"), /** * socket测试客 */ - socket(SocketTestClient.getInstance()), + socket(SocketTestClient.getInstance(), "Socket"), /** * https测试 */ - https(HTTPTestClient.getInstance()), + https(HTTPTestClient.getInstance(), "HTTPS"), /** * dubbo测试 */ - dubbo(DubboTestClient.getInstance()), + dubbo(DubboTestClient.getInstance(), "Dubbo"), /** * webSocket测试 */ - websocket(WebSocketTestClient.getInstance()); + websocket(WebSocketTestClient.getInstance(), "WebSocket"); + /** + * 对应的协议客户端 + */ private TestClient client; + /** + * 标识符号 + */ + private String identify; - ProtocolType(TestClient client) { + ProtocolType(TestClient client, String identify) { this.client = client; + this.identify = identify; } public TestClient getClient() { return client; } - public void setClient(TestClient client) { - this.client = client; - } + public String getIdentify() { + return identify; + } - public static TestClient getClientByType (String type) { + public static TestClient getClientByType (String type) { for (ProtocolType p:values()) { if (p.name().equalsIgnoreCase(type)) { return p.getClient(); diff --git a/src/main/java/yi/master/coretest/message/test/mock/MockServer.java b/src/main/java/yi/master/coretest/message/test/mock/MockServer.java index 2697679..fc0170d 100644 --- a/src/main/java/yi/master/coretest/message/test/mock/MockServer.java +++ b/src/main/java/yi/master/coretest/message/test/mock/MockServer.java @@ -12,6 +12,7 @@ import yi.master.business.advanced.service.InterfaceMockService; import yi.master.constant.MessageKeys; import yi.master.constant.SystemConsts; import yi.master.util.FrameworkUtil; +import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; import java.io.IOException; @@ -179,6 +180,23 @@ public abstract class MockServer { } return flag; } + + /** + * 获取空闲可使用端口 + * @author xuwangcheng + * @date 2019/11/26 9:40 + * @param + * @return {@link int} + */ + protected int getUnUsePort () { + int randomPort = PracticalUtils.getRandomNum(65535, 1024); + while (isLocalPortUsing(randomPort)) { + randomPort = PracticalUtils.getRandomNum(65535, 1024); + } + + return randomPort; + } + /*** * 测试主机Host的port端口是否被使用 * @param host @@ -188,14 +206,22 @@ public abstract class MockServer { private boolean isPortUsing(String host, int port) throws UnknownHostException { boolean flag = false; InetAddress Address = InetAddress.getByName(host); + Socket socket = null; try { //建立一个Socket连接 - Socket socket = new Socket(Address, port); + socket = new Socket(Address, port); + flag = true; + } catch (IOException e) { + logger.error("IOException", e); + } finally { if (socket != null) { - socket.close(); + try { + socket.close(); + } catch (IOException e) { + logger.error("IOException", e); + } } - flag = true; - } catch (IOException e) {} + } return flag; } diff --git a/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java b/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java index 9744f24..7c04a26 100644 --- a/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java +++ b/src/main/java/yi/master/coretest/message/test/mock/MockWebSocketServer.java @@ -30,12 +30,7 @@ public class MockWebSocketServer extends MockServer { @Override public void start() { - int randomPort = PracticalUtils.getRandomNum(65535, 1024); - while (isLocalPortUsing(randomPort)) { - randomPort = PracticalUtils.getRandomNum(65535, 1024); - } - - webSocketServer = new WebSocketServer(new InetSocketAddress(randomPort)) { + webSocketServer = new WebSocketServer(new InetSocketAddress(getUnUsePort())) { @Override public void onOpen(WebSocket conn, ClientHandshake handshake) { logger.debug(StrUtil.format("WebSocketMockServer {} on Open...", getMockUrl())); diff --git a/src/main/java/yi/master/exception/AppErrorCode.java b/src/main/java/yi/master/exception/AppErrorCode.java index 5677df2..e950e16 100644 --- a/src/main/java/yi/master/exception/AppErrorCode.java +++ b/src/main/java/yi/master/exception/AppErrorCode.java @@ -73,6 +73,7 @@ public enum AppErrorCode { //高级测试相关 MOCK_PROTOCOL_NOT_SUPPORT(360001, "不支持该协议接口的Mock"), + MOCK_URL_EXIST(360002, "已存在Url路径为{}的Mock信息,请重新选择或者修改接口场景中的请求路径!"), //场景相关 SCENE_INFO_NOT_EXIST(370001, "测试场景不存在") diff --git a/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java b/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java index 582e0df..c008d72 100644 --- a/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java +++ b/src/main/java/yi/master/interceptor/InterfaceMockInterceptor.java @@ -1,11 +1,11 @@ package yi.master.interceptor; -import javax.servlet.http.HttpServletRequest; - +import com.opensymphony.xwork2.ActionContext; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import org.apache.log4j.Logger; import org.apache.struts2.StrutsStatics; import org.springframework.beans.factory.annotation.Autowired; - import yi.master.business.advanced.action.MockAction; import yi.master.business.advanced.bean.InterfaceMock; import yi.master.business.advanced.enums.InterfaceMockStatus; @@ -15,14 +15,14 @@ import yi.master.business.log.enums.LogInterceptStatus; import yi.master.business.log.service.LogRecordService; import yi.master.business.system.bean.OperationInterface; import yi.master.business.user.bean.User; +import yi.master.constant.MessageKeys; import yi.master.constant.SystemConsts; import yi.master.exception.AppErrorCode; import yi.master.exception.YiException; import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; -import com.opensymphony.xwork2.ActionContext; -import com.opensymphony.xwork2.ActionInvocation; -import com.opensymphony.xwork2.interceptor.AbstractInterceptor; + +import javax.servlet.http.HttpServletRequest; public class InterfaceMockInterceptor extends AbstractInterceptor { @@ -61,7 +61,7 @@ public class InterfaceMockInterceptor extends AbstractInterceptor { String homeUrl = CacheUtil.getSettingValue(SystemConsts.GLOBAL_SETTING_HOME); callUrl = request.getRequestURI().replace(homeUrl.substring(homeUrl.lastIndexOf("/")), "").substring(5); - InterfaceMock mock = interfaceMockService.findByMockUrl(callUrl); + InterfaceMock mock = interfaceMockService.findByMockUrl(callUrl, MessageKeys.ProtocolType.http.name().toUpperCase()); if (mock == null) { interceptStatus = LogInterceptStatus.MOCK_NOT_EXIST.getStatus(); recordService.saveRecord(user, opInterface, callUrl, interceptStatus, callType, userHost, browserAgent, diff --git a/src/main/webapp/js/dcits.js b/src/main/webapp/js/dcits.js index 21d0262..001e0f6 100644 --- a/src/main/webapp/js/dcits.js +++ b/src/main/webapp/js/dcits.js @@ -121,6 +121,7 @@ var publish = { * columnsJson:不参与排序的列 * dtOtherSetting:DT其他的自定义设置 * dtAjaxCallback:DataTables在每次通过ajax.reload返回之后的回调 + * dtDrawCallback: DataTables每次重绘之后的回调 * exportExcel:是否在工具栏添加 导出到excel 的按钮工具 默认为true * dblclickEdit:开启双击行打开编辑页面 默认为true * @@ -219,7 +220,8 @@ var publish = { beforeInit:function(df) { df.resolve(); }, - dtAjaxCallback:function() {}, + dtAjaxCallback:function() {}, + dtDrawCallback:function() {}, tableObj:null, columnsSetting:{}, columnsJson:[], @@ -360,7 +362,7 @@ var publish = { if (p.userDefaultRender == true) { if (p.renderType == "list") { var l = p.listPage; - table = initDT(l.tableObj, l.listUrl, l.columnsSetting, l.columnsJson, l.dtOtherSetting); + table = initDT(l.tableObj, l.listUrl, l.columnsSetting, l.columnsJson, l.dtOtherSetting, l.dtDrawCallback); /***添加导入excel插件按钮**/ if (l.exportExcel) { @@ -546,7 +548,7 @@ $.fn.delegates = function(configs) { * @param columnsJson 不参与排序的列 jsonArray * @returns table 返回对应的DataTable实例 */ -function initDT (tableObj, ajaxUrl, columnsSetting, columnsJson, dtOtherSetting) { +function initDT (tableObj, ajaxUrl, columnsSetting, columnsJson, dtOtherSetting, dtDrawCallback) { var data = []; var table = $(tableObj) /*//发送ajax请求时 @@ -573,6 +575,7 @@ function initDT (tableObj, ajaxUrl, columnsSetting, columnsJson, dtOtherSetting) //重绘完毕 .on('draw.dt', function () { //初始化和刷新都会触发 controlButtonShowByPermission($('.table')); + typeof dtDrawCallback === 'function' && dtDrawCallback(); }) //初始化完毕 .on( 'init.dt', function () { //刷新表格不会触发此事件 只存在一次 diff --git a/src/main/webapp/resource/advanced/chooseMessageScene.js b/src/main/webapp/resource/advanced/chooseMessageScene.js index aacb4fd..7bbc86a 100644 --- a/src/main/webapp/resource/advanced/chooseMessageScene.js +++ b/src/main/webapp/resource/advanced/chooseMessageScene.js @@ -103,19 +103,33 @@ var columnsSetting = [ ]; var eventList = { "#batch-choose":function(){//批量选择 - var $checkbox = $(".selectScene:checked"); + let $checkbox = $(".selectScene:checked"); if ($checkbox.length < 1) { return false; } - var dataArr = []; + let dataArr = []; + let flag = true; $.each($checkbox, function(i, n){ - dataArr.push(table.row( $(n).parents('tr') ).data()); + let d = table.row( $(n).parents('tr') ).data(); + if (enabledProtocolTypes != null && enabledProtocolTypes.indexOf(d.protocolType) == -1) { + layer.alert('只能选择协议类型为' + enabledProtocolTypes.join('/') + '类型的接口场景,请重新选择!', {title:"提示", icon:5}); + flag = false; + return false; + } + dataArr.push(d); }); + if (!flag) { + return; + } choosedCallBackFun(dataArr); parent.layer.close(parent.layer.getFrameIndex(window.name)); }, ".choose-this-scene":function() {//选择场景 var data = table.row( $(this).parents('tr') ).data(); + if (enabledProtocolTypes != null && enabledProtocolTypes.indexOf(data.protocolType) == -1) { + layer.alert('只能选择协议类型为' + enabledProtocolTypes.join('/') + '类型的接口场景,请重新选择!', {title:"提示", icon:5}); + return; + } choosedCallBackFun(data); parent.layer.close(parent.layer.getFrameIndex(window.name)); }, @@ -152,7 +166,7 @@ var eventList = { } }; - +var enabledProtocolTypes; var mySetting = { eventList:eventList, templateCallBack:function(df) { @@ -161,6 +175,11 @@ var mySetting = { if (GetQueryString("notMultiple") == 'true') { $('#batch-choose').hide(); } + //指定查询的协议了类型 + let protocols = GetQueryString('protocolType'); + if (strIsNotEmpty(protocols)) { + enabledProtocolTypes = protocols.split(','); + } df.resolve(); }, diff --git a/src/main/webapp/resource/advanced/mockTest.html b/src/main/webapp/resource/advanced/mockTest.html index 1707ae0..a57eb49 100644 --- a/src/main/webapp/resource/advanced/mockTest.html +++ b/src/main/webapp/resource/advanced/mockTest.html @@ -16,8 +16,8 @@ - + + diff --git a/update.md b/update.md index e547e5b..777569e 100644 --- a/update.md +++ b/update.md @@ -6,14 +6,16 @@ 6、支持对数组的取值,设定值; 7、增加测试集全局配置:头信息、验证规则、测试集变量等功能; 8、完善操作说明手册, -9、支持从yapi/rap/postman/swagger/各种规范的日志文件中导入接口; ~~10、一键安装包 for linux;~~ ~~11、更加方便安全的版本更新方案;~~ 12、主页和论坛; -~~13、支持直接从接口的报文列表中新增Mock接口;~~(待验证) +~~13、支持直接从接口的报文列表中新增Mock接口;~~ ~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ ~~15、权限控制可以显示隐藏按钮。~~ ~~16、重写部分功能,使用websocket交互。~~ + + +9、支持从yapi/rap/postman/swagger/各种规范的日志文件中导入接口; 17、对文件上传类接口的支持。 @@ -21,8 +23,11 @@ ### v1.0.0正式版 #### 2019 - 新增:xss过滤器; -- 新增:webSocket接口Mock; -- 修复:接口权限修改删除之后不生效的问题; +- 新增:webSocket类型的接口Mock,支持选择指定的接口场景来新增接口Mock信息(支持Http/Socket/WebSocket协议); +- 更新:前后端部分交互使用WebSocket技术; +- 新增:角色权限控制支持精确到前端按钮级别(仅支持部分主要功能的按钮); +- 更新:默认不显示WebUI测试相关模块(暂时废弃,不更新了); +- 修复:前端弹出窗口大小没有跟随浏览器大小动态改变而导致显示异常的问题 -- Gitee From 7607dc35276ad1e26b51d9ab8475bb98f90b444b Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Wed, 27 Nov 2019 18:29:56 +0800 Subject: [PATCH 15/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/update/1.0.0 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/resources/update/1.0.0 b/src/main/resources/update/1.0.0 index 69ef962..82e3c1a 100644 --- a/src/main/resources/update/1.0.0 +++ b/src/main/resources/update/1.0.0 @@ -77,4 +77,8 @@ UPDATE `at_operation_interface` SET `op_name` = '编辑或新增菜单信息', ` UPDATE `at_operation_interface` SET `op_name` = '删除指定菜单信息', `call_name` = 'menu-del', `is_parent` = 'false', `op_type` = NULL, `mark` = '', `status` = '0', `parent_op_id` = 1134, `permission_mark` = '.object-del', `page_name` = 'menu' WHERE `op_id` = 1138; DELETE FROM `at_operation_interface` WHERE `op_id` = 81; DELETE FROM `at_operation_interface` WHERE `op_id` = 82; -UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; \ No newline at end of file +UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; + + +ALTER TABLE `at_test_config` ADD COLUMN `public_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共测试数据,json串存储' AFTER `mail_copy_address`; +ALTER TABLE `at_test_config` ADD COLUMN `public_header` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共请求头,只对HTTP/HTTPS有效,json串存储' AFTER `public_data`; -- Gitee From 287271b71712576f7d39ededacdd081f82147991 Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Thu, 28 Nov 2019 18:59:46 +0800 Subject: [PATCH 16/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/testconfig/bean/TestConfig.java | 3 + .../java/yi/master/constant/SystemConsts.java | 20 ++-- .../message/protocol/HTTPTestClient.java | 45 +++++--- .../message/test/MessageAutoTest.java | 8 +- .../yi/master/listener/VersionUpdateUtil.java | 4 +- .../java/yi/master/util/PracticalUtils.java | 100 +++++++++--------- src/main/resources/update/0.2.0beta | 1 - .../resources/update/{1.0.0 => 0.2.2beta} | 2 - .../webapp/resource/message/messageScene.js | 2 +- src/main/webapp/resource/message/setScene.js | 3 +- .../resource/template/customTemplate.htm | 2 +- update.md | 13 +-- 12 files changed, 109 insertions(+), 94 deletions(-) delete mode 100644 src/main/resources/update/0.2.0beta rename src/main/resources/update/{1.0.0 => 0.2.2beta} (99%) diff --git a/src/main/java/yi/master/business/testconfig/bean/TestConfig.java b/src/main/java/yi/master/business/testconfig/bean/TestConfig.java index 0d1d117..75fecff 100644 --- a/src/main/java/yi/master/business/testconfig/bean/TestConfig.java +++ b/src/main/java/yi/master/business/testconfig/bean/TestConfig.java @@ -1,6 +1,7 @@ package yi.master.business.testconfig.bean; import org.apache.log4j.Logger; +import org.apache.struts2.json.annotations.JSON; import yi.master.util.PracticalUtils; import java.io.Serializable; @@ -140,6 +141,7 @@ public class TestConfig implements Serializable, Cloneable { } + @JSON(serialize = false) public Map getPublicDataObject () { Map maps = PracticalUtils.jsonToMap(publicData); if (maps == null) { @@ -149,6 +151,7 @@ public class TestConfig implements Serializable, Cloneable { return maps; } + @JSON(serialize = false) public Map getPublicHeaderObject () { Map maps = PracticalUtils.jsonToMap(publicHeader); if (maps == null) { diff --git a/src/main/java/yi/master/constant/SystemConsts.java b/src/main/java/yi/master/constant/SystemConsts.java index 18dc245..faa1823 100644 --- a/src/main/java/yi/master/constant/SystemConsts.java +++ b/src/main/java/yi/master/constant/SystemConsts.java @@ -135,13 +135,7 @@ public interface SystemConsts { * 请求带上此token代表为内部自调用接口,不需要验证权限 */ String REQUEST_ALLOW_TOKEN = "ec189a1731d73dfe16d8f9df16d67187"; - - - /** - * 管理员角色名和用户名 - * - */ - String SYSTEM_ADMINISTRATOR_ROLE_NAME = "admin"; + String API_TOKEN_ATTRIBUTE_NAME = "token"; @@ -149,11 +143,15 @@ public interface SystemConsts { * sessionMap中登录用户key值 */ String SESSION_ATTRIBUTE_LOGIN_USER = "user"; - - //SessionMap中指定属性名 + + /** + * SessionMap中指定属性名 + */ String SESSION_ATTRIBUTE_VERIFY_CODE = "verifyCode"; - - //定时任务相关标志词语 + + /** + * 定时任务相关标志词语 + */ String QUARTZ_TIME_TASK_NAME_PREFIX_KEY = "timeScheduleJob"; String QUARTZ_PROBE_TASK_NAME_PREFIX_KEY = "probeScheduleJob"; String QUARTZ_SCHEDULER_START_FLAG = "quartzStatus"; diff --git a/src/main/java/yi/master/coretest/message/protocol/HTTPTestClient.java b/src/main/java/yi/master/coretest/message/protocol/HTTPTestClient.java index b565229..43f32f5 100644 --- a/src/main/java/yi/master/coretest/message/protocol/HTTPTestClient.java +++ b/src/main/java/yi/master/coretest/message/protocol/HTTPTestClient.java @@ -1,22 +1,7 @@ package yi.master.coretest.message.protocol; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - +import cn.hutool.core.collection.CollUtil; import net.sf.json.JSONObject; - import org.apache.commons.lang.StringUtils; import org.apache.http.*; import org.apache.http.client.entity.UrlEncodedFormEntity; @@ -37,7 +22,6 @@ import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.log4j.Logger; - import org.springframework.http.HttpMethod; import yi.master.business.testconfig.bean.TestConfig; import yi.master.constant.MessageKeys; @@ -46,6 +30,16 @@ import yi.master.coretest.message.protocol.entity.ClientTestResponseObject; import yi.master.coretest.message.protocol.entity.HttpDeleteWithBody; import yi.master.util.PracticalUtils; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.*; + /** * 接口自动化
    * Http协议接口测试客户端 @@ -194,6 +188,8 @@ public class HTTPTestClient extends TestClient { int connectTimeOut = config.getConnectTimeOut(); int readTimeOut = config.getReadTimeOut(); + + //报文配置的调用参数解析 if (callParameter != null) { try { headers = (Map) callParameter.get(MessageKeys.HTTP_PARAMETER_HEADER); @@ -215,6 +211,21 @@ public class HTTPTestClient extends TestClient { LOGGER.info("报文附加参数获取出错:" + callParameter.toString(), e); } } + + //替换测试集的公共测试头 + Map setPublicHeader = config.getPublicHeaderObject(); + if (CollUtil.isNotEmpty(setPublicHeader)) { + if (headers == null) { + headers = new HashMap<>(); + } + + for (String key:setPublicHeader.keySet()) { + if (setPublicHeader.get(key) != null) { + headers.put(key, setPublicHeader.get(key).toString()); + } + } + } + //请求超时 client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectTimeOut); //读取超时 diff --git a/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java b/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java index 1d775cf..f6ae47a 100644 --- a/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java +++ b/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java @@ -670,10 +670,12 @@ public class MessageAutoTest { } paramsData.put(MessageKeys.MESSAGE_PARAMETER_DEFAULT_ROOT_PATH + "." + entry.getKey(), replaceVariable); } - } + } + //替换测试集公共变量 + requestMessage = PracticalUtils.replaceSetPublicVariable(parseUtil.depacketizeMessageToString(msg.getComplexParameter() + , paramsData.toString()), config.getPublicDataObject()); //替换入参报文中的全局变量 - requestMessage = PracticalUtils.replaceGlobalVariable(parseUtil.depacketizeMessageToString(msg.getComplexParameter(), - paramsData.toString()), globalVariableService); + requestMessage = PracticalUtils.replaceGlobalVariable(requestMessage, globalVariableService); } testScene.setTestClient(TestClient.getTestClientInstance(info.getInterfaceProtocol())); diff --git a/src/main/java/yi/master/listener/VersionUpdateUtil.java b/src/main/java/yi/master/listener/VersionUpdateUtil.java index 11d4892..680c342 100644 --- a/src/main/java/yi/master/listener/VersionUpdateUtil.java +++ b/src/main/java/yi/master/listener/VersionUpdateUtil.java @@ -6,14 +6,11 @@ import cn.hutool.core.io.resource.ClassPathResource; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; import yi.master.business.system.dao.GlobalSettingDao; -import yi.master.business.system.service.GlobalSettingService; import yi.master.constant.SystemConsts; import yi.master.util.FrameworkUtil; @@ -46,6 +43,7 @@ public class VersionUpdateUtil { ALL_VERSION_LIST.add("0.1.5beta"); ALL_VERSION_LIST.add("0.2.0beta"); ALL_VERSION_LIST.add("0.2.1beta"); + ALL_VERSION_LIST.add("0.2.2beta"); } /** diff --git a/src/main/java/yi/master/util/PracticalUtils.java b/src/main/java/yi/master/util/PracticalUtils.java index be63c1b..8d98c76 100644 --- a/src/main/java/yi/master/util/PracticalUtils.java +++ b/src/main/java/yi/master/util/PracticalUtils.java @@ -1,37 +1,8 @@ package yi.master.util; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintStream; -import java.nio.file.Paths; -import java.security.NoSuchAlgorithmException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Scanner; -import java.util.Set; -import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletRequest; - +import cn.hutool.core.collection.CollUtil; +import net.sf.json.JSONObject; +import net.sf.json.JsonConfig; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; @@ -39,25 +10,15 @@ import org.apache.http.impl.client.DefaultHttpClient; import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; import org.hyperic.sigar.Sigar; - -import cn.hutool.captcha.CaptchaUtil; -import cn.hutool.captcha.LineCaptcha; -import net.sf.json.JSONObject; -import net.sf.json.JsonConfig; import yi.master.business.advanced.bean.config.probe.ProbeConfig; import yi.master.business.api.bean.ApiReturnInfo; -import yi.master.business.message.bean.ComplexSceneConfig; -import yi.master.business.message.bean.Parameter; -import yi.master.business.message.bean.TestReport; -import yi.master.business.message.bean.TestResult; -import yi.master.business.message.bean.TestSet; +import yi.master.business.message.bean.*; import yi.master.business.message.service.TestResultService; import yi.master.business.message.service.TestSetService; import yi.master.business.testconfig.bean.BusinessSystem; import yi.master.business.testconfig.bean.GlobalVariable; import yi.master.business.testconfig.service.BusinessSystemService; import yi.master.business.testconfig.service.GlobalVariableService; -import yi.master.constant.ReturnCodeConsts; import yi.master.constant.SystemConsts; import yi.master.coretest.message.parse.MessageParse; import yi.master.coretest.message.protocol.HTTPTestClient; @@ -66,6 +27,16 @@ import yi.master.util.cache.CacheUtil; import yi.master.util.jsonlib.JsonDateValueProcessor; import yi.master.util.message.JsonUtil; +import javax.servlet.http.HttpServletRequest; +import java.io.*; +import java.nio.file.Paths; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * 常用工具类 * @@ -260,7 +231,7 @@ public class PracticalUtils { /** * 时间格式化 * - * @param fromat + * @param format * @param date * @return */ @@ -320,7 +291,7 @@ public class PracticalUtils { /** * 生成静态报告文件
    * 2018-01-01报告模板有改动
    - * 参见 {@link #createReportNew(Map)} + * 参见 {@link #createReportNew} * @param report * @param title * html标题 @@ -400,7 +371,7 @@ public class PracticalUtils { /** * 生成离线的测试报告
    - * @param reportObject 包含报告所需的各种信息,同接口getReportDetail返回内容 + * @param reportDetails 包含报告所需的各种信息,同接口getReportDetail返回内容 * @return * @throws Exception */ @@ -644,7 +615,9 @@ public class PracticalUtils { */ public static String replaceGlobalVariable(String msg, GlobalVariableService globalVariableService) { - if (StringUtils.isBlank(msg)) return msg; + if (StringUtils.isBlank(msg)) { + return msg; + } if (globalVariableService == null) { globalVariableService = (GlobalVariableService) FrameworkUtil.getSpringBean("globalVariableService"); @@ -670,6 +643,37 @@ public class PracticalUtils { return msg; } + /** + * 替换测试集公共数据变量 + * @author xuwangcheng + * @date 2019/11/28 17:59 + * @param msg msg + * @param params params + * @return {@link String} + */ + public static String replaceSetPublicVariable(String msg, Map params) { + if (StringUtils.isBlank(msg) || CollUtil.isEmpty(params)) { + return msg; + } + + String regex = "\\$\\{__(.*?)\\}"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(msg); + + String dataKey = null; + while (matcher.find()) { + dataKey = "\\$\\{__" + matcher.group(1) + "\\}"; + if (!msg.contains("${__" + matcher.group(1) + "}")) { + continue; + } + if (params.get(matcher.group(1)) != null) { + msg = msg.replaceAll(dataKey, params.get(matcher.group(1)).toString()); + } + } + + return msg; + } + /** * 发送http请求-get方式 * @@ -979,7 +983,7 @@ public class PracticalUtils { /** * 使用关联配置获取指定内容 - * @param map 关联规则 + * @param maps 关联规则 * @param msg * @return */ diff --git a/src/main/resources/update/0.2.0beta b/src/main/resources/update/0.2.0beta deleted file mode 100644 index 58fb992..0000000 --- a/src/main/resources/update/0.2.0beta +++ /dev/null @@ -1 +0,0 @@ -update at_global_setting set setting_value='易大师接口自动化测试平台' where setting_name='siteName'; \ No newline at end of file diff --git a/src/main/resources/update/1.0.0 b/src/main/resources/update/0.2.2beta similarity index 99% rename from src/main/resources/update/1.0.0 rename to src/main/resources/update/0.2.2beta index 82e3c1a..8f141d7 100644 --- a/src/main/resources/update/1.0.0 +++ b/src/main/resources/update/0.2.2beta @@ -78,7 +78,5 @@ UPDATE `at_operation_interface` SET `op_name` = '删除指定菜单信息', `cal DELETE FROM `at_operation_interface` WHERE `op_id` = 81; DELETE FROM `at_operation_interface` WHERE `op_id` = 82; UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; - - ALTER TABLE `at_test_config` ADD COLUMN `public_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共测试数据,json串存储' AFTER `mail_copy_address`; ALTER TABLE `at_test_config` ADD COLUMN `public_header` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共请求头,只对HTTP/HTTPS有效,json串存储' AFTER `public_data`; diff --git a/src/main/webapp/resource/message/messageScene.js b/src/main/webapp/resource/message/messageScene.js index a61ac5c..a5f6a3b 100644 --- a/src/main/webapp/resource/message/messageScene.js +++ b/src/main/webapp/resource/message/messageScene.js @@ -328,7 +328,7 @@ var eventList = { }); if (JSON.stringify(updateConfig) != JSON.stringify(data.config)) { - $.post(REQUEST_URL.COMPLEX_SCENE.UPDATE_CONFIG_INFO, {id:complexSceneId, sequenceNum:data.sequenceNum, config:JSON.stringify(updateConfig)}, function (json) { + $.post(REQUEST_URL.COMPLEX_SCENE.UPDATE_SCENE_CONFIG, {id:complexSceneId, sequenceNum:data.sequenceNum, config:JSON.stringify(updateConfig)}, function (json) { if (json.returnCode == 0) { layer.msg("已更新配置信息", {icon:1, time:1800}); refreshTable(); diff --git a/src/main/webapp/resource/message/setScene.js b/src/main/webapp/resource/message/setScene.js index bbea062..1a8cb0b 100644 --- a/src/main/webapp/resource/message/setScene.js +++ b/src/main/webapp/resource/message/setScene.js @@ -280,6 +280,7 @@ var eventList = { let publicHeaderObject = JSON.parse(publicHeader); customDataSettingView({ title: '测试集公共请求头', + remark: '测试集公共请求头只对HTTP/HTTPS协议类型的接口场景有效,优先级高于测试报文中配置的请求头。', data: publicHeaderObject, saveCallback: function(d, index) { $("#publicHeader").val(JSON.stringify(d)); @@ -289,7 +290,7 @@ var eventList = { }, //测试集公共验证规则 "#set-public-validate-rule": function() { - + layer.msg('暂时不可用,请期待下个版本!', {time: 1600}); }, ".op-scene":function() {//单条删除或者添加 var tip = '删除'; diff --git a/src/main/webapp/resource/template/customTemplate.htm b/src/main/webapp/resource/template/customTemplate.htm index e236560..9d82a5c 100644 --- a/src/main/webapp/resource/template/customTemplate.htm +++ b/src/main/webapp/resource/template/customTemplate.htm @@ -600,7 +600,7 @@
    - +
    diff --git a/update.md b/update.md index 777569e..562b36d 100644 --- a/update.md +++ b/update.md @@ -13,21 +13,22 @@ ~~14、测试集中可以更加方便的管理组合场景,而不是直接打开新的tab窗口;~~ ~~15、权限控制可以显示隐藏按钮。~~ ~~16、重写部分功能,使用websocket交互。~~ - - 9、支持从yapi/rap/postman/swagger/各种规范的日志文件中导入接口; 17、对文件上传类接口的支持。 -### v1.0.0正式版 -#### 2019 -- 新增:xss过滤器; +### v0.2.2beta +#### 2019.11.28 +- 新增:更加简便安全的版本更新方案(只需要更新到最新War包即可); +- 新增:xss过滤器(考虑到接口问题,默认未启用,如有安全需求,联系作者如何开启); - 新增:webSocket类型的接口Mock,支持选择指定的接口场景来新增接口Mock信息(支持Http/Socket/WebSocket协议); -- 更新:前后端部分交互使用WebSocket技术; - 新增:角色权限控制支持精确到前端按钮级别(仅支持部分主要功能的按钮); +- 新增:测试集公共变量和公共请求头; +- 更新:前后端部分交互采用WebSocket技术; - 更新:默认不显示WebUI测试相关模块(暂时废弃,不更新了); - 修复:前端弹出窗口大小没有跟随浏览器大小动态改变而导致显示异常的问题 +- 修复:组合场景配置异常问题。 -- Gitee From cc5cef9ca89fc899c168cab09d7b0e26b15e750b Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Thu, 28 Nov 2019 19:17:50 +0800 Subject: [PATCH 17/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/update/0.2.2beta | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/update/0.2.2beta b/src/main/resources/update/0.2.2beta index 8f141d7..d617540 100644 --- a/src/main/resources/update/0.2.2beta +++ b/src/main/resources/update/0.2.2beta @@ -80,3 +80,4 @@ DELETE FROM `at_operation_interface` WHERE `op_id` = 82; UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; ALTER TABLE `at_test_config` ADD COLUMN `public_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共测试数据,json串存储' AFTER `mail_copy_address`; ALTER TABLE `at_test_config` ADD COLUMN `public_header` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共请求头,只对HTTP/HTTPS有效,json串存储' AFTER `public_data`; +CREATE TABLE `yi`.`at_config_validate_rule` (`config_id` int(11) NOT NULL,`validate_id` int(11) NOT NULL,PRIMARY KEY (`config_id`, `validate_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '测试集配置与验证规则关联表' ROW_FORMAT = Dynamic; \ No newline at end of file -- Gitee From 14e6b97f432ce111bbb2823c4c859ad57e655d0b Mon Sep 17 00:00:00 2001 From: xuwangcheng Date: Thu, 28 Nov 2019 23:54:00 +0800 Subject: [PATCH 18/18] =?UTF-8?q?v0.2.2beta-=E5=BE=85=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../action/SceneValidateRuleAction.java | 38 +++- .../message/bean/SceneValidateRule.hbm.xml | 3 + .../message/bean/SceneValidateRule.java | 15 +- .../message/dao/SceneValidateRuleDao.java | 13 +- .../dao/impl/SceneValidateRuleDaoImpl.java | 10 +- .../service/SceneValidateRuleService.java | 13 +- .../impl/SceneValidateRuleServiceImpl.java | 10 +- .../testconfig/bean/TestConfig.hbm.xml | 7 + .../business/testconfig/bean/TestConfig.java | 20 +- .../testconfig/dao/TestConfigDao.java | 2 +- .../java/yi/master/constant/SystemConsts.java | 2 +- .../message/test/MessageAutoTest.java | 2 +- .../message/test/MessageValidateResponse.java | 19 +- src/main/resources/update/0.2.2beta | 4 +- src/main/webapp/js/globalConstant.js | 3 +- .../webapp/js/json/HttpRequestHeader.json | 188 +++++++++--------- .../webapp/js/json/HttpResponseHeader.json | 148 +++++++------- src/main/webapp/resource/message/message.js | 14 +- src/main/webapp/resource/message/setScene.js | 12 +- .../resource/message/validateParameters.js | 38 +++- .../resource/template/customTemplate.htm | 4 +- update.md | 3 +- 22 files changed, 343 insertions(+), 225 deletions(-) diff --git a/src/main/java/yi/master/business/message/action/SceneValidateRuleAction.java b/src/main/java/yi/master/business/message/action/SceneValidateRuleAction.java index 83a2c29..129d28b 100644 --- a/src/main/java/yi/master/business/message/action/SceneValidateRuleAction.java +++ b/src/main/java/yi/master/business/message/action/SceneValidateRuleAction.java @@ -1,16 +1,13 @@ package yi.master.business.message.action; -import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; - import yi.master.business.base.action.BaseAction; -import yi.master.business.message.bean.MessageScene; import yi.master.business.message.bean.SceneValidateRule; import yi.master.business.message.service.SceneValidateRuleService; -import yi.master.constant.ReturnCodeConsts; + +import java.util.List; /** * 报文场景验证结果Action @@ -31,6 +28,8 @@ public class SceneValidateRuleAction extends BaseAction { private Integer messageSceneId; private SceneValidateRuleService sceneValidateRuleService; + + private Integer configId; @Autowired public void setSceneValidateRuleService( @@ -39,7 +38,18 @@ public class SceneValidateRuleAction extends BaseAction { this.sceneValidateRuleService = sceneValidateRuleService; } - + + @Override + public String edit() { + if (model.getTestConfig().getConfigId() == null) { + model.setTestConfig(null); + } + if (model.getMessageScene().getMessageSceneId() == null) { + model.setMessageScene(null); + } + return super.edit(); + } + /** * 全文验证规则更新 * @return @@ -68,10 +78,26 @@ public class SceneValidateRuleAction extends BaseAction { sceneValidateRuleService.updateStatus(model.getValidateId(), model.getStatus()); return SUCCESS; } + + /** + * 获取测试配置下的公共验证规则 + * @author xuwangcheng + * @date 2019/11/28 21:50 + * @param + * @return {@link String} + */ + public String getConfigValidates () { + List rules = sceneValidateRuleService.getConfigRules(configId); + setData(rules); + return SUCCESS; + } /***********************************GET-SET**********************************************************/ public void setMessageSceneId(Integer messageSceneId) { this.messageSceneId = messageSceneId; } + public void setConfigId(Integer configId) { + this.configId = configId; + } } diff --git a/src/main/java/yi/master/business/message/bean/SceneValidateRule.hbm.xml b/src/main/java/yi/master/business/message/bean/SceneValidateRule.hbm.xml index 0c1457f..02b5da7 100644 --- a/src/main/java/yi/master/business/message/bean/SceneValidateRule.hbm.xml +++ b/src/main/java/yi/master/business/message/bean/SceneValidateRule.hbm.xml @@ -13,6 +13,9 @@ + + + diff --git a/src/main/java/yi/master/business/message/bean/SceneValidateRule.java b/src/main/java/yi/master/business/message/bean/SceneValidateRule.java index eca4100..5f2e83a 100644 --- a/src/main/java/yi/master/business/message/bean/SceneValidateRule.java +++ b/src/main/java/yi/master/business/message/bean/SceneValidateRule.java @@ -1,11 +1,11 @@ package yi.master.business.message.bean; -import java.io.Serializable; - import org.apache.struts2.json.annotations.JSON; - import yi.master.annotation.FieldNameMapper; import yi.master.annotation.FieldRealSearch; +import yi.master.business.testconfig.bean.TestConfig; + +import java.io.Serializable; /** * 出参验证规则 @@ -22,6 +22,7 @@ public class SceneValidateRule implements Serializable { private static final long serialVersionUID = 1L; private Integer validateId; private MessageScene messageScene; + private TestConfig testConfig; /** * 根据validate_method_flag的值有不同的含义:
    @@ -152,8 +153,14 @@ public class SceneValidateRule implements Serializable { this.mark = mark; } + public void setTestConfig(TestConfig testConfig) { + this.testConfig = testConfig; + } - + @JSON(serialize=false) + public TestConfig getTestConfig() { + return testConfig; + } @Override public String toString() { diff --git a/src/main/java/yi/master/business/message/dao/SceneValidateRuleDao.java b/src/main/java/yi/master/business/message/dao/SceneValidateRuleDao.java index 21f9ef7..f6b2ff9 100644 --- a/src/main/java/yi/master/business/message/dao/SceneValidateRuleDao.java +++ b/src/main/java/yi/master/business/message/dao/SceneValidateRuleDao.java @@ -1,10 +1,10 @@ package yi.master.business.message.dao; -import java.util.List; - import yi.master.business.base.dao.BaseDao; import yi.master.business.message.bean.SceneValidateRule; +import java.util.List; + public interface SceneValidateRuleDao extends BaseDao{ /** * 获取指定messageScene的全文验证规则或者关键字验证 @@ -35,4 +35,13 @@ public interface SceneValidateRuleDao extends BaseDao{ * @param status */ void updateStatus(Integer validateId, String status); + + /** + * 获取配置下的公共验证规则 + * @author xuwangcheng + * @date 2019/11/28 21:46 + * @param configId configId + * @return {@link List} + */ + List getConfigRules (Integer configId); } diff --git a/src/main/java/yi/master/business/message/dao/impl/SceneValidateRuleDaoImpl.java b/src/main/java/yi/master/business/message/dao/impl/SceneValidateRuleDaoImpl.java index 4f247c8..6938b4c 100644 --- a/src/main/java/yi/master/business/message/dao/impl/SceneValidateRuleDaoImpl.java +++ b/src/main/java/yi/master/business/message/dao/impl/SceneValidateRuleDaoImpl.java @@ -13,14 +13,12 @@ public class SceneValidateRuleDaoImpl extends BaseDaoImpl imp @Override public SceneValidateRule getValidate(Integer messageSceneId, String type) { - String hql = "From SceneValidateRule s where s.messageScene.messageSceneId=:messageSceneId and s.validateMethodFlag=:type"; return (SceneValidateRule) getSession().createQuery(hql).setInteger("messageSceneId", messageSceneId).setString("type", type).uniqueResult(); } @Override public void updateValidate(Integer validateId, String validateValue, String parameterName) { - String hql = "update SceneValidateRule s set s.validateValue=:validateValue,s.parameterName=:parameterName where s.validateId=:validateId"; getSession().createQuery(hql).setString("validateValue", validateValue).setInteger("validateId", validateId).setString("parameterName", parameterName).executeUpdate(); } @@ -28,16 +26,20 @@ public class SceneValidateRuleDaoImpl extends BaseDaoImpl imp @SuppressWarnings("unchecked") @Override public List getParameterValidate(Integer messageSceneId) { - String hql = "From SceneValidateRule s where s.messageScene.messageSceneId=:messageSceneId"; return getSession().createQuery(hql).setInteger("messageSceneId", messageSceneId).setCacheable(true).list(); } @Override public void updateStatus(Integer validateId, String status) { - String hql = "update SceneValidateRule s set s.status=:status where s.validateId=:validateId"; getSession().createQuery(hql).setString("status", status).setInteger("validateId", validateId).executeUpdate(); } + @Override + public List getConfigRules(Integer configId) { + String hql = "From SceneValidateRule s where s.testConfig.configId=:configId"; + return getSession().createQuery(hql).setInteger("configId", configId).setCacheable(true).list(); + } + } diff --git a/src/main/java/yi/master/business/message/service/SceneValidateRuleService.java b/src/main/java/yi/master/business/message/service/SceneValidateRuleService.java index be029f5..f708c8e 100644 --- a/src/main/java/yi/master/business/message/service/SceneValidateRuleService.java +++ b/src/main/java/yi/master/business/message/service/SceneValidateRuleService.java @@ -1,10 +1,10 @@ package yi.master.business.message.service; -import java.util.List; - import yi.master.business.base.service.BaseService; import yi.master.business.message.bean.SceneValidateRule; +import java.util.List; + public interface SceneValidateRuleService extends BaseService{ /** @@ -36,4 +36,13 @@ public interface SceneValidateRuleService extends BaseService * @param status */ void updateStatus(Integer validateId, String status); + + /** + * 获取配置下的公共验证规则 + * @author xuwangcheng + * @date 2019/11/28 21:46 + * @param configId configId + * @return {@link List} + */ + List getConfigRules (Integer configId); } diff --git a/src/main/java/yi/master/business/message/service/impl/SceneValidateRuleServiceImpl.java b/src/main/java/yi/master/business/message/service/impl/SceneValidateRuleServiceImpl.java index 0d256f0..34af735 100644 --- a/src/main/java/yi/master/business/message/service/impl/SceneValidateRuleServiceImpl.java +++ b/src/main/java/yi/master/business/message/service/impl/SceneValidateRuleServiceImpl.java @@ -1,15 +1,14 @@ package yi.master.business.message.service.impl; -import java.util.List; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import yi.master.business.base.service.impl.BaseServiceImpl; import yi.master.business.message.bean.SceneValidateRule; import yi.master.business.message.dao.SceneValidateRuleDao; import yi.master.business.message.service.SceneValidateRuleService; +import java.util.List; + @Service("sceneValidateRuleService") public class SceneValidateRuleServiceImpl extends BaseServiceImpl implements SceneValidateRuleService { @@ -46,4 +45,9 @@ public class SceneValidateRuleServiceImpl extends BaseServiceImpl getConfigRules(Integer configId) { + return sceneValidateRuleDao.getConfigRules(configId); + } + } diff --git a/src/main/java/yi/master/business/testconfig/bean/TestConfig.hbm.xml b/src/main/java/yi/master/business/testconfig/bean/TestConfig.hbm.xml index a143d17..3231f09 100644 --- a/src/main/java/yi/master/business/testconfig/bean/TestConfig.hbm.xml +++ b/src/main/java/yi/master/business/testconfig/bean/TestConfig.hbm.xml @@ -59,5 +59,12 @@ + + + + + + + diff --git a/src/main/java/yi/master/business/testconfig/bean/TestConfig.java b/src/main/java/yi/master/business/testconfig/bean/TestConfig.java index 75fecff..02d91ea 100644 --- a/src/main/java/yi/master/business/testconfig/bean/TestConfig.java +++ b/src/main/java/yi/master/business/testconfig/bean/TestConfig.java @@ -2,10 +2,12 @@ package yi.master.business.testconfig.bean; import org.apache.log4j.Logger; import org.apache.struts2.json.annotations.JSON; +import yi.master.business.message.bean.SceneValidateRule; import yi.master.util.PracticalUtils; import java.io.Serializable; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -119,6 +121,11 @@ public class TestConfig implements Serializable, Cloneable { * 所属测试环境 */ private Set businessSystems; + + /** + * 关联的测试配置 + */ + private Set rules = new HashSet<>(); public TestConfig(Integer userId, String requestUrlFlag, Integer connectTimeOut, Integer readTimeOut, String httpMethodFlag, @@ -237,8 +244,6 @@ public class TestConfig implements Serializable, Cloneable { this.httpMethodFlag = httpMethodFlag; } - - public String getCustomRequestUrl() { return customRequestUrl; } @@ -287,7 +292,6 @@ public class TestConfig implements Serializable, Cloneable { this.publicData = publicData; } - public String getPublicHeader() { return publicHeader; } @@ -296,8 +300,16 @@ public class TestConfig implements Serializable, Cloneable { this.publicHeader = publicHeader; } + public void setRules(Set rules) { + this.rules = rules; + } - @Override + @JSON(serialize=false) + public Set getRules() { + return rules; + } + + @Override public Object clone() { TestConfig config = null; try { diff --git a/src/main/java/yi/master/business/testconfig/dao/TestConfigDao.java b/src/main/java/yi/master/business/testconfig/dao/TestConfigDao.java index 4d4cdad..76b25e8 100644 --- a/src/main/java/yi/master/business/testconfig/dao/TestConfigDao.java +++ b/src/main/java/yi/master/business/testconfig/dao/TestConfigDao.java @@ -18,6 +18,6 @@ public interface TestConfigDao extends BaseDao { * @return */ TestConfig getConfigByUserId(Integer userId); - + } diff --git a/src/main/java/yi/master/constant/SystemConsts.java b/src/main/java/yi/master/constant/SystemConsts.java index faa1823..563e5db 100644 --- a/src/main/java/yi/master/constant/SystemConsts.java +++ b/src/main/java/yi/master/constant/SystemConsts.java @@ -12,7 +12,7 @@ public interface SystemConsts { /** * 当前版本号 */ - String VERSION = "0.2.1beta"; + String VERSION = "0.2.2beta"; /** * 完成标志 */ diff --git a/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java b/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java index f6ae47a..c0d0255 100644 --- a/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java +++ b/src/main/java/yi/master/coretest/message/test/MessageAutoTest.java @@ -187,7 +187,7 @@ public class MessageAutoTest { } - Map map = validateUtil.validate(result.getResponseMessage(), testScene.getRequestMessage(), scene, msg.getMessageType()); + Map map = validateUtil.validate(result.getResponseMessage(), testScene.getRequestMessage(), scene, msg.getMessageType(), testScene.getConfig().getConfigId()); //变更数据状态 if (MessageValidateResponse.VALIDATE_SUCCESS_FLAG.equals(map.get(MessageValidateResponse.VALIDATE_MAP_STATUS_KEY))) { diff --git a/src/main/java/yi/master/coretest/message/test/MessageValidateResponse.java b/src/main/java/yi/master/coretest/message/test/MessageValidateResponse.java index ba0f7e2..1ecdfba 100644 --- a/src/main/java/yi/master/coretest/message/test/MessageValidateResponse.java +++ b/src/main/java/yi/master/coretest/message/test/MessageValidateResponse.java @@ -1,16 +1,11 @@ package yi.master.coretest.message.test; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - +import cn.hutool.core.collection.CollUtil; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.codehaus.jackson.map.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; - import yi.master.business.message.bean.MessageScene; import yi.master.business.message.bean.SceneValidateRule; import yi.master.business.message.enums.CommonStatus; @@ -24,6 +19,11 @@ import yi.master.util.DBUtil; import yi.master.util.PracticalUtils; import yi.master.util.cache.CacheUtil; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + /** * 接口自动化
    * 返回验证 @@ -61,9 +61,12 @@ public class MessageValidateResponse { * status 验证结果 0-成功 1-不成功
    * msg 备注信息 */ - public Map validate(String responseMessage, String requestMessage, MessageScene scene, String messageType) { + public Map validate(String responseMessage, String requestMessage, MessageScene scene, String messageType, Integer configId) { List rules = validateRuleService.getParameterValidate(scene.getMessageSceneId()); - + List configRules = validateRuleService.getConfigRules(configId); + + CollUtil.addAll(rules, configRules); + if (rules.size() < 1) { Map map = new HashMap(); map.put(VALIDATE_MAP_STATUS_KEY, VALIDATE_SUCCESS_FLAG); diff --git a/src/main/resources/update/0.2.2beta b/src/main/resources/update/0.2.2beta index d617540..6099797 100644 --- a/src/main/resources/update/0.2.2beta +++ b/src/main/resources/update/0.2.2beta @@ -80,4 +80,6 @@ DELETE FROM `at_operation_interface` WHERE `op_id` = 82; UPDATE at_busi_menu_info SET status='0' WHERE menu_id=27; ALTER TABLE `at_test_config` ADD COLUMN `public_data` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共测试数据,json串存储' AFTER `mail_copy_address`; ALTER TABLE `at_test_config` ADD COLUMN `public_header` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '属于该测试集的公共请求头,只对HTTP/HTTPS有效,json串存储' AFTER `public_data`; -CREATE TABLE `yi`.`at_config_validate_rule` (`config_id` int(11) NOT NULL,`validate_id` int(11) NOT NULL,PRIMARY KEY (`config_id`, `validate_id`) USING BTREE) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '测试集配置与验证规则关联表' ROW_FORMAT = Dynamic; \ No newline at end of file +ALTER TABLE `at_scene_validate_rule` ADD COLUMN `config_id` int(11) NULL DEFAULT NULL COMMENT '所属测试配置' AFTER `validate_id`; +ALTER TABLE `at_scene_validate_rule` ADD INDEX `at_scene_validate_rule_fk_config_id`(`config_id`) USING BTREE; +ALTER TABLE `at_scene_validate_rule` ADD CONSTRAINT `at_scene_validate_rule_fk_config_id` FOREIGN KEY (`config_id`) REFERENCES `at_test_config` (`config_id`) ON DELETE RESTRICT ON UPDATE RESTRICT; \ No newline at end of file diff --git a/src/main/webapp/js/globalConstant.js b/src/main/webapp/js/globalConstant.js index a973d26..c173139 100644 --- a/src/main/webapp/js/globalConstant.js +++ b/src/main/webapp/js/globalConstant.js @@ -141,7 +141,8 @@ var REQUEST_URL = { EDIT:"validate-edit", LIST: "validate-getValidates", FULL_RULE_GET: "validate-getValidate", - RULE_UPDATE_STATUS: "validate-updateValidateStatus" + RULE_UPDATE_STATUS: "validate-updateValidateStatus", + GET_CONFIG_VALIDATE_RULES: "validate-getConfigValidates", }, //定时任务 TASK: { diff --git a/src/main/webapp/js/json/HttpRequestHeader.json b/src/main/webapp/js/json/HttpRequestHeader.json index 90e8703..377e27f 100644 --- a/src/main/webapp/js/json/HttpRequestHeader.json +++ b/src/main/webapp/js/json/HttpRequestHeader.json @@ -1,96 +1,98 @@ { "returnCode": 0, - "error": "", - "rootPid": 1, - "data": [{ - "attributes": null, - "defaultValue": "", - "mark": "请求头", - "parameterId": 1, - "parameterIdentify": "RequestHeader", - "parameterName": "", - "parentId": 0, - "path": "TopRoot", - "type": "Map" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求头,标名请求主机器名,可为IP也可为域名,http1.1后强制使用,用此请求信息,可在服务端做WEB虚拟机,实现一机多WEB服务", - "parameterId": 2, - "parameterIdentify": "Host", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求、响应体的数据字节大小", - "parameterId": 3, - "parameterIdentify": "Content-Length", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求头,可接受的文本压缩算法,如: gzip, deflate", - "parameterId": 4, - "parameterIdentify": "Accept-Encoding", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求头,支持语言,客户端浏览器的设置,如:zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3", - "parameterId": 5, - "parameterIdentify": "Accept-Language", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求头,浏览器信息,如:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0,细心会注册到IE也会用Mozilla,这是一个历史问题,早期WEB服务器貌似有问题,只支持Mozilla,微软IE做为 后起之秀只能伪装成Mozilla", - "parameterId": 6, - "parameterIdentify": "User-Agent", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求头,服务器或客户端在上次设置的COOKIE,包括作用域名(.360buy.com),过 期时间,键与值。大部分WEB服务器都会在第一次访问时在响应头上加Set-Cookie, (指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密))如:BAIDUID=49415814CDBBB4CE65EC50EE4BB65E9A:FG=1; expires=Wed, 07-Nov-42 07:03:34 GMT; path=/; domain=.baidu.com", - "parameterId": 7, - "parameterIdentify": "Cookie", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "从一个连接打开一个新页面,新页面的请求一般会加此信息,标名是从哪里跳过来的,所有的页面的打开历史链就可被挖掘出来,有利于分析用户行为与CPS分成", - "parameterId": 8, - "parameterIdentify": "Referer", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "请求的数据类型:text/html;charset=gbk", - "parameterId": 9, - "parameterIdentify": "Content-Type", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.RequestHeader", - "type": "String" - }] + "data":{ + "error": "", + "rootPid": 1, + "data": [{ + "attributes": null, + "defaultValue": "", + "mark": "请求头", + "parameterId": 1, + "parameterIdentify": "RequestHeader", + "parameterName": "", + "parentId": 0, + "path": "TopRoot", + "type": "Map" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求头,标名请求主机器名,可为IP也可为域名,http1.1后强制使用,用此请求信息,可在服务端做WEB虚拟机,实现一机多WEB服务", + "parameterId": 2, + "parameterIdentify": "Host", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求、响应体的数据字节大小", + "parameterId": 3, + "parameterIdentify": "Content-Length", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求头,可接受的文本压缩算法,如: gzip, deflate", + "parameterId": 4, + "parameterIdentify": "Accept-Encoding", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求头,支持语言,客户端浏览器的设置,如:zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3", + "parameterId": 5, + "parameterIdentify": "Accept-Language", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求头,浏览器信息,如:Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20100101 Firefox/12.0,细心会注册到IE也会用Mozilla,这是一个历史问题,早期WEB服务器貌似有问题,只支持Mozilla,微软IE做为 后起之秀只能伪装成Mozilla", + "parameterId": 6, + "parameterIdentify": "User-Agent", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求头,服务器或客户端在上次设置的COOKIE,包括作用域名(.360buy.com),过 期时间,键与值。大部分WEB服务器都会在第一次访问时在响应头上加Set-Cookie, (指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密))如:BAIDUID=49415814CDBBB4CE65EC50EE4BB65E9A:FG=1; expires=Wed, 07-Nov-42 07:03:34 GMT; path=/; domain=.baidu.com", + "parameterId": 7, + "parameterIdentify": "Cookie", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "从一个连接打开一个新页面,新页面的请求一般会加此信息,标名是从哪里跳过来的,所有的页面的打开历史链就可被挖掘出来,有利于分析用户行为与CPS分成", + "parameterId": 8, + "parameterIdentify": "Referer", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "请求的数据类型:text/html;charset=gbk", + "parameterId": 9, + "parameterIdentify": "Content-Type", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.RequestHeader", + "type": "String" + }] + } } \ No newline at end of file diff --git a/src/main/webapp/js/json/HttpResponseHeader.json b/src/main/webapp/js/json/HttpResponseHeader.json index 278312f..ba5c271 100644 --- a/src/main/webapp/js/json/HttpResponseHeader.json +++ b/src/main/webapp/js/json/HttpResponseHeader.json @@ -1,76 +1,78 @@ { "returnCode": 0, - "error": "", - "rootPid": 1, - "data": [{ - "attributes": null, - "defaultValue": "", - "mark": "响应头", - "parameterId": 1, - "parameterIdentify": "ResponseHeader", - "parameterName": "", - "parentId": 0, - "path": "TopRoot", - "type": "Map" - },{ - "attributes": null, - "defaultValue": "", - "mark": "响应的数据类型:text/html;charset=gbk", - "parameterId": 2, - "parameterIdentify": "Content-Type", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "响应的数据体大小", - "parameterId": 3, - "parameterIdentify": "Content-Length", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "如果为文本、HTML信息,则使用的编码方式", - "parameterId": 4, - "parameterIdentify": "Content-Encoding", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "当前服务器日期", - "parameterId": 5, - "parameterIdentify": "Date", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "服务器名", - "parameterId": 6, - "parameterIdentify": "Server", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - },{ - "attributes": null, - "defaultValue": "", - "mark": "第一次访问或服务设置COOKIE时,响应头里会有此信息, 如,BAIDUID=49415814CDBBB4CE65EC50EE4BB65E9A:FG=1; expires=Wed, 07-Nov-42 07:03:34 GMT; path=/; domain=.baidu.com", - "parameterId": 7, - "parameterIdentify": "Set-Cookie", - "parameterName": "", - "parentId": 1, - "path": "TopRoot.ResponseHeader", - "type": "String" - }] + "data": { + "error": "", + "rootPid": 1, + "data": [{ + "attributes": null, + "defaultValue": "", + "mark": "响应头", + "parameterId": 1, + "parameterIdentify": "ResponseHeader", + "parameterName": "", + "parentId": 0, + "path": "TopRoot", + "type": "Map" + },{ + "attributes": null, + "defaultValue": "", + "mark": "响应的数据类型:text/html;charset=gbk", + "parameterId": 2, + "parameterIdentify": "Content-Type", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "响应的数据体大小", + "parameterId": 3, + "parameterIdentify": "Content-Length", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "如果为文本、HTML信息,则使用的编码方式", + "parameterId": 4, + "parameterIdentify": "Content-Encoding", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "当前服务器日期", + "parameterId": 5, + "parameterIdentify": "Date", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "服务器名", + "parameterId": 6, + "parameterIdentify": "Server", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + },{ + "attributes": null, + "defaultValue": "", + "mark": "第一次访问或服务设置COOKIE时,响应头里会有此信息, 如,BAIDUID=49415814CDBBB4CE65EC50EE4BB65E9A:FG=1; expires=Wed, 07-Nov-42 07:03:34 GMT; path=/; domain=.baidu.com", + "parameterId": 7, + "parameterIdentify": "Set-Cookie", + "parameterName": "", + "parentId": 1, + "path": "TopRoot.ResponseHeader", + "type": "String" + }] + } } \ No newline at end of file diff --git a/src/main/webapp/resource/message/message.js b/src/main/webapp/resource/message/message.js index 9b0b6d1..1a31853 100644 --- a/src/main/webapp/resource/message/message.js +++ b/src/main/webapp/resource/message/message.js @@ -406,11 +406,11 @@ var eventList = { callParameterViewHtml += '
    ' + '