Search in sources :

Example 1 with Header

use of io.github.microcks.domain.Header in project microcks by microcks.

the class RestController method execute.

@RequestMapping(value = "/{service}/{version}/**", method = { RequestMethod.HEAD, RequestMethod.OPTIONS, RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH, RequestMethod.DELETE })
public ResponseEntity<?> execute(@PathVariable("service") String serviceName, @PathVariable("version") String version, @RequestParam(value = "delay", required = false) Long delay, @RequestBody(required = false) String body, HttpServletRequest request) {
    log.info("Servicing mock response for service [{}, {}] on uri {} with verb {}", serviceName, version, request.getRequestURI(), request.getMethod());
    log.debug("Request body: {}", body);
    long startTime = System.currentTimeMillis();
    // Extract resourcePath for matching with correct operation.
    String requestURI = request.getRequestURI();
    String serviceAndVersion = null;
    String resourcePath = null;
    // Build the encoded URI fragment to retrieve simple resourcePath.
    serviceAndVersion = "/" + UriUtils.encodeFragment(serviceName, "UTF-8") + "/" + version;
    resourcePath = requestURI.substring(requestURI.indexOf(serviceAndVersion) + serviceAndVersion.length());
    // resourcePath = UriUtils.decode(resourcePath, "UTF-8");
    log.debug("Found resourcePath: {}", resourcePath);
    // If serviceName was encoded with '+' instead of '%20', remove them.
    if (serviceName.contains("+")) {
        serviceName = serviceName.replace('+', ' ');
    }
    // If resourcePath was encoded with '+' instead of '%20', replace them .
    if (resourcePath.contains("+")) {
        resourcePath = resourcePath.replace("+", "%20");
    }
    Service service = serviceRepository.findByNameAndVersion(serviceName, version);
    Operation rOperation = null;
    for (Operation operation : service.getOperations()) {
        // Select operation based onto Http verb (GET, POST, PUT, etc ...)
        if (operation.getMethod().equals(request.getMethod().toUpperCase())) {
            // ... then check is we have a matching resource path.
            if (operation.getResourcePaths() != null && operation.getResourcePaths().contains(resourcePath)) {
                rOperation = operation;
                break;
            }
        }
    }
    // using a Fallback dispatcher. Try again, just considering the verb and path pattern of operation.
    if (rOperation == null) {
        for (Operation operation : service.getOperations()) {
            // Select operation based onto Http verb (GET, POST, PUT, etc ...)
            if (operation.getMethod().equals(request.getMethod().toUpperCase())) {
                // ... then check is current resource path matches operation path pattern.
                if (operation.getResourcePaths() != null) {
                    // Produce a matching regexp removing {part} and :part from pattern.
                    String operationPattern = getURIPattern(operation.getName());
                    operationPattern = operationPattern.replaceAll("\\{.+\\}", "(.)+");
                    operationPattern = operationPattern.replaceAll("(/:[^:^/]+)", "\\/(.+)");
                    if (resourcePath.matches(operationPattern)) {
                        rOperation = operation;
                        break;
                    }
                }
            }
        }
    }
    if (rOperation != null) {
        log.debug("Found a valid operation {} with rules: {}", rOperation.getName(), rOperation.getDispatcherRules());
        String violationMsg = validateParameterConstraintsIfAny(rOperation, request);
        if (violationMsg != null) {
            return new ResponseEntity<Object>(violationMsg + ". Check parameter constraints.", HttpStatus.BAD_REQUEST);
        }
        // We must find dispatcher and its rules. Default to operation ones but
        // if we have a Fallback this is the one who is holding the first pass rules.
        String dispatcher = rOperation.getDispatcher();
        String dispatcherRules = rOperation.getDispatcherRules();
        FallbackSpecification fallback = MockControllerCommons.getFallbackIfAny(rOperation);
        if (fallback != null) {
            dispatcher = fallback.getDispatcher();
            dispatcherRules = fallback.getDispatcherRules();
        }
        // 
        String dispatchCriteria = computeDispatchCriteria(dispatcher, dispatcherRules, getURIPattern(rOperation.getName()), UriUtils.decode(resourcePath, "UTF-8"), request, body);
        log.debug("Dispatch criteria for finding response is {}", dispatchCriteria);
        Response response = null;
        // Filter depending on requested media type.
        List<Response> responses = responseRepository.findByOperationIdAndDispatchCriteria(IdBuilder.buildOperationId(service, rOperation), dispatchCriteria);
        response = getResponseByMediaType(responses, request);
        if (response == null) {
            // When using the SCRIPT or JSON_BODY dispatchers, return of evaluation may be the name of response.
            responses = responseRepository.findByOperationIdAndName(IdBuilder.buildOperationId(service, rOperation), dispatchCriteria);
            response = getResponseByMediaType(responses, request);
        }
        if (response == null && fallback != null) {
            // If we've found nothing and got a fallback, that's the moment!
            responses = responseRepository.findByOperationIdAndName(IdBuilder.buildOperationId(service, rOperation), fallback.getFallback());
            response = getResponseByMediaType(responses, request);
        }
        if (response == null) {
            // In case no response found (because dispatcher is null for example), just get one for the operation.
            // This will allow also OPTIONS operations (like pre-flight requests) with no dispatch criteria to work.
            log.debug("No responses found so far, tempting with just bare operationId...");
            responses = responseRepository.findByOperationId(IdBuilder.buildOperationId(service, rOperation));
            if (!responses.isEmpty()) {
                response = getResponseByMediaType(responses, request);
            }
        }
        if (response != null) {
            HttpStatus status = (response.getStatus() != null ? HttpStatus.valueOf(Integer.parseInt(response.getStatus())) : HttpStatus.OK);
            // Deal with specific headers (content-type and redirect directive).
            HttpHeaders responseHeaders = new HttpHeaders();
            if (response.getMediaType() != null) {
                responseHeaders.setContentType(MediaType.valueOf(response.getMediaType() + ";charset=UTF-8"));
            }
            // Deal with headers from parameter constraints if any?
            recopyHeadersFromParameterConstraints(rOperation, request, responseHeaders);
            // Adding other generic headers (caching directives and so on...)
            if (response.getHeaders() != null) {
                for (Header header : response.getHeaders()) {
                    if ("Location".equals(header.getName())) {
                        // We should process location in order to make relative URI specified an absolute one from
                        // the client perspective.
                        String location = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/rest" + serviceAndVersion + header.getValues().iterator().next();
                        responseHeaders.add(header.getName(), location);
                    } else {
                        if (!HttpHeaders.TRANSFER_ENCODING.equalsIgnoreCase(header.getName())) {
                            responseHeaders.put(header.getName(), new ArrayList<>(header.getValues()));
                        }
                    }
                }
            }
            // Render response content before waiting and returning.
            String responseContent = MockControllerCommons.renderResponseContent(body, resourcePath, request, response);
            // Setting delay to default one if not set.
            if (delay == null && rOperation.getDefaultDelay() != null) {
                delay = rOperation.getDefaultDelay();
            }
            MockControllerCommons.waitForDelay(startTime, delay);
            // Publish an invocation event before returning if enabled.
            if (enableInvocationStats) {
                MockControllerCommons.publishMockInvocation(applicationContext, this, service, response, startTime);
            }
            return new ResponseEntity<Object>(responseContent, responseHeaders, status);
        }
        return new ResponseEntity<Object>(HttpStatus.BAD_REQUEST);
    } else // Handle OPTIONS request if CORS policy is enabled.
    if (enableCorsPolicy && "OPTIONS".equals(request.getMethod().toUpperCase())) {
        log.debug("No valid operation found but Microcks configured to apply CORS policy");
        return handleCorsRequest(request);
    }
    log.debug("No valid operation found and Microcks configured to not apply CORS policy...");
    return new ResponseEntity<Object>(HttpStatus.NOT_FOUND);
}
Also used : Response(io.github.microcks.domain.Response) HttpHeaders(org.springframework.http.HttpHeaders) ResponseEntity(org.springframework.http.ResponseEntity) Header(io.github.microcks.domain.Header) FallbackSpecification(io.github.microcks.util.dispatcher.FallbackSpecification) HttpStatus(org.springframework.http.HttpStatus) Service(io.github.microcks.domain.Service) Operation(io.github.microcks.domain.Operation) RequestMapping(org.springframework.web.bind.annotation.RequestMapping)

