The road of quality system construction -- visual MockServer

Posted by kosstr12 on Sun, 27 Feb 2022 02:42:12 +0100

1, Background

As basic necessities of life and interest, the company has been covering the rights and interests of our life and clothing scenes, and has been able to provide fast interface services to Alipay, Jingdong and bank APP. This requires our electric team to do a faster test than the channel. At the same time, as a group company, the internal information system connects the relevant payment businesses of many banks, involving daily capital businesses such as balance checking, down flow, payment and reconciliation, which requires the information department to ensure that the relevant scenes of capital payment can be fully covered before going online, and the business Party's new business access or demand scenarios change frequently, In the context of rapid iteration of version, how to ensure that many scenarios can be covered quickly, through completely real business operation, the cost is huge;

2, Introducing MOCK

Based on the above business system testing pain points, the quality management team decided to introduce mock service. Our first thought is to complete it at the lowest cost. There are many open-source software of mockserver on the market, but after investigating the relevant open-source products, we find that there is no product that fits our business needs better; For example, the banks connected in our fund payment related scenarios all request and return in the format of xml message; Some scenarios have dynamic requirements for the data returned to the template. For example, the first request for a payment status is being processed, and the nth request becomes successful; Some bank communication protocols are socket s. After investigation, we decided to develop a set of mock service ourselves.

