Search in sources :

Example 11 with Operation

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

the class AsyncMockDefinitionUpdater method onServiceUpdate.

@Incoming("microcks-services-updates")
public void onServiceUpdate(ServiceViewChangeEvent serviceViewChangeEvent) {
    logger.info("Received a new change event [" + serviceViewChangeEvent.getChangeType() + "] for '" + serviceViewChangeEvent.getServiceId() + "', at " + serviceViewChangeEvent.getTimestamp());
    // Remove existing definitions or add/update existing for EVENT services.
    if (serviceViewChangeEvent.getChangeType().equals(ChangeType.DELETED)) {
        logger.info("Removing mock definitions for " + serviceViewChangeEvent.getServiceId());
        mockRepository.removeMockDefinitions(serviceViewChangeEvent.getServiceId());
        schemaRegistry.clearRegistryForService(serviceViewChangeEvent.getServiceId());
    } else {
        // Only deal with service of type EVENT...
        if (serviceViewChangeEvent.getServiceView() != null && serviceViewChangeEvent.getServiceView().getService().getType().equals(ServiceType.EVENT)) {
            // Browse and check operation regarding restricted frequencies and supported bindings.
            boolean scheduled = false;
            for (Operation operation : serviceViewChangeEvent.getServiceView().getService().getOperations()) {
                if (Arrays.asList(restrictedFrequencies).contains(operation.getDefaultDelay()) && operation.getBindings().keySet().stream().anyMatch(Arrays.asList(supportedBindings)::contains)) {
                    logger.info("Found '" + operation.getName() + "' as a candidate for async message mocking");
                    // Build an Async mock definition and store it into repository.
                    AsyncMockDefinition mockDefinition = new AsyncMockDefinition(serviceViewChangeEvent.getServiceView().getService(), operation, serviceViewChangeEvent.getServiceView().getMessagesMap().get(operation.getName()).stream().filter(e -> e instanceof UnidirectionalEvent).map(e -> ((UnidirectionalEvent) e).getEventMessage()).collect(Collectors.toList()));
                    mockRepository.storeMockDefinition(mockDefinition);
                    schemaRegistry.updateRegistryForService(mockDefinition.getOwnerService());
                    scheduled = true;
                }
            }
            if (!scheduled) {
                logger.info("Ensure to un-schedule " + serviceViewChangeEvent.getServiceId() + " on this minion. Removing definitions.");
                mockRepository.removeMockDefinitions(serviceViewChangeEvent.getServiceId());
                schemaRegistry.clearRegistryForService(serviceViewChangeEvent.getServiceId());
            }
        }
    }
}
Also used : Inject(javax.inject.Inject) Arrays(java.util.Arrays) Operation(io.github.microcks.domain.Operation) ServiceType(io.github.microcks.domain.ServiceType) ChangeType(io.github.microcks.event.ChangeType) Logger(org.jboss.logging.Logger) ApplicationScoped(javax.enterprise.context.ApplicationScoped) ConfigProperty(org.eclipse.microprofile.config.inject.ConfigProperty) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) Collectors(java.util.stream.Collectors) ServiceViewChangeEvent(io.github.microcks.event.ServiceViewChangeEvent) Incoming(org.eclipse.microprofile.reactive.messaging.Incoming) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) Operation(io.github.microcks.domain.Operation) Incoming(org.eclipse.microprofile.reactive.messaging.Incoming)

Example 12 with Operation

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

the class GraphQLController method processGraphQLQuery.

/**
 * Process a GraphQL field selection query (an Http query may contain many field selection queries).
 * @param service The Service this query is targeting
 * @param operationType The type of GraphQL operation (QUERY or MUTATION)
 * @param graphqlField The Field selection we should apply
 * @param fragmentDefinitions A list of fragment field selection
 * @param body The Http request body
 * @param graphqlHttpReq The Http GraphQL request wrapper
 * @param request The bare Http Servlet request
 * @return A GraphQL query response wrapper with some elements from the Microcks domain matching Response
 * @throws GraphQLQueryProcessingException if incoming field selection query cannot be processed
 */