Example 2 with Header

use of io.github.microcks.domain.Header in project microcks by microcks.

the class AMQPMessageConsumptionTask method buildHeaders.

/**
 * Build set of Microcks headers from RabbitMQ headers.
 */
private Set<Header> buildHeaders(Map<String, Object> headers) {
    if (headers == null || headers.isEmpty()) {
        return null;
    }
    Set<Header> results = new HashSet<>();
    for (String key : headers.keySet()) {
        Header result = new Header();
        result.setName(key);
        result.setValues(Set.of(headers.get(key).toString()));
        results.add(result);
    }
    return results;
}
Also used : Header(io.github.microcks.domain.Header) HashSet(java.util.HashSet)

Example 3 with Header

use of io.github.microcks.domain.Header in project microcks by microcks.

the class KafkaMessageConsumptionTask method buildHeaders.

/**
 * Build set of Microcks headers from Kafka headers.
 */
private Set<Header> buildHeaders(Headers headers) {
    if (headers == null || !headers.iterator().hasNext()) {
        return null;
    }
    Set<Header> results = new HashSet<>();
    Iterator<org.apache.kafka.common.header.Header> headersIterator = headers.iterator();
    while (headersIterator.hasNext()) {
        org.apache.kafka.common.header.Header header = headersIterator.next();
        Header result = new Header();
        result.setName(header.key());
        result.setValues(Set.of(new String(header.value())));
        results.add(result);
    }
    return results;
}
Also used : Header(io.github.microcks.domain.Header)