3, Frame selection

  1. Interface visualization operation In order to maintain the unity of system style, we decided to use the front-end framework of QECS platform (QECS detailed introduction moves to: https://www.cnblogs.com/fulu/p/15419208.html)
  2. High performance In order to meet the requirements of high performance, we use redis for template data storage; At first, we planned to use the back-end framework flash of QECS. After a series of performance tests, we found that it could not support our needs of 5KTPS. Later, we used springBoot, which can meet our needs after testing;

4, Concrete implementation

4.1 design scheme

The external request enters the Mock service, the listening service obtains the request, matches the rules through the existing template in Redis, and returns the corresponding template data if the matching rules are met; Not satisfied, return unmatched data prompt.

4.2 function description

data format At present, matching rules support json, form, query and xml parameter types; Return supports json, xml and text data types Status code Various http status codes such as 200, 500, 304, 502, 503 and 400 can be simulated and returned Return time You can set the return interval after requesting the mock service, which is more effective for the timeout return scenario Dynamic value The built-in function and value from matching rules are set to dynamically set the field value of the returned data Custom code For the personalized requirements that cannot be supported by the platform interface temporarily, it can be realized through code in Hermes, which is flexible and convenient High performance The template data is stored through redis. The request comes in and is matched with the simulation return through redis. It can provide high-performance return and can be used as a baffle service for performance pressure measurement

4.3 platform function introduction

4.3.1 main interface

4.3.2 create API, that is, we need to simulate the interface of the other party to be called

4.3.3 configure the template and configure the expected template of API

The template data is stored in REDIS

4.3.4 simulation request Obtain the actual request value, obtain the expected template value, compare and match the template with the request value. When the template request parameters belong to a subset of the real request parameters, the matching is successful

4.3.5 implementation of user-defined functions In order to meet personalized usage scenarios, a number of built-in functions are built into the service to meet the scenarios of dynamic values

private static String getReplaceStr(String str){
    if(str.contains("Random")){
        String[] strA = str.trim().split(",");
        int i1 = strA[0].indexOf("(");
        int i2 = strA[1].indexOf(")");
        String min = strA[0].substring(i1+1);
        String max = strA[1].substring(0,i2);
        return getRandom(Integer.valueOf(min), Integer.valueOf(max)).toString();
    }
    if(str.contains("CurrentDate")){
        return getCurrentDate();
    }
    if(str.contains("SecondTime")){
        return getSecondTime().toString();
    }
    if(str.contains("MicTime")){
        return getMicTime().toString();
    }
    if(str.contains("CardID")){
        return getCardID();
    }
    if(str.contains("Phone")){
        return getPhone();
    }
    return str;
}

4.3.6 expert mode: for the personalized needs that cannot be supported by the current interface, we adopt the way of back-end service coding

@RequestMapping(value = {"/test"})
public void loadNum(HttpServletRequest request, HttpServletResponse httpServletResponse){
    TimerTool timerTool = new TimerTool();
    RestfulRequest restfulRequest = requestService.analyseRequest(request);
    restfulRequest = filterHeader(restfulRequest);
    log.info("Analysis request cost: {}", timerTool.cut());

    List<MockInfo> mockRules = mockInfoService.getMockRules(restfulRequest.getPath());
    log.info("obtain mock Configuration record:{}, cost: {}", mockRules, timerTool.cut());

    MockInfo mockRule = mockService.matchRulesNew(restfulRequest, mockRules);
    log.info("matching tag...cost: {}", timerTool.cut());
    //Go to the platform template first. If it cannot be matched, go to the MOCK matching logic of expert mode (code implementation)
    if(mockRule != null){
        mockService.doResponseNew(mockRule, httpServletResponse);
    }else {
        mockExpertService.doResponse(restfulRequest, httpServletResponse);
    }
}

Expert mode to realize personalized mock logic

public void doResponse(RestfulRequest request, HttpServletResponse response){
    try {

        RestfulBody body = request.getBody();
        String ip = request.getIp();
        JSONObject requestParams = body.getParams();
        String funName = requestParams.getJSONObject("CMBSDKPGK").getJSONObject("INFO").getString("FUNNAM");

        Integer responseStatus = 200 ;
        Integer responseSleep = 0;
        String responseString = "mock The data went to Mars!";
        String responseInfo = mockInfoService.getMockExpert(ip,funName);
        JSONObject responseInfoJson;

        if(StringUtils.isEmpty(responseInfo)){
            responseInfoJson = new JSONObject(true);
            responseInfoJson.put("count", 0);
            responseInfoJson.put("firstTime", TimeUtils.nowTimeStamp() / 1000);
            responseInfoJson.put("response", getJsonResponse("xmlResource/resp_" + funName + ".xml"));
        }else {
            responseInfoJson = JSONObject.parseObject(responseInfo);
        }
        int count = responseInfoJson.getInteger("count");
        JSONObject responseObj = responseInfoJson.getJSONObject("response");
        // Batch query balance
        if("NTQADINF".equals(funName)){
            long time_lag = (TimeUtils.nowTimeStamp() / 1000) -  responseInfoJson.getLong("firstTime");
            Object obj = responseObj.getJSONObject("CMBSDKPGK").get("NTQADINFZ");
            // Balance + 5000 more than 60s from the first request
            if(time_lag > 60){
                if(obj instanceof JSONArray){
                    JSONArray jsonA = (JSONArray)obj;
                    for(int i=0; i<jsonA.size();i++){
                        Double avlblv_value = jsonA.getJSONObject(i).getDoubleValue("AVLBLV");
                        avlblv_value = avlblv_value + 5000;
                        jsonA.getJSONObject(i).put("AVLBLV", String.format("%.2f",avlblv_value));
                    }
                    responseObj.put("NTQADINFZ", jsonA);
                }
                if(obj instanceof JSONObject){
                    JSONObject jsono = (JSONObject)obj;
                    Double avlblv_value = jsono.getDoubleValue("AVLBLV");
                    avlblv_value = avlblv_value + 5000;
                    jsono.put("AVLBLV", String.format("%.2f",avlblv_value));
                    responseObj.put("NTQADINFZ", jsono);
                }
            }
        };

5, Future outlook

At present, this version adapts to most data formats under http protocol. As mentioned above, for some personalized requirements, we temporarily adopt the expert mode code implementation, which reflects the flexibility of our own platform on the one hand, on the other hand, we will abstract and refine them into common requirements in the process of continuous use, and continue to realize visualization. With the application scope and depth of the platform, it is believed that there will be more demand scenarios that need to be met by the implementation of relevant functions, and constantly enrich these functions, which is also a manifestation of the robustness of the platform; In addition, the supplement to other relevant agreements is also the starting point for the platform to carry out follow-up planning and improvement. What are your actual use scenarios of mock? Welcome to communicate