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());
}
}
}
}
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);
}
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());
}
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());
}
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);
}
Aggregations