protected GraphQLQueryResponse processGraphQLQuery(Service service, String operationType, Field graphqlField, List<FragmentDefinition> fragmentDefinitions, String body, GraphQLHttpRequest graphqlHttpReq, HttpServletRequest request) throws GraphQLQueryProcessingException {
    GraphQLQueryResponse result = new GraphQLQueryResponse();
    String operationName = graphqlField.getName();
    result.setAlias(graphqlField.getAlias());
    result.setOperationName(operationName);
    log.debug("Processing a '{}' operation with name '{}'", operationType, operationName);
    Operation rOperation = null;
    for (Operation operation : service.getOperations()) {
        // Select operation based on type (QUERY or MUTATION)...
        if (operation.getMethod().equals(operationType)) {
            // ... then chek the operation name itself.
            if (operation.getName().startsWith(operationName)) {
                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) {
            throw new GraphQLQueryProcessingException(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, graphqlField, graphqlHttpReq.getVariables(), request, body);
        log.debug("Dispatch criteria for finding response is {}", dispatchCriteria);
        // First try: using computed dispatchCriteria on main dispatcher.
        Response response = null;
        List<Response> responses = responseRepository.findByOperationIdAndDispatchCriteria(IdBuilder.buildOperationId(service, rOperation), dispatchCriteria);
        if (!responses.isEmpty()) {
            response = responses.get(0);
        }
        if (response == null) {
            // When using the SCRIPT dispatcher, return of evaluation may be the name of response.
            log.debug("No responses with dispatch criteria, trying the name...");
            responses = responseRepository.findByOperationIdAndName(IdBuilder.buildOperationId(service, rOperation), dispatchCriteria);
            if (!responses.isEmpty()) {
                response = responses.get(0);
            }
        }
        if (response == null && fallback != null) {
            // If we've found nothing and got a fallback, that's the moment!
            log.debug("No responses till now so far, applying the fallback...");
            responses = responseRepository.findByOperationIdAndName(IdBuilder.buildOperationId(service, rOperation), fallback.getFallback());
            if (!responses.isEmpty()) {
                response = responses.get(0);
            }
        }
        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 = responses.get(0);
            }
        }
        if (response != null) {
            result.setResponse(response);
            result.setOperationDelay(rOperation.getDefaultDelay());
            // Prepare headers for evaluation.
            Map<String, String> evaluableHeaders = new HashMap<>();
            if (response.getHeaders() != null) {
                for (Header header : response.getHeaders()) {
                    evaluableHeaders.put(header.getName(), request.getHeader(header.getName()));
                }
            }
            // Render response content before waiting and returning.
            String responseContent = MockControllerCommons.renderResponseContent(body, null, evaluableHeaders, response);
            try {
                JsonNode responseJson = mapper.readTree(responseContent);
                filterFieldSelection(graphqlField.getSelectionSet(), fragmentDefinitions, responseJson.get("data").get(operationName));
                result.setJsonResponse(responseJson);
            } catch (JsonProcessingException pe) {
                log.error("JsonProcessingException while filtering response according GraphQL field selection", pe);
                throw new GraphQLQueryProcessingException("Exception while filtering response JSON", HttpStatus.INTERNAL_SERVER_ERROR);
            }
            return result;
        }
        log.debug("No response found. Throwing a BAD_REQUEST exception...");
        throw new GraphQLQueryProcessingException("No matching response found", HttpStatus.BAD_REQUEST);
    }
    log.debug("No valid operation found. Throwing a NOT_FOUND exception...");
    throw new GraphQLQueryProcessingException("No '" + operationName + "' operation found", HttpStatus.NOT_FOUND);
}
Also used : Response(io.github.microcks.domain.Response) Header(io.github.microcks.domain.Header) FallbackSpecification(io.github.microcks.util.dispatcher.FallbackSpecification) HashMap(java.util.HashMap) JsonNode(com.fasterxml.jackson.databind.JsonNode) Operation(io.github.microcks.domain.Operation) JsonProcessingException(com.fasterxml.jackson.core.JsonProcessingException)

