test master 변경

This commit is contained in:
현성필
2024-01-23 11:24:09 +09:00
parent 75a695897d
commit 91e902af25
121 changed files with 329 additions and 338 deletions
@@ -0,0 +1,14 @@
package com.eactive.testmaster.api.condition;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import java.util.Map;
public interface ConditionMatcher {
boolean matches(MockCondition condition, MockRequest request, Map<String, String> pathVariables);
String getType();
String getDisplayName();
}
@@ -0,0 +1,29 @@
package com.eactive.testmaster.api.condition;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Service(value = "ConditionMatcherService")
public class ConditionMatcherService {
private final Map<String, ConditionMatcher> matchers;
private final List<ConditionMatcher> matchersList;
public ConditionMatcherService(List<ConditionMatcher> matchersList) {
this.matchersList = matchersList;
this.matchers = this.matchersList.stream().collect(Collectors.toMap(ConditionMatcher::getType, Function.identity()));
}
public ConditionMatcher getMatcher(String key) {
return matchers.get(key);
}
public List<ConditionMatcher> getMatchersList() {
return matchersList;
}
}
@@ -0,0 +1,25 @@
package com.eactive.testmaster.api.condition;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class HeaderMatcher implements ConditionMatcher {
@Override
public boolean matches(MockCondition condition, MockRequest request, Map<String, String> pathVariables) {
return condition.getValue().equals(request.getHeader(condition.getKey()));
}
@Override
public String getType() {
return "header";
}
@Override
public String getDisplayName() {
return "Header";
}
}
@@ -0,0 +1,33 @@
package com.eactive.testmaster.api.condition;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class JsonPathMatcher implements ConditionMatcher {
@Override
public boolean matches(MockCondition condition, MockRequest request, Map<String, String> pathVariables) {
try {
Object value = JsonPath.read(request.getBody(), condition.getKey());
return value.toString().equals(condition.getValue());
} catch (PathNotFoundException e) {
return false;
}
}
@Override
public String getType() {
return "jsonpath";
}
@Override
public String getDisplayName() {
return "JSON Path";
}
}
@@ -0,0 +1,26 @@
package com.eactive.testmaster.api.condition;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class PathMatcher implements ConditionMatcher {
@Override
public boolean matches(MockCondition condition, MockRequest request, Map<String, String> pathVariables) {
return condition.getValue().equals(pathVariables.get(condition.getKey()));
}
@Override
public String getType() {
return "path";
}
@Override
public String getDisplayName() {
return "Path";
}
}
@@ -0,0 +1,26 @@
package com.eactive.testmaster.api.condition;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class QueryMatcher implements ConditionMatcher {
@Override
public boolean matches(MockCondition condition, MockRequest request, Map<String, String> pathVariables) {
return condition.getValue().equals(request.getParam(condition.getKey()));
}
@Override
public String getType() {
return "query";
}
@Override
public String getDisplayName() {
return "Query";
}
}
@@ -0,0 +1,123 @@
package com.eactive.testmaster.api.controller;
import com.eactive.testmaster.api.condition.ConditionMatcher;
import com.eactive.testmaster.api.condition.ConditionMatcherService;
import com.eactive.testmaster.api.dto.MockRequest;
import com.eactive.testmaster.api.entity.MockCondition;
import com.eactive.testmaster.api.entity.MockResponse;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.service.MockRouteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RestController
public class MockApiController {
private final MockRouteService mockRouteService;
private final ConditionMatcherService conditionMatcherService;
public MockApiController(MockRouteService mockRouteService, ConditionMatcherService conditionMatcherService) {
this.mockRouteService = mockRouteService;
this.conditionMatcherService = conditionMatcherService;
}
private static final Logger logger = LoggerFactory.getLogger(MockApiController.class);
public ResponseEntity<String> handleRequest(HttpServletRequest httpRequest) throws IOException {
MockRequest request = new MockRequest(httpRequest);
AntPathMatcher pathMatcher = new AntPathMatcher();
logger.debug("===========================");
logger.debug("Request: " + request.getMethod() + " " + request.getUri());
logger.debug("Headers:" + request.getHeaders().toString());
logger.debug("Params: " + request.getParams().toString());
logger.debug("Body: ");
logger.debug(request.getBody());
logger.debug("===========================");
for (MockRoute mockRoute : mockRouteService.getAllRoutes()) {
if (isRouteMatch(mockRoute, request)) {
Map<String, String> pathVariables = pathMatcher.extractUriTemplateVariables(mockRoute.getPathPattern(), request.getUri());
MockResponse matchingResponse = findMatchingResponse(mockRoute, request, pathVariables);
if (matchingResponse != null) {
if (matchingResponse.getDelay() > 0) {
try {
Thread.sleep(matchingResponse.getDelay());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.error("Error while delaying response", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error processing request due to interruption.");
}
}
HttpHeaders responseHeaders = new HttpHeaders();
matchingResponse.getHeaders().forEach(responseHeaders::set);
request.getParams().putAll(pathVariables);
return new ResponseEntity<>(replaceParams(matchingResponse.getBody(), request.getParams()), responseHeaders, HttpStatus.valueOf(matchingResponse.getStatusCode()));
}
}
}
// If no matching route or response is found, return a 404 Not Found
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Not Found");
}
private String replaceParams(String responseBody, Map<String, String> params) {
for (Map.Entry<String, String> entry : params.entrySet()) {
responseBody = responseBody.replace("{" + entry.getKey() + "}", entry.getValue());
}
return responseBody;
}
private boolean isRouteMatch(MockRoute mockRoute, MockRequest request) {
AntPathMatcher pathMatcher = new AntPathMatcher();
return mockRoute.getMethod().equalsIgnoreCase(request.getMethod()) && pathMatcher.match(mockRoute.getPathPattern(), request.getUri());
}
private MockResponse findMatchingResponse(MockRoute mockRoute, MockRequest mockRequest, Map<String, String> pathVariables) {
MockResponse defaultResponse = mockRoute.getResponses().stream().filter(MockResponse::isDefaultResponse).findFirst().orElse(null);
List<MockResponse> responses = mockRoute.getResponses().stream().filter(response -> !response.isDefaultResponse()).collect(Collectors.toList());
if (defaultResponse != null) {
responses.add(defaultResponse);
}
for (MockResponse response : responses) {
if (response.getConditions() == null || isRequestMatching(response.getConditions(), mockRequest, pathVariables)) {
return response;
}
}
return null;
}
private boolean isRequestMatching(List<MockCondition> conditions, MockRequest request, Map<String, String> pathVariables) {
if (conditions == null) {
return true;
}
for (MockCondition condition : conditions) {
ConditionMatcher matcher = conditionMatcherService.getMatcher(condition.getType().toLowerCase());
if (matcher != null && !matcher.matches(condition, request, pathVariables)) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,61 @@
package com.eactive.testmaster.api.controller;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.service.MockRouteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
@Component
public class MockApiHandlerMapping {
private static final Logger logger = LoggerFactory.getLogger(MockApiHandlerMapping.class);
@Autowired
private MockRouteService mockRouteService;
@Autowired
private MockApiController mockApiController;
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
@PostConstruct
public void initialize() {
mockRouteService.initAllRoutes();
for (MockRoute mockRoute : mockRouteService.getAllRoutes()) {
registerMapping(mockRoute);
}
}
public void registerMapping(MockRoute mockRoute) {
RequestMappingInfo mappingInfo = RequestMappingInfo
.paths(mockRoute.getPathPattern())
.methods(RequestMethod.valueOf(mockRoute.getMethod()))
.build();
try {
requestMappingHandlerMapping.registerMapping(mappingInfo, mockApiController, MockApiController.class.getDeclaredMethod("handleRequest", HttpServletRequest.class));
logger.info("Registered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
} catch (NoSuchMethodException e) {
logger.error("Error registering mapping", e);
}
}
public void unregisterMapping(MockRoute mockRoute) {
RequestMappingInfo mappingInfo = RequestMappingInfo
.paths(mockRoute.getPathPattern())
.methods(RequestMethod.valueOf(mockRoute.getMethod()))
.build();
requestMappingHandlerMapping.unregisterMapping(mappingInfo);
logger.info("Unregistered mapping for {} {}", mockRoute.getMethod(), mockRoute.getPathPattern());
}
}
@@ -0,0 +1,156 @@
package com.eactive.testmaster.api.controller;
import com.eactive.testmaster.api.dto.MockResponseDTO;
import com.eactive.testmaster.api.dto.MockRouteRegisterDTO;
import com.eactive.testmaster.api.dto.MockRouteSearch;
import com.eactive.testmaster.api.dto.MockRouteUpdateDTO;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.mapper.MockRouteMapper;
import com.eactive.testmaster.api.service.MockRouteService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.PostConstruct;
import java.util.List;
@Controller
@RequestMapping("/mgmt/routes")
public class MockRouteMgmtController {
private static final String MOCK_ROUTE = "mockRoute";
@PostConstruct
public void init() {
mockRouteService.initAllRoutes();
}
private final MockRouteService mockRouteService;
private final Validator validator;
private final MockRouteMapper mockRouteMapper;
private final MockApiHandlerMapping mockApiHandlerMapping;
public MockRouteMgmtController(MockRouteService mockRouteService, Validator validator, MockRouteMapper mockRouteMapper, MockApiHandlerMapping mockApiHandlerMapping) {
this.mockRouteService = mockRouteService;
this.validator = validator;
this.mockRouteMapper = mockRouteMapper;
this.mockApiHandlerMapping = mockApiHandlerMapping;
}
public static final String MOCK_ROUTE_EDIT = "page/routes/mockRouteEdit";
public static final String MOCK_ROUTE_LIST_VIEW = "redirect:/mgmt/routes/list_view.do";
@GetMapping("/list_view.do")
public ModelAndView listView(@ModelAttribute("mockRouteSearch") MockRouteSearch mockRouteSearch, Pageable pageable) {
ModelAndView mav = new ModelAndView("page/routes/mockRouteList");
Page<MockRoute> page = mockRouteService.findAll(mockRouteSearch.buildSpecification(), pageable);
mav.addObject("page", page);
mav.addObject("pageable", pageable);
mav.addObject("modelSearch", mockRouteSearch);
return mav;
}
@GetMapping("/create_view.do")
public ModelAndView createView() {
ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
MockRouteRegisterDTO defaultRoute = new MockRouteRegisterDTO();
MockResponseDTO defaultResponse = new MockResponseDTO();
defaultResponse.setDefaultResponse("true");
defaultRoute.getResponses().add(defaultResponse);
mav.addObject(MOCK_ROUTE, defaultRoute);
return mav;
}
@GetMapping("/update_view.do")
public ModelAndView updateView(@RequestParam("id") Long id) {
ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
MockRoute found = mockRouteService.findById(id);
mav.addObject(MOCK_ROUTE, mockRouteMapper.map(found));
return mav;
}
@PostMapping("/clone_view.do")
public ModelAndView cloneView(@RequestParam("id") Long id) {
ModelAndView mav = new ModelAndView(MOCK_ROUTE_EDIT);
MockRoute found = mockRouteService.findById(id);
MockRouteRegisterDTO dto = mockRouteMapper.map(found);
dto.setId(null);
mav.addObject(MOCK_ROUTE, dto);
return mav;
}
@PostMapping("/register.do")
public String register(@ModelAttribute("mockRoute") MockRouteRegisterDTO dto, BindingResult bindingResult, ModelMap model) {
if (dto == null) {
return "redirect:/mgmt/routes/create_view.do";
}
validator.validate(dto, bindingResult);
if (bindingResult.hasErrors()) {
model.addAttribute(MOCK_ROUTE, dto);
return MOCK_ROUTE_EDIT;
}
MockRoute mockRoute = mockRouteMapper.map(dto);
mockRouteService.create(mockRoute);
mockRouteService.initAllRoutes();
mockApiHandlerMapping.registerMapping(mockRoute);
return MOCK_ROUTE_LIST_VIEW;
}
@PostMapping("/update.do")
public String update(@RequestParam("id") String id,
@ModelAttribute("mockRoute") MockRouteUpdateDTO dto,
BindingResult bindingResult, ModelMap model) {
if (StringUtils.isEmpty(id)) {
return MOCK_ROUTE_LIST_VIEW;
}
validator.validate(dto, bindingResult);
if (bindingResult.hasErrors()) {
model.addAttribute(MOCK_ROUTE, dto);
return MOCK_ROUTE_EDIT;
}
MockRoute prev = mockRouteService.findById(Long.parseLong(id));
mockApiHandlerMapping.unregisterMapping(prev);
MockRoute mockRoute = mockRouteMapper.map(dto);
mockRouteService.update(Long.parseLong(id), mockRoute);
mockRouteService.initAllRoutes();
mockApiHandlerMapping.registerMapping(mockRoute);
return MOCK_ROUTE_LIST_VIEW;
}
@PostMapping("/delete.do")
public String delete(@RequestParam("checkedIdForDel") List<String> ids) {
for (String id : ids) {
MockRoute mockRoute = mockRouteService.findById(Long.parseLong(id));
mockApiHandlerMapping.unregisterMapping(mockRoute);
mockRouteService.deleteById(Long.parseLong(id));
}
mockRouteService.initAllRoutes();
return MOCK_ROUTE_LIST_VIEW;
}
}
@@ -0,0 +1,33 @@
package com.eactive.testmaster.api.dto;
public class MockConditionDTO {
private String type;
private String key;
private String value;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@@ -0,0 +1,23 @@
package com.eactive.testmaster.api.dto;
public class MockHeaderDTO {
private String key;
private String value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@@ -0,0 +1,96 @@
package com.eactive.testmaster.api.dto;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class MockRequest {
public static Map<String, String> parseQueryString(HttpServletRequest request) {
Map<String, String> queryParams = new HashMap<>();
String queryString = request.getQueryString();
if (queryString != null) {
String[] queryParamsArr = queryString.split("&");
for (String queryParam : queryParamsArr) {
String[] pair = queryParam.split("=");
String key = pair[0];
String value = "";
if (pair.length > 1) {
value = pair[1];
}
queryParams.put(key, value);
}
}
return queryParams;
}
public MockRequest(HttpServletRequest request) throws IOException {
this.method = request.getMethod();
this.uri = request.getRequestURI();
this.headers = Collections.list(request.getHeaderNames()).stream()
.collect(Collectors.toMap(name -> name, request::getHeader));
this.params = parseQueryString(request);
this.body = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
}
private String uri;
private String method;
private String body;
private Map<String, String> headers;
private Map<String, String> params;
public String getUri() {
return uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public String getHeader(String key) {
return this.headers.get(key);
}
public String getParam(String key) {
return this.params.get(key);
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
}
@@ -0,0 +1,68 @@
package com.eactive.testmaster.api.dto;
import javax.validation.constraints.Min;
import java.util.ArrayList;
import java.util.List;
public class MockResponseDTO {
@Min(100)
private int statusCode = 200;
private List<MockHeaderDTO> headers = new ArrayList<>();
private String body;
private long delay = 0; //millisecond
private String defaultResponse;
private List<MockConditionDTO> conditions;
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public List<MockHeaderDTO> getHeaders() {
return headers;
}
public void setHeaders(List<MockHeaderDTO> headers) {
this.headers = headers;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public long getDelay() {
return delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
public List<MockConditionDTO> getConditions() {
return conditions;
}
public void setConditions(List<MockConditionDTO> conditions) {
this.conditions = conditions;
}
public String getDefaultResponse() {
return defaultResponse;
}
public void setDefaultResponse(String defaultResponse) {
this.defaultResponse = defaultResponse;
}
}
@@ -0,0 +1,76 @@
package com.eactive.testmaster.api.dto;
import com.eactive.testmaster.common.validator.UniqueRoute;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
@UniqueRoute(path = "pathPattern", method = "method")
public class MockRouteRegisterDTO {
private Long id;
@NotEmpty
private String method;
@NotEmpty
private String pathPattern;
@NotEmpty
private String name;
private String description;
@Size(min = 1, message = "Response must have at least one item")
private List<MockResponseDTO> responses = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPathPattern() {
return pathPattern;
}
public void setPathPattern(String pathPattern) {
this.pathPattern = pathPattern;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<MockResponseDTO> getResponses() {
return responses;
}
public void setResponses(List<MockResponseDTO> responses) {
this.responses = responses;
}
}
@@ -0,0 +1,31 @@
package com.eactive.testmaster.api.dto;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.common.search.BaseSearch;
import com.eactive.testmaster.common.search.ColumnSearchModel;
import com.eactive.testmaster.common.search.SearchCondition;
import com.eactive.testmaster.common.search.SearchModel;
import java.util.ArrayList;
import java.util.List;
public class MockRouteSearch implements BaseSearch<MockRoute> {
private String name;
@Override
public List<SearchModel> buildSearchCondition() {
List<SearchModel> models = new ArrayList<>();
models.add(new ColumnSearchModel("name", SearchCondition.LIKE, name));
return models;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@@ -0,0 +1,73 @@
package com.eactive.testmaster.api.dto;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.List;
public class MockRouteUpdateDTO {
private Long id;
@NotEmpty
private String method;
@NotEmpty
private String pathPattern;
@NotEmpty
private String name;
private String description;
@Size(min = 1, message = "Response must have at least one item")
private List<MockResponseDTO> responses = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPathPattern() {
return pathPattern;
}
public void setPathPattern(String pathPattern) {
this.pathPattern = pathPattern;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<MockResponseDTO> getResponses() {
return responses;
}
public void setResponses(List<MockResponseDTO> responses) {
this.responses = responses;
}
}
@@ -0,0 +1,63 @@
package com.eactive.testmaster.api.entity;
import javax.persistence.*;
@Entity
@Table(name = "MOCK_RESPONSE_CONDITION")
public class MockCondition {
@ManyToOne
@JoinColumn(name = "MOCK_RESPONSE_ID", nullable = false)
private MockResponse mockResponse;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String type;
private String key;
private String value;
public MockResponse getMockResponse() {
return mockResponse;
}
public void setMockResponse(MockResponse mockResponse) {
this.mockResponse = mockResponse;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@@ -0,0 +1,103 @@
package com.eactive.testmaster.api.entity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Entity
@Table(name = "MOCK_RESPONSE")
public class MockResponse {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private int statusCode = 200;
@ElementCollection
@CollectionTable(name = "MOCK_RESPONSE_HEADERS", joinColumns = @JoinColumn(name = "RESPONSE_ID"))
@MapKeyColumn(name = "HEADER_KEY")
@Column(name = "HEADER_VALUE")
private Map<String, String> headers = new HashMap<>();
@Lob
private String body;
private long delay = 0; //millisecond
@Column(name = "DEFAULT_RESPONSE", nullable = false, columnDefinition = "boolean default false")
private boolean defaultResponse = false;
@ManyToOne
@JoinColumn(name = "ROUTE_ID", nullable = false)
private MockRoute route;
@OneToMany(mappedBy = "mockResponse", cascade = CascadeType.ALL, orphanRemoval = true)
private List<MockCondition> conditions = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public int getStatusCode() {
return statusCode;
}
public void setStatusCode(int statusCode) {
this.statusCode = statusCode;
}
public Map<String, String> getHeaders() {
return headers;
}
public void setHeaders(Map<String, String> headers) {
this.headers = headers;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public long getDelay() {
return delay;
}
public void setDelay(long delay) {
this.delay = delay;
}
public MockRoute getRoute() {
return route;
}
public void setRoute(MockRoute route) {
this.route = route;
}
public List<MockCondition> getConditions() {
return conditions;
}
public void setConditions(List<MockCondition> conditions) {
this.conditions = conditions;
}
public boolean isDefaultResponse() {
return defaultResponse;
}
public void setDefaultResponse(boolean defaultResponse) {
this.defaultResponse = defaultResponse;
}
}
@@ -0,0 +1,76 @@
package com.eactive.testmaster.api.entity;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "MOCK_ROUTE")
public class MockRoute {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String method;
private String pathPattern;
private String name;
private String description;
@OneToMany(mappedBy = "route", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private List<MockResponse> responses = new ArrayList<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPathPattern() {
return pathPattern;
}
public void setPathPattern(String pathPattern) {
this.pathPattern = pathPattern;
}
public List<MockResponse> getResponses() {
return responses;
}
public void setResponses(List<MockResponse> responses) {
this.responses = responses;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
@@ -0,0 +1,105 @@
package com.eactive.testmaster.api.mapper;
import com.eactive.testmaster.api.dto.MockHeaderDTO;
import com.eactive.testmaster.api.dto.MockResponseDTO;
import com.eactive.testmaster.api.dto.MockRouteRegisterDTO;
import com.eactive.testmaster.api.dto.MockRouteUpdateDTO;
import com.eactive.testmaster.api.entity.MockResponse;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.common.mapper.CommonMapper;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.ReportingPolicy;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Mapper(componentModel = "spring",
uses = {CommonMapper.class},
unmappedTargetPolicy = ReportingPolicy.IGNORE)
@Component
public abstract class MockRouteMapper {
private static final Map<String, String> XML_ESCAPE_MAP;
static {
XML_ESCAPE_MAP = new HashMap<>();
XML_ESCAPE_MAP.put("&lt;", "<");
XML_ESCAPE_MAP.put("&gt;", ">");
XML_ESCAPE_MAP.put("&amp;", "&");
XML_ESCAPE_MAP.put("&quot;", "\"");
XML_ESCAPE_MAP.put("&apos;", "'");
}
public abstract MockRoute map(MockRouteRegisterDTO dto);
public abstract MockRoute map(MockRouteUpdateDTO dto);
public abstract MockRouteRegisterDTO map(MockRoute entity);
@Mapping(target = "headers", source = "headers", qualifiedByName = "mapHeadersToMap")
@Mapping(target = "defaultResponse", source = "defaultResponse", qualifiedByName = "mapEntityDefaultResponse")
@Mapping(target = "body", source="body" , qualifiedByName = "unescapeBody")
public abstract MockResponse map(MockResponseDTO dto);
@Mapping(target = "headers", source = "headers", qualifiedByName = "mapHeadersToList")
@Mapping(target = "defaultResponse", source = "defaultResponse", qualifiedByName = "mapDTODefaultResponse")
@Mapping(target = "body", source="body" , qualifiedByName = "unescapeBody")
public abstract MockResponseDTO map(MockResponse entity);
@Named("unescapeBody")
public static String unescapeXml(String escapedXml) {
if (escapedXml == null || escapedXml.isEmpty()) {
return escapedXml;
}
for (Map.Entry<String, String> entry : XML_ESCAPE_MAP.entrySet()) {
escapedXml = escapedXml.replace(entry.getKey(), entry.getValue());
}
return escapedXml;
}
@Named("mapDTODefaultResponse")
public String map(boolean value) {
return value ? "true" : "false";
}
@Named("mapEntityDefaultResponse")
public boolean map(String value) {
if (value == null) return false;
return value.equals("true");
}
@Named("mapHeadersToList")
public List<MockHeaderDTO> mapHeadersToList(Map<String, String> headers) {
List<MockHeaderDTO> list = new ArrayList<>();
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
MockHeaderDTO header = new MockHeaderDTO();
header.setKey(key);
header.setValue(value);
list.add(header);
}
}
return list;
}
@Named("mapHeadersToMap")
public Map<String, String> mapHeadersToMap(List<MockHeaderDTO> headers) {
Map<String, String> map = new HashMap<>();
if (headers != null) {
for (MockHeaderDTO header : headers) {
map.put(header.getKey(), header.getValue());
}
}
return map;
}
}
@@ -0,0 +1,10 @@
package com.eactive.testmaster.api.repository;
import com.eactive.testmaster.api.entity.MockRoute;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface MockRouteRepository extends JpaRepository<MockRoute, Long>, JpaSpecificationExecutor<MockRoute> {
long countByMethodAndPathPattern(String method, String pathPattern);
}
@@ -0,0 +1,121 @@
package com.eactive.testmaster.api.service;
import com.eactive.testmaster.api.entity.MockCondition;
import com.eactive.testmaster.api.entity.MockResponse;
import com.eactive.testmaster.api.entity.MockRoute;
import com.eactive.testmaster.api.repository.MockRouteRepository;
import com.eactive.testmaster.common.exception.NotFoundException;
import org.apache.commons.beanutils.BeanUtils;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
@Service
@Transactional
public class MockRouteService {
private static final String NOT_FOUND_MESSAGE = "Route Not Found";
@Autowired
MockRouteRepository mockRouteRepository;
private List<MockRoute> allRoutes = new ArrayList<>();
public List<MockRoute> getAllRoutes() {
return allRoutes;
}
public void setAllRoutes(List<MockRoute> allRoutes) {
this.allRoutes = allRoutes;
}
public Page<MockRoute> findAll(Specification<MockRoute> mockRouteSpecification, Pageable pageable) {
return mockRouteRepository.findAll(mockRouteSpecification, pageable);
}
public MockRoute findById(Long id) {
return mockRouteRepository.findById(id).orElseThrow(() -> new NotFoundException(NOT_FOUND_MESSAGE));
}
public void create(MockRoute mockRoute) {
if (!mockRoute.getPathPattern().startsWith("/")) {
mockRoute.setPathPattern("/" + mockRoute.getPathPattern());
}
for (MockResponse response : mockRoute.getResponses()) {
response.setRoute(mockRoute);
if (response.getConditions() != null) {
for (MockCondition condition : response.getConditions()) {
condition.setMockResponse(response);
}
}
}
mockRouteRepository.save(mockRoute);
}
public void deleteById(long id) {
mockRouteRepository.deleteById(id);
}
public void update(Long id, MockRoute updated) {
MockRoute route = mockRouteRepository.findById(id).orElseThrow(() -> new NotFoundException(NOT_FOUND_MESSAGE));
route.getResponses().clear();
route.setName(updated.getName());
route.setDescription(updated.getDescription());
// route.setMethod(updated.getMethod());
// route.setPathPattern(updated.getPathPattern());
if (!route.getPathPattern().startsWith("/")) {
route.setPathPattern("/" + route.getPathPattern());
}
route.getResponses().addAll(updated.getResponses());
for (MockResponse response : route.getResponses()) {
response.setRoute(route);
if (response.getConditions() != null) {
for (MockCondition condition : response.getConditions()) {
condition.setMockResponse(response);
}
}
}
mockRouteRepository.save(route);
}
public void initAllRoutes() {
allRoutes.clear();
List<MockRoute> routes = mockRouteRepository.findAll();
for (MockRoute route : routes) {
for (MockResponse response : route.getResponses()) {
if (response.getConditions() != null) {
for (MockCondition condition : response.getConditions()) {
Hibernate.initialize(condition.getMockResponse());
}
}
if (response.getHeaders() != null) {
Hibernate.initialize(response.getHeaders());
}
Hibernate.initialize(response);
}
try {
MockRoute cloned = (MockRoute) BeanUtils.cloneBean(route);
allRoutes.add(cloned);
} catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
}