diff --git a/pom.xml b/pom.xml index aee415d..410a1b2 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ net.coru scc-multiapi-converter - 2.6.2 + 2.7.0 SCC-MultiApi-Converter Generates Spring Cloud Contracts based on an OpenApi and AsyncApi document https://github.com/corunet/scc-multiapi-converter @@ -35,7 +35,7 @@ jegarcia Jose Enrique Garcia Maciñeiras - jegarcia@corunet.com + joseenrique.garcia@sngular.com Corunet https://corunet.github.io/ @@ -47,7 +47,7 @@ cmunozgomez Cesar Munoz Gomez - cmunoz@corunet.com + cesar.munoz@sngular.com Corunet https://corunet.github.io/ @@ -58,7 +58,7 @@ Rivarsal Pablo José López Rivadulla - plopez@corunet.com + pablo.lopezr@sngular.com Corunet https://corunet.github.io/ @@ -69,7 +69,7 @@ fcampostato Fernando Campos Tato - fcampos@corunet.com + fernando.campos@sngular.com Corunet https://corunet.github.io/ @@ -80,7 +80,7 @@ jmejutovazquez Javier Mejuto Vázquez - jmejuto@corunet.com + javier.mejuto@sngular.com Corunet https://corunet.github.io/ @@ -91,7 +91,7 @@ mcabezasp Miguel Cabezas Puerto - mcabezas@corunet.com + miguel.cabezas@sngular.com Corunet https://corunet.github.io/ @@ -192,7 +192,43 @@ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + + com.puppycrawl.tools + checkstyle + 10.2 + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + styles/checkstyle/OSS_checkstyle.xml + UTF-8 + true + true + false + + + + validate + + check + + validate + + + org.apache.maven.plugins maven-plugin-plugin @@ -287,4 +323,16 @@ + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + styles/checkstyle/OSS_checkstyle.xml + + + + diff --git a/src/main/java/net/coru/multiapi/converter/MultiApiContractConverter.java b/src/main/java/net/coru/multiapi/converter/MultiApiContractConverter.java index a15648c..3664a83 100644 --- a/src/main/java/net/coru/multiapi/converter/MultiApiContractConverter.java +++ b/src/main/java/net/coru/multiapi/converter/MultiApiContractConverter.java @@ -21,7 +21,7 @@ import org.springframework.cloud.contract.spec.ContractConverter; @Slf4j -public class MultiApiContractConverter implements ContractConverter> { +public final class MultiApiContractConverter implements ContractConverter> { private static final OpenApiContractConverter OPEN_API_CONTRACT_CONVERTER = new OpenApiContractConverter(); @@ -35,8 +35,8 @@ public boolean isAccepted(final File file) { try { final JsonNode node; node = BasicTypeConstants.OBJECT_MAPPER.readTree(file); - isAccepted = (node != null && node.size() > 0 && (Objects.nonNull(node.get(BasicTypeConstants.ASYNCAPI)) || Objects.nonNull(node.get(BasicTypeConstants.OPENAPI)))); - } catch (IOException e) { + isAccepted = node != null && node.size() > 0 && (Objects.nonNull(node.get(BasicTypeConstants.ASYNCAPI)) || Objects.nonNull(node.get(BasicTypeConstants.OPENAPI))); + } catch (final IOException e) { isAccepted = false; } } @@ -47,7 +47,7 @@ public boolean isAccepted(final File file) { public Collection convertFrom(final File file) { Collection contracts = null; - JsonNode node; + final JsonNode node; if (isAccepted(file)) { try { node = BasicTypeConstants.OBJECT_MAPPER.readTree(file); @@ -60,7 +60,7 @@ public Collection convertFrom(final File file) { } else { throw new MultiApiContractConverterException("Yaml file is not correct"); } - } catch (IOException e) { + } catch (final IOException e) { throw new MultiApiContractConverterException(e); } } @@ -68,5 +68,7 @@ public Collection convertFrom(final File file) { } @Override - public Collection convertTo(final Collection contract) {return contract;} + public Collection convertTo(final Collection contract) { + return contract; + } } diff --git a/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverter.java b/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverter.java index 0de8f89..16f7456 100644 --- a/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverter.java +++ b/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverter.java @@ -34,72 +34,76 @@ import org.springframework.cloud.contract.spec.internal.ResponseBodyMatchers; @Slf4j -public class AsyncApiContractConverter { +public final class AsyncApiContractConverter { + + private File basePath; public Collection convertFrom(final File file) { + basePath = file; final Collection sccContracts = new ArrayList<>(); try { - final var fileContent = BasicTypeConstants.OBJECT_MAPPER.readTree(file); + final var fileContent = BasicTypeConstants.OBJECT_MAPPER.readTree(basePath); final var channelsNode = fileContent.get(BasicTypeConstants.CHANNELS); - Iterator it = channelsNode.elements(); - Iterator topicIterator = channelsNode.fieldNames(); + final Iterator it = channelsNode.elements(); + final Iterator topicIterator = channelsNode.fieldNames(); while (it.hasNext()) { final Contract contract = new Contract(); - final JsonNode operationContent; - final String operationType; - final Map bodyProcessed; - - JsonNode channel = it.next(); - operationType = channel.fieldNames().next(); - operationContent = subscribeOrPublishOperation(channel); - String operationId = operationContent.get("operationId").asText(); + + final JsonNode channel = it.next(); + final String operationType = channel.fieldNames().next(); + final JsonNode operationContent = AsyncApiContractConverterUtils.subscribeOrPublishOperation(channel); + final String operationId = operationContent.get("operationId").asText(); contract.setName(operationId); - ResponseBodyMatchers responseBodyMatchers = new ResponseBodyMatchers(); - bodyProcessed = processMessage(responseBodyMatchers, operationContent, fileContent, operationType, file); + final ResponseBodyMatchers responseBodyMatchers = new ResponseBodyMatchers(); + final Map bodyProcessed = processMessage(responseBodyMatchers, operationContent, fileContent, operationType); contract.label(operationId); - String topicName = topicIterator.next(); + final String topicName = topicIterator.next(); if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - Input input = new Input(); - input.messageFrom(topicName); - input.messageBody(bodyProcessed); - input.messageHeaders(headers -> headers.accept("application/json")); - contract.setInput(input); - - OutputMessage outputMessage = new OutputMessage(); - outputMessage.headers(headers -> headers.accept("application/json")); - outputMessage.sentTo(topicName); - outputMessage.body(bodyProcessed); - contract.setOutputMessage(outputMessage); - + processSubscribeOperation(contract, bodyProcessed, topicName); } else if (operationType.equals(BasicTypeConstants.PUBLISH)) { - Input input = new Input(); - input.triggeredBy(operationId + "()"); - contract.setInput(input); - - OutputMessage outputMessage = new OutputMessage(); - outputMessage.sentTo(topicName); - - outputMessage.body(bodyProcessed); - outputMessage.setBodyMatchers(responseBodyMatchers); - contract.setOutputMessage(outputMessage); + processPublishOperation(contract, operationId, responseBodyMatchers, bodyProcessed, topicName); } - sccContracts.add(contract); } - - - } catch (Exception e) { + } catch (final IOException e) { log.error("Error", e); } return sccContracts; } + private void processPublishOperation( + final Contract contract, final String operationId, final ResponseBodyMatchers responseBodyMatchers, final Map bodyProcessed, final String topicName) { + final Input input = new Input(); + input.triggeredBy(operationId + "()"); + contract.setInput(input); + + final OutputMessage outputMessage = new OutputMessage(); + outputMessage.sentTo(topicName); + + outputMessage.body(bodyProcessed); + outputMessage.setBodyMatchers(responseBodyMatchers); + contract.setOutputMessage(outputMessage); + } + + private void processSubscribeOperation(final Contract contract, final Map bodyProcessed, final String topicName) { + final Input input = new Input(); + input.messageFrom(topicName); + input.messageBody(bodyProcessed); + input.messageHeaders(headers -> headers.accept("application/json")); + contract.setInput(input); + + final OutputMessage outputMessage = new OutputMessage(); + outputMessage.headers(headers -> headers.accept("application/json")); + outputMessage.sentTo(topicName); + outputMessage.body(bodyProcessed); + contract.setOutputMessage(outputMessage); + } + private Map processMessage( - final ResponseBodyMatchers responseBodyMatchers, final JsonNode operationContent, final JsonNode fileContent, final String operationType, - final File basePath) + final ResponseBodyMatchers responseBodyMatchers, final JsonNode operationContent, final JsonNode fileContent, final String operationType) throws IOException { final JsonNode message; JsonNode propertiesJson; @@ -107,16 +111,16 @@ private Map processMessage( final Map messageBody = new HashMap<>(); message = operationContent.get("message"); - checkIfReferenceWithProperties(message); + AsyncApiContractConverterUtils.checkIfReferenceWithProperties(message); - if (message.get(BasicTypeConstants.REF) != null && message.get(BasicTypeConstants.REF).asText().startsWith("#")) { + if (Objects.nonNull(message.get(BasicTypeConstants.REF)) && message.get(BasicTypeConstants.REF).asText().startsWith("#")) { final String[] pathToRef = message.get(BasicTypeConstants.REF).asText().split("/"); ref = pathToRef[pathToRef.length - 1]; final var payload = fileContent.findPath(ref); - messageBody.putAll(processSchemas(responseBodyMatchers, operationType, payload.fieldNames().next(), payload, basePath, fileContent, "")); + messageBody.putAll(processSchemas(responseBodyMatchers, operationType, payload.fieldNames().next(), payload, fileContent, "")); - } else if (message.get(BasicTypeConstants.REF) != null) { + } else if (Objects.nonNull(message.get(BasicTypeConstants.REF))) { final var fillProperties = processAvro(responseBodyMatchers, message); messageBody.putAll(fillProperties.getValue()); } else { @@ -127,12 +131,12 @@ private Map processMessage( final var length = pathToRef.length; ref = pathToRef[length - 1]; propertiesJson = fileContent.findPath(ref).get(BasicTypeConstants.PROPERTIES); - messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesJson, "", operationType, basePath, fileContent)); - } else if (propertiesJson.get(BasicTypeConstants.REF) != null && propertiesJson.get(BasicTypeConstants.REF).asText().contains(".yml")) { + messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesJson, "", operationType, fileContent)); + } else if (Objects.nonNull(propertiesJson.get(BasicTypeConstants.REF)) && propertiesJson.get(BasicTypeConstants.REF).asText().contains(".yml")) { final String[] pathToRef = propertiesJson.get(BasicTypeConstants.REF).asText().split("#"); - messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, basePath, "")); + messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, "")); } else { - messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesJson, "", operationType, basePath, fileContent)); + messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesJson, "", operationType, fileContent)); } } @@ -140,31 +144,31 @@ private Map processMessage( } private Map processSchemas( - final ResponseBodyMatchers responseBodyMatchers, final String operationType, String fieldName, - final JsonNode payload, final File basePath, final JsonNode fileContent, final String bodyMatcherPath) throws IOException { + final ResponseBodyMatchers responseBodyMatchers, final String operationType, final String fieldName, + final JsonNode payload, final JsonNode fileContent, final String bodyMatcherPath) throws IOException { final JsonNode properties; final String ref; final Map messageBody = new HashMap<>(); - checkIfReferenceWithProperties(payload.get(fieldName)); + AsyncApiContractConverterUtils.checkIfReferenceWithProperties(payload.get(fieldName)); if (Objects.nonNull(payload.get(fieldName).get(BasicTypeConstants.REF)) && payload.get(fieldName).get(BasicTypeConstants.REF).asText().startsWith("#")) { final String[] pathToRef = payload.get(fieldName).get(BasicTypeConstants.REF).asText().split("/"); final var length = pathToRef.length; ref = pathToRef[length - 1]; properties = fileContent.findPath(ref).get(BasicTypeConstants.PROPERTIES); - messageBody.putAll(processProperties(responseBodyMatchers, operationType, basePath, fileContent, bodyMatcherPath, properties)); + messageBody.putAll(processProperties(responseBodyMatchers, operationType, fileContent, bodyMatcherPath, properties)); } else if (Objects.nonNull(payload.get(fieldName).get(BasicTypeConstants.REF)) && payload.get(fieldName).get(BasicTypeConstants.REF).asText().contains(".yml")) { final String[] pathToRef = payload.get(fieldName).get(BasicTypeConstants.REF).asText().split("#"); - messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, basePath, bodyMatcherPath)); - } else if (payload.get(fieldName).get(BasicTypeConstants.REF) != null) { + messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, bodyMatcherPath)); + } else if (Objects.nonNull(payload.get(fieldName).get(BasicTypeConstants.REF))) { final var fillProperties = processAvro(responseBodyMatchers, payload); messageBody.putAll(fillProperties.getValue()); } else { if (Objects.nonNull(payload.get(BasicTypeConstants.PAYLOAD).get(BasicTypeConstants.PROPERTIES))) { properties = payload.get(BasicTypeConstants.PAYLOAD).get(BasicTypeConstants.PROPERTIES); - messageBody.putAll(processProperties(responseBodyMatchers, operationType, basePath, fileContent, bodyMatcherPath, properties)); + messageBody.putAll(processProperties(responseBodyMatchers, operationType, fileContent, bodyMatcherPath, properties)); } else { if (Objects.nonNull(payload.get(BasicTypeConstants.PAYLOAD))) { @@ -172,7 +176,7 @@ private Map processSchemas( } else { properties = payload; } - messageBody.putAll(fillObjectProperties(responseBodyMatchers, properties, bodyMatcherPath, operationType, basePath, fileContent)); + messageBody.putAll(fillObjectProperties(responseBodyMatchers, properties, bodyMatcherPath, operationType, fileContent)); } } @@ -180,67 +184,61 @@ private Map processSchemas( } private Map processProperties( - final ResponseBodyMatchers responseBodyMatchers, final String operationType, final File basePath, final JsonNode fileContent, final String bodyMatcherPath, + final ResponseBodyMatchers responseBodyMatchers, final String operationType, final JsonNode fileContent, final String bodyMatcherPath, final JsonNode properties) throws IOException { - var propertiesName = properties.fieldNames(); + final var propertiesName = properties.fieldNames(); final Map messageBody = new HashMap<>(); while (propertiesName.hasNext()) { - var propertyName = propertiesName.next(); + final var propertyName = propertiesName.next(); if (Objects.nonNull(properties.get(propertyName).get(BasicTypeConstants.REF))) { - messageBody.put(propertyName, processSchemas(responseBodyMatchers, operationType, propertyName, properties, basePath, fileContent, propertyName + ".")); + messageBody.put(propertyName, processSchemas(responseBodyMatchers, operationType, propertyName, properties, fileContent, propertyName + ".")); } else { final ObjectNode propertiesToFill = BasicTypeConstants.OBJECT_MAPPER.createObjectNode(); propertiesToFill.set(propertyName, properties.get(propertyName)); - messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesToFill, bodyMatcherPath, operationType, basePath, fileContent)); + messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesToFill, bodyMatcherPath, operationType, fileContent)); } } return messageBody; } private Map processExternalFile( - final String externalFilePath, final String schemaPath, final ResponseBodyMatchers responseBodyMatchers, final String operationType, final File basePath, - String bodyMatcherPath) + final String externalFilePath, final String schemaPath, final ResponseBodyMatchers responseBodyMatchers, final String operationType, + final String bodyMatcherPath) throws IOException { final Map messageBody = new HashMap<>(); final JsonNode schema; final Path externalFile = composePath(basePath.toPath(), externalFilePath); - var externalFileContent = BasicTypeConstants.OBJECT_MAPPER.readTree(externalFile.toFile()); + final var externalFileContent = BasicTypeConstants.OBJECT_MAPPER.readTree(externalFile.toFile()); final String[] splitSchemaPath = schemaPath.split("/"); final var length = splitSchemaPath.length; final String ref = splitSchemaPath[length - 1]; schema = externalFileContent.findPath(ref).get(BasicTypeConstants.PROPERTIES); - var fieldNames = schema.fieldNames(); + final var fieldNames = schema.fieldNames(); while (fieldNames.hasNext()) { - var fieldName = fieldNames.next(); + final var fieldName = fieldNames.next(); if (Objects.nonNull(schema.get(BasicTypeConstants.REF)) && schema.get(BasicTypeConstants.REF).asText().contains(".yml")) { final String[] pathToRef = schema.get(BasicTypeConstants.REF).asText().split("#"); - messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, basePath, bodyMatcherPath)); + messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, bodyMatcherPath)); } else if (Objects.nonNull(schema.get(fieldName).get(BasicTypeConstants.REF))) { - var bodyMatcherPathObject = bodyMatcherPath + fieldName + "."; - messageBody.put(fieldName, processSchemas(responseBodyMatchers, operationType, fieldName, schema, basePath, externalFileContent, bodyMatcherPathObject)); + final var bodyMatcherPathObject = bodyMatcherPath + fieldName + "."; + messageBody.put(fieldName, processSchemas(responseBodyMatchers, operationType, fieldName, schema, externalFileContent, bodyMatcherPathObject)); } else { final ObjectNode propertiesToFill = BasicTypeConstants.OBJECT_MAPPER.createObjectNode(); propertiesToFill.set(fieldName, schema.get(fieldName)); - messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesToFill, bodyMatcherPath, operationType, basePath, externalFileContent)); + messageBody.putAll(fillObjectProperties(responseBodyMatchers, propertiesToFill, bodyMatcherPath, operationType, externalFileContent)); } } return messageBody; } - private void checkIfReferenceWithProperties(final JsonNode jsonNode) { - if (jsonNode.size() > 1 && Objects.nonNull(jsonNode.get(BasicTypeConstants.REF))) { - throw new MultiApiContractConverterException("If reference exists no other additional properties are allowed"); - } - } - private Path composePath(final Path basePath, final String uriComponent) { Path finalFilePath = null; if (uriComponent.startsWith(".")) { @@ -255,112 +253,30 @@ private Path composePath(final Path basePath, final String uriComponent) { return finalFilePath; } - private JsonNode subscribeOrPublishOperation(final JsonNode rootNode) { - final JsonNode result; - - if (rootNode.has(BasicTypeConstants.SUBSCRIBE)) { - result = rootNode.get(BasicTypeConstants.SUBSCRIBE); - } else { - result = rootNode.get(BasicTypeConstants.PUBLISH); - } - return result; - } - private Map fillObjectProperties( final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String rootProperty, final String operationType, - final File basePath, final JsonNode fileContent) - throws IOException { - Iterator fieldNames = properties.fieldNames(); + final JsonNode fileContent) throws IOException { + + final Iterator fieldNames = properties.fieldNames(); final Map messageBody = new HashMap<>(); while (fieldNames.hasNext()) { - var property = fieldNames.next(); - var path = rootProperty + property; - - if (!Objects.nonNull(properties.get(property).get(BasicTypeConstants.PROPERTIES)) || - !Objects.nonNull(properties.get(property).get(BasicTypeConstants.PROPERTIES).get(BasicTypeConstants.REF))) { - String enumType = ""; - var type = getType(properties.get(property)); - - if (isEnum(properties.get(property))) { - enumType = type; - type = BasicTypeConstants.ENUM; - } - - switch (type) { - case BasicTypeConstants.STRING: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asText()); - } else { - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - messageBody.put(property, RandomStringUtils.random(5, true, false)); - } - break; - case BasicTypeConstants.INT_32: - case BasicTypeConstants.NUMBER: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asInt()); - } else { - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - messageBody.put(property, BasicTypeConstants.RANDOM.nextInt()); - } - break; - case BasicTypeConstants.INT_64: - case BasicTypeConstants.FLOAT: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asDouble()); - } else { - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - messageBody.put(property, Math.abs(BasicTypeConstants.RANDOM.nextFloat())); - } - break; - case BasicTypeConstants.DOUBLE: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asDouble()); - } else { - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - messageBody.put(property, BasicTypeConstants.RANDOM.nextDouble()); - } - break; - case BasicTypeConstants.BOOLEAN: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asBoolean()); - } else { - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - messageBody.put(property, BasicTypeConstants.RANDOM.nextBoolean()); - } - break; - case BasicTypeConstants.ENUM: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - messageBody.put(property, processEnumTypes(properties.get(property).get(BasicTypeConstants.EXAMPLE), enumType)); - } else { - var enumList = properties.get(property).get(BasicTypeConstants.ENUM); - responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(getEnumRegex(enumType, properties, property))); - messageBody.put(property, processEnumTypes(enumList.get(BasicTypeConstants.RANDOM.nextInt(enumList.size())), enumType)); - } - break; - case BasicTypeConstants.OBJECT: - messageBody.put(property, fillObjectProperties(responseBodyMatchers, properties.get(property).get(BasicTypeConstants.PROPERTIES), path + ".", operationType, - basePath, fileContent)); - break; - case BasicTypeConstants.ARRAY: - messageBody.put(property, - processArray(responseBodyMatchers, property, properties.get(property).get("items"), path, operationType, fileContent, basePath)); - break; - default: - throw new ElementNotFoundException(BasicTypeConstants.TYPE); - } + final var property = fieldNames.next(); + final var path = rootProperty + property; + if (!Objects.nonNull(properties.get(property).get(BasicTypeConstants.PROPERTIES)) + || !Objects.nonNull(properties.get(property).get(BasicTypeConstants.PROPERTIES).get(BasicTypeConstants.REF))) { + messageBody.putAll(processObjectProperties(responseBodyMatchers, properties, operationType, fileContent, property, path)); } else { final var subProperties = properties.get(property).get(BasicTypeConstants.PROPERTIES); if (subProperties.get(BasicTypeConstants.REF).asText().contains(".yml")) { final String[] pathToRef = subProperties.get(BasicTypeConstants.REF).asText().split("#"); - messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, basePath, path)); + messageBody.putAll(processExternalFile(pathToRef[0], pathToRef[1], responseBodyMatchers, operationType, path)); } else { final String[] pathToObject = subProperties.get(BasicTypeConstants.REF).asText().split("/"); final var body = pathToObject[pathToObject.length - 1]; final var schema = fileContent.findPath(body).get(BasicTypeConstants.PROPERTIES); - messageBody.put(property, fillObjectProperties(responseBodyMatchers, schema, path + ".", operationType, basePath, fileContent)); + messageBody.put(property, fillObjectProperties(responseBodyMatchers, schema, path + ".", operationType, fileContent)); } } } @@ -368,262 +284,163 @@ private Map fillObjectProperties( return messageBody; } - private List processArray( - final ResponseBodyMatchers responseBodyMatchers, String property, final JsonNode properties, final String path, - final String operationType, final JsonNode node, final File basePath) throws IOException { - List resultArray = new ArrayList<>(); - JsonNode internalProperties = properties; - - checkIfReferenceWithProperties(properties); - - if (properties.get(BasicTypeConstants.REF) != null && properties.get(BasicTypeConstants.REF).asText().contains(".yml")) { - final String[] pathToSchema = properties.get(BasicTypeConstants.REF).asText().split("#"); - resultArray.add(processExternalFile(pathToSchema[0], pathToSchema[1], responseBodyMatchers, operationType, basePath, path)); - } else { - if (properties.get(BasicTypeConstants.REF) != null && properties.get(BasicTypeConstants.REF).asText().startsWith("#")) { - final String[] pathToObject = properties.get(BasicTypeConstants.REF).asText().split("/"); - final var body = pathToObject[pathToObject.length - 1]; - internalProperties = node.findPath(body); - } - resultArray = processInternalArray(responseBodyMatchers, property, internalProperties, path, operationType, node, basePath); - } - - return resultArray; - } + private Map processObjectProperties( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final JsonNode fileContent, + final String property, final String path) throws IOException { + final Map messageBody = new HashMap<>(); - private List processInternalArray( - final ResponseBodyMatchers responseBodyMatchers, final String property, final JsonNode properties, final String path, final String operationType, final JsonNode node, - final File basePath) - throws IOException { - final List arrayValues = new ArrayList<>(); String enumType = ""; - String type; - JsonNode internalProperties; - - type = getType(properties); - - if (type.equals(BasicTypeConstants.OBJECT)) { - internalProperties = properties.get(BasicTypeConstants.PROPERTIES); - } else { - internalProperties = properties; - } + var type = AsyncApiContractConverterUtils.getType(properties.get(property)); - if (isEnum(internalProperties)) { + if (AsyncApiContractConverterUtils.isEnum(properties.get(property))) { enumType = type; type = BasicTypeConstants.ENUM; } switch (type) { case BasicTypeConstants.STRING: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(arrayNode.get(i).asText()); - } - } else { - arrayValues.add(RandomStringUtils.random(5, true, false)); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - } - } + AsyncApiContractConverterUtils.processStringPropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path); break; case BasicTypeConstants.INT_32: case BasicTypeConstants.NUMBER: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(arrayNode.get(i).asInt()); - } - } else { - arrayValues.add(BasicTypeConstants.RANDOM.nextInt()); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - } - } + AsyncApiContractConverterUtils.processNumberPropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path); break; case BasicTypeConstants.INT_64: case BasicTypeConstants.FLOAT: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(arrayNode.get(i).asDouble()); - } - } else { - arrayValues.add(Math.abs(BasicTypeConstants.RANDOM.nextFloat())); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } - } + AsyncApiContractConverterUtils.processFloatPropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path); break; case BasicTypeConstants.DOUBLE: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(arrayNode.get(i).asDouble()); - } - } else { - arrayValues.add(BasicTypeConstants.RANDOM.nextDouble()); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } - } + AsyncApiContractConverterUtils.processDoublePropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path); break; case BasicTypeConstants.BOOLEAN: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(arrayNode.get(i).asBoolean()); - } - } else { - arrayValues.add(BasicTypeConstants.RANDOM.nextBoolean()); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - } - } + AsyncApiContractConverterUtils.processBooleanPropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path); break; case BasicTypeConstants.ENUM: - if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { - var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); - for (int i = 0; i < arrayNode.size(); i++) { - arrayValues.add(processEnumTypes(arrayNode.get(i), enumType)); - } - } else { - var enumList = internalProperties.get(BasicTypeConstants.ENUM); - arrayValues.add(processEnumTypes(enumList.get(BasicTypeConstants.RANDOM.nextInt(enumList.size())), enumType)); - if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { - responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(getEnumRegex(enumType, internalProperties, property))); - } - } + AsyncApiContractConverterUtils.processEnumPropertyType(responseBodyMatchers, properties, operationType, messageBody, property, path, enumType); break; case BasicTypeConstants.OBJECT: - arrayValues.add(fillObjectProperties(responseBodyMatchers, internalProperties, path + ".", operationType, basePath, node)); + messageBody.put(property, fillObjectProperties(responseBodyMatchers, properties.get(property).get(BasicTypeConstants.PROPERTIES), path + ".", operationType, + fileContent)); + break; + case BasicTypeConstants.ARRAY: + messageBody.put(property, + processArray(responseBodyMatchers, property, properties.get(property).get("items"), path, operationType, fileContent)); break; default: throw new ElementNotFoundException(BasicTypeConstants.TYPE); } - return arrayValues; + return messageBody; } - private String getType(final JsonNode node) { - String type; - if (node.get(BasicTypeConstants.FORMAT) != null) { - type = node.get(BasicTypeConstants.FORMAT).asText(); - } else if (node.get(BasicTypeConstants.TYPE) != null) { - type = node.get(BasicTypeConstants.TYPE).asText(); + private List processArray( + final ResponseBodyMatchers responseBodyMatchers, final String property, final JsonNode properties, final String path, + final String operationType, final JsonNode node) throws IOException { + List resultArray = new ArrayList<>(); + JsonNode internalProperties = properties; + + AsyncApiContractConverterUtils.checkIfReferenceWithProperties(properties); + + if (Objects.nonNull(properties.get(BasicTypeConstants.REF)) && properties.get(BasicTypeConstants.REF).asText().contains(".yml")) { + final String[] pathToSchema = properties.get(BasicTypeConstants.REF).asText().split("#"); + resultArray.add(processExternalFile(pathToSchema[0], pathToSchema[1], responseBodyMatchers, operationType, path)); } else { - type = node.get(node.fieldNames().next()).get(BasicTypeConstants.TYPE).asText(); + if (Objects.nonNull(properties.get(BasicTypeConstants.REF)) && properties.get(BasicTypeConstants.REF).asText().startsWith("#")) { + final String[] pathToObject = properties.get(BasicTypeConstants.REF).asText().split("/"); + final var body = pathToObject[pathToObject.length - 1]; + internalProperties = node.findPath(body); + } + resultArray = processInternalArray(responseBodyMatchers, property, internalProperties, path, operationType, node); } - return type; + + return resultArray; } - private Object processEnumTypes(final JsonNode value, final String type) { - Object enumValue; + private List processInternalArray( + final ResponseBodyMatchers responseBodyMatchers, final String property, final JsonNode properties, final String path, final String operationType, final JsonNode node) + throws IOException { + final List arrayValues = new ArrayList<>(); + String enumType = ""; + String type; + type = AsyncApiContractConverterUtils.getType(properties); + + final JsonNode internalProperties = AsyncApiContractConverterUtils.getInternalProperties(properties, type); + + if (AsyncApiContractConverterUtils.isEnum(internalProperties)) { + enumType = type; + type = BasicTypeConstants.ENUM; + } switch (type) { case BasicTypeConstants.STRING: - enumValue = value.asText(); + AsyncApiContractConverterUtils.processArrayStringType(responseBodyMatchers, path, operationType, arrayValues, internalProperties); break; case BasicTypeConstants.INT_32: case BasicTypeConstants.NUMBER: - enumValue = value.asInt(); + AsyncApiContractConverterUtils.processArrayNumberType(responseBodyMatchers, path, operationType, arrayValues, internalProperties); break; case BasicTypeConstants.INT_64: case BasicTypeConstants.FLOAT: + AsyncApiContractConverterUtils.processArrayFloatType(responseBodyMatchers, path, operationType, arrayValues, internalProperties); + break; case BasicTypeConstants.DOUBLE: - enumValue = value.asDouble(); + AsyncApiContractConverterUtils.processArrayDoubleType(responseBodyMatchers, path, operationType, arrayValues, internalProperties); break; case BasicTypeConstants.BOOLEAN: - enumValue = value.asBoolean(); + AsyncApiContractConverterUtils.processArrayBooleanType(responseBodyMatchers, path, operationType, arrayValues, internalProperties); + break; + case BasicTypeConstants.ENUM: + AsyncApiContractConverterUtils.processArrayEnumType(responseBodyMatchers, property, path, operationType, arrayValues, enumType, internalProperties); + break; + case BasicTypeConstants.OBJECT: + arrayValues.add(fillObjectProperties(responseBodyMatchers, internalProperties, path + ".", operationType, node)); break; default: throw new ElementNotFoundException(BasicTypeConstants.TYPE); } - - return enumValue; - } - - private boolean isNotRegexIncluded(final ResponseBodyMatchers responseBodyMatchers, final String property) { - var isIncluded = false; - - for (final org.springframework.cloud.contract.spec.internal.BodyMatcher bodyMatcher : responseBodyMatchers.matchers()) { - if (Objects.equals(bodyMatcher.path(), property)) { - isIncluded = true; - } - } - return !isIncluded; - } - - private String getEnumRegex(final String type, final JsonNode properties, final String property) { - String regex = ""; - Iterator enumObjects = properties.get(property).get(BasicTypeConstants.ENUM).iterator(); - while (enumObjects.hasNext()) { - if (BasicTypeConstants.STRING.equalsIgnoreCase(type)) { - while (enumObjects.hasNext()) { - JsonNode nextObject = enumObjects.next(); - if (!enumObjects.hasNext()) { - regex = regex.concat(nextObject.asText()); - } else { - regex = regex.concat(nextObject.asText() + "|"); - } - } - } - } - return regex; - } - - private boolean isEnum(final JsonNode properties) { - boolean isEnum = false; - Iterator ite = properties.fieldNames(); - - while (ite.hasNext()) { - if (ite.next().equals(BasicTypeConstants.ENUM)) { - isEnum = true; - } - } - return isEnum; + return arrayValues; } - private Pair> fillObjectPropertiesFromAvro(ResponseBodyMatchers responseBodyMatchers, ArrayNode properties, String rootProperty) { + private Pair> fillObjectPropertiesFromAvro(final ResponseBodyMatchers responseBodyMatchers, final ArrayNode properties, final String rootProperty) { final ObjectNode result = BasicTypeConstants.OBJECT_MAPPER.createObjectNode(); - Map messageBody = new HashMap<>(); + final Map messageBody = new HashMap<>(); for (int i = 0; i < properties.size(); i++) { - var type = getType(properties.get(i)); + var type = AsyncApiContractConverterUtils.getType(properties.get(i)); if (type.equals("")) { type = properties.get(i).get(BasicTypeConstants.TYPE).get(BasicTypeConstants.TYPE).asText(); } - String fieldName = properties.get(i).get(BasicTypeConstants.NAME).asText(); - String path = rootProperty + properties.get(i).get(BasicTypeConstants.NAME).asText(); + final String fieldName = properties.get(i).get(BasicTypeConstants.NAME).asText(); + final String path = rootProperty + properties.get(i).get(BasicTypeConstants.NAME).asText(); switch (type) { case BasicTypeConstants.STRING: - String randomString = RandomStringUtils.random(5, true, false); + final String randomString = RandomStringUtils.random(5, true, false); result.put(fieldName, randomString); responseBodyMatchers.jsonPath("$." + path, responseBodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); messageBody.put(fieldName, randomString); break; case BasicTypeConstants.INT_32: - int randomInt = BasicTypeConstants.RANDOM.nextInt(); + final int randomInt = BasicTypeConstants.RANDOM.nextInt(); result.put(properties.get(i).get(BasicTypeConstants.NAME).asText(), randomInt); responseBodyMatchers.jsonPath("$." + path, responseBodyMatchers.byRegex("[0-9]+")); messageBody.put(fieldName, randomInt); break; case BasicTypeConstants.BOOLEAN: - List list = new ArrayList<>(); + final List list = new ArrayList<>(); list.add(true); list.add(false); - Boolean randomBoolean = list.get(BasicTypeConstants.RANDOM.nextInt(2)); + final Boolean randomBoolean = list.get(BasicTypeConstants.RANDOM.nextInt(2)); result.put(fieldName, randomBoolean); responseBodyMatchers.jsonPath("$." + path, responseBodyMatchers.byRegex("^(true|false)$")); messageBody.put(fieldName, randomBoolean); break; case BasicTypeConstants.FLOAT: - float randomDecimal = BasicTypeConstants.RANDOM.nextFloat() * BasicTypeConstants.RANDOM.nextInt(); + final float randomDecimal = BasicTypeConstants.RANDOM.nextFloat() * BasicTypeConstants.RANDOM.nextInt(); result.put(fieldName, randomDecimal); responseBodyMatchers.jsonPath("$." + path, responseBodyMatchers.byRegex("/^\\d*\\.?\\d*$/")); messageBody.put(fieldName, randomDecimal); break; case "record": - var subObject = fillObjectPropertiesFromAvro(responseBodyMatchers, (ArrayNode) properties.get(i).get(BasicTypeConstants.TYPE).get("fields"), path + "."); + final var subObject = fillObjectPropertiesFromAvro(responseBodyMatchers, (ArrayNode) properties.get(i).get(BasicTypeConstants.TYPE).get("fields"), path + "."); result.putIfAbsent(fieldName, subObject.getKey()); messageBody.put(fieldName, subObject.getValue()); break; @@ -634,12 +451,12 @@ private Pair> fillObjectPropertiesFromAvro(Respons return new MutablePair<>(result, messageBody); } - private Pair> processAvro(ResponseBodyMatchers responseBodyMatchers, JsonNode jsonNode) { - File avroFile = new File(jsonNode.get(BasicTypeConstants.REF).asText()); + private Pair> processAvro(final ResponseBodyMatchers responseBodyMatchers, final JsonNode jsonNode) { + final File avroFile = new File(jsonNode.get(BasicTypeConstants.REF).asText()); JsonNode fileTree = null; try { fileTree = BasicTypeConstants.OBJECT_MAPPER.readTree(avroFile); - } catch (IOException e) { + } catch (final IOException e) { log.error("Error", e); } return fillObjectPropertiesFromAvro(responseBodyMatchers, (ArrayNode) fileTree.get("fields"), ""); diff --git a/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterUtils.java b/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterUtils.java new file mode 100644 index 0000000..be6dd89 --- /dev/null +++ b/src/main/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterUtils.java @@ -0,0 +1,300 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * * License, v. 2.0. If a copy of the MPL was not distributed with this + * * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package net.coru.multiapi.converter.asyncapi; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import net.coru.multiapi.converter.exception.ElementNotFoundException; +import net.coru.multiapi.converter.exception.MultiApiContractConverterException; +import net.coru.multiapi.converter.utils.BasicTypeConstants; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.cloud.contract.spec.internal.ResponseBodyMatchers; + +public final class AsyncApiContractConverterUtils { + + private AsyncApiContractConverterUtils() {} + + public static void processEnumPropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path, final String enumType) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, processEnumTypes(properties.get(property).get(BasicTypeConstants.EXAMPLE), enumType)); + } else { + final var enumList = properties.get(property).get(BasicTypeConstants.ENUM); + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(getEnumRegex(enumType, properties, property))); + messageBody.put(property, processEnumTypes(enumList.get(BasicTypeConstants.RANDOM.nextInt(enumList.size())), enumType)); + } + } + + public static void processBooleanPropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asBoolean()); + } else { + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); + messageBody.put(property, BasicTypeConstants.RANDOM.nextBoolean()); + } + } + + public static void processDoublePropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asDouble()); + } else { + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + messageBody.put(property, BasicTypeConstants.RANDOM.nextDouble()); + } + } + + public static void processFloatPropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, Float.parseFloat(properties.get(property).get(BasicTypeConstants.EXAMPLE).asText())); + } else { + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + messageBody.put(property, Math.abs(BasicTypeConstants.RANDOM.nextFloat())); + } + } + + public static void processNumberPropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asInt()); + } else { + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + messageBody.put(property, BasicTypeConstants.RANDOM.nextInt()); + } + } + + public static void processStringPropertyType( + final ResponseBodyMatchers responseBodyMatchers, final JsonNode properties, final String operationType, final Map messageBody, final String property, + final String path) { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + messageBody.put(property, properties.get(property).get(BasicTypeConstants.EXAMPLE).asText()); + } else { + responseBodyMatchers.jsonPath(path, responseBodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); + messageBody.put(property, RandomStringUtils.random(5, true, false)); + } + } + + public static Object processEnumTypes(final JsonNode value, final String type) { + final Object enumValue; + + switch (type) { + case BasicTypeConstants.STRING: + enumValue = value.asText(); + break; + case BasicTypeConstants.INT_32: + case BasicTypeConstants.NUMBER: + enumValue = value.asInt(); + break; + case BasicTypeConstants.INT_64: + case BasicTypeConstants.FLOAT: + case BasicTypeConstants.DOUBLE: + enumValue = value.asDouble(); + break; + case BasicTypeConstants.BOOLEAN: + enumValue = value.asBoolean(); + break; + default: + throw new ElementNotFoundException(BasicTypeConstants.TYPE); + } + + return enumValue; + } + + public static String getEnumRegex(final String type, final JsonNode properties, final String property) { + String regex = ""; + final Iterator enumObjects = properties.get(property).get(BasicTypeConstants.ENUM).iterator(); + while (enumObjects.hasNext()) { + if (BasicTypeConstants.STRING.equalsIgnoreCase(type)) { + while (enumObjects.hasNext()) { + final JsonNode nextObject = enumObjects.next(); + if (!enumObjects.hasNext()) { + regex = regex.concat(nextObject.asText()); + } else { + regex = regex.concat(nextObject.asText() + "|"); + } + } + } + } + return regex; + } + + public static void processArrayEnumType( + final ResponseBodyMatchers responseBodyMatchers, final String property, final String path, final String operationType, final List arrayValues, final String enumType, + final JsonNode internalProperties) throws JsonProcessingException { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + final var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); + for (int i = 0; i < arrayNode.size(); i++) { + arrayValues.add(AsyncApiContractConverterUtils.processEnumTypes(arrayNode.get(i), enumType)); + } + } else { + final var enumList = internalProperties.get(BasicTypeConstants.ENUM); + arrayValues.add(AsyncApiContractConverterUtils.processEnumTypes(enumList.get(BasicTypeConstants.RANDOM.nextInt(enumList.size())), enumType)); + if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { + responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(AsyncApiContractConverterUtils.getEnumRegex(enumType, internalProperties, property))); + } + } + } + + public static void processArrayBooleanType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties) + throws JsonProcessingException { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + final var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); + for (int i = 0; i < arrayNode.size(); i++) { + arrayValues.add(arrayNode.get(i).asBoolean()); + } + } else { + arrayValues.add(BasicTypeConstants.RANDOM.nextBoolean()); + if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { + responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); + } + } + } + + public static void processArrayDoubleType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties) + throws JsonProcessingException { + processArrayDecimalNumberType(responseBodyMatchers, path, operationType, arrayValues, internalProperties, BasicTypeConstants.DOUBLE); + } + + public static void processArrayFloatType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties) + throws JsonProcessingException { + processArrayDecimalNumberType(responseBodyMatchers, path, operationType, arrayValues, internalProperties, BasicTypeConstants.FLOAT); + } + + private static void processArrayDecimalNumberType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties, + final String type) throws JsonProcessingException { + + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + final var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); + for (int i = 0; i < arrayNode.size(); i++) { + if (BasicTypeConstants.DOUBLE.equals(type)) { + arrayValues.add(arrayNode.get(i).asDouble()); + } else { + arrayValues.add(Float.parseFloat(arrayNode.get(i).textValue())); + } + } + } else { + if (BasicTypeConstants.DOUBLE.equals(type)) { + arrayValues.add(BasicTypeConstants.RANDOM.nextDouble()); + } else { + arrayValues.add(Math.abs(BasicTypeConstants.RANDOM.nextFloat())); + } + if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { + responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } + } + } + + public static void processArrayNumberType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties) + throws JsonProcessingException { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + final var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); + for (int i = 0; i < arrayNode.size(); i++) { + arrayValues.add(arrayNode.get(i).asInt()); + } + } else { + arrayValues.add(BasicTypeConstants.RANDOM.nextInt()); + if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { + responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + } + } + } + + public static void processArrayStringType( + final ResponseBodyMatchers responseBodyMatchers, final String path, final String operationType, final List arrayValues, final JsonNode internalProperties) + throws JsonProcessingException { + if (operationType.equals(BasicTypeConstants.SUBSCRIBE)) { + final var arrayNode = BasicTypeConstants.OBJECT_MAPPER.readTree(internalProperties.toString()).get(BasicTypeConstants.EXAMPLE); + for (int i = 0; i < arrayNode.size(); i++) { + arrayValues.add(arrayNode.get(i).asText()); + } + } else { + arrayValues.add(RandomStringUtils.random(5, true, false)); + if (isNotRegexIncluded(responseBodyMatchers, path + "[0]")) { + responseBodyMatchers.jsonPath(path + "[0]", responseBodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); + } + } + } + + public static boolean isNotRegexIncluded(final ResponseBodyMatchers responseBodyMatchers, final String property) { + var isIncluded = false; + + for (final org.springframework.cloud.contract.spec.internal.BodyMatcher bodyMatcher : responseBodyMatchers.matchers()) { + if (Objects.equals(bodyMatcher.path(), property)) { + isIncluded = true; + } + } + return !isIncluded; + } + + public static JsonNode getInternalProperties(final JsonNode properties, final String type) { + final JsonNode internalProperties; + if (type.equals(BasicTypeConstants.OBJECT)) { + internalProperties = properties.get(BasicTypeConstants.PROPERTIES); + } else { + internalProperties = properties; + } + return internalProperties; + } + + public static String getType(final JsonNode node) { + final String type; + if (node.get(BasicTypeConstants.FORMAT) != null) { + type = node.get(BasicTypeConstants.FORMAT).asText(); + } else if (node.get(BasicTypeConstants.TYPE) != null) { + type = node.get(BasicTypeConstants.TYPE).asText(); + } else { + type = node.get(node.fieldNames().next()).get(BasicTypeConstants.TYPE).asText(); + } + return type; + } + + public static boolean isEnum(final JsonNode properties) { + boolean isEnum = false; + final Iterator ite = properties.fieldNames(); + + while (ite.hasNext()) { + if (ite.next().equals(BasicTypeConstants.ENUM)) { + isEnum = true; + } + } + return isEnum; + } + + public static JsonNode subscribeOrPublishOperation(final JsonNode rootNode) { + final JsonNode result; + + if (rootNode.has(BasicTypeConstants.SUBSCRIBE)) { + result = rootNode.get(BasicTypeConstants.SUBSCRIBE); + } else { + result = rootNode.get(BasicTypeConstants.PUBLISH); + } + return result; + } + + public static void checkIfReferenceWithProperties(final JsonNode jsonNode) { + if (jsonNode.size() > 1 && Objects.nonNull(jsonNode.get(BasicTypeConstants.REF))) { + throw new MultiApiContractConverterException("If reference exists no other additional properties are allowed"); + } + } +} diff --git a/src/main/java/net/coru/multiapi/converter/exception/MultiApiContractConverterException.java b/src/main/java/net/coru/multiapi/converter/exception/MultiApiContractConverterException.java index 0a1a8d6..c7f1047 100644 --- a/src/main/java/net/coru/multiapi/converter/exception/MultiApiContractConverterException.java +++ b/src/main/java/net/coru/multiapi/converter/exception/MultiApiContractConverterException.java @@ -8,7 +8,9 @@ public class MultiApiContractConverterException extends RuntimeException { - public MultiApiContractConverterException(final String message) {super(message);} + public MultiApiContractConverterException(final String message) { + super(message); + } public MultiApiContractConverterException(final Exception e) { super(e); diff --git a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java index 1f29b42..e70e307 100644 --- a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java +++ b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverter.java @@ -39,8 +39,6 @@ import org.springframework.cloud.contract.spec.internal.Body; import org.springframework.cloud.contract.spec.internal.BodyMatchers; import org.springframework.cloud.contract.spec.internal.Headers; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy; -import org.springframework.cloud.contract.spec.internal.MatchingStrategy.Type; import org.springframework.cloud.contract.spec.internal.QueryParameters; import org.springframework.cloud.contract.spec.internal.Request; import org.springframework.cloud.contract.spec.internal.Response; @@ -49,7 +47,7 @@ import org.springframework.cloud.contract.spec.internal.UrlPath; @Slf4j -public class OpenApiContractConverter { +public final class OpenApiContractConverter { public Collection convertFrom(final File file) { @@ -57,7 +55,7 @@ public Collection convertFrom(final File file) { try { contracts.addAll(getContracts(getOpenApi(file))); - } catch (MultiApiContractConverterException e) { + } catch (final MultiApiContractConverterException e) { log.error("Error processing the file", e); } return contracts; @@ -87,7 +85,7 @@ private Collection getContracts(final OpenAPI openApi) { return contracts; } - private void processContract(final List contracts, OpenAPI openAPI, Entry pathItem, Operation operation, String name) { + private void processContract(final List contracts, final OpenAPI openAPI, final Entry pathItem, final Operation operation, final String name) { for (Entry response : operation.getResponses().entrySet()) { final Contract contract = new Contract(); final String fileName = name + pathItem.getKey().replaceAll("[{}]", "") + response.getKey().substring(0, 1).toUpperCase() + response.getKey().substring(1) + "Response"; @@ -99,7 +97,7 @@ private void processContract(final List contracts, OpenAPI openAPI, En } } - private Response processResponse(final OpenAPI openAPI, String name, ApiResponse apiResponse) { + private Response processResponse(final OpenAPI openAPI, final String name, final ApiResponse apiResponse) { final Response response = new Response(); if (Objects.nonNull(apiResponse)) { if ("default".equalsIgnoreCase(name)) { @@ -112,7 +110,7 @@ private Response processResponse(final OpenAPI openAPI, String name, ApiResponse return response; } - private void processResponseContent(OpenAPI openAPI, ApiResponse apiResponse, Response response) { + private void processResponseContent(final OpenAPI openAPI, final ApiResponse apiResponse, final Response response) { final ResponseBodyMatchers responseBodyMatchers = new ResponseBodyMatchers(); final HashMap bodyMap = new HashMap<>(); if (Objects.nonNull(apiResponse.getContent())) { @@ -122,34 +120,41 @@ private void processResponseContent(OpenAPI openAPI, ApiResponse apiResponse, Re headers.contentType(content.getKey()); headers.accept(); response.setHeaders(headers); - if (content.getValue().getSchema() instanceof ComposedSchema) { - final ComposedSchema composedSchema = (ComposedSchema) content.getValue().getSchema(); - processComposedSchema(openAPI, responseBodyMatchers, bodyMap, composedSchema); - response.setBody(new Body(bodyMap)); - response.setBodyMatchers(responseBodyMatchers); - } else if (Objects.nonNull(schema.getType()) && BasicTypeConstants.BASIC_OBJECT_TYPE.contains(schema.getType())) { - OpenApiContractConverterUtils.processBasicResponseTypeBody(response, schema); - } else { - processBodyAndMatchers(bodyMap, schema, openAPI, responseBodyMatchers); - Schema checkArraySchema = new Schema<>(); - if (schema.get$ref() != null){ - checkArraySchema = openAPI.getComponents().getSchemas().get(OpenApiContractConverterUtils.mapRefName(schema)); - } - if ((schema.getType() != null && "array".equalsIgnoreCase(schema.getType())) || (checkArraySchema.getType() != null && "array".equalsIgnoreCase(checkArraySchema.getType()))){ - response.setBody(new Body(bodyMap.values().toArray()[0])); - } else { - response.setBody(new Body(bodyMap)); - } - response.setBodyMatchers(responseBodyMatchers); - } + processResponseBody(openAPI, response, responseBodyMatchers, bodyMap, content, schema); } } else { response.body(response.anyAlphaNumeric()); } + } + private void processResponseBody( + final OpenAPI openAPI, final Response response, final ResponseBodyMatchers responseBodyMatchers, final HashMap bodyMap, + final Entry content, final Schema schema) { + + if (content.getValue().getSchema() instanceof ComposedSchema) { + final ComposedSchema composedSchema = (ComposedSchema) content.getValue().getSchema(); + processComposedSchema(openAPI, responseBodyMatchers, bodyMap, composedSchema); + response.setBody(new Body(bodyMap)); + response.setBodyMatchers(responseBodyMatchers); + } else if (Objects.nonNull(schema.getType()) && BasicTypeConstants.BASIC_OBJECT_TYPE.contains(schema.getType())) { + OpenApiContractConverterUtils.processBasicResponseTypeBody(response, schema); + } else { + processBodyAndMatchers(bodyMap, schema, openAPI, responseBodyMatchers); + Schema checkArraySchema = new Schema<>(); + if (Objects.nonNull(schema.get$ref())) { + checkArraySchema = openAPI.getComponents().getSchemas().get(OpenApiContractConverterUtils.mapRefName(schema)); + } + if (Objects.nonNull(schema.getType()) && "array".equalsIgnoreCase(schema.getType()) + || Objects.nonNull(checkArraySchema.getType()) && "array".equalsIgnoreCase(checkArraySchema.getType())) { + response.setBody(new Body(bodyMap.values().toArray()[0])); + } else { + response.setBody(new Body(bodyMap)); + } + response.setBodyMatchers(responseBodyMatchers); + } } - private Request processRequest(final OpenAPI openAPI, Entry pathItem, Operation operation, String name) { + private Request processRequest(final OpenAPI openAPI, final Entry pathItem, final Operation operation, final String name) { final Request request = new Request(); if (Objects.nonNull(operation.getParameters()) || Objects.nonNull(pathItem.getValue().getParameters())) { final UrlPath url = new UrlPath(pathItem.getKey()); @@ -166,16 +171,16 @@ private Request processRequest(final OpenAPI openAPI, Entry pa return request; } - private void processRequestContent(final OpenAPI openAPI, Operation operation, Request request) { + private void processRequestContent(final OpenAPI openAPI, final Operation operation, final Request request) { final BodyMatchers bodyMatchers = new BodyMatchers(); - HashMap bodyMap = new HashMap<>(); + final HashMap bodyMap = new HashMap<>(); for (Entry content : operation.getRequestBody().getContent().entrySet()) { - Schema schema = content.getValue().getSchema(); - Headers headers = new Headers(); + final Schema schema = content.getValue().getSchema(); + final Headers headers = new Headers(); headers.header("Content-Type", content.getKey()); request.setHeaders(headers); if (content.getValue().getSchema() instanceof ComposedSchema) { - ComposedSchema composedSchema = (ComposedSchema) content.getValue().getSchema(); + final ComposedSchema composedSchema = (ComposedSchema) content.getValue().getSchema(); processComposedSchema(openAPI, bodyMatchers, bodyMap, composedSchema); request.body(bodyMap); request.setBodyMatchers(bodyMatchers); @@ -187,138 +192,198 @@ private void processRequestContent(final OpenAPI openAPI, Operation operation, R request.setBodyMatchers(bodyMatchers); } } - } - private void processBodyAndMatchers(final Map bodyMap, Schema schema, OpenAPI openAPI, BodyMatchers bodyMatchers) { + private void processBodyAndMatchers(final Map bodyMap, final Schema schema, final OpenAPI openAPI, final BodyMatchers bodyMatchers) { if (Objects.nonNull(schema.getType())) { - if (Objects.nonNull(schema.getProperties())){ - final Map basicObjectProperties = schema.getProperties(); - for (Entry property : basicObjectProperties.entrySet()) { - if (Objects.nonNull(property.getValue().get$ref())) { - final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); - final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); - bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subProperties, openAPI, bodyMatchers)); + processBodyAndMatchersByType(bodyMap, schema, openAPI, bodyMatchers); + } + if (Objects.nonNull(schema.get$ref())) { + processBodyAndMatchersByRef(bodyMap, schema, openAPI, bodyMatchers); + } + } + + private void processBodyAndMatchersByRef(final Map bodyMap, final Schema schema, final OpenAPI openAPI, final BodyMatchers bodyMatchers) { + final String ref = OpenApiContractConverterUtils.mapRefName(schema); + if (Objects.nonNull(openAPI.getComponents().getSchemas().get(ref).getProperties())) { + final HashMap properties = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); + for (Entry property : properties.entrySet()) { + if (property.getValue() instanceof ComposedSchema) { + processComposedSchema(openAPI, bodyMatchers, bodyMap, (ComposedSchema) property.getValue()); + } else if (Objects.nonNull(property.getValue().get$ref())) { + final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); + final Schema subSchema = openAPI.getComponents().getSchemas().get(subRef); + if (Objects.nonNull(subSchema.getProperties())) { + bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subSchema.getProperties(), openAPI, bodyMatchers)); + } else if (((ArraySchema) subSchema).getItems() instanceof ComposedSchema) { + final Schema arraySchema = ((ArraySchema) subSchema).getItems(); + processComposedSchema(openAPI, bodyMatchers, bodyMap, (ComposedSchema) arraySchema); + } else { + final Schema arraySchema = ((ArraySchema) subSchema).getItems(); + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, ref, arraySchema, arraySchema.getType()); + } + } else { + if (Objects.nonNull(property.getValue().getEnum())) { + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, property.getKey(), property.getValue(), BasicTypeConstants.ENUM); } else { - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, property.getKey(), property.getValue(), property.getValue().getType()); + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, property.getKey(), property.getValue(), property.getValue().getType()); } } - } else { - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, "[0]", schema, schema.getType()); } + } else { + final Schema arraySchema = openAPI.getComponents().getSchemas().get(ref); + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, "[0]", arraySchema, arraySchema.getType()); } - if (Objects.nonNull(schema.get$ref())) { - final String ref = OpenApiContractConverterUtils.mapRefName(schema); - if (Objects.nonNull(openAPI.getComponents().getSchemas().get(ref).getProperties())) { - final HashMap properties = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); - for (Entry property : properties.entrySet()) { - if (property.getValue() instanceof ComposedSchema) { - final ComposedSchema subComposedSchema = (ComposedSchema) property.getValue(); - processComposedSchema(openAPI, bodyMatchers, bodyMap, subComposedSchema); - } else if (Objects.nonNull(property.getValue().get$ref())) { - String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); - Schema subSchema = openAPI.getComponents().getSchemas().get(subRef); - if(Objects.nonNull(subSchema.getProperties())){ - Map subProperties = subSchema.getProperties(); - bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subProperties, openAPI, bodyMatchers)); - } else { - final Schema arraySchema = ((ArraySchema) subSchema).getItems(); - if(arraySchema instanceof ComposedSchema){ - processComposedSchema(openAPI, bodyMatchers, bodyMap, (ComposedSchema) arraySchema); - } else{ - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, ref, arraySchema, arraySchema.getType()); - } - } - } else { - final String refType; - if (Objects.nonNull(property.getValue().getEnum())) { - refType = BasicTypeConstants.ENUM; - } else { - refType = property.getValue().getType(); - } - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, property.getKey(), property.getValue(), refType); - } + } + + private void processBodyAndMatchersByType(final Map bodyMap, final Schema schema, final OpenAPI openAPI, final BodyMatchers bodyMatchers) { + if (Objects.nonNull(schema.getProperties())) { + final Map basicObjectProperties = schema.getProperties(); + for (Entry property : basicObjectProperties.entrySet()) { + if (Objects.nonNull(property.getValue().get$ref())) { + final String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); + final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); + bodyMap.put(property.getKey(), processComplexBodyAndMatchers(property.getKey(), subProperties, openAPI, bodyMatchers)); + } else { + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, property.getKey(), property.getValue(), property.getValue().getType()); } - } else { - Schema arraySchema = openAPI.getComponents().getSchemas().get(ref); - writeBodyMatcher(bodyMap, openAPI, bodyMatchers, "[0]", arraySchema, arraySchema.getType()); } + } else { + writeBodyMatcher(bodyMap, openAPI, bodyMatchers, null, "[0]", schema, schema.getType()); } } - private void writeBodyMatcher(final Map bodyMap, OpenAPI openAPI, BodyMatchers bodyMatchers, String fieldName, Schema schema, String type) { - if (Objects.nonNull(schema.getExample())) { + private void writeBodyMatcher( + final Map bodyMap, final OpenAPI openAPI, final BodyMatchers bodyMatchers, final Entry property, final String fieldName, final Schema schema, + final String type) { + final var example = Objects.nonNull(property) ? property.getValue().getExample() : schema.getExample(); + + if (Objects.nonNull(example)) { bodyMap.put(fieldName, schema.getExample()); } else { + final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName; + switch (type) { case BasicTypeConstants.STRING: bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - bodyMap.put(fieldName, RandomStringUtils.random(5, true, true)); + bodyMap.put(mapKey, RandomStringUtils.random(5, true, true)); break; case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(schema.getFormat()) || !Objects.nonNull(schema.getFormat())) { - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - bodyMap.put(fieldName, BasicTypeConstants.RANDOM.nextInt()); - } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(schema.getFormat())) { - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - bodyMap.put(fieldName, BasicTypeConstants.RANDOM.nextFloat()); - } + processIntegerBodyMatcher(bodyMap, bodyMatchers, property, fieldName, schema); break; case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(schema.getFormat())) { - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - bodyMap.put(fieldName, Math.abs(BasicTypeConstants.RANDOM.nextFloat())); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(schema.getFormat())) { - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - bodyMap.put(fieldName, Math.abs(BasicTypeConstants.RANDOM.nextDouble())); - } else if (schema.getFormat() == null || schema.getFormat().isEmpty()) { - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - bodyMap.put(fieldName, BasicTypeConstants.RANDOM.nextInt()); - } + processNumberBodyMatcher(bodyMap, bodyMatchers, property, fieldName, schema); break; case BasicTypeConstants.BOOLEAN: bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - bodyMap.put(fieldName, BasicTypeConstants.RANDOM.nextBoolean()); + bodyMap.put(mapKey, BasicTypeConstants.RANDOM.nextBoolean()); break; case BasicTypeConstants.OBJECT: - if (Objects.nonNull(schema.get$ref())) { - final String subRef = OpenApiContractConverterUtils.mapRefName(schema); - final HashMap subPropertiesWithRef = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); - bodyMap.put(fieldName, processComplexBodyAndMatchers(fieldName, subPropertiesWithRef, openAPI, bodyMatchers)); - } else { - final HashMap subProperties = (HashMap) schema.getProperties(); - bodyMap.put(fieldName, processComplexBodyAndMatchers(fieldName, subProperties, openAPI, bodyMatchers)); - } + processObjectBodyMatcher(bodyMap, openAPI, property, bodyMatchers, fieldName, schema); break; case BasicTypeConstants.ARRAY: - final Schema arraySchema = ((ArraySchema) schema).getItems(); - if (Objects.nonNull(arraySchema.getExample())) { - bodyMap.put(fieldName, arraySchema.getExample()); - } else { - final List propertyList = new ArrayList<>(); - bodyMap.put(fieldName, processArray(arraySchema, propertyList, fieldName, bodyMatchers, openAPI)); - } + final var arraySchema = Objects.nonNull(property) ? null : (ArraySchema) schema; + processArrayBodyMatcher(bodyMap, openAPI, bodyMatchers, property, fieldName, arraySchema); break; case BasicTypeConstants.ENUM: - processEnum(bodyMap, bodyMatchers, fieldName, schema); + processEnum(bodyMap, bodyMatchers, mapKey, Objects.nonNull(property) ? property.getValue() : schema); break; default: - bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DEFAULT_REGEX)); - bodyMap.put(fieldName, RandomStringUtils.random(5, true, true)); + bodyMatchers.jsonPath(mapKey, bodyMatchers.byRegex(BasicTypeConstants.DEFAULT_REGEX)); + bodyMap.put(mapKey, RandomStringUtils.random(5, true, true)); break; } } } - private HashMap processComplexBodyAndMatchers(final String objectName, Map properties, OpenAPI openAPI, BodyMatchers bodyMatchers) { + private void processArrayBodyMatcher( + final Map bodyMap, final OpenAPI openAPI, final BodyMatchers bodyMatchers, final Entry property, final String fieldName, + final ArraySchema schema) { + final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName; + final Schema arraySchema = Objects.nonNull(property) ? ((ArraySchema) property.getValue()).getItems() : schema.getItems(); + if (Objects.nonNull(arraySchema.getExample())) { + bodyMap.put(mapKey, arraySchema.getExample()); + } else { + bodyMap.put(mapKey, processArray(arraySchema, new ArrayList<>(), fieldName, bodyMatchers, openAPI)); + } + } + + private void processObjectBodyMatcher( + final Map bodyMap, final OpenAPI openAPI, final Entry property, final BodyMatchers bodyMatchers, final String fieldName, + final Schema schema) { + final String ref = Objects.nonNull(property) ? property.getValue().get$ref() : schema.get$ref(); + final Schema internalRef = Objects.nonNull(property) ? property.getValue() : schema; + final String subRef = OpenApiContractConverterUtils.mapRefName(internalRef); + final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName; + + if (Objects.nonNull(ref)) { + final HashMap subPropertiesWithRef = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); + bodyMap.put(mapKey, processComplexBodyAndMatchers(fieldName, subPropertiesWithRef, openAPI, bodyMatchers)); + } else { + final HashMap subProperties = (HashMap) internalRef.getProperties(); + bodyMap.put(mapKey, processComplexBodyAndMatchers(fieldName, subProperties, openAPI, bodyMatchers)); + } + } + + private void processNumberBodyMatcher( + final Map bodyMap, final BodyMatchers bodyMatchers, final Entry property, final String fieldName, + final Schema schema) { + final String format = Objects.nonNull(property) ? property.getValue().getFormat() : schema.getFormat(); + final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName; + + if (BasicTypeConstants.FLOAT.equalsIgnoreCase(format)) { + bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + bodyMap.put(mapKey, Math.abs(BasicTypeConstants.RANDOM.nextFloat())); + } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(format)) { + bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + bodyMap.put(mapKey, Math.abs(BasicTypeConstants.RANDOM.nextDouble())); + } else if (!Objects.nonNull(format) || format.isEmpty()) { + bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + bodyMap.put(mapKey, BasicTypeConstants.RANDOM.nextInt()); + } + } + + private void processIntegerBodyMatcher( + final Map bodyMap, final BodyMatchers bodyMatchers, final Entry property, final String fieldName, + final Schema schema) { + final String format = Objects.nonNull(property) ? property.getValue().getFormat() : schema.getFormat(); + final String mapKey = Objects.nonNull(property) ? property.getKey() : fieldName; + + if (BasicTypeConstants.INT_32.equalsIgnoreCase(format) || !Objects.nonNull(format)) { + bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + bodyMap.put(mapKey, BasicTypeConstants.RANDOM.nextInt()); + } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(format)) { + bodyMatchers.jsonPath(fieldName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + bodyMap.put(mapKey, BasicTypeConstants.RANDOM.nextFloat()); + } + } + + private void processEnum(final Map bodyMap, final BodyMatchers bodyMatchers, final String enumName, final Schema property) { + String regex = ""; + final Iterator enumObjects = property.getEnum().iterator(); + while (enumObjects.hasNext()) { + final Object nextObject = enumObjects.next(); + if (!enumObjects.hasNext()) { + regex = regex.concat(nextObject.toString()); + } else { + regex = regex.concat(nextObject.toString() + "|"); + } + } + bodyMatchers.jsonPath(enumName, bodyMatchers.byRegex(regex)); + bodyMap.put(enumName, property.getEnum().get(BasicTypeConstants.RANDOM.nextInt(property.getEnum().size()))); + } + + private HashMap processComplexBodyAndMatchers( + final String objectName, final Map properties, final OpenAPI openAPI, + final BodyMatchers bodyMatchers) { final HashMap propertyMap = new HashMap<>(); for (Entry property : properties.entrySet()) { final String newObjectName = objectName + "." + property.getKey(); if (Objects.nonNull(property.getValue().get$ref())) { final String ref = OpenApiContractConverterUtils.mapRefName(property.getValue()); - if (Objects.nonNull(openAPI.getComponents().getSchemas().get(ref).getProperties())){ + if (Objects.nonNull(openAPI.getComponents().getSchemas().get(ref).getProperties())) { final HashMap subProperties = (HashMap) openAPI.getComponents().getSchemas().get(ref).getProperties(); propertyMap.put(property.getKey(), processComplexBodyAndMatchers(newObjectName, subProperties, openAPI, bodyMatchers)); } else { @@ -333,73 +398,13 @@ private HashMap processComplexBodyAndMatchers(final String objec } else { type = property.getValue().getType(); } - if (Objects.nonNull(property.getValue().getExample())) { - propertyMap.put(property.getKey(), property.getValue().getExample()); - } else { - switch (type) { - case BasicTypeConstants.STRING: - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - propertyMap.put(property.getKey(), RandomStringUtils.random(5, true, true)); - break; - case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(property.getValue().getFormat()) || !Objects.nonNull(property.getValue().getFormat())) { - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - propertyMap.put(property.getKey(), BasicTypeConstants.RANDOM.nextInt()); - } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(property.getValue().getFormat())) { - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - propertyMap.put(property.getKey(), Math.abs(BasicTypeConstants.RANDOM.nextFloat())); - } - break; - case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(property.getValue().getFormat())) { - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - propertyMap.put(property.getKey(), BasicTypeConstants.RANDOM.nextFloat()); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(property.getValue().getFormat())) { - bodyMatchers.jsonPath(property.getKey(), bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - propertyMap.put(property.getKey(), BasicTypeConstants.RANDOM.nextDouble()); - } else if (property.getValue().getFormat() == null || property.getValue().getFormat().isEmpty()) { - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - propertyMap.put(property.getKey(), BasicTypeConstants.RANDOM.nextInt()); - } - break; - case BasicTypeConstants.BOOLEAN: - bodyMatchers.jsonPath(newObjectName, bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - propertyMap.put(property.getKey(), BasicTypeConstants.RANDOM.nextBoolean()); - break; - case BasicTypeConstants.ENUM: - processEnum(propertyMap, bodyMatchers, property.getKey(), property.getValue()); - break; - case BasicTypeConstants.OBJECT: - if (Objects.nonNull(property.getValue().get$ref())) { - String subRef = OpenApiContractConverterUtils.mapRefName(property.getValue()); - HashMap subPropertiesWithRef = (HashMap) openAPI.getComponents().getSchemas().get(subRef).getProperties(); - propertyMap.put(property.getKey(), processComplexBodyAndMatchers(newObjectName, subPropertiesWithRef, openAPI, bodyMatchers)); - } else { - final HashMap subProperties = (HashMap) property.getValue().getProperties(); - propertyMap.put(property.getKey(), processComplexBodyAndMatchers(newObjectName, subProperties, openAPI, bodyMatchers)); - } - break; - case BasicTypeConstants.ARRAY: - final Schema arraySchema = ((ArraySchema) property.getValue()).getItems(); - if (Objects.nonNull(arraySchema.getExample())) { - propertyMap.put(property.getKey(), arraySchema.getExample()); - } else { - List propertyList = new ArrayList<>(); - propertyMap.put(property.getKey(), processArray(arraySchema, propertyList, newObjectName, bodyMatchers, openAPI)); - } - break; - default: - bodyMatchers.jsonPath(property.getKey(), bodyMatchers.byRegex(BasicTypeConstants.DEFAULT_REGEX)); - propertyMap.put(property.getKey(), RandomStringUtils.random(5, true, true)); - break; - } - } + writeBodyMatcher(propertyMap, openAPI, bodyMatchers, property, newObjectName, null, type); } } return propertyMap; } - private List processArray(final Schema arraySchema, List propertyList, String objectName, BodyMatchers bodyMatchers, OpenAPI openAPI) { + private List processArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers, final OpenAPI openAPI) { if (Objects.nonNull(arraySchema.get$ref())) { final String ref = OpenApiContractConverterUtils.mapRefName(arraySchema); @@ -409,74 +414,22 @@ private List processArray(final Schema arraySchema, List prop final String type = arraySchema.getType(); switch (type) { case BasicTypeConstants.STRING: - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); - } - propertyList.add(RandomStringUtils.random(5, true, true)); + processStringArray(arraySchema, propertyList, objectName, bodyMatchers); break; case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(arraySchema.getFormat()) || !Objects.nonNull(arraySchema.getFormat())) { - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - } - propertyList.add(BasicTypeConstants.RANDOM.nextInt()); - } else { - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } - propertyList.add(Math.abs(BasicTypeConstants.RANDOM.nextFloat())); - } + processIntegerArray(arraySchema, propertyList, objectName, bodyMatchers); break; case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(arraySchema.getFormat())) { - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } - propertyList.add(BasicTypeConstants.RANDOM.nextFloat()); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(arraySchema.getFormat())) { - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); - } - propertyList.add(Math.abs(BasicTypeConstants.RANDOM.nextDouble())); - } else { - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); - } - propertyList.add(BasicTypeConstants.RANDOM.nextInt()); - } + processNumberArray(arraySchema, propertyList, objectName, bodyMatchers); break; case BasicTypeConstants.BOOLEAN: - if (Objects.nonNull(arraySchema.getName())) { - bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - } else { - bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); - } - propertyList.add(BasicTypeConstants.RANDOM.nextBoolean()); + processBooleanArray(arraySchema, propertyList, objectName, bodyMatchers); break; case BasicTypeConstants.ARRAY: - final Schema subArray = ((ArraySchema) arraySchema).getItems(); - if (Objects.nonNull(subArray.getExample())) { - propertyList.add(subArray.getExample()); - } else { - List subPropertyList = new ArrayList<>(); - propertyList.add(processArray(subArray, subPropertyList, objectName, bodyMatchers, openAPI)); - } + processArrayArray((ArraySchema) arraySchema, propertyList, objectName, bodyMatchers, openAPI); break; case BasicTypeConstants.OBJECT: - HashMap subObject = (HashMap) arraySchema.getProperties(); - propertyList.add(processComplexBodyAndMatchers(objectName + "[0]", subObject, openAPI, bodyMatchers)); + processObjectArray(arraySchema, propertyList, objectName, bodyMatchers, openAPI); break; default: log.error("Format not supported"); @@ -486,98 +439,123 @@ private List processArray(final Schema arraySchema, List prop return propertyList; } - private void processQueryParameters(final QueryParameters queryParameters, final List parameters, final PathItem pathItem) { - if (Objects.nonNull(pathItem.getParameters())) { - if (Objects.nonNull(parameters) && Objects.nonNull(pathItem.getParameters())) { - throw new MultiApiContractConverterException("Defining parameters in both Path and Operations is not supported in this plugin"); - } else { - mapQueryParameters(queryParameters, pathItem.getParameters()); + private void processObjectArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers, final OpenAPI openAPI) { + final HashMap subObject = (HashMap) arraySchema.getProperties(); + propertyList.add(processComplexBodyAndMatchers(objectName + "[0]", subObject, openAPI, bodyMatchers)); + } - } + private void processArrayArray(final ArraySchema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers, final OpenAPI openAPI) { + final Schema subArray = arraySchema.getItems(); + if (Objects.nonNull(subArray.getExample())) { + propertyList.add(subArray.getExample()); } else { - mapQueryParameters(queryParameters, parameters); + final List subPropertyList = new ArrayList<>(); + propertyList.add(processArray(subArray, subPropertyList, objectName, bodyMatchers, openAPI)); + } + } + private void processBooleanArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers) { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.BOOLEAN_REGEX)); } + propertyList.add(BasicTypeConstants.RANDOM.nextBoolean()); + } + private void processNumberArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers) { + if (BasicTypeConstants.FLOAT.equalsIgnoreCase(arraySchema.getFormat())) { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } + propertyList.add(BasicTypeConstants.RANDOM.nextFloat()); + } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(arraySchema.getFormat())) { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } + propertyList.add(Math.abs(BasicTypeConstants.RANDOM.nextDouble())); + } else { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + } + propertyList.add(BasicTypeConstants.RANDOM.nextInt()); + } } - private void mapQueryParameters(final QueryParameters queryParameters, final List parameters) { - for (Parameter parameter : parameters) { - if (Objects.nonNull(parameter.getExample())) { - queryParameters.parameter(parameter.getName(), new MatchingStrategy(parameter.getExample(), Type.EQUAL_TO)); - } else if (Objects.nonNull(parameter.getSchema().getExample())) { - queryParameters.parameter(parameter.getName(), new MatchingStrategy(parameter.getSchema().getExample(), Type.EQUAL_TO)); + private void processIntegerArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers) { + if (BasicTypeConstants.INT_32.equalsIgnoreCase(arraySchema.getFormat()) || !Objects.nonNull(arraySchema.getFormat())) { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); } else { - String type = parameter.getSchema().getType(); - switch (type) { - case BasicTypeConstants.STRING: - queryParameters.parameter(parameter.getName(), BasicTypeConstants.STRING_REGEX); - break; - case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(parameter.getSchema().getFormat()) || !Objects.nonNull(parameter.getSchema().getFormat())) { - queryParameters.parameter(parameter.getName(), BasicTypeConstants.INT_REGEX); - } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(parameter.getSchema().getFormat())) { - queryParameters.parameter(parameter.getName(), BasicTypeConstants.DECIMAL_REGEX); - } - break; - case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(parameter.getSchema().getFormat())) { - queryParameters.parameter(parameter.getName(), BasicTypeConstants.INT_REGEX); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(parameter.getSchema().getFormat())) { - queryParameters.parameter(parameter.getName(), BasicTypeConstants.DECIMAL_REGEX); - } else { - queryParameters.parameter(parameter.getName(), BasicTypeConstants.INT_REGEX); - } - break; - case BasicTypeConstants.BOOLEAN: - queryParameters.parameter(parameter.getName(), BasicTypeConstants.BOOLEAN_REGEX); - break; - default: - queryParameters.parameter(parameter.getName(), BasicTypeConstants.DEFAULT_REGEX); - break; - } + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.INT_REGEX)); + } + propertyList.add(BasicTypeConstants.RANDOM.nextInt()); + } else { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.DECIMAL_REGEX)); } + propertyList.add(Math.abs(BasicTypeConstants.RANDOM.nextFloat())); } } - private void processEnum(Map bodyMap, BodyMatchers bodyMatchers, String enumName, Schema property) { - String regex = ""; - Iterator enumObjects = property.getEnum().iterator(); - while (enumObjects.hasNext()) { - Object nextObject = enumObjects.next(); - if (!enumObjects.hasNext()) { - regex = regex.concat(nextObject.toString()); + private void processStringArray(final Schema arraySchema, final List propertyList, final String objectName, final BodyMatchers bodyMatchers) { + if (Objects.nonNull(arraySchema.getName())) { + bodyMatchers.jsonPath(arraySchema.getName() + "[0]", bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); + } else { + bodyMatchers.jsonPath(objectName + "[0]", bodyMatchers.byRegex(BasicTypeConstants.STRING_REGEX)); + } + propertyList.add(RandomStringUtils.random(5, true, true)); + } + + private void processQueryParameters(final QueryParameters queryParameters, final List parameters, final PathItem pathItem) { + if (Objects.nonNull(pathItem.getParameters())) { + if (Objects.nonNull(parameters) && Objects.nonNull(pathItem.getParameters())) { + throw new MultiApiContractConverterException("Defining parameters in both Path and Operations is not supported in this plugin"); } else { - regex = regex.concat(nextObject.toString() + "|"); + mapQueryParameters(queryParameters, pathItem.getParameters()); } + } else { + mapQueryParameters(queryParameters, parameters); + } + } + + private void mapQueryParameters(final QueryParameters queryParameters, final List parameters) { + for (Parameter parameter : parameters) { + OpenApiContractConverterUtils.processBasicQueryParameterTypeBody(queryParameters, parameter); } - bodyMatchers.jsonPath(enumName, bodyMatchers.byRegex(regex)); - bodyMap.put(enumName, property.getEnum().get(BasicTypeConstants.RANDOM.nextInt(property.getEnum().size()))); } - private OpenAPI getOpenApi(File file) throws MultiApiContractConverterException { - OpenAPI openAPI; - ParseOptions options = new ParseOptions(); + private OpenAPI getOpenApi(final File file) throws MultiApiContractConverterException { + final OpenAPI openAPI; + final ParseOptions options = new ParseOptions(); options.setResolve(true); try { - SwaggerParseResult result = new OpenAPIParser().readLocation(file.getPath(), null, options); + final SwaggerParseResult result = new OpenAPIParser().readLocation(file.getPath(), null, options); openAPI = result.getOpenAPI(); - } catch (ReadContentException e) { + } catch (final ReadContentException e) { throw new MultiApiContractConverterException("Code generation failed when parser the .yaml file "); } - if (openAPI == null) { + if (!Objects.nonNull(openAPI)) { throw new MultiApiContractConverterException("Code generation failed why .yaml is empty"); } return openAPI; } - private void processComposedSchema(OpenAPI openAPI, BodyMatchers bodyMatchers, Map bodyMap, ComposedSchema composedSchema) { + private void processComposedSchema(final OpenAPI openAPI, final BodyMatchers bodyMatchers, final Map bodyMap, final ComposedSchema composedSchema) { if (Objects.nonNull(composedSchema.getAllOf())) { for (Schema schema : composedSchema.getAllOf()) { processBodyAndMatchers(bodyMap, schema, openAPI, bodyMatchers); } } else if (Objects.nonNull(composedSchema.getOneOf())) { - int oneOfNumber = BasicTypeConstants.RANDOM.nextInt(composedSchema.getOneOf().size()); + final int oneOfNumber = BasicTypeConstants.RANDOM.nextInt(composedSchema.getOneOf().size()); processBodyAndMatchers(bodyMap, composedSchema.getOneOf().get(oneOfNumber), openAPI, bodyMatchers); } else if (Objects.nonNull(composedSchema.getAnyOf())) { for (int i = 0; i < BasicTypeConstants.RANDOM.nextInt(composedSchema.getAnyOf().size()) + 1; i++) { diff --git a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterUtils.java b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterUtils.java index b065cd0..6657767 100644 --- a/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterUtils.java +++ b/src/main/java/net/coru/multiapi/converter/openapi/OpenApiContractConverterUtils.java @@ -6,11 +6,17 @@ package net.coru.multiapi.converter.openapi; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; -import net.coru.multiapi.converter.utils.BasicTypeConstants; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import net.coru.multiapi.converter.utils.BasicTypeConstants; +import org.springframework.cloud.contract.spec.internal.MatchingStrategy; +import org.springframework.cloud.contract.spec.internal.MatchingStrategy.Type; +import org.springframework.cloud.contract.spec.internal.QueryParameters; import org.springframework.cloud.contract.spec.internal.Request; import org.springframework.cloud.contract.spec.internal.Response; @@ -33,7 +39,7 @@ public static String mapRefName(final Schema schema) { return refName; } - public static void processBasicResponseTypeBody(final Response response, Schema schema) { + public static void processBasicResponseTypeBody(final Response response, final Schema schema) { if (Objects.nonNull(schema.getExample())) { response.body(schema.getExample()); } else { @@ -42,20 +48,10 @@ public static void processBasicResponseTypeBody(final Response response, Schema response.body(response.anyAlphaNumeric()); break; case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(schema.getFormat()) || !Objects.nonNull(schema.getFormat())) { - response.body(response.anyPositiveInt()); - } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(schema.getFormat())) { - response.body(response.anyNumber()); - } + processIntegerFormat(response, schema); break; case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(schema.getFormat())) { - response.body(response.anyNumber()); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(schema.getFormat())) { - response.body(response.anyDouble()); - } else if (schema.getFormat().isEmpty()) { - response.body(response.anyPositiveInt()); - } + processNumberFormat(response, schema); break; case BasicTypeConstants.BOOLEAN: response.body(response.anyBoolean()); @@ -67,7 +63,7 @@ public static void processBasicResponseTypeBody(final Response response, Schema } } - public static void processBasicRequestTypeBody(final Request request, Schema schema) { + public static void processBasicRequestTypeBody(final Request request, final Schema schema) { if (Objects.nonNull(schema.getExample())) { request.body(schema.getExample()); @@ -77,20 +73,10 @@ public static void processBasicRequestTypeBody(final Request request, Schema sch request.body(request.anyAlphaNumeric()); break; case BasicTypeConstants.INTEGER: - if (BasicTypeConstants.INT_32.equalsIgnoreCase(schema.getFormat()) || !Objects.nonNull(schema.getFormat())) { - request.body(request.anyPositiveInt()); - } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(schema.getFormat())) { - request.body(request.anyNumber()); - } + processIntegerFormat(request, schema); break; case BasicTypeConstants.NUMBER: - if (BasicTypeConstants.FLOAT.equalsIgnoreCase(schema.getFormat())) { - request.body(request.anyNumber()); - } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(schema.getFormat())) { - request.body(request.anyDouble()); - } else if (schema.getFormat().isEmpty()) { - request.body(request.anyPositiveInt()); - } + processNumberFormat(request, schema); break; case BasicTypeConstants.BOOLEAN: request.body(request.anyBoolean()); @@ -101,4 +87,78 @@ public static void processBasicRequestTypeBody(final Request request, Schema sch } } } + + public static void processBasicQueryParameterTypeBody(final QueryParameters queryParameters, final Parameter parameter) { + if (Objects.nonNull(parameter.getExample())) { + queryParameters.parameter(parameter.getName(), new MatchingStrategy(parameter.getExample(), Type.EQUAL_TO)); + } else if (Objects.nonNull(parameter.getSchema().getExample())) { + queryParameters.parameter(parameter.getName(), new MatchingStrategy(parameter.getSchema().getExample(), Type.EQUAL_TO)); + } else { + final String type = parameter.getSchema().getType(); + switch (type) { + case BasicTypeConstants.STRING: + queryParameters.parameter(parameter.getName(), BasicTypeConstants.STRING_REGEX); + break; + case BasicTypeConstants.INTEGER: + OpenApiContractConverterUtils.processIntegerFormat(queryParameters, parameter); + break; + case BasicTypeConstants.NUMBER: + OpenApiContractConverterUtils.processNumberFormat(queryParameters, parameter); + break; + case BasicTypeConstants.BOOLEAN: + queryParameters.parameter(parameter.getName(), BasicTypeConstants.BOOLEAN_REGEX); + break; + default: + queryParameters.parameter(parameter.getName(), BasicTypeConstants.DEFAULT_REGEX); + break; + } + } + } + + public static void processNumberFormat(final Response response, final Schema schema) { + response.body(processNumberFormat(schema.getFormat(), schema.getName())); + } + + public static void processNumberFormat(final Request request, final Schema schema) { + request.body(processNumberFormat(schema.getFormat(), schema.getName())); + } + + public static void processNumberFormat(final QueryParameters queryParameters, final Parameter parameter) { + queryParameters.parameter(processNumberFormat(parameter.getSchema().getFormat(), parameter.getName())); + } + + private static Map processNumberFormat(final String format, final String name) { + final Map parameter = new HashMap<>(); + if (BasicTypeConstants.FLOAT.equalsIgnoreCase(format)) { + parameter.put(name, BasicTypeConstants.INT_REGEX); + } else if (BasicTypeConstants.DOUBLE.equalsIgnoreCase(format)) { + parameter.put(name, BasicTypeConstants.DECIMAL_REGEX); + } else { + parameter.put(name, BasicTypeConstants.INT_REGEX); + } + return parameter; + } + + public static void processIntegerFormat(final Response response, final Schema schema) { + response.body(processIntegerFormat(schema.getFormat(), schema.getName())); + } + + public static void processIntegerFormat(final Request request, final Schema schema) { + request.body(processIntegerFormat(schema.getFormat(), schema.getName())); + } + + public static void processIntegerFormat(final QueryParameters queryParameters, final Parameter parameter) { + queryParameters.parameter(processIntegerFormat(parameter.getSchema().getFormat(), parameter.getName())); + } + + private static Map processIntegerFormat(final String format, final String name) { + final Map parameter = new HashMap<>(); + if (BasicTypeConstants.INT_32.equalsIgnoreCase(format) || !Objects.nonNull(format)) { + parameter.put(name, BasicTypeConstants.INT_REGEX); + } else if (BasicTypeConstants.INT_64.equalsIgnoreCase(format)) { + parameter.put(name, BasicTypeConstants.DECIMAL_REGEX); + } + return parameter; + } + } \ No newline at end of file diff --git a/src/test/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterTest.java b/src/test/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterTest.java index 3dfe19a..30d117e 100644 --- a/src/test/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterTest.java +++ b/src/test/java/net/coru/multiapi/converter/asyncapi/AsyncApiContractConverterTest.java @@ -220,8 +220,8 @@ void testBasicTypes() { } else { assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.INTEGER_TYPE, 3); assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.INTEGER_TYPE_2, 10); - assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.FLOAT_TYPE, 3.5); - assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.FLOAT_TYPE_2, 2.9); + assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.FLOAT_TYPE, 3.5f); + assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.FLOAT_TYPE_2, 2.9f); assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.DOUBLE_TYPE, 100.55); assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.STRING_TYPE, asyncApiContractConverterTestFixtures.CORUNET); assertThat(orderValue).containsEntry(asyncApiContractConverterTestFixtures.BOOLEAN_TYPE, true); diff --git a/styles/OSS_style_idea.xml b/styles/OSS_style_idea.xml new file mode 100644 index 0000000..8cb64cb --- /dev/null +++ b/styles/OSS_style_idea.xml @@ -0,0 +1,900 @@ + + + \ No newline at end of file diff --git a/styles/checkstyle/OSS_checkstyle.xml b/styles/checkstyle/OSS_checkstyle.xml new file mode 100644 index 0000000..8bab5d6 --- /dev/null +++ b/styles/checkstyle/OSS_checkstyle.xml @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/styles/checkstyle/OSS_checkstyle_suppressions.xml b/styles/checkstyle/OSS_checkstyle_suppressions.xml new file mode 100644 index 0000000..860eede --- /dev/null +++ b/styles/checkstyle/OSS_checkstyle_suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file