Example 13 with Operation

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

the class ProtobufImporterTest method testSimpleProtobufImport.

@Test
public void testSimpleProtobufImport() {
    ProtobufImporter importer = null;
    try {
        importer = new ProtobufImporter("target/test-classes/io/github/microcks/util/grpc/hello-v1.proto", null);
    } catch (IOException ioe) {
        fail("Exception should not be thrown");
    }
    // Check that basic service properties are there.
    List<Service> services = null;
    try {
        services = importer.getServiceDefinitions();
    } catch (MockRepositoryImportException e) {
        fail("Service definition import should not fail");
    }
    assertEquals(1, services.size());
    Service service = services.get(0);
    assertEquals("HelloService", service.getName());
    assertEquals(ServiceType.GRPC, service.getType());
    assertEquals("v1", service.getVersion());
    assertEquals("io.github.microcks.grpc.hello.v1", service.getXmlNS());
    // Check that resources have been parsed, correctly renamed, etc...
    List<Resource> resources = null;
    try {
        resources = importer.getResourceDefinitions(service);
    } catch (MockRepositoryImportException mrie) {
        fail("Resource definition import should not fail");
    }
    assertEquals(2, resources.size());
    for (Resource resource : resources) {
        assertNotNull(resource.getContent());
        if (ResourceType.PROTOBUF_SCHEMA.equals(resource.getType())) {
            assertEquals("HelloService-v1.proto", resource.getName());
        } else if (ResourceType.PROTOBUF_DESCRIPTOR.equals(resource.getType())) {
            assertEquals("HelloService-v1.pbb", resource.getName());
        } else {
            fail("Resource has not the expected type");
        }
    }
    // Check that operations and input/output have been found.
    assertEquals(1, service.getOperations().size());
    Operation operation = service.getOperations().get(0);
    assertEquals("greeting", operation.getName());
    assertEquals(".io.github.microcks.grpc.hello.v1.HelloRequest", operation.getInputName());
    assertEquals(".io.github.microcks.grpc.hello.v1.HelloResponse", operation.getOutputName());
}
Also used : Resource(io.github.microcks.domain.Resource) Service(io.github.microcks.domain.Service) IOException(java.io.IOException) Operation(io.github.microcks.domain.Operation) MockRepositoryImportException(io.github.microcks.util.MockRepositoryImportException) Test(org.junit.Test)

Example 14 with Operation

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

the class MetadataImporterTest method testAPIMetadataImport.

@Test
public void testAPIMetadataImport() {
    MetadataImporter importer = null;
    try {
        importer = new MetadataImporter("target/test-classes/io/github/microcks/util/metadata/hello-grpc-v1-metadata.yml");
    } catch (IOException ioe) {
        ioe.printStackTrace();
        fail("Exception should not be thrown");
    }
    // Check that basic service properties are there.
    List<Service> services = null;
    try {
        services = importer.getServiceDefinitions();
    } catch (MockRepositoryImportException e) {
        fail("Exception should not be thrown");
    }
    assertEquals(1, services.size());
    Service service = services.get(0);
    assertEquals("HelloService", service.getName());
    assertEquals("v1", service.getVersion());
    assertEquals(3, service.getMetadata().getLabels().size());
    assertEquals("greeting", service.getMetadata().getLabels().get("domain"));
    assertEquals("stable", service.getMetadata().getLabels().get("status"));
    assertEquals("Team A", service.getMetadata().getLabels().get("team"));
    assertEquals(1, service.getOperations().size());
    Operation operation = service.getOperations().get(0);
    assertEquals("POST /greeting", operation.getName());
    assertEquals(Long.valueOf(100), operation.getDefaultDelay());
    assertEquals(DispatchStyles.JSON_BODY, operation.getDispatcher());
    assertNotNull(operation.getDispatcherRules());
}
Also used : Service(io.github.microcks.domain.Service) IOException(java.io.IOException) Operation(io.github.microcks.domain.Operation) MockRepositoryImportException(io.github.microcks.util.MockRepositoryImportException) Test(org.junit.Test)