Example 4 with Header

use of io.github.microcks.domain.Header in project microcks by microcks.

the class PostmanCollectionImporter method buildResponse.

private Response buildResponse(JsonNode responseNode, String dispatchCriteria) {
    Response response = new Response();
    response.setName(responseNode.path("name").asText());
    if (isV2Collection) {
        response.setStatus(responseNode.path("code").asText("200"));
        response.setHeaders(buildHeaders(responseNode.path("header")));
        response.setContent(responseNode.path("body").asText(""));
    } else {
        response.setStatus(responseNode.path("responseCode").path("code").asText());
        response.setHeaders(buildHeaders(responseNode.path("headers")));
        response.setContent(responseNode.path("text").asText());
    }
    if (response.getHeaders() != null) {
        for (Header header : response.getHeaders()) {
            if (header.getName().equalsIgnoreCase("Content-Type")) {
                response.setMediaType(header.getValues().toArray(new String[] {})[0]);
            }
        }
    }
    // assume it is its content-type.
    if (!isV2Collection && response.getMediaType() == null) {
        if ("json".equals(responseNode.path("language").asText())) {
            response.setMediaType("application/json");
        }
    }
    // assume it is its content-type.
    if (isV2Collection && response.getMediaType() == null) {
        if ("json".equals(responseNode.path("_postman_previewlanguage").asText())) {
            response.setMediaType("application/json");
        } else if ("xml".equals(responseNode.path("_postman_previewlanguage").asText())) {
            response.setMediaType("text/xml");
        }
    }
    response.setDispatchCriteria(dispatchCriteria);
    return response;
}
Also used : Response(io.github.microcks.domain.Response) Header(io.github.microcks.domain.Header)

Example 5 with Header

use of io.github.microcks.domain.Header in project microcks by microcks.

the class PostmanTestStepsRunner method runTest.