Example 15 with Operation

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

the class ServiceController method getService.

@RequestMapping(value = "/services/{id:.+}", method = RequestMethod.GET)
public ResponseEntity<?> getService(@PathVariable("id") String serviceId, @RequestParam(value = "messages", required = false, defaultValue = "true") boolean messages) {
    log.debug("Retrieving service with id {}", serviceId);
    Service service = null;
    // serviceId may have the form of <service_name>:<service_version>
    if (serviceId.contains(":")) {
        String name = serviceId.substring(0, serviceId.indexOf(':'));
        String version = serviceId.substring(serviceId.indexOf(':') + 1);
        // If service name was encoded with '+' instead of '%20', replace them.
        if (name.contains("+")) {
            name = name.replace('+', ' ');
        }
        service = serviceRepository.findByNameAndVersion(name, version);
    } else {
        service = serviceRepository.findById(serviceId).orElse(null);
    }
    if (messages) {
        // Put messages into a map where key is operation name.
        Map<String, List<? extends Exchange>> messagesMap = new HashMap<>();
        for (Operation operation : service.getOperations()) {
            if (service.getType() == ServiceType.EVENT) {
                // If an event, we should explicitly retrieve event messages.
                List<UnidirectionalEvent> events = messageService.getEventByOperation(IdBuilder.buildOperationId(service, operation));
                messagesMap.put(operation.getName(), events);
            } else {
                // Otherwise we have traditional request / response pairs.
                List<RequestResponsePair> pairs = messageService.getRequestResponseByOperation(IdBuilder.buildOperationId(service, operation));
                messagesMap.put(operation.getName(), pairs);
            }
        }
        return new ResponseEntity<>(new ServiceView(service, messagesMap), HttpStatus.OK);
    }
    return new ResponseEntity<>(service, HttpStatus.OK);
}
Also used : RequestResponsePair(io.github.microcks.domain.RequestResponsePair) ServiceView(io.github.microcks.domain.ServiceView) HashMap(java.util.HashMap) UnidirectionalEvent(io.github.microcks.domain.UnidirectionalEvent) MessageService(io.github.microcks.service.MessageService) ServiceService(io.github.microcks.service.ServiceService) Service(io.github.microcks.domain.Service) Operation(io.github.microcks.domain.Operation) Exchange(io.github.microcks.domain.Exchange) ResponseEntity(org.springframework.http.ResponseEntity) List(java.util.List)

Aggregations

Operation (io.github.microcks.domain.Operation)26 Service (io.github.microcks.domain.Service)14 JsonNode (com.fasterxml.jackson.databind.JsonNode)7 IOException (java.io.IOException)7 ArrayList (java.util.ArrayList)7 MockRepositoryImportException (io.github.microcks.util.MockRepositoryImportException)6 Resource (io.github.microcks.domain.Resource)5 UnidirectionalEvent (io.github.microcks.domain.UnidirectionalEvent)5 Exchange (io.github.microcks.domain.Exchange)4 RequestResponsePair (io.github.microcks.domain.RequestResponsePair)4 Response (io.github.microcks.domain.Response)4 ServiceType (io.github.microcks.domain.ServiceType)4 Test (org.junit.Test)4 Header (io.github.microcks.domain.Header)3 ServiceView (io.github.microcks.domain.ServiceView)3 List (java.util.List)3 Collectors (java.util.stream.Collectors)3 FieldDefinition (graphql.language.FieldDefinition)2 InputValueDefinition (graphql.language.InputValueDefinition)2 Metadata (io.github.microcks.domain.Metadata)2