@Override
public List<TestReturn> runTest(Service service, Operation operation, TestResult testResult, List<Request> requests, String endpointUrl, HttpMethod method) throws URISyntaxException, IOException {
    if (log.isDebugEnabled()) {
        log.debug("Launching test run on " + endpointUrl + " for " + requests.size() + " request(s)");
    }
    if (endpointUrl.endsWith("/")) {
        endpointUrl = endpointUrl.substring(0, endpointUrl.length() - 1);
    }
    // Microcks-postman-runner interface object building.
    ObjectNode jsonArg = mapper.createObjectNode();
    jsonArg.put("operation", operation.getName());
    jsonArg.put("callbackUrl", testsCallbackUrl + "/api/tests/" + testResult.getId() + "/testCaseResult");
    // First we have to retrieved and add the test script for this operation from within Postman collection.
    JsonNode testScript = extractOperationTestScript(operation);
    if (testScript != null) {
        log.debug("Found a testScript for this operation !");
        jsonArg.set("testScript", testScript);
    }
    // Then we have to add the corresponding 'requests' objects.
    ArrayNode jsonRequests = mapper.createArrayNode();
    for (Request request : requests) {
        ObjectNode jsonRequest = mapper.createObjectNode();
        String operationName = operation.getName().substring(operation.getName().indexOf(" ") + 1);
        String customizedEndpointUrl = endpointUrl + URIBuilder.buildURIFromPattern(operationName, request.getQueryParameters());
        log.debug("Using customized endpoint url: " + customizedEndpointUrl);
        jsonRequest.put("endpointUrl", customizedEndpointUrl);
        jsonRequest.put("method", operation.getMethod());
        jsonRequest.put("name", request.getName());
        if (request.getContent() != null && request.getContent().length() > 0) {
            jsonRequest.put("body", request.getContent());
        }
        if (request.getQueryParameters() != null && request.getQueryParameters().size() > 0) {
            ArrayNode jsonParams = buildQueryParams(request.getQueryParameters());
            jsonRequest.set("queryParams", jsonParams);
        }
        // Set headers to request if any. Start with those coming from request itself.
        // Add or override existing headers with test specific ones for operation and globals.
        Set<Header> headers = new HashSet<>();
        if (request.getHeaders() != null) {
            headers.addAll(request.getHeaders());
        }
        if (testResult.getOperationsHeaders() != null) {
            if (testResult.getOperationsHeaders().getGlobals() != null) {
                headers.addAll(testResult.getOperationsHeaders().getGlobals());
            }
            if (testResult.getOperationsHeaders().get(operation.getName()) != null) {
                headers.addAll(testResult.getOperationsHeaders().get(operation.getName()));
            }
        }
        if (headers != null && headers.size() > 0) {
            ArrayNode jsonHeaders = buildHeaders(headers);
            jsonRequest.set("headers", jsonHeaders);
        }
        jsonRequests.add(jsonRequest);
    }
    jsonArg.set("requests", jsonRequests);
    URI postmanRunnerURI = new URI(postmanRunnerUrl + "/tests/" + testResult.getId());
    ClientHttpRequest httpRequest = clientHttpRequestFactory.createRequest(postmanRunnerURI, HttpMethod.POST);
    httpRequest.getBody().write(mapper.writeValueAsBytes(jsonArg));
    httpRequest.getHeaders().add("Content-Type", "application/json");
    // Actually execute request.
    ClientHttpResponse httpResponse = null;
    try {
        httpResponse = httpRequest.execute();
    } catch (IOException ioe) {
        log.error("IOException while executing request ", ioe);
    } finally {
        if (httpResponse != null) {
            httpResponse.close();
        }
    }
    return new ArrayList<>();
}
Also used : ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ClientHttpRequest(org.springframework.http.client.ClientHttpRequest) Request(io.github.microcks.domain.Request) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) IOException(java.io.IOException) ClientHttpRequest(org.springframework.http.client.ClientHttpRequest) URI(java.net.URI) Header(io.github.microcks.domain.Header) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) ClientHttpResponse(org.springframework.http.client.ClientHttpResponse) HashSet(java.util.HashSet)

Aggregations

Header (io.github.microcks.domain.Header)19 JsonNode (com.fasterxml.jackson.databind.JsonNode)6 ArrayList (java.util.ArrayList)5 EventMessage (io.github.microcks.domain.EventMessage)4 Response (io.github.microcks.domain.Response)4 IOException (java.io.IOException)4 HashMap (java.util.HashMap)4 HashSet (java.util.HashSet)4 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)3 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)3 Operation (io.github.microcks.domain.Operation)3 Service (io.github.microcks.domain.Service)3 HttpHeaders (org.springframework.http.HttpHeaders)3 JsonProcessingException (com.fasterxml.jackson.core.JsonProcessingException)2 Request (io.github.microcks.domain.Request)2 Resource (io.github.microcks.domain.Resource)2 FallbackSpecification (io.github.microcks.util.dispatcher.FallbackSpecification)2 URI (java.net.URI)2 ResponseEntity (org.springframework.http.ResponseEntity)2 ClientHttpRequest (org.springframework.http.client.ClientHttpRequest)2