diff --git a/Example-Test-Plan.jmx b/Example-Test-Plan.jmx index e157244a..a014aa80 100644 --- a/Example-Test-Plan.jmx +++ b/Example-Test-Plan.jmx @@ -16,10 +16,10 @@ continue false - 1 + 1000 - 1 - 1 + 1000 + 10 false @@ -376,7 +376,7 @@ false - customer_account.billing_party.party_contact[].contact_id + customer_account.billing_party.party_contact[4].contact_id 0 int @@ -387,7 +387,7 @@ customer_account.billing_party.party_contact[].contact_name 0 string - + Juan, Pedro, tomas, brais, jose, Adrian true false @@ -408,7 +408,7 @@ false - details.in_details.customs_details.party.party_contact[].contact_id + details.in_details.customs_details.party.party_contact[6].contact_id 0 int @@ -424,10 +424,10 @@ false - details.in_details.customs_details.party.p_contact[].contact_id + details.in_details.customs_details.party.p_contact[2].contact_id 0 - int - + seq + 2000 true false diff --git a/docs/_Sidebar.md b/docs/_Sidebar.md index ba20f1d8..78fd07a7 100644 --- a/docs/_Sidebar.md +++ b/docs/_Sidebar.md @@ -16,6 +16,7 @@ - [Consumer configuration](consumer-configuration.md) - [Schemas](schemas.md) - [Schema Registry](schema-registry.md) + - [Asyncapi support](asyncapi.md) # Knowledge center - [How to run a test plan](how-to-run.md) diff --git a/docs/asyncapi.md b/docs/asyncapi.md new file mode 100644 index 00000000..997f493a --- /dev/null +++ b/docs/asyncapi.md @@ -0,0 +1,22 @@ +# Asyncapi Support + +Here you can find the way to use your asyncapi.yml definition (v. 2.X.X) to produce a performance load test. +The only requirement is to use the AsyncApi Sampler component. There you can load the asyncapi file into the plugin. + +![AsyncApi Component](images/AsyncapiComponent.png) + +Once the file is loaded, information will appear in the elements below. +First tab you can see the broker configuration where you can choose to which broker you want to connect to. + +![Broker Selection](images/AsyncApiComponent-ComboBroker.png) + +Once the broker has been choose the data will be loaded. By default the first server configuration will be selected + +![Development Broker](images/AsyncApiComponent-FileLoaded.png) + +In order to choose which payload you want to use for the test just move to the second tab and use the combo to select which topic you want to use. +As for in AsyncApi specification channel/topic contains the payload will be transmitted. + +![Payload configuration](images/AsyncApiComponent-SchemaLoaded.png) + +Data generation use the same engine that the rest of the samplers so information from [schemas page](schemas.md) apply. \ No newline at end of file diff --git a/docs/getting-started.md b/docs/getting-started.md index 02f5bdaf..84675b6e 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -6,10 +6,8 @@ Now that you know what KLoadGen is and that you are familiar with its components You will need these tools to start using the plugin: -- JDK/JRE 11+ - - (17 recommended) -- JMeter 5.4+ - - (5.6.2 recommended) +- JDK/JRE 17+ +- JMeter 5.6.2+ - Maven ## Quickstart diff --git a/docs/images/AsyncApiComponent-ComboBroker.png b/docs/images/AsyncApiComponent-ComboBroker.png new file mode 100644 index 00000000..cd363ab5 Binary files /dev/null and b/docs/images/AsyncApiComponent-ComboBroker.png differ diff --git a/docs/images/AsyncApiComponent-FileLoaded.png b/docs/images/AsyncApiComponent-FileLoaded.png new file mode 100644 index 00000000..05d29707 Binary files /dev/null and b/docs/images/AsyncApiComponent-FileLoaded.png differ diff --git a/docs/images/AsyncApiComponent-SchemaLoaded.png b/docs/images/AsyncApiComponent-SchemaLoaded.png new file mode 100644 index 00000000..883b4222 Binary files /dev/null and b/docs/images/AsyncApiComponent-SchemaLoaded.png differ diff --git a/docs/images/AsyncapiComponent.png b/docs/images/AsyncapiComponent.png new file mode 100644 index 00000000..ae5f31e0 Binary files /dev/null and b/docs/images/AsyncapiComponent.png differ diff --git a/pom-maven-central.xml b/pom-maven-central.xml index 71ca6d5c..4a9c9cee 100644 --- a/pom-maven-central.xml +++ b/pom-maven-central.xml @@ -7,7 +7,7 @@ kloadgen - 5.6.10 + 5.7.0 KLoadGen Load Generation Jmeter plugin for Kafka Cluster. Supporting AVRO, JSON Schema and Protobuf schema types. Generate Artificial @@ -225,24 +225,24 @@ Europe/Madrid - nuriaricorf - Nuria Rico Freire - nuria.rico@sngular.com + rabad-sng + Raúl Abad + raul.abad@sngular.com Sngular - https://sngular.github.io/ + https://www.sngular.com - Junior Developer + Senior Backend Developer Europe/Madrid - rabad-sng - Raúl Abad - raul.abad@sngular.com + nuriaricorf + Nuria Rico Freire + nuria.rico@sngular.com Sngular - https://www.sngular.com + https://sngular.github.io/ - Senior Backend Developer + Junior Developer Europe/Madrid @@ -306,6 +306,27 @@ Roberto Riveira Veiga roberto.riveira@sngular.com Sngular + https://www.sngular.com + + Trainee Backend Developer + + + + GraciMndzSNG + Graciela Méndez Olmos + graciela.mendez@sngular.com + Sngular + https://sngular.github.io/ + + Backend Developer + + Europe/Madrid + + + pablorodriguez-sngular + Pablo Rodríguez Pérez + pablo.rodriguezp@sngular.com + Sngular https://sngular.github.io/ Backend Developer @@ -335,7 +356,7 @@ 3.24.2 1.2.0 1.5.1 - 1.11.2 + 1.11.3 1.9.4 4.4 3.12.0 @@ -358,6 +379,8 @@ 2.0.0-alpha1 1.3.1 2.35.1 + 2.15.2 + 2.15.3 @@ -395,12 +418,12 @@ com.fasterxml.jackson.core jackson-core - 2.15.2 + ${jackson-annotations.version} com.fasterxml.jackson.core jackson-annotations - 2.15.2 + ${jackson-annotations.version} org.projectlombok @@ -408,6 +431,11 @@ ${lombok.version} provided + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson-dataformat-yaml.version} + org.apache.commons commons-lang3 @@ -686,6 +714,7 @@ maven-checkstyle-plugin checkstyle.xml + UTF-8 true true false diff --git a/pom.xml b/pom.xml index 1bd1946a..508361d3 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ kloadgen - 5.6.12 + 5.8.0 KLoadGen Load Generation Jmeter plugin for Kafka Cluster. Supporting AVRO, JSON Schema and Protobuf schema types. Generate Artificial @@ -20,7 +20,7 @@ Mozilla Public License 2.0 https://github.com/sngular/kloadgen/blob/master/LICENSE repo - + @@ -370,15 +370,17 @@ 5.8.2 7.1.1 2.4.3.Final - 3.5.1 + 3.6.1 1.18.22 0.9.5 4.2.0 UTF-8 4.5.0 - 2.0.0-alpha1 + 2.0.9 1.3.1 - 2.35.1 + 3.0.0-beta-4 + 2.15.2 + 2.15.3 @@ -411,17 +413,26 @@ com.fasterxml.jackson.core jackson-core + + org.apache.commons + commons-compress + + + org.apache.commons + commons-compress + 1.24.0 + com.fasterxml.jackson.core jackson-core - 2.15.2 + ${jackson-annotations.version} com.fasterxml.jackson.core jackson-annotations - 2.15.2 + ${jackson-annotations.version} org.projectlombok @@ -429,6 +440,11 @@ ${lombok.version} provided + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson-dataformat-yaml.version} + org.apache.commons commons-lang3 @@ -438,6 +454,17 @@ io.confluent kafka-schema-registry-client ${kafka-schema-registry-client.version} + + + com.google.guava + guava + + + + + com.google.guava + guava + 32.0.1-jre io.confluent @@ -458,12 +485,32 @@ com.github.everit-org.json-schema org.everit.json.schema + + org.jetbrains.kotlin + kotlin-stdlib + + + org.jetbrains.kotlin + kotlin-stdlib + 1.9.0 + io.confluent kafka-protobuf-serializer ${kafka-schema-registry-client.version} + + + com.google.code.gson + gson + + + + + com.google.code.gson + gson + 2.10.1 io.apicurio @@ -491,6 +538,26 @@ apicurio-registry-serdes-protobuf-serde ${apicurio-registry.version} + + org.json + json + 20231013 + + + com.charleskorn.kaml + kaml + 0.53.0 + + + com.squareup.okio + okio + 3.4.0 + + + com.squareup.okhttp3 + okhttp + 5.0.0-alpha.11 + io.apicurio apicurio-registry-utils-serde @@ -499,28 +566,23 @@ org.apache.avro avro-protobuf - 1.11.2 + 1.11.3 com.github.os72 protobuf-dynamic 1.0.1 - - com.squareup.wire - wire-java-generator - 4.0.1 - runtime - + com.google.api.grpc proto-google-common-protos - 2.24.0 + 2.30.0 com.google.protobuf protobuf-java - 3.24.3 + 3.25.1 org.slf4j @@ -552,6 +614,12 @@ com.github.everit-org.json-schema org.everit.json.schema 1.14.2 + + + commons-collections + commons-collections + + @@ -629,7 +697,7 @@ com.github.tomakehurst - wiremock-jre8 + wiremock ${wiremock.version} test @@ -665,13 +733,17 @@ + + jitpack.io + https://jitpack.io + confluent https://packages.confluent.io/maven/ - jitpack.io - https://jitpack.io + central + https://repo1.maven.org/maven2/ @@ -690,7 +762,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 3.1.2 + 3.3.0 com.puppycrawl.tools @@ -725,7 +797,7 @@ com.github.ekryd.sortpom sortpom-maven-plugin - 3.0.0 + 3.3.0 @@ -738,7 +810,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.9.0 true true @@ -757,7 +829,7 @@ cobertura-maven-plugin 2.7 - + xml @@ -828,7 +900,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.4 + 3.3.0 diff --git a/src/main/java/com/sngular/kloadgen/common/tools/ApiTool.java b/src/main/java/com/sngular/kloadgen/common/tools/ApiTool.java new file mode 100644 index 00000000..59484f3d --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/common/tools/ApiTool.java @@ -0,0 +1,286 @@ +/* + * 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 com.sngular.kloadgen.common.tools; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.IteratorUtils; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.lang3.StringUtils; + +public final class ApiTool { + + public static final String FORMAT = "format"; + public static final String ALL_OF = "allOf"; + public static final String ANY_OF = "anyOf"; + public static final String ONE_OF = "oneOf"; + public static final String COMPONENTS = "components"; + public static final String SCHEMAS = "schemas"; + + public static final String MESSAGES = "messages"; + public static final String REQUIRED = "required"; + + public static final String PARAMETERS = "parameters"; + + public static final String RESPONSES = "responses"; + + private ApiTool() { + } + + public static JsonNode findNodeValue(final JsonNode node, final String valueName) { + return node.findValue(valueName); + } + + public static String getType(final JsonNode schema) { + return hasType(schema) ? getNodeAsString(schema, "type") : ""; + } + + public static Iterator> getProperties(final JsonNode schema) { + return getNode(schema, "properties").fields(); + } + + public static String getRefValue(final JsonNode schema) { + return getNode(schema, "$ref").textValue(); + } + + public static JsonNode getAdditionalProperties(final JsonNode schema) { + return getNode(schema, "additionalProperties"); + } + + public static String getFormat(final JsonNode schema) { + return getNodeAsString(schema, FORMAT); + } + + public static JsonNode getAllOf(final JsonNode schema) { + return getNode(schema, ALL_OF); + } + + public static JsonNode getAnyOf(final JsonNode schema) { + return getNode(schema, ANY_OF); + } + + public static JsonNode getOneOf(final JsonNode schema) { + return getNode(schema, ONE_OF); + } + + public static JsonNode getNode(final JsonNode schema, final String nodeName) { + return schema.get(nodeName); + } + + public static String getNodeAsString(final JsonNode schema, final String nodeName) { + return hasNode(schema, nodeName) ? getNode(schema, nodeName).textValue() : null; + } + + public static boolean getNodeAsBoolean(final JsonNode schema, final String nodeName) { + return hasNode(schema, nodeName) && getNode(schema, nodeName).booleanValue(); + } + + public static Iterator> getFieldIterator(final JsonNode schema) { + return Objects.nonNull(schema) ? schema.fields() : IteratorUtils.emptyIterator(); + } + + public static String getName(final JsonNode node) { + return hasNode(node, "name") ? getNodeAsString(node, "name") : node.textValue(); + } + + public static List getEnumValues(final JsonNode schema) { + return new ArrayList<>(CollectionUtils.collect( + IteratorUtils.toList(schema.get("enum").elements()), + getTextValue())); + } + + public static JsonNode getItems(final JsonNode schema) { + return getNode(schema, "items"); + } + + public static Map getComponentSchemas(final JsonNode openApi) { + return getSchemas(openApi, SCHEMAS); + } + + public static Map getComponentMessages(final JsonNode openApi) { + return getSchemas(openApi, MESSAGES); + } + + public static Map getParameterSchemas(final JsonNode openApi) { + return getSchemas(openApi, PARAMETERS); + } + + public static Map getResponseSchemas(final JsonNode openApi) { + + return getSchemas(openApi, RESPONSES); + } + + public static Map getSchemas(final JsonNode openApi, final String schemaType) { + final var schemasMap = new HashMap(); + + if (hasNode(openApi, COMPONENTS)) { + final var components = getNode(openApi, COMPONENTS); + if (hasNode(components, schemaType)) { + final var schemas = getNode(components, schemaType); + final var schemasIt = schemas.fieldNames(); + schemasIt.forEachRemaining(name -> schemasMap.put(schemaType + "/" + name, getNode(schemas, name))); + } + } + + return schemasMap; + } + + public static Map getComponentSecuritySchemes(final JsonNode openApi) { + final var schemasMap = new HashMap(); + + if (hasNode(openApi, COMPONENTS)) { + final var components = getNode(openApi, COMPONENTS); + if (hasNode(components, "securitySchemes")) { + getNode(components, "securitySchemes").fields().forEachRemaining(schema -> schemasMap.put(schema.getKey(), schema.getValue())); + } + } + + return schemasMap; + } + + public static String getNumberType(final JsonNode schema) { + final String type; + if (hasType(schema)) { + type = switch (getType(schema)) { + case TypeConstants.DOUBLE -> TypeConstants.DOUBLE; + case TypeConstants.FLOAT -> TypeConstants.FLOAT; + case TypeConstants.NUMBER -> TypeConstants.NUMBER; + case TypeConstants.INT_64 -> TypeConstants.INT_64; + case TypeConstants.INT_32 -> TypeConstants.INT_32; + default -> TypeConstants.INTEGER; + }; + } else { + type = TypeConstants.INTEGER; + } + return type; + } + + public static boolean hasItems(final JsonNode schema) { + return hasNode(schema, "items"); + } + + public static boolean hasNode(final JsonNode schema, final String nodeName) { + return Objects.nonNull(schema) && schema.has(nodeName); + } + + public static boolean hasField(final JsonNode schema, final String... fieldNameArray) { + final var nodeNamesList = Arrays.asList(fieldNameArray); + return StringUtils.isNotEmpty(IteratorUtils.find(schema.fieldNames(), nodeNamesList::contains)); + } + + public static boolean hasRequired(final JsonNode schema) { + return hasNode(schema, REQUIRED); + } + + public static boolean hasType(final JsonNode schema) { + return hasNode(schema, "type"); + } + + public static boolean hasRef(final JsonNode schema) { + return hasNode(schema, "$ref"); + } + + public static boolean hasProperties(final JsonNode schema) { + return hasNode(schema, "properties"); + } + + public static boolean hasContent(final JsonNode schema) { + return hasNode(schema, "content"); + } + + public static boolean hasAdditionalProperties(final JsonNode schema) { + return hasNode(schema, "additionalProperties"); + } + + public static boolean hasFormat(final JsonNode schema) { + return hasNode(schema, "format"); + } + + public static boolean isObject(final JsonNode schema) { + return hasType(schema) && TypeConstants.OBJECT.equalsIgnoreCase(getType(schema)); + } + + public static boolean isArray(final JsonNode schema) { + return hasType(schema) && TypeConstants.ARRAY.equalsIgnoreCase(getType(schema)); + } + + public static boolean isComposed(final JsonNode schema) { + return ApiTool.hasField(schema, ANY_OF, ALL_OF, ONE_OF); + } + + public static boolean isString(final JsonNode schema) { + return hasType(schema) && TypeConstants.STRING.equalsIgnoreCase(getType(schema)); + } + + public static boolean isBoolean(final JsonNode schema) { + return hasType(schema) && TypeConstants.BOOLEAN.equalsIgnoreCase(getType(schema)); + } + + public static boolean isNumber(final JsonNode schema) { + return hasType(schema) + && (TypeConstants.INTEGER.equalsIgnoreCase(getType(schema)) + || TypeConstants.NUMBER.equalsIgnoreCase(getType(schema)) + || TypeConstants.INT_64.equalsIgnoreCase(getType(schema)) + || TypeConstants.INT_32.equalsIgnoreCase(getType(schema))); + } + + public static boolean isEnum(final JsonNode schema) { + return schema.has("enum"); + } + + public static boolean isAllOf(final JsonNode schema) { + return hasNode(schema, ALL_OF); + } + + public static boolean isAnyOf(final JsonNode schema) { + return hasNode(schema, ANY_OF); + } + + public static boolean isOneOf(final JsonNode schema) { + return hasNode(schema, ONE_OF); + } + + public static boolean isDateTime(final JsonNode schema) { + final boolean isDateTime; + if (hasType(schema) && TypeConstants.STRING.equalsIgnoreCase(getType(schema))) { + if (hasNode(schema, FORMAT)) { + isDateTime = "date".equalsIgnoreCase(getNode(schema, FORMAT).textValue()) + || "date-time".equalsIgnoreCase(getNode(schema, FORMAT).textValue()); + } else { + isDateTime = false; + } + } else { + isDateTime = false; + } + return isDateTime; + } + + public static boolean checkIfRequired(final JsonNode schema, final String fieldName) { + boolean isRequired = false; + if (hasNode(schema, REQUIRED)) { + final var fieldIt = getNode(schema, REQUIRED).elements(); + while (fieldIt.hasNext() && !isRequired) { + isRequired = fieldName.equalsIgnoreCase(fieldIt.next().textValue()); + } + } + return isRequired; + } + + private static Transformer getTextValue() { + return JsonNode::asText; + } + +} diff --git a/src/main/java/com/sngular/kloadgen/common/tools/MapperUtil.java b/src/main/java/com/sngular/kloadgen/common/tools/MapperUtil.java new file mode 100644 index 00000000..32b8b64a --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/common/tools/MapperUtil.java @@ -0,0 +1,136 @@ +/* + * 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 com.sngular.kloadgen.common.tools; + +import java.util.Objects; + +import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.lang3.StringUtils; + +public class MapperUtil { + + public static final String INTEGER = "integer"; + + public static final String DOUBLE = "double"; + + public static final String FLOAT = "float"; + + public static final String NUMBER = "number"; + + public static final String INT_64 = "int64"; + + public static final String LONG = "long"; + + public static final String BIG_DECIMAL = "bigDecimal"; + + public static final String REF = "$ref"; + + private static final String DIVISOR = "([./])"; + + private MapperUtil() {} + + public static String getSimpleType(final JsonNode schema, final String prefix, final String suffix) { + String type = schema.textValue(); + if (schema.has("type")) { + type = schema.get("type").textValue(); + String format = null; + if ("string".equalsIgnoreCase(type)) { + type = "String"; + } + if (schema.has("format")) { + format = schema.get("format").textValue(); + } + if (NUMBER.equalsIgnoreCase(type)) { + if (FLOAT.equalsIgnoreCase(format)) { + type = FLOAT; + } else if (DOUBLE.equalsIgnoreCase(format)) { + type = DOUBLE; + } else { + type = BIG_DECIMAL; + } + } else if (INTEGER.equalsIgnoreCase(type)) { + if (INT_64.equalsIgnoreCase(format)) { + type = LONG; + } else { + type = INTEGER; + } + } + } else if (schema.has(REF)) { + type = getRef(schema, prefix, suffix); + } + return type; + } + + public static String getRef(final JsonNode schema, final String prefix, final String suffix) { + return getPojoName(getRefClass(schema), prefix, suffix); + } + + public static String getLongRefClass(final JsonNode schema) { + final String[] pathObjectRef = getStrings(schema); + return pathObjectRef[pathObjectRef.length - 2] + "/" + pathObjectRef[pathObjectRef.length - 1]; + } + + private static String[] getStrings(final JsonNode schema) { + return splitName(schema.get(REF).textValue()); + } + + public static String getRefClass(final JsonNode schema) { + final String[] pathObjectRef = getStrings(schema); + return pathObjectRef[pathObjectRef.length - 1]; + } + + public static String getTypeMap(final JsonNode mapSchema, final String prefix, final String suffix) { + var typeMap = ""; + final var mapNode = mapSchema.get("additionalProperties"); + final var mapValueType = mapNode.findPath("type"); + typeMap = getCollectionType(mapNode, mapValueType, prefix, suffix); + return typeMap; + } + + public static String getTypeArray(final JsonNode array, final String prefix, final String suffix) { + var typeArray = ""; + final var arrayNode = array.get("items"); + final JsonNode mapValueType; + if (arrayNode.has("type")) { + mapValueType = arrayNode.get("type"); + } else { + mapValueType = arrayNode.get(REF); + } + typeArray = getCollectionType(arrayNode, mapValueType, prefix, suffix); + return typeArray; + } + + private static String getCollectionType(final JsonNode mapNode, final JsonNode mapValueType, final String prefix, final String suffix) { + var typeMap = mapValueType.textValue(); + if (!typeMap.contains("#")) { + if ("string".equalsIgnoreCase(mapValueType.textValue())) { + typeMap = "String"; + } else if (INTEGER.equalsIgnoreCase(mapValueType.textValue())) { + typeMap = "Integer"; + } else { + typeMap = mapValueType.textValue(); + } + } else { + final var valueSchema = mapNode.findPath(REF); + if (Objects.nonNull(valueSchema)) { + getRef(valueSchema, prefix, suffix); + } + } + return typeMap; + } + + public static String getPojoName(final String namePojo, final String prefix, final String suffix) { + return StringUtils.defaultIfBlank(prefix, "") + + StringUtils.capitalize(namePojo) + + StringUtils.defaultIfBlank(suffix, ""); + } + + public static String[] splitName(final String name) { + return name.split(DIVISOR); + } + +} diff --git a/src/main/java/com/sngular/kloadgen/common/tools/TypeConstants.java b/src/main/java/com/sngular/kloadgen/common/tools/TypeConstants.java new file mode 100644 index 00000000..e02a7e59 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/common/tools/TypeConstants.java @@ -0,0 +1,35 @@ +/* + * 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 com.sngular.kloadgen.common.tools; + +public final class TypeConstants { + + public static final String NUMBER = "number"; + + public static final String BOOLEAN = "boolean"; + + public static final String OBJECT = "object"; + + public static final String ARRAY = "array"; + + public static final String INTEGER = "integer"; + + public static final String DOUBLE = "double"; + + public static final String FLOAT = "float"; + + public static final String LONG = "long"; + + public static final String STRING = "string"; + + public static final String INT_32 = "int32"; + + public static final String INT_64 = "int64"; + + private TypeConstants() { + } +} diff --git a/src/main/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElement.java b/src/main/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElement.java index 5878bd68..5698d1dc 100644 --- a/src/main/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElement.java +++ b/src/main/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElement.java @@ -32,7 +32,7 @@ public class KafkaHeadersConfigElement extends ConfigTestElement implements Test private List kafkaHeaders; @Override - public final void iterationStart(final LoopIterationEvent iterEvent) { + public final void iterationStart(final LoopIterationEvent iteEvent) { final JMeterContext context = getThreadContext(); diff --git a/src/main/java/com/sngular/kloadgen/config/keydeserialized/KeyDeserializedConfigElement.java b/src/main/java/com/sngular/kloadgen/config/keydeserialized/KeyDeserializedConfigElement.java index 1d868bac..0cdfe368 100644 --- a/src/main/java/com/sngular/kloadgen/config/keydeserialized/KeyDeserializedConfigElement.java +++ b/src/main/java/com/sngular/kloadgen/config/keydeserialized/KeyDeserializedConfigElement.java @@ -4,12 +4,6 @@ * * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -/* - * 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 com.sngular.kloadgen.config.keydeserialized; import java.util.List; diff --git a/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementBeanInfo.java b/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementBeanInfo.java index ad9072e6..e369f9fc 100644 --- a/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementBeanInfo.java +++ b/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementBeanInfo.java @@ -11,6 +11,7 @@ import com.sngular.kloadgen.model.PropertyMapping; import com.sngular.kloadgen.property.editor.SchemaRegistryConfigPropertyEditor; import com.sngular.kloadgen.property.editor.SchemaRegistryNamePropertyEditor; +import com.sngular.kloadgen.sampler.gui.DefaultPropertiesHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; import org.apache.jmeter.testbeans.BeanInfoSupport; import org.apache.jmeter.testbeans.gui.TableEditor; diff --git a/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementValue.java b/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementValue.java index 8aeae711..7ee3078c 100644 --- a/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementValue.java +++ b/src/main/java/com/sngular/kloadgen/config/schemaregistry/SchemaRegistryConfigElementValue.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.config.schemaregistry; public final class SchemaRegistryConfigElementValue { diff --git a/src/main/java/com/sngular/kloadgen/extractor/ApiExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/ApiExtractor.java new file mode 100644 index 00000000..d6eda7a7 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/ApiExtractor.java @@ -0,0 +1,33 @@ +/* + * 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 com.sngular.kloadgen.extractor; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.extractor.model.AsyncApiSR; +import com.sngular.kloadgen.extractor.model.AsyncApiSchema; +import com.sngular.kloadgen.extractor.model.AsyncApiServer; + +public interface ApiExtractor { + + AsyncApiFile processFile(final File apiFile); + + AsyncApiFile processNode(final JsonNode apiFile); + + Map getBrokerData(final AsyncApiFile asyncApiFile); + + List getSchemaRegistryData(final AsyncApiFile asyncApiFile); + + AsyncApiSchema getSchemaData(final AsyncApiFile asyncApiFile, final String topic); + + Map getSchemaDataMap(final AsyncApiFile asyncApiFile); + +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/SchemaExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/SchemaExtractor.java index 034e5e89..c356bd24 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/SchemaExtractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/SchemaExtractor.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.extractor; import java.io.IOException; @@ -10,7 +16,7 @@ import com.sngular.kloadgen.common.SchemaRegistryEnum; import com.sngular.kloadgen.extractor.extractors.ExtractorFactory; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import lombok.Getter; import org.apache.commons.lang3.tuple.Pair; @@ -30,7 +36,7 @@ public static Pair> flatPropertiesList(final Str return ExtractorFactory.flatPropertiesList(subjectName); } - public static List flatPropertiesList(final ParsedSchema parserSchema) { + public static List flatPropertiesList(final AbstractParsedSchema parserSchema) { return ExtractorFactory.getExtractor(parserSchema.schemaType()).processSchema(parserSchema, SchemaRegistryEnum.CONFLUENT); } diff --git a/src/main/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImpl.java b/src/main/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImpl.java new file mode 100644 index 00000000..d0d05263 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImpl.java @@ -0,0 +1,330 @@ +package com.sngular.kloadgen.extractor.asyncapi; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.sngular.kloadgen.common.tools.ApiTool; +import com.sngular.kloadgen.common.tools.MapperUtil; +import com.sngular.kloadgen.exception.KLoadGenException; +import com.sngular.kloadgen.extractor.ApiExtractor; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.extractor.model.AsyncApiSR; +import com.sngular.kloadgen.extractor.model.AsyncApiSchema; +import com.sngular.kloadgen.extractor.model.AsyncApiServer; +import com.sngular.kloadgen.model.ConstraintTypeEnum; +import com.sngular.kloadgen.model.FieldValueMapping; +import org.apache.commons.lang3.StringUtils; + +public class AsyncApiExtractorImpl implements ApiExtractor { + + private static final Set COMPLEX_TYPES = Set.of("record", "array"); + private static final String ERROR_WRONG_ASYNC_API_SCHEMA = "Wrong AsyncApi Schema"; + + private static final String SERVERS = "servers"; + + private static final String CHANNELS = "channels"; + + private final ObjectMapper om = new ObjectMapper(new YAMLFactory()); + + @Override + public final AsyncApiFile processFile(final File apiFile) { + final AsyncApiFile asyncApiFile; + try { + final JsonNode openApi = om.readTree(apiFile); + asyncApiFile = processNode(openApi); + } catch (final IOException e) { + throw new KLoadGenException(ERROR_WRONG_ASYNC_API_SCHEMA, e); + } + + return asyncApiFile; + } + + @Override + public final AsyncApiFile processNode(final JsonNode apiFile) { + return AsyncApiFile.builder() + .asyncApiFileNode(apiFile) + .apiServerMap(nodeToApServer(ApiTool.getNode(apiFile, SERVERS))) + .apiSchemaList(nodeToSchema(apiFile)) + .build(); + } + + private Map nodeToSchema(final JsonNode openApi) { + final var channels = ApiTool.getNode(openApi, CHANNELS); + final var schemaList = new HashMap(); + final Map totalSchemas = new HashMap<>(ApiTool.getComponentSchemas(openApi)); + totalSchemas.putAll(ApiTool.getComponentMessages(openApi)); + channels + .fields() + .forEachRemaining(channel -> + schemaList.put(channel.getKey(), + mapNodeToSchema(totalSchemas, channel.getKey(), channel.getValue()))); + return schemaList; + } + + private AsyncApiSchema mapNodeToSchema(final Map components, final String topic, final JsonNode node) { + final var antiLoopList = new ArrayList(); + final var builder = AsyncApiSchema.builder(); + builder.topicName(topic); + final var message = ApiTool.findNodeValue(node, "message"); + if (ApiTool.hasNode(message, "bindings")) { + builder.key(true); + // builder.keyType(ApiTool.findValue(message, "key")); + } + builder.model(messageToFieldList(message, components, antiLoopList)); + return builder.build(); + } + + private List messageToFieldList(final JsonNode message, final Map components, final List antiLoopList) { + var payload = ApiTool.getNode(message, "payload"); + if (ApiTool.hasRef(message)) { + payload = ApiTool.getNode(solveRef(message, components, antiLoopList, "messages"), "payload"); + } else if (!ApiTool.hasNode(message, "payload")) { + throw new KLoadGenException("AsyncApi format still not supported"); + } + + + return extractFieldList(payload, components, antiLoopList); + } + + private List extractFieldList(final JsonNode payload, final Map components, final List antiLoopList) { + var finalPayload = payload; + if (ApiTool.hasRef(payload)) { + final var payloadPath = MapperUtil.splitName(ApiTool.getRefValue(payload)); + final String objectName = payloadPath[payloadPath.length - 1]; + if (!antiLoopList.contains(objectName)) { + finalPayload = components.get("schemas/" + objectName); + antiLoopList.add(objectName); + } + } + if (!ApiTool.hasProperties(finalPayload)) { + throw new KLoadGenException("Wrong Payload for message "); + } + return new ArrayList<>(processPayload(finalPayload, "", components, antiLoopList)); + } + + private List processPayload(final JsonNode finalPayload, final String root, final Map components, final List antiLoopList) { + final var fieldList = new ArrayList(); + if (ApiTool.hasRef(finalPayload)) { + fieldList.addAll(processPayload(solveRef(finalPayload, components, antiLoopList, "schemas"), root, components, antiLoopList)); + } else if (ApiTool.hasAdditionalProperties(finalPayload)) { + fieldList.addAll(processMap(finalPayload, root, components, antiLoopList)); + } else if (ApiTool.hasProperties(finalPayload)) { + for (Iterator> it = ApiTool.getProperties(finalPayload); it.hasNext();) { + final var property = it.next(); + final var propertyDef = property.getValue(); + final var propertyName = calculateName(property.getKey(), root); + if (ApiTool.hasRef(propertyDef)) { + final var solvedPayload = solveRef(propertyDef, components, antiLoopList, "schemas"); + if (Objects.nonNull(solvedPayload)) { + fieldList.addAll(processPayload(solvedPayload, propertyName, components, antiLoopList)); + } + } else if (COMPLEX_TYPES.contains(ApiTool.getType(propertyDef)) || ApiTool.hasAdditionalProperties(propertyDef)) { + fieldList.addAll(calculatePayload(propertyDef, propertyName, components, antiLoopList)); + } else { + fieldList.add(FieldValueMapping + .builder() + .fieldName(propertyName) + .fieldType(getType(propertyDef)) + .fieldValueList(hasValues(propertyDef)) + .required(ApiTool.checkIfRequired(finalPayload, property.getKey())) + .constraints(getConstraints(propertyDef)) + .build()); + } + } + } else { + fieldList.add(FieldValueMapping + .builder() + .fieldName(calculateName(null, root)) + .fieldType(getType(finalPayload)) + .fieldValueList(hasValues(finalPayload)) + .required(true) + .constraints(getConstraints(finalPayload)) + .build()); + } + return fieldList; + } + + private String getType(final JsonNode finalPayload) { + String type = ApiTool.getType(finalPayload); + if (ApiTool.hasFormat(finalPayload)) { + type = switch (ApiTool.getFormat(finalPayload)) { + case "date-time" -> "datetime"; + case "int64" -> "long"; + case "double" -> "double"; + case "date" -> "date"; + case "string" -> ApiTool.isEnum(finalPayload) ? "enum" : "string"; + default -> ApiTool.getType(finalPayload); + }; + + } + return type; + } + + private Map getConstraints(final JsonNode finalPayload) { + final Map constraints = new EnumMap<>(ConstraintTypeEnum.class); + if (ApiTool.hasNode(finalPayload, "minLength")) { + constraints.put(ConstraintTypeEnum.MIN_LENGTH, ApiTool.getNodeAsString(finalPayload, "minLength")); + } + if (ApiTool.hasNode(finalPayload, "maxLength")) { + constraints.put(ConstraintTypeEnum.MAX_LENGTH, ApiTool.getNodeAsString(finalPayload, "minLength")); + } + if (ApiTool.hasNode(finalPayload, "minimum")) { + constraints.put(ConstraintTypeEnum.MINIMUM_VALUE, ApiTool.getNodeAsString(finalPayload, "minimum")); + } + if (ApiTool.hasNode(finalPayload, "maximum")) { + constraints.put(ConstraintTypeEnum.MAXIMUM_VALUE, ApiTool.getNodeAsString(finalPayload, "maximum")); + } + if (ApiTool.hasNode(finalPayload, "exclusiveMinimum")) { + constraints.put(ConstraintTypeEnum.EXCLUDED_MINIMUM_VALUE, ApiTool.getNodeAsString(finalPayload, "exclusiveMinimum")); + } + if (ApiTool.hasNode(finalPayload, "exclusiveMaximum")) { + constraints.put(ConstraintTypeEnum.EXCLUDED_MAXIMUM_VALUE, ApiTool.getNodeAsString(finalPayload, "exclusiveMaximum")); + } + if (ApiTool.hasNode(finalPayload, "multipleOf")) { + constraints.put(ConstraintTypeEnum.MULTIPLE_OF, ApiTool.getNodeAsString(finalPayload, "multipleOf")); + } + + return constraints; + } + + private String hasValues(final JsonNode propertyDef) { + String values = null; + if (ApiTool.isEnum(propertyDef)) { + values = String.join(",", ApiTool.getEnumValues(propertyDef)); + } + return values; + } + + private List calculatePayload(final JsonNode propertyDef, final String root, final Map components, final List antiLoopList) { + final var fieldList = new ArrayList(); + if (!ApiTool.hasAdditionalProperties(propertyDef)) { + switch (ApiTool.getType(propertyDef)) { + case "object" -> fieldList.addAll(processPayload(propertyDef, root, components, antiLoopList)); + case "array" -> fieldList.addAll(processArray(propertyDef, root, components, antiLoopList)); + default -> { + } + } + } else { + fieldList.addAll(processMap(propertyDef, root, components, antiLoopList)); + } + return fieldList; + } + + private List processArray(final JsonNode propertyDef, final String root, final Map components, final List antiLoopList) { + final List fieldList = new ArrayList<>(); + + if (ApiTool.hasItems(propertyDef)) { + final var itemNode = ApiTool.getItems(propertyDef); + if (ApiTool.hasRef(itemNode)) { + fieldList.addAll(processPayload(itemNode, root + "[]", components, antiLoopList)); + } else { + switch (ApiTool.getType(itemNode)) { + case "object" -> fieldList.addAll(processPayload(itemNode, root + "[]", components, antiLoopList)); + case "string", "number", "integer", "boolean" -> fieldList.add(FieldValueMapping + .builder() + .fieldName(root + "[]") + .fieldType(ApiTool.getType(itemNode) + "-array") + .build()); + + default -> throw new KLoadGenException("Unexpected value: " + ApiTool.getType(itemNode)); + } + } + } else { + throw new KLoadGenException(String.format("Wrong Array Definition for %s", root)); + } + return fieldList; + } + + private List processMap(final JsonNode propertyDef, final String root, final Map components, final List antiLoopList) { + final List fieldList = new ArrayList<>(); + + if (ApiTool.hasAdditionalProperties(propertyDef)) { + final var itemNode = ApiTool.getAdditionalProperties(propertyDef); + + switch (ApiTool.getType(itemNode)) { + case "object" -> fieldList.addAll(processPayload(itemNode, root + "[:]", components, antiLoopList)); + case "string", "number", "integer", "boolean" -> fieldList.add(FieldValueMapping + .builder() + .fieldName(root + "[:]") + .fieldType(ApiTool.getType(itemNode) + "-map") + .build()); + default -> throw new KLoadGenException("Unexpected value: " + ApiTool.getType(itemNode)); + } + } else { + throw new KLoadGenException(String.format("Wrong Array Definition for %s", root)); + } + return fieldList; + } + + private String calculateName(final String propertyName, final String root) { + final String finalName; + if (Objects.nonNull(propertyName)) { + if (StringUtils.isEmpty(root)) { + finalName = propertyName; + } else { + finalName = root + "." + propertyName; + } + } else { + finalName = root.substring(root.lastIndexOf(".")); + } + return finalName; + } + + private Map nodeToApServer(final JsonNode node) { + final var serverList = new HashMap(); + node.fields().forEachRemaining(server -> serverList.put(server.getKey(), mapNodeToServer(server.getKey(), server.getValue()))); + return serverList; + } + + private JsonNode solveRef(final JsonNode message, final Map components, final List antiLoopList, final String schemaType) { + JsonNode payload = null; + final var payloadPath = MapperUtil.splitName(ApiTool.getRefValue(message)); + final var objectName = payloadPath[payloadPath.length - 1]; + if (!antiLoopList.contains(objectName)) { + payload = components.get(schemaType + "/" + objectName); + antiLoopList.add(objectName); + } + return payload; + } + + private AsyncApiServer mapNodeToServer(final String serverName, final JsonNode server) { + final var builder = AsyncApiServer.builder(); + builder.name(serverName); + builder.url(ApiTool.getNodeAsString(server, "url")); + builder.protocol(ApiTool.getNodeAsString(server, "protocol")); + builder.description(ApiTool.getNodeAsString(server, "description")); + return builder.build(); + } + + @Override + public final Map getBrokerData(final AsyncApiFile asyncApiFile) { + return asyncApiFile.getApiServerMap(); + } + + @Override + public final List getSchemaRegistryData(final AsyncApiFile asyncApiFile) { + return asyncApiFile.getApiAsyncApiSRList(); + } + + @Override + public final AsyncApiSchema getSchemaData(final AsyncApiFile asyncApiFile, final String topic) { + return asyncApiFile.getApiSchemaList().get(topic); + } + + @Override + public final Map getSchemaDataMap(final AsyncApiFile asyncApiFile) { + return asyncApiFile.getApiSchemaList(); + } +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/Extractor.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/Extractor.java index b67f7eaa..447e5161 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/Extractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/Extractor.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.extractor.extractors; import java.util.List; diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactory.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactory.java index 3189f117..892ecb77 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactory.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactory.java @@ -1,8 +1,13 @@ +/* + * 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 com.sngular.kloadgen.extractor.extractors; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Properties; import com.sngular.kloadgen.common.SchemaRegistryEnum; @@ -12,12 +17,10 @@ import com.sngular.kloadgen.extractor.extractors.json.JsonExtractor; import com.sngular.kloadgen.extractor.extractors.protobuf.ProtobufExtractor; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; -import com.sngular.kloadgen.schemaregistry.adapter.impl.AbstractParsedSchemaAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ApicurioAbstractParsedSchemaMetadata; import com.sngular.kloadgen.util.JMeterHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.jmeter.threads.JMeterContextService; @@ -37,16 +40,14 @@ public static void configExtractorFactory(final AvroExtractor avroExtractor, fin ExtractorFactory.protobufExtractor = protobufExtractor; } - public static ExtractorRegistry getExtractor(final String schemaType) { + public static ExtractorRegistry getExtractor(final String schemaType) { if (schemaType != null && EnumUtils.isValidEnum(SchemaTypeEnum.class, schemaType.toUpperCase())) { - final ExtractorRegistry response = switch (SchemaTypeEnum.valueOf(schemaType.toUpperCase())) { + return switch (SchemaTypeEnum.valueOf(schemaType.toUpperCase())) { case JSON -> jsonExtractor; case AVRO -> avroExtractor; case PROTOBUF -> protobufExtractor; - default -> throw new KLoadGenException(String.format("Schema type not supported %s", schemaType)); }; - return response; } else { throw new KLoadGenException(String.format("Schema type not supported %s", schemaType)); } @@ -56,20 +57,13 @@ public static Pair> flatPropertiesList(final Str final Properties properties = JMeterContextService.getContext().getProperties(); final var schemaParsed = JMeterHelper.getParsedSchema(subjectName, properties); final String registryName = properties.getProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME); - final AbstractParsedSchemaAdapter abstractParsedSchemaAdapter = schemaParsed.getParsedSchemaAdapter(); - final String schemaType = abstractParsedSchemaAdapter.getType(); + final String schemaType = schemaParsed.getSchemaType(); final List attributeList = new ArrayList<>(); final SchemaRegistryEnum schemaRegistryEnum = SchemaRegistryEnum.valueOf(registryName.toUpperCase()); - final Object schema; - if (Objects.nonNull(registryName)) { - //TODO change parser - schema = switch (schemaRegistryEnum) { - case APICURIO -> ((ApicurioAbstractParsedSchemaMetadata) abstractParsedSchemaAdapter).getSchema(); - case CONFLUENT -> abstractParsedSchemaAdapter.getRawSchema(); - }; - attributeList.addAll(getExtractor(schemaType).processSchema(new ParsedSchema(schema), schemaRegistryEnum)); + if (StringUtils.isNotEmpty(registryName)) { + attributeList.addAll(getExtractor(schemaType).processSchema(schemaParsed, schemaRegistryEnum)); } return Pair.of(schemaType, attributeList); } diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorRegistry.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorRegistry.java index 27026c59..1c61c373 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorRegistry.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/ExtractorRegistry.java @@ -1,14 +1,22 @@ +/* + * 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 com.sngular.kloadgen.extractor.extractors; import java.util.List; import com.sngular.kloadgen.common.SchemaRegistryEnum; import com.sngular.kloadgen.model.FieldValueMapping; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; + +public interface ExtractorRegistry> { -public interface ExtractorRegistry { - List processSchema(final T schema, SchemaRegistryEnum registry); + List processSchema(final AbstractParsedSchema schema, SchemaRegistryEnum registry); - Object processSchema(final String fileContent); + T processSchema(final String fileContent); List getSchemaNameList(final String schema, SchemaRegistryEnum registryEnum); diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/SchemaExtractorUtil.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/SchemaExtractorUtil.java index 4b512103..821be7e6 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/SchemaExtractorUtil.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/SchemaExtractorUtil.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.extractor.extractors; public final class SchemaExtractorUtil { diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/avro/AvroExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/avro/AvroExtractor.java index d5589ac0..c78f8d59 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/avro/AvroExtractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/avro/AvroExtractor.java @@ -7,23 +7,25 @@ import com.sngular.kloadgen.extractor.extractors.Extractor; import com.sngular.kloadgen.extractor.extractors.ExtractorRegistry; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; +import org.apache.avro.Schema; -public class AvroExtractor implements ExtractorRegistry { +public class AvroExtractor implements ExtractorRegistry { - private static Map schemaRegistryMap = Map.of(SchemaRegistryEnum.CONFLUENT, new AvroConfluentExtractor(), SchemaRegistryEnum.APICURIO, + private static final Map SCHEMA_REGISTRY_MAP = Map.of(SchemaRegistryEnum.CONFLUENT, new AvroConfluentExtractor(), SchemaRegistryEnum.APICURIO, new AvroApicurioExtractor()); - public final List processSchema(final ParsedSchema schema, final SchemaRegistryEnum registryEnum) { - return schemaRegistryMap.get(registryEnum).processSchema(schema.rawSchema()); + public final List processSchema(final AbstractParsedSchema schema, final SchemaRegistryEnum registryEnum) { + return SCHEMA_REGISTRY_MAP.get(registryEnum).processSchema(schema.getSchema()); } - public final ParsedSchema processSchema(final String fileContent) { - return new ParsedSchema(fileContent, "AVRO"); + public final AvroParsedSchema processSchema(final String fileContent) { + return new AvroParsedSchema(null, new Schema.Parser().parse(fileContent)); } public final List getSchemaNameList(final String schema, final SchemaRegistryEnum registryEnum) { - return schemaRegistryMap.get(registryEnum).getSchemaNameList(schema); + return SCHEMA_REGISTRY_MAP.get(registryEnum).getSchemaNameList(schema); } } \ No newline at end of file diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/json/JsonExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/json/JsonExtractor.java index 80c6ba24..ca3ac322 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/json/JsonExtractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/json/JsonExtractor.java @@ -7,20 +7,21 @@ import com.sngular.kloadgen.extractor.extractors.Extractor; import com.sngular.kloadgen.extractor.extractors.ExtractorRegistry; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.JsonParsedSchema; +public class JsonExtractor implements ExtractorRegistry { -public class JsonExtractor implements ExtractorRegistry { - - private static final Map SCHEMA_REGISTRY_MAP = Map.of(SchemaRegistryEnum.CONFLUENT, new JsonDefaultExtractor(), + private static final Map> SCHEMA_REGISTRY_MAP = Map.of(SchemaRegistryEnum.CONFLUENT, new JsonDefaultExtractor(), SchemaRegistryEnum.APICURIO, new JsonDefaultExtractor()); - public final List processSchema(final ParsedSchema schemaReceived, final SchemaRegistryEnum registryEnum) { - return SCHEMA_REGISTRY_MAP.get(registryEnum).processSchema(schemaReceived.rawSchema().toString()); + public final List processSchema(final AbstractParsedSchema schemaReceived, final SchemaRegistryEnum registryEnum) { + return SCHEMA_REGISTRY_MAP.get(registryEnum).processSchema(schemaReceived.getRawSchema().toString()); } - public final ParsedSchema processSchema(final String fileContent) { - return new ParsedSchema(fileContent, "JSON"); + + public final JsonParsedSchema processSchema(final String fileContent) { + return new JsonParsedSchema(null, fileContent); } public final List getSchemaNameList(final String schema, final SchemaRegistryEnum registryEnum) { diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtoBufConfluentExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtoBufConfluentExtractor.java index 62f3b73c..ea73b9a6 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtoBufConfluentExtractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtoBufConfluentExtractor.java @@ -4,14 +4,14 @@ import com.sngular.kloadgen.extractor.extractors.Extractor; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchema; -public class ProtoBufConfluentExtractor extends AbstractProtoFileExtractor implements Extractor { +public class ProtoBufConfluentExtractor extends AbstractProtoFileExtractor implements Extractor> { - public final List processSchema(final ParsedSchema schemaReceived) { - return processSchemaDefault((ProtoFileElement) schemaReceived.rawSchema()); + public final List processSchema(final AbstractParsedSchema schemaReceived) { + return processSchemaDefault(schemaReceived.getRawSchema()); } public final List getSchemaNameList(final String schema) { diff --git a/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufExtractor.java b/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufExtractor.java index 0133c261..d1944c11 100644 --- a/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufExtractor.java +++ b/src/main/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufExtractor.java @@ -8,19 +8,23 @@ import com.sngular.kloadgen.extractor.extractors.Extractor; import com.sngular.kloadgen.extractor.extractors.ExtractorRegistry; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; +import com.squareup.wire.schema.Location; +import com.squareup.wire.schema.internal.parser.ProtoParser; -public class ProtobufExtractor implements ExtractorRegistry { +public class ProtobufExtractor implements ExtractorRegistry { private static final Map SCHEMA_REGISTRY_MAP = Map.of(SchemaRegistryEnum.CONFLUENT, new ProtoBufConfluentExtractor(), SchemaRegistryEnum.APICURIO, new ProtoBufApicurioExtractor()); - public final List processSchema(final ParsedSchema schemaReceived, final SchemaRegistryEnum registryEnum) { + public final List processSchema(final AbstractParsedSchema schemaReceived, final SchemaRegistryEnum registryEnum) { return new ArrayList(SCHEMA_REGISTRY_MAP.get(registryEnum).processSchema(schemaReceived)); } - public final ParsedSchema processSchema(final String fileContent) { - return new ParsedSchema(fileContent, "PROTOBUF"); + public final ProtobufParsedSchema processSchema(final String fileContent) { + final var protoDescriptor = new ProtoParser(Location.get("/"), fileContent.toCharArray()); + return new ProtobufParsedSchema(null, protoDescriptor.readProtoFile()); } public final List getSchemaNameList(final String schema, final SchemaRegistryEnum registryEnum) { diff --git a/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiAbstract.java b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiAbstract.java new file mode 100644 index 00000000..c2b8c44e --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiAbstract.java @@ -0,0 +1,20 @@ +/* + * 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 com.sngular.kloadgen.extractor.model; + +import java.util.Collections; +import java.util.Map; + +public interface AsyncApiAbstract { + + Object[] getProperties(); + + default Map getPropertiesMap() { + return Collections.emptyMap(); + } + +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiFile.java b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiFile.java new file mode 100644 index 00000000..ea05aa49 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiFile.java @@ -0,0 +1,31 @@ +/* + * 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 com.sngular.kloadgen.extractor.model; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.Builder; +import lombok.Singular; +import lombok.Value; + +@Value +@Builder +public class AsyncApiFile { + + JsonNode asyncApiFileNode; + + @Singular("apiServer") + transient Map apiServerMap; + + @Singular("apiAsyncApiSR") + transient List apiAsyncApiSRList; + + @Singular("apiSchema") + transient Map apiSchemaList; +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSR.java b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSR.java new file mode 100644 index 00000000..d4ee6446 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSR.java @@ -0,0 +1,17 @@ +package com.sngular.kloadgen.extractor.model; + +import java.util.Map; + +public record AsyncApiSR(String name, String schemaRegistryUrl, + String schemaRegistryVendor) implements AsyncApiAbstract { + + @Override + public Object[] getProperties() { + return new Object[]{schemaRegistryUrl, schemaRegistryVendor}; + } + + @Override + public Map getPropertiesMap() { + return Map.of("url", schemaRegistryUrl, "type", schemaRegistryVendor); + } +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSchema.java b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSchema.java new file mode 100644 index 00000000..3537cd33 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiSchema.java @@ -0,0 +1,33 @@ +package com.sngular.kloadgen.extractor.model; + +import java.util.List; + +import com.sngular.kloadgen.model.FieldValueMapping; +import lombok.Builder; +import lombok.Value; + +@Value +@Builder + +public class AsyncApiSchema implements AsyncApiAbstract { + + String topicName; + + boolean key; + + String keyType; + + String schemaLookupStrategy; + + List model; + + @Override + public Object[] getProperties() { + return model.toArray(); + } + + @Override + public String toString() { + return topicName; + } +} diff --git a/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiServer.java b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiServer.java new file mode 100644 index 00000000..a27ec386 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/extractor/model/AsyncApiServer.java @@ -0,0 +1,29 @@ +package com.sngular.kloadgen.extractor.model; + +import java.util.Map; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class AsyncApiServer implements AsyncApiAbstract { + + String name; + + String url; + + String protocol; + + String description; + + @Override + public Object[] getProperties() { + return new Object[] {name, url, protocol, description}; + } + + @Override + public Map getPropertiesMap() { + return Map.of("name", name, "url", url, "protocol", protocol); + } +} diff --git a/src/main/java/com/sngular/kloadgen/loadgen/BaseLoadGenerator.java b/src/main/java/com/sngular/kloadgen/loadgen/BaseLoadGenerator.java index 83851d01..388e3053 100644 --- a/src/main/java/com/sngular/kloadgen/loadgen/BaseLoadGenerator.java +++ b/src/main/java/com/sngular/kloadgen/loadgen/BaseLoadGenerator.java @@ -18,5 +18,9 @@ public interface BaseLoadGenerator { void setUpGenerator(String schema, List fieldExprMappings); + default void setUpGenerator(List fieldExprMappings) { + this.setUpGenerator(null, fieldExprMappings); + } + EnrichedRecord nextMessage(); } diff --git a/src/main/java/com/sngular/kloadgen/loadgen/impl/JsonSRLoadGenerator.java b/src/main/java/com/sngular/kloadgen/loadgen/impl/JsonSRLoadGenerator.java index 55faf553..5f45062c 100644 --- a/src/main/java/com/sngular/kloadgen/loadgen/impl/JsonSRLoadGenerator.java +++ b/src/main/java/com/sngular/kloadgen/loadgen/impl/JsonSRLoadGenerator.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.exception.KLoadGenException; @@ -56,10 +57,23 @@ public void setUpGenerator(final String schema, final List fi this.jsonSchemaProcessor.processSchema(SchemaTypeEnum.JSON, null, null, fieldExprMappings); } + @Override + public void setUpGenerator(final List fieldExprMappings) { + + this.jsonSchemaProcessor.processSchema(SchemaTypeEnum.JSON, null, null, fieldExprMappings); + } + public EnrichedRecord nextMessage() { - return EnrichedRecord.builder().schemaMetadata( - metadata.getLeft().getSchemaMetadataAdapter() - ).genericRecord(jsonSchemaProcessor.next()).build(); + final EnrichedRecord.EnrichedRecordBuilder builder = EnrichedRecord.builder(); + + if (Objects.nonNull(metadata)) { + builder.schemaMetadata( + metadata.getLeft().getSchemaMetadataAdapter() + ); + } + builder.genericRecord(jsonSchemaProcessor.next()).build(); + + return builder.build(); } } diff --git a/src/main/java/com/sngular/kloadgen/model/ConstraintTypeEnum.java b/src/main/java/com/sngular/kloadgen/model/ConstraintTypeEnum.java index 81f10718..a3abce2a 100644 --- a/src/main/java/com/sngular/kloadgen/model/ConstraintTypeEnum.java +++ b/src/main/java/com/sngular/kloadgen/model/ConstraintTypeEnum.java @@ -15,5 +15,5 @@ public enum ConstraintTypeEnum { REGEX, FORMAT, PRECISION, - SCALE + MIN_LENGTH, MAX_LENGTH, SCALE } diff --git a/src/main/java/com/sngular/kloadgen/model/FieldValueMapping.java b/src/main/java/com/sngular/kloadgen/model/FieldValueMapping.java index c7882fae..6950ff1b 100644 --- a/src/main/java/com/sngular/kloadgen/model/FieldValueMapping.java +++ b/src/main/java/com/sngular/kloadgen/model/FieldValueMapping.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.sngular.kloadgen.extractor.model.AsyncApiAbstract; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -29,7 +30,7 @@ @ToString @NoArgsConstructor @EqualsAndHashCode(callSuper = false) -public class FieldValueMapping extends AbstractTestElement { +public class FieldValueMapping extends AbstractTestElement implements AsyncApiAbstract { public static final String FIELD_CONSTRAINTS = "constraints"; @@ -182,6 +183,10 @@ public final void setConstraints(final Map constrain this.constraints = constraints; } + public final Object[] getProperties() { + return new Object[] {getFieldName(), getFieldType(), getValueLength(), getRequired(), getFieldValuesList()}; + } + public static final class FieldValueMappingBuilder { private final Map constraints = new EnumMap<>(ConstraintTypeEnum.class); diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/AbstractParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/AbstractParsedSchema.java new file mode 100644 index 00000000..5df54d30 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/parsedschema/AbstractParsedSchema.java @@ -0,0 +1,33 @@ +/* + * 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 com.sngular.kloadgen.parsedschema; + +import lombok.Getter; + +@Getter +public abstract class AbstractParsedSchema { + + private final T schema; + private final String schemaType; + private final String name; + + public AbstractParsedSchema(final String name, final String type, final T schema) { + this.name = name; + this.schemaType = type; + this.schema = schema; + } + + public final T schema() { + return this.schema; + } + + public final String schemaType() { + return this.schemaType; + } + + public abstract T getRawSchema(); +} diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/AvroParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/AvroParsedSchema.java new file mode 100644 index 00000000..5d5a855b --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/parsedschema/AvroParsedSchema.java @@ -0,0 +1,21 @@ +/* + * 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 com.sngular.kloadgen.parsedschema; + +import org.apache.avro.Schema; + +public class AvroParsedSchema extends AbstractParsedSchema { + + public AvroParsedSchema(final String name, final Schema schema) { + super(name, "AVRO", schema); + } + + @Override + public final Schema getRawSchema() { + return getSchema(); + } +} diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/IParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/IParsedSchema.java deleted file mode 100644 index b7d46327..00000000 --- a/src/main/java/com/sngular/kloadgen/parsedschema/IParsedSchema.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.sngular.kloadgen.parsedschema; - -public interface IParsedSchema { - - String schemaType(); - - String name(); - - String canonicalString(); - - Object rawSchema(); - -} diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/JsonParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/JsonParsedSchema.java new file mode 100644 index 00000000..e5813c50 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/parsedschema/JsonParsedSchema.java @@ -0,0 +1,19 @@ +/* + * 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 com.sngular.kloadgen.parsedschema; + +public class JsonParsedSchema extends AbstractParsedSchema { + + public JsonParsedSchema(final String name, final String schema) { + super(name, "JSON", schema); + } + + @Override + public final String getRawSchema() { + return getSchema(); + } +} diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/ParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/ParsedSchema.java deleted file mode 100644 index 43aec860..00000000 --- a/src/main/java/com/sngular/kloadgen/parsedschema/ParsedSchema.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.sngular.kloadgen.parsedschema; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; - -import com.sngular.kloadgen.exception.KLoadGenException; -import com.squareup.wire.schema.internal.parser.ProtoFileElement; -import io.confluent.kafka.schemaregistry.avro.AvroSchema; -import io.confluent.kafka.schemaregistry.json.JsonSchema; -import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchema; -import org.apache.avro.Schema; - -public class ParsedSchema implements IParsedSchema { - - private final T schema; - private final String schemaType; - - public ParsedSchema(final String fileContent, final String schemaType) { - switch (schemaType) { - case "AVRO" -> { - this.schema = (T) new Schema.Parser().parse(fileContent); - } - case "JSON" -> { - this.schema = (T) new JsonSchema(fileContent); - } - case "PROTOBUF" -> { - this.schema = (T) new ProtobufSchema(fileContent); - } - default -> throw new IllegalArgumentException("schemaType not supported: " + schemaType); - } - this.schemaType = schemaType; - } - - public ParsedSchema(final File file, final String schemaType) throws IOException { - this(new String(Files.readAllBytes(file.toPath())), schemaType); - } - - public ParsedSchema(final T schema, final String type) { - this.schema = schema; - this.schemaType = type; - } - - public ParsedSchema(final T schema) { - this.schema = schema; - this.schemaType = switch (this.schema.getClass().getSimpleName()) { - case "Schema", "AvroSchema", "UnionSchema", "RecordSchema" -> "AVRO"; - case "ProtoBuf", "ProtoFileElement" -> "PROTOBUF"; - case "JsonSchema", "ObjectSchema" -> "JSON"; - default -> throw new KLoadGenException(String.format("Need to specify schemaType for %s", this.schema.getClass().getSimpleName())); - }; - } - - public ParsedSchema(final io.confluent.kafka.schemaregistry.ParsedSchema parsedSchema) throws IOException { - this(parsedSchema.canonicalString(), parsedSchema.schemaType()); - } - - public final Object schema() { - return this.schema; - } - - public final String schemaType() { - return this.schemaType; - } - - public final String name() { - return null; - } - - public final String canonicalString() { - return switch (this.schemaType) { - case "AVRO" -> stringAvro(this.schema); - case "JSON" -> stringJson(this.schema); - case "PROTOBUF" -> stringProto(this.schema); - default -> this.schema.toString(); - }; - } - - private String stringAvro(final T schema) { - final String result; - if (schema instanceof AvroSchema) { - result = ((AvroSchema) this.schema).canonicalString(); - } else { - result = this.schema.toString(); - } - return result; - } - - private String stringJson(final T schema) { - final String result; - if (schema instanceof JsonSchema) { - result = ((JsonSchema) this.schema).canonicalString(); - } else { - result = this.schema.toString(); - } - return result; - } - - private String stringProto(final T schema) { - final String result; - if (schema instanceof ProtobufSchema) { - result = ((ProtobufSchema) this.schema).canonicalString(); - } else if (schema instanceof ProtoFileElement) { - result = ((ProtoFileElement) this.schema).toSchema(); - } else { - result = this.schema.toString(); - } - return result; - } - - public final Object rawSchema() { - return switch (this.schemaType) { - case "AVRO" -> rawAvro(this.schema); - case "JSON" -> rawJson(this.schema); - case "PROTOBUF" -> rawProto(this.schema); - default -> this.schema; - }; - } - - private Object rawAvro(final T schema) { - final Object result; - if (schema instanceof AvroSchema) { - result = ((AvroSchema) this.schema).rawSchema(); - } else { - result = this.schema; - } - return result; - } - - private Object rawJson(final T schema) { - final Object result; - if (schema instanceof JsonSchema) { - result = ((JsonSchema) this.schema).rawSchema(); - } else { - result = this.schema.toString(); - } - return result; - } - - private Object rawProto(final T schema) { - final Object result; - if (schema instanceof ProtobufSchema) { - result = ((ProtobufSchema) this.schema).rawSchema(); - } else { - result = this.schema; - } - return result; - } - -} diff --git a/src/main/java/com/sngular/kloadgen/parsedschema/ProtobufParsedSchema.java b/src/main/java/com/sngular/kloadgen/parsedschema/ProtobufParsedSchema.java new file mode 100644 index 00000000..bf2fc862 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/parsedschema/ProtobufParsedSchema.java @@ -0,0 +1,21 @@ +/* + * 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 com.sngular.kloadgen.parsedschema; + +import com.squareup.wire.schema.internal.parser.ProtoFileElement; + +public class ProtobufParsedSchema extends AbstractParsedSchema { + + public ProtobufParsedSchema(final String name, final ProtoFileElement schema) { + super(name, "PROTOBUF", schema); + } + + @Override + public final ProtoFileElement getRawSchema() { + return getSchema(); + } +} diff --git a/src/main/java/com/sngular/kloadgen/processor/SchemaProcessor.java b/src/main/java/com/sngular/kloadgen/processor/SchemaProcessor.java index b5f44f6a..cf930146 100644 --- a/src/main/java/com/sngular/kloadgen/processor/SchemaProcessor.java +++ b/src/main/java/com/sngular/kloadgen/processor/SchemaProcessor.java @@ -21,6 +21,7 @@ import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; import lombok.SneakyThrows; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.RandomUtils; public class SchemaProcessor { @@ -165,9 +166,34 @@ private void makeFieldValueMappingRequired(final FieldValueMapping fieldValueMap } private ArrayDeque calculateFieldsToProcess() { + + ArrayDeque fieldToProcess; final ArrayDeque initialFieldExpMappingsQueue = new ArrayDeque<>(fieldExprMappings); - return initialFieldExpMappingsQueue.stream().filter(fieldValueMapping -> shouldProcessField(fieldValueMapping, initialFieldExpMappingsQueue)) - .collect(Collectors.toCollection(ArrayDeque::new)); + fieldToProcess = new ArrayDeque<>(ListUtils.select(fieldExprMappings, fieldValueMapping -> shouldProcessField(fieldValueMapping, initialFieldExpMappingsQueue))); + + + if (fieldToProcess.isEmpty()) { + fieldToProcess = new ArrayDeque<>(ListUtils.select(fieldExprMappings, this::shouldProcessFieldIfIsNonRequiered)); + if (fieldToProcess.isEmpty()) { + while (initialFieldExpMappingsQueue.size() > 1) { + initialFieldExpMappingsQueue.removeFirst(); + } + fieldToProcess = initialFieldExpMappingsQueue; + } + } + + return fieldToProcess; + } + + private boolean shouldProcessFieldIfIsNonRequiered(final FieldValueMapping fieldValueMapping) { + + boolean shouldProcess = false; + if (fieldValueMapping.getFieldValuesList().isEmpty() || fieldValueMapping.getFieldValuesList().contains("null")) { + fieldValueMapping.getFieldValuesList().remove("null"); + } else { + shouldProcess = true; + } + return shouldProcess; } private boolean shouldProcessField(final FieldValueMapping fieldValueMapping, final ArrayDeque initialFieldExpMappingsQueue) { diff --git a/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/AvroObjectCreatorFactory.java b/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/AvroObjectCreatorFactory.java index 5bb260bc..d631c43a 100644 --- a/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/AvroObjectCreatorFactory.java +++ b/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/AvroObjectCreatorFactory.java @@ -14,14 +14,11 @@ import com.sngular.kloadgen.exception.KLoadGenException; import com.sngular.kloadgen.model.ConstraintTypeEnum; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.processor.model.SchemaProcessorPOJO; import com.sngular.kloadgen.processor.objectcreatorfactory.ObjectCreatorFactory; import com.sngular.kloadgen.processor.util.SchemaProcessorUtils; import com.sngular.kloadgen.randomtool.generator.AvroGeneratorTool; -import com.sngular.kloadgen.schemaregistry.adapter.impl.AbstractParsedSchemaAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ApicurioAbstractParsedSchemaMetadata; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; import com.sngular.kloadgen.serializer.EnrichedRecord; @@ -44,18 +41,10 @@ public final class AvroObjectCreatorFactory implements ObjectCreatorFactory { private final Map entity = new HashMap<>(); public AvroObjectCreatorFactory(final Object schema, final BaseSchemaMetadata metadata) { - if (schema instanceof ParsedSchema) { - this.schema = (Schema) ((ParsedSchema) schema).rawSchema(); + if (schema instanceof AvroParsedSchema) { + this.schema = ((AvroParsedSchema) schema).getRawSchema(); } else if (schema instanceof Schema) { this.schema = (Schema) schema; - } else if (schema instanceof BaseParsedSchema) { - final BaseParsedSchema schemaParse = (BaseParsedSchema) schema; - final AbstractParsedSchemaAdapter adapterParse = schemaParse.getParsedSchemaAdapter(); - if (adapterParse instanceof ApicurioAbstractParsedSchemaMetadata) { - this.schema = (Schema) ((ApicurioAbstractParsedSchemaMetadata) adapterParse).getSchema(); - } else { - this.schema = adapterParse.getRawSchema(); - } } else { throw new KLoadGenException("Unsupported schema type"); } diff --git a/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/ProtobufObjectCreatorFactory.java b/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/ProtobufObjectCreatorFactory.java index 9420c220..2559fa3b 100644 --- a/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/ProtobufObjectCreatorFactory.java +++ b/src/main/java/com/sngular/kloadgen/processor/objectcreatorfactory/impl/ProtobufObjectCreatorFactory.java @@ -20,13 +20,11 @@ import com.google.protobuf.DynamicMessage.Builder; import com.google.protobuf.Message; import com.sngular.kloadgen.exception.KLoadGenException; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import com.sngular.kloadgen.processor.model.SchemaProcessorPOJO; import com.sngular.kloadgen.processor.objectcreatorfactory.ObjectCreatorFactory; import com.sngular.kloadgen.processor.util.SchemaProcessorUtils; import com.sngular.kloadgen.randomtool.generator.ProtoBufGeneratorTool; -import com.sngular.kloadgen.schemaregistry.adapter.impl.AbstractParsedSchemaAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; import com.sngular.kloadgen.serializer.EnrichedRecord; @@ -44,15 +42,10 @@ public class ProtobufObjectCreatorFactory implements ObjectCreatorFactory { private final Map entity = new HashMap<>(); public ProtobufObjectCreatorFactory(final Object schema, final BaseSchemaMetadata metadata) throws DescriptorValidationException, IOException { - if (schema instanceof ParsedSchema) { - this.schema = SchemaProcessorUtils.buildProtoDescriptor((ProtoFileElement) ((ParsedSchema) schema).rawSchema(), metadata); + if (schema instanceof AbstractParsedSchema) { + this.schema = SchemaProcessorUtils.buildProtoDescriptor((ProtoFileElement) ((AbstractParsedSchema) schema).getRawSchema(), metadata); } else if (schema instanceof ProtoFileElement) { this.schema = SchemaProcessorUtils.buildProtoDescriptor((ProtoFileElement) schema, metadata); - } else if (schema instanceof BaseParsedSchema) { - final BaseParsedSchema schemaParse = (BaseParsedSchema) schema; - final AbstractParsedSchemaAdapter adapterParse = schemaParse.getParsedSchemaAdapter(); - final Object schemaParsed = adapterParse.getRawSchema(); - this.schema = SchemaProcessorUtils.buildProtoDescriptor((ProtoFileElement) schemaParsed, metadata); } else { throw new KLoadGenException("Unsupported schema type"); } diff --git a/src/main/java/com/sngular/kloadgen/processor/util/SchemaProcessorUtils.java b/src/main/java/com/sngular/kloadgen/processor/util/SchemaProcessorUtils.java index 8f035c90..468108cb 100644 --- a/src/main/java/com/sngular/kloadgen/processor/util/SchemaProcessorUtils.java +++ b/src/main/java/com/sngular/kloadgen/processor/util/SchemaProcessorUtils.java @@ -26,7 +26,6 @@ import com.google.protobuf.Descriptors; import com.google.protobuf.Descriptors.DescriptorValidationException; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.schemaregistry.adapter.impl.AbstractParsedSchemaAdapter; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; import com.sngular.kloadgen.util.JMeterHelper; @@ -187,9 +186,10 @@ private static void processImport(final BaseSchemaMetadata()); + final var protoFileElement = JMeterHelper.getParsedSchema(getSubjectName(importedClass, metadata), + JMeterContextService.getContext().getProperties()); + final var importedProtobufSchema = new ProtobufSchema( + (ProtoFileElement) protoFileElement.getSchema(), metadata.getSchemaMetadataAdapter().getReferences(), new HashMap<>()); if (!ProtobufHelper.NOT_ACCEPTED_IMPORTS.contains(importedClass)) { schemaBuilder.addDependency(importedProtobufSchema.toDescriptor().getFullName()); schemaBuilder.addSchema(convertDynamicSchema(importedProtobufSchema, metadata)); diff --git a/src/main/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditor.java b/src/main/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditor.java index 33413c8c..7cc17314 100644 --- a/src/main/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditor.java +++ b/src/main/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditor.java @@ -30,9 +30,8 @@ import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.extractor.SchemaExtractor; import com.sngular.kloadgen.extractor.extractors.ExtractorFactory; -import com.sngular.kloadgen.extractor.extractors.ExtractorRegistry; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import com.sngular.kloadgen.util.PropsKeysHelper; import lombok.extern.slf4j.Slf4j; import org.apache.avro.AvroRuntimeException; @@ -94,9 +93,9 @@ public final void actionFileChooser(final ActionEvent event) { final File schemaFile = Objects.requireNonNull(fileChooser.getSelectedFile()); try { final String schemaType = schemaTypeComboBox.getSelectedItem().toString(); - final ExtractorRegistry extractor = ExtractorFactory.getExtractor(schemaType); + final var extractor = ExtractorFactory.getExtractor(schemaType); final String fileContent = SchemaExtractor.readSchemaFile(schemaFile.getPath()); - final ParsedSchema parserSchema = (ParsedSchema) extractor.processSchema(fileContent); + final var parserSchema = extractor.processSchema(fileContent); final List schemaFieldList = extractor.processSchema(parserSchema, SchemaRegistryEnum.CONFLUENT); buildTable(schemaFieldList, fileContent, schemaType); } catch (final IOException e) { @@ -107,7 +106,7 @@ public final void actionFileChooser(final ActionEvent event) { } } - public final List getAttributeList(final ParsedSchema selectedSchema) { + public final List getAttributeList(final AbstractParsedSchema selectedSchema) { final List result = new ArrayList<>(); if (Objects.nonNull(selectedSchema)) { result.addAll(SchemaExtractor.flatPropertiesList(selectedSchema)); diff --git a/src/main/java/com/sngular/kloadgen/property/editor/SerDesPackageValue.java b/src/main/java/com/sngular/kloadgen/property/editor/SerDesPackageValue.java index cf55f1c9..760ae41a 100644 --- a/src/main/java/com/sngular/kloadgen/property/editor/SerDesPackageValue.java +++ b/src/main/java/com/sngular/kloadgen/property/editor/SerDesPackageValue.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.property.editor; public class SerDesPackageValue { diff --git a/src/main/java/com/sngular/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java b/src/main/java/com/sngular/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java index f3fe5164..4def6ee0 100644 --- a/src/main/java/com/sngular/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java +++ b/src/main/java/com/sngular/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.randomtool.generator; import java.util.ArrayList; diff --git a/src/main/java/com/sngular/kloadgen/randomtool/random/RandomObject.java b/src/main/java/com/sngular/kloadgen/randomtool/random/RandomObject.java index 0a959b62..aa5dfd5d 100644 --- a/src/main/java/com/sngular/kloadgen/randomtool/random/RandomObject.java +++ b/src/main/java/com/sngular/kloadgen/randomtool/random/RandomObject.java @@ -85,7 +85,8 @@ public Object generateRandom( break; case ValidTypeConstants.BYTES: try { - value = getIntegerValueOrRandom(valueLength, Collections.emptyList(), Collections.emptyMap()).byteValueExact(); + value = getIntegerValueOrRandom(valueLength, Collections.emptyList(), Collections.emptyMap()) + .byteValueExact(); } catch (final ArithmeticException exception) { value = Byte.MAX_VALUE; } @@ -149,7 +150,8 @@ public Object generateRandom( return value; } - private BigInteger getIntegerValueOrRandom(final Integer valueLength, final List fieldValueList, final Map constraints) { + private BigInteger getIntegerValueOrRandom(final Integer valueLength, final List fieldValueList, + final Map constraints) { final BigInteger value; if (!fieldValueList.isEmpty()) { @@ -176,7 +178,8 @@ private BigInteger getIntegerValueOrRandom(final Integer valueLength, final List return value; } - private BigDecimal getDecimalValueOrRandom(final Integer valueLength, final List fieldValueList, final Map constraints) { + private BigDecimal getDecimalValueOrRandom(final Integer valueLength, final List fieldValueList, + final Map constraints) { final BigDecimal value; if (!fieldValueList.isEmpty()) { @@ -421,8 +424,10 @@ private static LocalTime getTimeMicrosValueOrRandom(final List fieldValu private static LocalDateTime getRandomLocalDateTime(final List fieldValueList) { final LocalDateTime value; - final long minDay = LocalDateTime.of(1900, 1, 1, 0, 0).toEpochSecond(ZoneOffset.UTC); - final long maxDay = LocalDateTime.of(2100, 1, 1, 0, 0).toEpochSecond(ZoneOffset.UTC); + final long minDay = LocalDateTime.of(1900, 1, 1, 0, 0) + .toEpochSecond(ZoneOffset.UTC); + final long maxDay = LocalDateTime.of(2100, 1, 1, 0, 0) + .toEpochSecond(ZoneOffset.UTC); final long randomSeconds = minDay + RandomUtils.nextLong(0, maxDay - minDay); if (fieldValueList.isEmpty()) { diff --git a/src/main/java/com/sngular/kloadgen/randomtool/util/ValueUtils.java b/src/main/java/com/sngular/kloadgen/randomtool/util/ValueUtils.java index 285d9442..c06c8ac2 100644 --- a/src/main/java/com/sngular/kloadgen/randomtool/util/ValueUtils.java +++ b/src/main/java/com/sngular/kloadgen/randomtool/util/ValueUtils.java @@ -16,6 +16,7 @@ import java.util.UUID; import org.apache.avro.Schema; +import org.apache.commons.collections4.CollectionUtils; import org.apache.jmeter.threads.JMeterContextService; public class ValueUtils { @@ -25,11 +26,13 @@ private ValueUtils() { } public static List replaceValuesContext(final List fieldValuesList) { - final List parameterList = new ArrayList<>(fieldValuesList); - - parameterList.replaceAll(fieldValue -> - fieldValue.matches("\\$\\{\\w*}") - ? JMeterContextService.getContext().getVariables().get(fieldValue.substring(2, fieldValue.length() - 1)) : fieldValue); + final List parameterList = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(fieldValuesList)) { + parameterList.addAll(fieldValuesList); + parameterList.replaceAll(fieldValue -> + fieldValue.matches("\\$\\{\\w*}") + ? JMeterContextService.getContext().getVariables().get(fieldValue.substring(2, fieldValue.length() - 1)) : fieldValue); + } return parameterList; } diff --git a/src/main/java/com/sngular/kloadgen/sampler/AsyncApiSampler.java b/src/main/java/com/sngular/kloadgen/sampler/AsyncApiSampler.java new file mode 100644 index 00000000..2705b831 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/sampler/AsyncApiSampler.java @@ -0,0 +1,210 @@ +package com.sngular.kloadgen.sampler; + +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ExecutionException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sngular.kloadgen.exception.KLoadGenException; +import com.sngular.kloadgen.extractor.ApiExtractor; +import com.sngular.kloadgen.extractor.asyncapi.AsyncApiExtractorImpl; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.loadgen.BaseLoadGenerator; +import com.sngular.kloadgen.loadgen.impl.JsonSRLoadGenerator; +import com.sngular.kloadgen.model.FieldValueMapping; +import com.sngular.kloadgen.model.PropertyMapping; +import com.sngular.kloadgen.serializer.EnrichedRecord; +import com.sngular.kloadgen.serializer.GenericJsonRecordSerializer; +import com.sngular.kloadgen.util.PropsKeysHelper; +import org.apache.jmeter.config.ConfigTestElement; +import org.apache.jmeter.gui.GUIMenuSortOrder; +import org.apache.jmeter.samplers.AbstractSampler; +import org.apache.jmeter.samplers.Entry; +import org.apache.jmeter.samplers.SampleResult; +import org.apache.jmeter.testelement.property.CollectionProperty; +import org.apache.jmeter.testelement.property.TestElementProperty; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@GUIMenuSortOrder(Integer.MIN_VALUE) +public class AsyncApiSampler extends AbstractSampler implements Serializable { + + private static final Logger LOG = LoggerFactory.getLogger(AsyncApiSampler.class); + + private static final String TEMPLATE = "Topic: %s, partition: %s, offset: %s"; + + private final transient ApiExtractor apiExtractor; + + private final transient BaseLoadGenerator generator; + + private final transient ObjectMapper mapper = new ObjectMapper(); + + private JsonNode asyncApiFileNode; + + public AsyncApiSampler() { + apiExtractor = new AsyncApiExtractorImpl(); + generator = new JsonSRLoadGenerator(); + } + + @Override + public final boolean applies(final ConfigTestElement configElement) { + return super.applies(configElement); + } + + @Override + public final SampleResult sample(final Entry entry) { + + final var sampleResult = new SampleResult(); + sampleResult.setThreadName("AsyncApi Sampler"); + sampleResult.sampleStart(); + try (final KafkaProducer producer = getKafkaProducer()) { + generator.setUpGenerator(getSchemaFieldConfiguration()); + final var messageVal = generator.nextMessage(); + if (Objects.nonNull(messageVal)) { + final var producerRecord = getProducerRecord(messageVal, enrichedValueFlag()); + fillSamplerResult(producerRecord, sampleResult); + final var result = producer.send(producerRecord, (metadata, e) -> { + if (e != null) { + LOG.error("Send failed for record {}", producerRecord, e); + throw new KLoadGenException("Failed to sent message due ", e); + } + }); + fillSampleResult(sampleResult, prettyPrint(result.get()), true); + } else { + LOG.error("Failed to Generate message"); + fillSampleResult(sampleResult, "Failed to Generate message", false); + } + } catch (final KLoadGenException | InterruptedException | ExecutionException e) { + LOG.error("Failed to send message", e); + fillSampleResult(sampleResult, e.getMessage() != null ? e.getMessage() : "", false); + } + + return sampleResult; + } + + @SuppressWarnings("checkstyle:DesignForExtension") + public KafkaProducer getKafkaProducer() { + return new KafkaProducer<>(extractProps()); + } + + public final List getSchemaFieldConfiguration() { + final List propertyList = new ArrayList<>(); + for (TestElementProperty elementProperty : (List) this.getProperty("schemaFieldConfiguration").getObjectValue()) { + propertyList.add(FieldValueMapping + .builder() + .fieldName(elementProperty.getElement().getPropertyAsString("fieldName")) + .fieldType(elementProperty.getElement().getPropertyAsString("fieldType")) + .required(elementProperty.getElement().getPropertyAsBoolean("required", true)) + .valueLength(elementProperty.getElement().getPropertyAsInt("valueLength", 0)) + .fieldValueList(elementProperty.getElement().getPropertyAsString("fieldValuesList")) + .build()); + } + return propertyList; + } + + public final void setSchemaFieldConfiguration(final List asyncApiServerName) { + this.setProperty(new CollectionProperty("schemaFieldConfiguration", asyncApiServerName)); + } + + private ProducerRecord getProducerRecord(final EnrichedRecord messageVal, final boolean valueFlag) { + final ProducerRecord producerRecord; + producerRecord = new ProducerRecord<>(getAsyncApiSchemaName(), getObject(messageVal, valueFlag)); + return producerRecord; + } + + private Boolean enrichedValueFlag() { + return false; + } + + private void fillSamplerResult(final ProducerRecord producerRecord, final SampleResult sampleResult) { + final String result = "key: " + producerRecord.key() + ", payload: " + producerRecord.value(); + sampleResult.setSamplerData(result); + } + + private void fillSampleResult(final SampleResult sampleResult, final String responseData, final boolean successful) { + sampleResult.setResponseData(responseData, StandardCharsets.UTF_8.name()); + sampleResult.setSuccessful(successful); + sampleResult.sampleEnd(); + } + + private String prettyPrint(final RecordMetadata recordMetadata) { + return String.format(TEMPLATE, recordMetadata.topic(), recordMetadata.partition(), recordMetadata.offset()); + } + + private Map extractProps() { + final var properties = new HashMap(); + getBrokerConfiguration().forEach(property -> properties.put(property.getPropertyName(), property.getPropertyValue())); + properties.put(PropsKeysHelper.SCHEMA_KEYED_MESSAGE_KEY, Boolean.FALSE); + properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, GenericJsonRecordSerializer.class.getCanonicalName()); + properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, GenericJsonRecordSerializer.class.getCanonicalName()); + return properties; + } + + public final String getAsyncApiSchemaName() { + return this.getPropertyAsString("asyncapischemaname"); + } + + public final void setAsyncApiSchemaName(final String asyncApiSchemaName) { + this.setProperty("asyncapischemaname", asyncApiSchemaName); + } + + private Object getObject(final EnrichedRecord messageVal, final boolean isKloadSerializer) { + return isKloadSerializer ? messageVal : messageVal.getGenericRecord(); + } + + public final List getBrokerConfiguration() { + final List propertyList = new ArrayList<>(); + for (TestElementProperty elementProperty : (List) this.getProperty("brokerConfiguration").getObjectValue()) { + propertyList.add(PropertyMapping + .builder() + .propertyName(elementProperty.getElement().getPropertyAsString("propertyName")) + .propertyValue(elementProperty.getElement().getPropertyAsString("propertyValue")) + .build()); + } + return propertyList; + } + + public final void setBrokerConfiguration(final List asyncApiServerName) { + this.setProperty(new CollectionProperty("brokerConfiguration", asyncApiServerName)); + } + + public final AsyncApiFile getAsyncApiFileNode() { + AsyncApiFile asyncApiFile = null; + if (Objects.isNull(asyncApiFileNode)) { + try { + asyncApiFileNode = mapper.readTree(this.getPropertyAsString("asyncapifilestr")); + } catch (final IOException e) { + throw new KLoadGenException(e); + } + } + if (Objects.nonNull(asyncApiFileNode) && !asyncApiFileNode.isMissingNode()) { + asyncApiFile = apiExtractor.processNode(asyncApiFileNode); + } + return asyncApiFile; + } + + public final void setAsyncApiFileNode(final JsonNode asyncApiFileNode) { + this.asyncApiFileNode = asyncApiFileNode; + try { + this.setProperty("asyncapifilestr", mapper.writeValueAsString(asyncApiFileNode)); + } catch (final JsonProcessingException e) { + throw new KLoadGenException(e); + } + } + + public final void setAsyncApiServerName(final String asyncApiServerName) { + this.setProperty("asyncApiServerName", asyncApiServerName); + } +} diff --git a/src/main/java/com/sngular/kloadgen/sampler/KafkaProducerSampler.java b/src/main/java/com/sngular/kloadgen/sampler/KafkaProducerSampler.java index fdbd905e..9e649348 100644 --- a/src/main/java/com/sngular/kloadgen/sampler/KafkaProducerSampler.java +++ b/src/main/java/com/sngular/kloadgen/sampler/KafkaProducerSampler.java @@ -193,8 +193,8 @@ private ProducerRecord getProducerRecord(final EnrichedRecord me private void fillSamplerResult(final ProducerRecord producerRecord, final SampleResult sampleResult) { final String result = "key: " - + producerRecord.key() - + ", payload: " + stringValue(producerRecord.value()); + + producerRecord.key() + + ", payload: " + stringValue(producerRecord.value()); sampleResult.setSamplerData(result); } diff --git a/src/main/java/com/sngular/kloadgen/sampler/SamplerUtil.java b/src/main/java/com/sngular/kloadgen/sampler/SamplerUtil.java index 4c25c2d8..2209a858 100644 --- a/src/main/java/com/sngular/kloadgen/sampler/SamplerUtil.java +++ b/src/main/java/com/sngular/kloadgen/sampler/SamplerUtil.java @@ -18,6 +18,8 @@ import java.util.Properties; import java.util.Set; +import javax.validation.constraints.NotNull; + import com.sngular.kloadgen.exception.KLoadGenException; import com.sngular.kloadgen.loadgen.BaseLoadGenerator; import com.sngular.kloadgen.loadgen.impl.AvroSRLoadGenerator; @@ -49,7 +51,6 @@ import org.apache.kafka.common.config.SaslConfigs; import org.apache.kafka.common.config.SslConfigs; import org.apache.kafka.common.security.auth.SecurityProtocol; -import org.jetbrains.annotations.NotNull; public final class SamplerUtil { @@ -395,6 +396,13 @@ public static BaseLoadGenerator configureValueGenerator(final Properties props) } } else { try { + final String schema; + if (ObjectUtils.isEmpty(jMeterVariables.get(PropsKeysHelper.VALUE_SCHEMA))) { + schema = props.getProperty(PropsKeysHelper.VALUE_SCHEMA); + } else { + schema = jMeterVariables.get(PropsKeysHelper.VALUE_SCHEMA); + } + generator.setUpGenerator(schema, (List) jMeterVariables.getObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES)); generator.setUpGenerator(jMeterVariables.get(PropsKeysHelper.VALUE_SCHEMA), (List) jMeterVariables.getObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES)); } catch (final SchemaParseException exc) { generator.setUpGenerator(jMeterVariables.get(PropsKeysHelper.VALUE_SCHEMA), (List) jMeterVariables.getObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES)); diff --git a/src/main/java/com/sngular/kloadgen/sampler/gui/ApiSchemaRenderer.java b/src/main/java/com/sngular/kloadgen/sampler/gui/ApiSchemaRenderer.java new file mode 100644 index 00000000..7449f474 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/sampler/gui/ApiSchemaRenderer.java @@ -0,0 +1,52 @@ +package com.sngular.kloadgen.sampler.gui; + +import java.awt.Color; +import java.awt.Component; +import java.util.Objects; + +import javax.swing.JLabel; +import javax.swing.JList; + +import com.sngular.kloadgen.extractor.model.AsyncApiSchema; + +public class ApiSchemaRenderer extends JLabel implements javax.swing.ListCellRenderer { + + protected ApiSchemaRenderer() { + setOpaque(true); + } + + @Override + public final Component getListCellRendererComponent( + final JList list, final AsyncApiSchema value, final int index, final boolean isSelected, final boolean cellHasFocus) { + if (Objects.nonNull(value)) { + setText(value.getTopicName()); + + final Color background; + final Color foreground; + + // check if this cell represents the current DnD drop location + final JList.DropLocation dropLocation = list.getDropLocation(); + if (dropLocation != null + && !dropLocation.isInsert() + && dropLocation.getIndex() == index) { + + background = Color.BLUE; + foreground = Color.WHITE; + + // check if this cell is selected + } else if (isSelected) { + background = Color.RED; + foreground = Color.WHITE; + + // unselected, and not the DnD drop location + } else { + background = Color.WHITE; + foreground = Color.BLACK; + } + + setBackground(background); + setForeground(foreground); + } + return this; + } +} diff --git a/src/main/java/com/sngular/kloadgen/sampler/gui/ApiServerRenderer.java b/src/main/java/com/sngular/kloadgen/sampler/gui/ApiServerRenderer.java new file mode 100644 index 00000000..11e72a8d --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/sampler/gui/ApiServerRenderer.java @@ -0,0 +1,53 @@ +package com.sngular.kloadgen.sampler.gui; + +import java.awt.Color; +import java.awt.Component; +import java.util.Objects; + +import javax.swing.JLabel; +import javax.swing.JList; + +import com.sngular.kloadgen.extractor.model.AsyncApiServer; + +public class ApiServerRenderer extends JLabel implements javax.swing.ListCellRenderer { + + protected ApiServerRenderer() { + setOpaque(true); + } + + @Override + public final Component getListCellRendererComponent( + final JList list, final AsyncApiServer value, final int index, final boolean isSelected, final boolean cellHasFocus) { + + if (Objects.nonNull(value)) { + setText(value.getName()); + + final Color background; + final Color foreground; + + // check if this cell represents the current DnD drop location + final JList.DropLocation dropLocation = list.getDropLocation(); + if (dropLocation != null + && !dropLocation.isInsert() + && dropLocation.getIndex() == index) { + + background = Color.BLUE; + foreground = Color.WHITE; + + // check if this cell is selected + } else if (isSelected) { + background = Color.RED; + foreground = Color.WHITE; + + // unselected, and not the DnD drop location + } else { + background = Color.WHITE; + foreground = Color.BLACK; + } + + setBackground(background); + setForeground(foreground); + } + return this; + } +} diff --git a/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSRRenderer.java b/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSRRenderer.java new file mode 100644 index 00000000..97bf1392 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSRRenderer.java @@ -0,0 +1,53 @@ +package com.sngular.kloadgen.sampler.gui; + +import java.awt.Color; +import java.awt.Component; +import java.util.Objects; + +import javax.swing.JLabel; +import javax.swing.JList; + +import com.sngular.kloadgen.extractor.model.AsyncApiSR; + +public final class AsyncApiSRRenderer extends JLabel implements javax.swing.ListCellRenderer { + + public AsyncApiSRRenderer() { + setOpaque(true); + } + + @Override + public Component getListCellRendererComponent( + final JList list, final AsyncApiSR value, final int index, final boolean isSelected, final boolean cellHasFocus) { + if (Objects.nonNull(value)) { + setText(value.name()); + + final Color background; + final Color foreground; + + // check if this cell represents the current DnD drop location + final JList.DropLocation dropLocation = list.getDropLocation(); + if (dropLocation != null + && !dropLocation.isInsert() + && dropLocation.getIndex() == index) { + + background = Color.BLUE; + foreground = Color.WHITE; + + // check if this cell is selected + } else if (isSelected) { + background = Color.RED; + foreground = Color.WHITE; + + // unselected, and not the DnD drop location + } else { + background = Color.WHITE; + foreground = Color.BLACK; + } + + setBackground(background); + setForeground(foreground); + } + return this; + } + +} diff --git a/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSamplerGui.java b/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSamplerGui.java new file mode 100644 index 00000000..596e2492 --- /dev/null +++ b/src/main/java/com/sngular/kloadgen/sampler/gui/AsyncApiSamplerGui.java @@ -0,0 +1,401 @@ +/* + * 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/. + */ + +/* + * 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 com.sngular.kloadgen.sampler.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.Vector; + +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.border.TitledBorder; +import javax.swing.filechooser.FileSystemView; +import javax.swing.table.DefaultTableModel; + +import com.sngular.kloadgen.exception.KLoadGenException; +import com.sngular.kloadgen.extractor.ApiExtractor; +import com.sngular.kloadgen.extractor.asyncapi.AsyncApiExtractorImpl; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.extractor.model.AsyncApiSR; +import com.sngular.kloadgen.extractor.model.AsyncApiSchema; +import com.sngular.kloadgen.extractor.model.AsyncApiServer; +import com.sngular.kloadgen.model.FieldValueMapping; +import com.sngular.kloadgen.model.PropertyMapping; +import com.sngular.kloadgen.sampler.AsyncApiSampler; +import com.sngular.kloadgen.sampler.SamplerUtil; +import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.jmeter.config.Argument; +import org.apache.jmeter.samplers.gui.AbstractSamplerGui; +import org.apache.jmeter.testelement.TestElement; +import org.apache.jmeter.testelement.property.JMeterProperty; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.jorphan.gui.JLabeledTextField; +import org.apache.kafka.clients.producer.ProducerConfig; + +@SuppressWarnings("checkstyle:ClassDataAbstractionCoupling") +public final class AsyncApiSamplerGui extends AbstractSamplerGui { + + private final JFileChooser fileChooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory()); + + private final ApiExtractor asyncApiExtractor = new AsyncApiExtractorImpl(); + + private final DefaultTableModel schemaFieldModel = new DefaultTableModel(new String[]{"Field Name", "Field Type", "Field Length", "Required", "Field Values List"}, 20); + + private final DefaultTableModel brokerFieldModel = new DefaultTableModel(new String[]{"Property name", "Property Value"}, 20); + + private final DefaultTableModel schemaRegistryFieldModel = new DefaultTableModel(new String[]{"Property name", "Property Value"}, 20); + + private JPanel mainPanel; + + private JTextField asyncApiFileTextField; + + private JComboBox serverComboBox; + + private JComboBox topicComboBox; + + private AsyncApiFile asyncApiFile; + + public AsyncApiSamplerGui() { + init(); + } + + private static void extractArgument(final JMeterProperty jmeterproperty, final ArrayList> propertyList) { + final var argument = (Argument) jmeterproperty.getObjectValue(); + propertyList.add(Pair.of(argument.getPropertyAsString("Argument.name"), argument.getPropertyAsString("Argument.value"))); + } + + @Override + public String getLabelResource() { + return "Asyncapi"; + } + + @Override + public TestElement createTestElement() { + return new AsyncApiSampler(); + } + + @Override + public void modifyTestElement(final TestElement element) { + super.configureTestElement(element); + if (element instanceof AsyncApiSampler asyncApiSampler) { + if (Objects.nonNull(asyncApiFile)) { + asyncApiSampler.setAsyncApiFileNode(asyncApiFile.getAsyncApiFileNode()); + if (serverComboBox.getItemCount() > 0) { + asyncApiSampler.setAsyncApiServerName(((AsyncApiServer) serverComboBox.getSelectedItem()).getName()); + asyncApiSampler.setBrokerConfiguration(mapVectorConf(brokerFieldModel.getDataVector())); + } + final var selectedSchema = (AsyncApiSchema) topicComboBox.getSelectedItem(); + if (Objects.nonNull(selectedSchema)) { + asyncApiSampler.setAsyncApiSchemaName(selectedSchema.getTopicName()); + asyncApiSampler.setSchemaFieldConfiguration(mapVector(schemaFieldModel.getDataVector())); + } + } + // asyncApiSampler.setAsyncApiRegistry((AsyncApiSR) registryComboBox.getSelectedItem()); + } + configureTestElement(element); + } + + private List mapVectorConf(final Vector dataVector) { + final var mapResult = new ArrayList(); + for (final Vector v : dataVector) { + mapResult.add(PropertyMapping + .builder() + .propertyName(v.get(0).toString()) + .propertyValue(v.get(1).toString()) + .build()); + } + return mapResult; + } + + private List mapVector(final Vector dataVector) { + final var mapResult = new ArrayList(); + for (Vector v : dataVector) { + mapResult.add(FieldValueMapping + .builder() + .fieldName(v.get(0).toString()) + .fieldType(v.get(1).toString()) + .valueLength(Integer.parseInt(v.get(2).toString())) + .fieldValueList(v.get(4).toString()) + .required((Boolean) v.get(3)) + .build()); + } + return mapResult; + } + + @Override + public void configure(final TestElement element) { + super.configure(element); + if (element instanceof AsyncApiSampler) { + asyncApiFile = ((AsyncApiSampler) element).getAsyncApiFileNode(); + if (Objects.nonNull(asyncApiFile)) { + populateData((AsyncApiSampler) element); + } + } + } + + @Override + public void clearGui() { + super.clearGui(); + asyncApiFileTextField.setText(""); + schemaFieldModel.setNumRows(0); + brokerFieldModel.setNumRows(0); + // registryUrl.setText(""); + } + + @Override + public String getStaticLabel() { + return "AsyncApi Sampler"; + } + + private void populateData(final AsyncApiSampler element) { + + serverComboBox.removeAllItems(); + asyncApiFile.getApiServerMap().forEach((name, value) -> serverComboBox.addItem(value)); + serverComboBox.setSelectedIndex(0); + final Collection> propertyList = new ArrayList<>(); + element.getBrokerConfiguration() + .forEach(propertyMapping -> + propertyList.add(Pair.of(propertyMapping.getPropertyName(), propertyMapping.getPropertyValue()))); + fillTable(brokerFieldModel, propertyList); + /*final var schemaRegistryList = asyncApiExtractor.getSchemaRegistryData(asyncApiFile); + if (!schemaRegistryList.isEmpty()) { + fillTable(schemaRegistryFieldModel, prepareSRServer(schemaRegistryList.get(0))); + }*/ + topicComboBox.removeAllItems(); + asyncApiExtractor.getSchemaDataMap(asyncApiFile).values().forEach(topicComboBox::addItem); + topicComboBox.setSelectedIndex(0); + fillTable(schemaFieldModel, element.getSchemaFieldConfiguration()); + } + + private void populateData() { + if (Objects.nonNull(asyncApiFile)) { + asyncApiFile.getApiServerMap().forEach((name, value) -> serverComboBox.addItem(value)); + serverComboBox.setSelectedIndex(0); + fillTable(brokerFieldModel, prepareServer((AsyncApiServer) serverComboBox.getSelectedItem())); + final var schemaRegistryList = asyncApiExtractor.getSchemaRegistryData(asyncApiFile); + if (!schemaRegistryList.isEmpty()) { + fillTable(schemaRegistryFieldModel, prepareSRServer(schemaRegistryList.get(0))); + } + asyncApiExtractor.getSchemaDataMap(asyncApiFile).values().forEach(topicComboBox::addItem); + topicComboBox.setSelectedIndex(0); + } + } + + private void fillTable(final DefaultTableModel schemaFields, final Collection> schemaData) { + if (Objects.nonNull(schemaData)) { + final var count = schemaFields.getRowCount(); + for (var i = 0; i < count; i++) { + schemaFields.removeRow(0); + } + schemaData.forEach(data -> schemaFields.addRow(dataToRow(data))); + } + } + + private void fillTable(final DefaultTableModel schemaFields, final List schemaData) { + if (Objects.nonNull(schemaData)) { + final var count = schemaFields.getRowCount(); + for (var i = 0; i < count; i++) { + schemaFields.removeRow(0); + } + for (var data : schemaData) { + schemaFields.addRow(data.getProperties()); + } + } + } + + private void fillTable(final DefaultTableModel schemaFields, final Object[] schemaData) { + if (Objects.nonNull(schemaData)) { + final var count = schemaFields.getRowCount(); + for (var i = 0; i < count; i++) { + schemaFields.removeRow(0); + } + for (var data : schemaData) { + schemaFields.addRow(((FieldValueMapping) data).getProperties()); + } + } + } + + private Object[] dataToRow(final Pair data) { + return new Object[]{data.getKey(), data.getValue()}; + } + + private void actionFileChooser(final ActionEvent event) { + + final int returnValue = fileChooser.showDialog(mainPanel, JMeterUtils.getResString("file_visualizer_open")); + + if (JFileChooser.APPROVE_OPTION == returnValue) { + try { + final File apiFile = Objects.requireNonNull(fileChooser.getSelectedFile()); + asyncApiFileTextField.setText(apiFile.getAbsolutePath()); + asyncApiFile = asyncApiExtractor.processFile(apiFile); + populateData(); + } catch (final KLoadGenException ex) { + JOptionPane.showMessageDialog(mainPanel, "Error has occurred: " + ex.getMessage(), "Weird Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + private Collection> prepareSRServer(final AsyncApiSR schemaRegistryData) { + final var srPropoMap = schemaRegistryData.getPropertiesMap(); + final var propertyList = new ArrayList>(); + propertyList.add(Pair.of(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_URL, srPropoMap.get("url"))); + propertyList.add(Pair.of(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, srPropoMap.get("type"))); + DefaultPropertiesHelper.DEFAULTS.forEach(jmeterproperty -> propertyList.add(Pair.of(jmeterproperty.getName(), jmeterproperty.getPropertyValue()))); + return propertyList; + } + + private Collection> prepareServer(final AsyncApiServer asyncApiServer) { + final var propertyList = new ArrayList>(); + if (Objects.nonNull(asyncApiServer)) { + final var serverProps = asyncApiServer.getPropertiesMap(); + propertyList.add(Pair.of(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, serverProps.get("url"))); + CollectionUtils.select(SamplerUtil + .getCommonDefaultParameters(), + property -> !property.getName().equalsIgnoreCase(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG)) + .forEach(jmeterproperty -> extractArgument(jmeterproperty, propertyList)); + } + return propertyList; + } + + private void init() { + setLayout(new BorderLayout()); + setBorder(makeBorder()); + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.putClientProperty("html.disable", Boolean.FALSE); + mainPanel.setBorder( + BorderFactory + .createTitledBorder(BorderFactory.createLoweredBevelBorder(), "AsyncApi Module", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null)); + + mainPanel.add(createAsyncApiFileSelectPanel(), BorderLayout.NORTH); + mainPanel.add(createAsyncApiTabs(), BorderLayout.CENTER); + add(mainPanel); + } + + private JPanel createAsyncApiFileSelectPanel() { + final JPanel fileChoosingPanel = new JPanel(); + fileChoosingPanel.setLayout(new GridBagLayout()); + fileChoosingPanel.setName("AsyncApi File"); + gridEstablish(0, 0, 0.03, GridBagConstraints.BOTH, -1); + asyncApiFileTextField = new JTextField(); + asyncApiFileTextField.setPreferredSize(new Dimension(249, 30)); + asyncApiFileTextField.setText(""); + fileChoosingPanel.add(asyncApiFileTextField, gridEstablish(1, 0, -1, GridBagConstraints.HORIZONTAL, GridBagConstraints.WEST)); + final JButton fileButton = new JButton(); + fileButton.setText("Open File"); + fileButton.addActionListener(this::actionFileChooser); + fileChoosingPanel.add(fileButton, gridEstablish(2, 0, -1, GridBagConstraints.HORIZONTAL, -1)); + final JLabel label1 = new JLabel(); + label1.setText("AsyncApi File"); + fileChoosingPanel.add(label1, gridEstablish(0, 0, -1, -1, GridBagConstraints.WEST)); + return fileChoosingPanel; + } + + private GridBagConstraints gridEstablish(final int x, final int y, final double w, final int fill, final int anchor) { + final var gridBagConstraints = new GridBagConstraints(); + gridBagConstraints.gridx = x; + gridBagConstraints.gridy = y; + if (w != -1) { + gridBagConstraints.weighty = w; + } + if (fill != -1) { + gridBagConstraints.fill = fill; + } + if (anchor != -1) { + gridBagConstraints.anchor = anchor; + } + return gridBagConstraints; + } + + private JTabbedPane createAsyncApiTabs() { + final var tabbedPanel = new JTabbedPane(); + tabbedPanel.addTab("Broker", createBrokerPanel()); + // tabbedPanel.addTab("Registry", createRegistryTab()); + tabbedPanel.addTab("Schema", createSchemaTab()); + return tabbedPanel; + } + + private JPanel createBrokerPanel() { + final JPanel brokerPanel = new JPanel(); + brokerPanel.setLayout(new BorderLayout(0, 0)); + brokerPanel.add(new JLabeledTextField("Broker Server")); + serverComboBox = new JComboBox<>(); + serverComboBox.setRenderer(new ApiServerRenderer()); + serverComboBox.addActionListener(this::serverChooseActionListener); + brokerPanel.add(serverComboBox, BorderLayout.NORTH); + brokerPanel.add(new JScrollPane(new JTable(brokerFieldModel)), BorderLayout.CENTER); + return brokerPanel; + } + + private JPanel createRegistryTab() { + final JPanel registryUrlPanel = new JPanel(); + registryUrlPanel.setLayout(new BorderLayout(0, 0)); + registryUrlPanel.add(new JLabeledTextField("Schema Registry URL")); + final JComboBox registryComboBox = new JComboBox<>(); + registryComboBox.setRenderer(new AsyncApiSRRenderer()); + registryComboBox.addActionListener(this::registryComboActionListener); + registryUrlPanel.add(registryComboBox, BorderLayout.NORTH); + registryUrlPanel.add(new JScrollPane(new JTable(schemaRegistryFieldModel)), BorderLayout.CENTER); + return registryUrlPanel; + } + + private void registryComboActionListener(final ActionEvent actionEvent) { + } + + private JPanel createSchemaTab() { + final JPanel schemaTab = new JPanel(); + schemaTab.setLayout(new BorderLayout(0, 0)); + schemaTab.add(new JLabeledTextField("Schema Configuration")); + topicComboBox = new JComboBox<>(); + topicComboBox.setRenderer(new ApiSchemaRenderer()); + topicComboBox.addActionListener(this::topicComboActionListener); + schemaTab.add(topicComboBox, BorderLayout.NORTH); + final var schemaTable = new JTable(schemaFieldModel); + schemaTab.add(new JScrollPane(schemaTable), BorderLayout.CENTER); + return schemaTab; + } + + private void topicComboActionListener(final ActionEvent event) { + final JComboBox cb = (JComboBox) event.getSource(); + final var selectedSchema = (AsyncApiSchema) cb.getSelectedItem(); + if (Objects.nonNull(selectedSchema)) { + fillTable(schemaFieldModel, selectedSchema.getProperties()); + } + } + + private void serverChooseActionListener(final ActionEvent actionEvent) { + final JComboBox serverChoose = (JComboBox) actionEvent.getSource(); + if (Objects.nonNull(serverChoose)) { + fillTable(brokerFieldModel, prepareServer((AsyncApiServer) serverChoose.getSelectedItem())); + } + } +} diff --git a/src/main/java/com/sngular/kloadgen/config/schemaregistry/DefaultPropertiesHelper.java b/src/main/java/com/sngular/kloadgen/sampler/gui/DefaultPropertiesHelper.java similarity index 93% rename from src/main/java/com/sngular/kloadgen/config/schemaregistry/DefaultPropertiesHelper.java rename to src/main/java/com/sngular/kloadgen/sampler/gui/DefaultPropertiesHelper.java index e977d8ff..6d02fa00 100644 --- a/src/main/java/com/sngular/kloadgen/config/schemaregistry/DefaultPropertiesHelper.java +++ b/src/main/java/com/sngular/kloadgen/sampler/gui/DefaultPropertiesHelper.java @@ -4,7 +4,7 @@ * * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -package com.sngular.kloadgen.config.schemaregistry; +package com.sngular.kloadgen.sampler.gui; import java.util.ArrayList; import java.util.Arrays; @@ -14,9 +14,9 @@ import com.sngular.kloadgen.util.ProducerKeysHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; -class DefaultPropertiesHelper { +public class DefaultPropertiesHelper { - protected static final List DEFAULTS = new ArrayList<>(Arrays.asList( + public static final List DEFAULTS = new ArrayList<>(Arrays.asList( PropertyMapping.builder().propertyName(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_AUTH_FLAG).propertyValue(ProducerKeysHelper.FLAG_NO).build(), PropertyMapping.builder().propertyName(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_AUTH_KEY).propertyValue(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_AUTH_BASIC_TYPE).build(), PropertyMapping.builder().propertyName(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_USERNAME_KEY).propertyValue(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_USERNAME_DEFAULT).build(), @@ -32,6 +32,7 @@ class DefaultPropertiesHelper { PropertyMapping.builder().propertyName(SchemaRegistryKeyHelper.SSL_TRUSTSTORE_LOCATION_KEY).propertyValue("").build(), PropertyMapping.builder().propertyName(SchemaRegistryKeyHelper.SSL_TRUSTSTORE_PASSWORD_KEY).propertyValue("").build() )); + private DefaultPropertiesHelper() { } diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/SchemaRegistryAdapter.java b/src/main/java/com/sngular/kloadgen/schemaregistry/SchemaRegistryAdapter.java index 17571aa5..e478ca25 100644 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/SchemaRegistryAdapter.java +++ b/src/main/java/com/sngular/kloadgen/schemaregistry/SchemaRegistryAdapter.java @@ -3,7 +3,7 @@ import java.util.Collection; import java.util.Map; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; @@ -17,9 +17,9 @@ public interface SchemaRegistryAdapter { Collection getAllSubjects(); - BaseSchemaMetadata getLatestSchemaMetadata(String subjectName); + BaseSchemaMetadata getLatestSchemaMetadata(String subjectName); - BaseParsedSchema getSchemaBySubject(String subjectName); + AbstractParsedSchema getSchemaBySubject(String subjectName); - BaseParsedSchema getSchemaBySubjectAndId(String subjectName, BaseSchemaMetadata metadata); + AbstractParsedSchema getSchemaBySubjectAndId(String subjectName, BaseSchemaMetadata metadata); } diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/AbstractParsedSchemaAdapter.java b/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/AbstractParsedSchemaAdapter.java deleted file mode 100644 index 527f6ee4..00000000 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/AbstractParsedSchemaAdapter.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.sngular.kloadgen.schemaregistry.adapter.impl; - -public abstract class AbstractParsedSchemaAdapter { - - public abstract T getType(); - - public abstract T getRawSchema(); -} diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ApicurioAbstractParsedSchemaMetadata.java b/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ApicurioAbstractParsedSchemaMetadata.java deleted file mode 100644 index c5015fc7..00000000 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ApicurioAbstractParsedSchemaMetadata.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.sngular.kloadgen.schemaregistry.adapter.impl; - -import com.sngular.kloadgen.parsedschema.ParsedSchema; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Getter -@Setter -@NoArgsConstructor -public class ApicurioAbstractParsedSchemaMetadata extends AbstractParsedSchemaAdapter { - - private Object schema; - - private String rawSchema; - - private String type; - - public ApicurioAbstractParsedSchemaMetadata(final ParsedSchema parsedSchema) { - this.rawSchema = parsedSchema.canonicalString(); - this.type = parsedSchema.schemaType(); - this.schema = parsedSchema.rawSchema(); - } - - public static AbstractParsedSchemaAdapter parse(final ParsedSchema parsedSchema) { - return new ApicurioAbstractParsedSchemaMetadata(parsedSchema); - } -} diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/BaseParsedSchema.java b/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/BaseParsedSchema.java deleted file mode 100644 index 407c1339..00000000 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/BaseParsedSchema.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.sngular.kloadgen.schemaregistry.adapter.impl; - -import org.apache.avro.Schema.Parser; - -public class BaseParsedSchema extends Parser { - - private final T parsedSchemaAdapter; - - public BaseParsedSchema(final T parsedSchemaAdapter) { - this.parsedSchemaAdapter = parsedSchemaAdapter; - } - - public final T getParsedSchemaAdapter() { - return parsedSchemaAdapter; - } -} diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ConfluentAbstractParsedSchemaMetadata.java b/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ConfluentAbstractParsedSchemaMetadata.java deleted file mode 100644 index deb79876..00000000 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/adapter/impl/ConfluentAbstractParsedSchemaMetadata.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.sngular.kloadgen.schemaregistry.adapter.impl; - -import com.sngular.kloadgen.parsedschema.IParsedSchema; -import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchema; -import lombok.Getter; -import org.apache.avro.Schema; - -@Getter -public final class ConfluentAbstractParsedSchemaMetadata extends AbstractParsedSchemaAdapter { - - private final String schemaType; - - private final String name; - - private String canonicalString; - - private Object rawSchema; - - private ConfluentAbstractParsedSchemaMetadata(final IParsedSchema parsedSchema) { - this.schemaType = parsedSchema.schemaType(); - this.name = parsedSchema.name(); - this.canonicalString = parsedSchema.canonicalString(); - this.rawSchema = parsedSchema.rawSchema(); - } - - private ConfluentAbstractParsedSchemaMetadata(final Schema schema) { - this.schemaType = schema.getType().getName(); - this.name = schema.getName(); - } - - public ConfluentAbstractParsedSchemaMetadata(final ProtobufSchema schema) { - this.schemaType = schema.schemaType(); - this.name = schema.name(); - this.rawSchema = schema.rawSchema(); - this.canonicalString = schema.canonicalString(); - } - - public static AbstractParsedSchemaAdapter parse(final IParsedSchema parsedSchema) { - return new ConfluentAbstractParsedSchemaMetadata(parsedSchema); - } - - public static AbstractParsedSchemaAdapter parse(final Schema schema) { - return new ConfluentAbstractParsedSchemaMetadata(schema); - } - - public static AbstractParsedSchemaAdapter parse(final ProtobufSchema schema) { - return new ConfluentAbstractParsedSchemaMetadata(schema); - } - - @Override - public String getType() { - return this.schemaType; - } - - @Override - public Object getRawSchema() { - return this.rawSchema; - } -} diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ApicurioSchemaRegistry.java b/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ApicurioSchemaRegistry.java index ad990e80..2e5a7a0b 100644 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ApicurioSchemaRegistry.java +++ b/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ApicurioSchemaRegistry.java @@ -12,10 +12,12 @@ import com.google.protobuf.Message; import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.exception.KLoadGenException; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; +import com.sngular.kloadgen.parsedschema.JsonParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.schemaregistry.SchemaRegistryAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ApicurioAbstractParsedSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ApicurioSchemaMetadata; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; import io.apicurio.registry.resolver.SchemaParser; @@ -80,56 +82,46 @@ public BaseSchemaMetadata getLatestSchemaMetadata(final } @Override - public BaseParsedSchema getSchemaBySubject(final String artifactId) { - final ApicurioAbstractParsedSchemaMetadata schema = new ApicurioAbstractParsedSchemaMetadata(); + public AbstractParsedSchema getSchemaBySubject(final String artifactId) { try { final SearchedArtifact searchedArtifact = getLastestSearchedArtifact(artifactId); final InputStream inputStream = this.schemaRegistryClient.getLatestArtifact(searchedArtifact.getGroupId(), searchedArtifact.getId()); - final String searchedArtifactType = searchedArtifact.getType(); - setSchemaBySchemaType(schema, inputStream.readAllBytes(), searchedArtifactType); - schema.setType(searchedArtifactType); - return new BaseParsedSchema<>(schema); + return extractSchema(inputStream.readAllBytes(), searchedArtifact); } catch (final IOException e) { throw new KLoadGenException(e); } } - private static void setSchemaBySchemaType(final ApicurioAbstractParsedSchemaMetadata schema, final byte[] result, final String searchedArtifactType) { - - switch (SchemaTypeEnum.valueOf(searchedArtifactType)) { - case AVRO: - final SchemaParser parserAvro = new AvroSchemaParser<>(null); - schema.setSchema(parserAvro.parseSchema(result, new HashMap<>())); - break; - case PROTOBUF: - final SchemaParser parserProtobuf = new ProtobufSchemaParser<>(); - schema.setSchema(parserProtobuf.parseSchema(result, new HashMap<>())); - break; - case JSON: - final SchemaParser parserJson = new JsonSchemaParser<>(); - schema.setSchema(parserJson.parseSchema(result, new HashMap<>())); - break; - default: - throw new KLoadGenException(String.format("Schema type not supported %s", searchedArtifactType)); - - } - } - @Override - public final BaseParsedSchema getSchemaBySubjectAndId( - final String subjectName, final BaseSchemaMetadata metadata) { - final ApicurioAbstractParsedSchemaMetadata schema = new ApicurioAbstractParsedSchemaMetadata(); - + public AbstractParsedSchema getSchemaBySubjectAndId(final String subjectName, final BaseSchemaMetadata metadata) { final SchemaMetadataAdapter schemaMetadataAdapter = metadata.getSchemaMetadataAdapter(); try { final InputStream inputStream = this.schemaRegistryClient.getContentByGlobalId(schemaMetadataAdapter.getGlobalId()); - - final String searchedArtifactType = schemaMetadataAdapter.getType(); - setSchemaBySchemaType(schema, inputStream.readAllBytes(), searchedArtifactType); + return extractSchema(inputStream.readAllBytes(), subjectName, schemaMetadataAdapter.getType()); } catch (final IOException e) { throw new RuntimeException(e); } - return new BaseParsedSchema<>(schema); + } + + private AbstractParsedSchema extractSchema(final byte[] schema, final SearchedArtifact searchedArtifact) { + return extractSchema(schema, searchedArtifact.getName(), searchedArtifact.getType()); + } + + private AbstractParsedSchema extractSchema(final byte[] schemaInputStream, final String schemaName, final String schemaType) { + return switch (SchemaTypeEnum.valueOf(schemaType)) { + case AVRO -> { + final SchemaParser parserAvro = new AvroSchemaParser<>(null); + yield new AvroParsedSchema(schemaName, parserAvro.parseSchema(schemaInputStream, new HashMap<>())); + } + case PROTOBUF -> { + final SchemaParser parserProtobuf = new ProtobufSchemaParser<>(); + yield new ProtobufParsedSchema(schemaName, parserProtobuf.parseSchema(schemaInputStream, new HashMap<>()).getProtoFileElement()); + } + case JSON -> { + final SchemaParser parserJson = new JsonSchemaParser<>(); + yield new JsonParsedSchema(schemaName, parserJson.parseSchema(schemaInputStream, new HashMap<>()).toString()); + } + }; } private SearchedArtifact getLastestSearchedArtifact(final String artifactId) { diff --git a/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ConfluentSchemaRegistry.java b/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ConfluentSchemaRegistry.java index fd36e771..a88bf1e0 100644 --- a/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ConfluentSchemaRegistry.java +++ b/src/main/java/com/sngular/kloadgen/schemaregistry/impl/ConfluentSchemaRegistry.java @@ -6,15 +6,18 @@ import java.util.List; import java.util.Map; +import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.exception.KLoadGenException; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; +import com.sngular.kloadgen.parsedschema.JsonParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.schemaregistry.SchemaRegistryAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.AbstractParsedSchemaAdapter; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentAbstractParsedSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.SchemaMetadataAdapter; +import com.squareup.wire.schema.internal.parser.ProtoFileElement; +import io.confluent.kafka.schemaregistry.ParsedSchema; import io.confluent.kafka.schemaregistry.avro.AvroSchemaProvider; import io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient; import io.confluent.kafka.schemaregistry.client.SchemaRegistryClient; @@ -23,6 +26,7 @@ import io.confluent.kafka.schemaregistry.protobuf.ProtobufSchemaProvider; import io.confluent.kafka.serializers.AbstractKafkaSchemaSerDeConfig; import lombok.extern.slf4j.Slf4j; +import org.apache.avro.Schema; import org.apache.jmeter.threads.JMeterContextService; @Slf4j @@ -68,28 +72,35 @@ public BaseSchemaMetadata getLatestSchemaMetadata(final } } - public BaseParsedSchema getSchemaBySubject(final String subjectName) { + public AbstractParsedSchema getSchemaBySubject(final String subjectName) { try { final ConfluentSchemaMetadata schemaMetadata = ConfluentSchemaMetadata.parse(this.schemaRegistryClient.getLatestSchemaMetadata(subjectName)); - final ParsedSchema parsedSchema = new ParsedSchema(this.schemaRegistryClient.getSchemaBySubjectAndId(subjectName, schemaMetadata.getId())); - final AbstractParsedSchemaAdapter abstractParsedSchemaAdapter = ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema); - return new BaseParsedSchema(abstractParsedSchemaAdapter); + final var parsedSchema = this.schemaRegistryClient.getSchemaBySubjectAndId(subjectName, schemaMetadata.getId()); + return extractSchema(parsedSchema, subjectName, schemaMetadata.getSchemaType()); } catch (RestClientException | IOException e) { throw new KLoadGenException(e.getMessage()); } } - public BaseParsedSchema getSchemaBySubjectAndId(final String subjectName, + public AbstractParsedSchema getSchemaBySubjectAndId(final String subjectName, final BaseSchemaMetadata metadata) { + final SchemaMetadataAdapter schemaMetadataAdapter = metadata.getSchemaMetadataAdapter(); try { - final ParsedSchema parsedSchema = new ParsedSchema(this.schemaRegistryClient.getSchemaBySubjectAndId(subjectName, metadata.getSchemaMetadataAdapter().getId())); - final AbstractParsedSchemaAdapter abstractParsedSchemaAdapter = ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema); - return new BaseParsedSchema(abstractParsedSchemaAdapter); - } catch (RestClientException | IOException e) { - throw new KLoadGenException(e.getMessage()); + final var parsedSchema = this.schemaRegistryClient.getSchemaBySubjectAndId(subjectName, schemaMetadataAdapter.getGlobalId()); + return extractSchema(parsedSchema, subjectName, schemaMetadataAdapter.getType()); + } catch (final IOException | RestClientException e) { + throw new KLoadGenException(e); } } + private AbstractParsedSchema extractSchema(final ParsedSchema parsedSchema, final String schemaName, final String schemaType) { + return switch (SchemaTypeEnum.valueOf(schemaType)) { + case AVRO -> new AvroParsedSchema(schemaName, (Schema) parsedSchema.rawSchema()); + case PROTOBUF -> new ProtobufParsedSchema(schemaName, (ProtoFileElement) parsedSchema.rawSchema()); + case JSON -> new JsonParsedSchema(schemaName, parsedSchema.rawSchema().toString()); + }; + } + private String checkPropertyOrVariable(final String textToCheck) { final String result; if (textToCheck.matches("\\$\\{__P\\(.*\\)}")) { diff --git a/src/main/java/com/sngular/kloadgen/serializer/AvroSerializersUtil.java b/src/main/java/com/sngular/kloadgen/serializer/AvroSerializersUtil.java index c6bb437a..3b9d5748 100644 --- a/src/main/java/com/sngular/kloadgen/serializer/AvroSerializersUtil.java +++ b/src/main/java/com/sngular/kloadgen/serializer/AvroSerializersUtil.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.serializer; import org.apache.avro.Conversions; diff --git a/src/main/java/com/sngular/kloadgen/serializer/ProtobufSerializer.java b/src/main/java/com/sngular/kloadgen/serializer/ProtobufSerializer.java index 18a264cd..c50f0fe7 100644 --- a/src/main/java/com/sngular/kloadgen/serializer/ProtobufSerializer.java +++ b/src/main/java/com/sngular/kloadgen/serializer/ProtobufSerializer.java @@ -22,6 +22,7 @@ import org.apache.kafka.common.header.Headers; import org.apache.kafka.common.serialization.Serializer; + @Slf4j public class ProtobufSerializer implements Serializer { diff --git a/src/main/java/com/sngular/kloadgen/util/JMeterHelper.java b/src/main/java/com/sngular/kloadgen/util/JMeterHelper.java index 0115fb62..0d386e04 100644 --- a/src/main/java/com/sngular/kloadgen/util/JMeterHelper.java +++ b/src/main/java/com/sngular/kloadgen/util/JMeterHelper.java @@ -8,9 +8,9 @@ import java.util.Properties; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; import com.sngular.kloadgen.schemaregistry.SchemaRegistryAdapter; import com.sngular.kloadgen.schemaregistry.SchemaRegistryManagerFactory; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.jmeter.threads.JMeterContextService; @@ -22,7 +22,7 @@ public final class JMeterHelper { private JMeterHelper() { } - public static BaseParsedSchema getParsedSchema(final String subjectName, final Properties properties) { + public static AbstractParsedSchema getParsedSchema(final String subjectName, final Properties properties) { String schemaRegistryName = properties.getProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME); if (schemaRegistryName == null || StringUtils.isEmpty(schemaRegistryName)) { schemaRegistryName = SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME_DEFAULT; diff --git a/src/main/java/com/sngular/kloadgen/util/ProtobufHelper.java b/src/main/java/com/sngular/kloadgen/util/ProtobufHelper.java index 24e28715..e37dc563 100644 --- a/src/main/java/com/sngular/kloadgen/util/ProtobufHelper.java +++ b/src/main/java/com/sngular/kloadgen/util/ProtobufHelper.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.util; import java.util.Map; diff --git a/src/main/resources/com/sngular/kloadgen/sampler/AsyncApiSamplerResources.properties b/src/main/resources/com/sngular/kloadgen/sampler/AsyncApiSamplerResources.properties new file mode 100644 index 00000000..972891dd --- /dev/null +++ b/src/main/resources/com/sngular/kloadgen/sampler/AsyncApiSamplerResources.properties @@ -0,0 +1 @@ +async_api_sampler=AsyncApi Sampler \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElementBeanInfoTest.java b/src/test/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElementBeanInfoTest.java index a950dd82..7a23f9bb 100644 --- a/src/test/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElementBeanInfoTest.java +++ b/src/test/java/com/sngular/kloadgen/config/kafkaheaders/KafkaHeadersConfigElementBeanInfoTest.java @@ -9,16 +9,21 @@ import java.beans.PropertyDescriptor; import java.util.Locale; +import lombok.extern.slf4j.Slf4j; import org.apache.jmeter.util.JMeterUtils; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +@Slf4j class KafkaHeadersConfigElementBeanInfoTest { private static final String KAFKA_HEADERS = "kafkaHeaders"; + private static final String PROPERTIES = "props"; + private static final String SCHEMA = "schema"; + private KafkaHeadersConfigElementBeanInfo kafkaHeadersConfigElementBeanInfo; @BeforeEach diff --git a/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementBeanInfoTest.java b/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementBeanInfoTest.java index a9057b4c..07d2501d 100644 --- a/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementBeanInfoTest.java +++ b/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementBeanInfoTest.java @@ -25,7 +25,9 @@ class KeySerializedConfigElementBeanInfoTest { private static final String KEY_NAME_STRATEGY = "keyNameStrategy"; private static final String KEY_SERIALIZER_CONFIGURATION = "keySerializerConfiguration"; + private static final String PROPERTIES = "props"; + private static final String SCHEMA = "schema"; private KeySerializedConfigElementBeanInfo keySerializedConfigElementBeanInfo; diff --git a/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementTest.java b/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementTest.java index d8759db7..9d2c9264 100644 --- a/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementTest.java +++ b/src/test/java/com/sngular/kloadgen/config/keyserialized/KeySerializedConfigElementTest.java @@ -47,7 +47,7 @@ void iterationStart(final WireMockRuntimeInfo wmRuntimeInfo) { JMeterContextService.getContext().getProperties().put(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_PASSWORD_KEY, "foo"); final var keySerializedConfigElement = new KeySerializedConfigElement("avroSubject", Collections.emptyList(), "AVRO", - AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); + AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); keySerializedConfigElement.iterationStart(null); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.KEY_SUBJECT_NAME)).isNotNull(); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.KEY_SCHEMA_PROPERTIES)).isNotNull(); diff --git a/src/test/java/com/sngular/kloadgen/config/keysimple/KeySimpleConfigElementTest.java b/src/test/java/com/sngular/kloadgen/config/keysimple/KeySimpleConfigElementTest.java index c50f9640..37886ce0 100644 --- a/src/test/java/com/sngular/kloadgen/config/keysimple/KeySimpleConfigElementTest.java +++ b/src/test/java/com/sngular/kloadgen/config/keysimple/KeySimpleConfigElementTest.java @@ -50,9 +50,9 @@ void iterationStart() { Assertions.assertThat(variables.entrySet()) .hasSize(4) .containsExactlyInAnyOrder(new SimpleEntry<>("key.type", "string"), - new SimpleEntry<>("key.value", ""), - new SimpleEntry<>("key.serializer.class.property", "org.apache.kafka.common.serialization.StringSerializer"), - new SimpleEntry<>("simple.keyed.message", true)); + new SimpleEntry<>("key.value", ""), + new SimpleEntry<>("key.serializer.class.property", "org.apache.kafka.common.serialization.StringSerializer"), + new SimpleEntry<>("simple.keyed.message", true)); } } \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/config/valuefileserialized/ValueFileSerializedConfigElementTest.java b/src/test/java/com/sngular/kloadgen/config/valuefileserialized/ValueFileSerializedConfigElementTest.java index 70565aa7..bca47f88 100644 --- a/src/test/java/com/sngular/kloadgen/config/valuefileserialized/ValueFileSerializedConfigElementTest.java +++ b/src/test/java/com/sngular/kloadgen/config/valuefileserialized/ValueFileSerializedConfigElementTest.java @@ -41,7 +41,7 @@ void iterationStart() { + ".topic.value\"}"; final var valueFileSerializedConfigElement = new ValueFileSerializedConfigElement("avroSubject", Collections.emptyList(), definitionSchema, "AVRO", - AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); + AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); valueFileSerializedConfigElement.iterationStart(null); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.VALUE_SUBJECT_NAME)).isNotNull(); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES)).isNotNull(); diff --git a/src/test/java/com/sngular/kloadgen/config/valueserialized/ValueSerializedConfigElementTest.java b/src/test/java/com/sngular/kloadgen/config/valueserialized/ValueSerializedConfigElementTest.java index adc5af03..a0cb544d 100644 --- a/src/test/java/com/sngular/kloadgen/config/valueserialized/ValueSerializedConfigElementTest.java +++ b/src/test/java/com/sngular/kloadgen/config/valueserialized/ValueSerializedConfigElementTest.java @@ -39,7 +39,7 @@ public void setUp() { void iterationStart() { final var valueSerializedConfigElement = new ValueSerializedConfigElement("avroSubject", Collections.emptyList(), "AVRO", - AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); + AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); valueSerializedConfigElement.iterationStart(null); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.VALUE_SUBJECT_NAME)).isNotNull(); Assertions.assertThat(JMeterContextService.getContext().getVariables().getObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES)).isNotNull(); diff --git a/src/test/java/com/sngular/kloadgen/config/valuesimple/ValueSimpleConfigElementTest.java b/src/test/java/com/sngular/kloadgen/config/valuesimple/ValueSimpleConfigElementTest.java index 46ea8c60..2ca37a19 100644 --- a/src/test/java/com/sngular/kloadgen/config/valuesimple/ValueSimpleConfigElementTest.java +++ b/src/test/java/com/sngular/kloadgen/config/valuesimple/ValueSimpleConfigElementTest.java @@ -19,7 +19,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; - class ValueSimpleConfigElementTest { private JMeterContext jmcx; @@ -53,6 +52,6 @@ void iterationStart() { .containsExactlyInAnyOrder(new SimpleEntry<>("message.value", "data"), new SimpleEntry<>("message.type", "String"), new SimpleEntry<>("value.schema.type", "NoSchema"), - new SimpleEntry<>("value.serializer.class.property", "org.apache.kafka.common.serialization.StringSerializer")); + new SimpleEntry<>("value.serializer.class.property", "org.apache.kafka.common.serialization.StringSerializer")); } } \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/extractor/FakeParsedSchema.java b/src/test/java/com/sngular/kloadgen/extractor/FakeParsedSchema.java new file mode 100644 index 00000000..ff76c5a4 --- /dev/null +++ b/src/test/java/com/sngular/kloadgen/extractor/FakeParsedSchema.java @@ -0,0 +1,21 @@ +/* + * 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 com.sngular.kloadgen.extractor; + +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; + +public class FakeParsedSchema extends AbstractParsedSchema { + + public FakeParsedSchema(final String name, final String type, final String schema) { + super(name, type, schema); + } + + @Override + public final String getRawSchema() { + return getSchema(); + } +} diff --git a/src/test/java/com/sngular/kloadgen/extractor/SchemaExtractorTest.java b/src/test/java/com/sngular/kloadgen/extractor/SchemaExtractorTest.java index f08661c3..a9401ddc 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/SchemaExtractorTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/SchemaExtractorTest.java @@ -13,14 +13,15 @@ import com.sngular.kloadgen.common.SchemaRegistryEnum; import com.sngular.kloadgen.exception.KLoadGenException; -import com.sngular.kloadgen.parsedschema.ParsedSchema; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ApicurioAbstractParsedSchemaMetadata; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentAbstractParsedSchemaMetadata; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; +import com.sngular.kloadgen.parsedschema.JsonParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.testutil.FileHelper; -import com.sngular.kloadgen.testutil.ParsedSchemaUtil; import com.sngular.kloadgen.util.JMeterHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; +import com.squareup.wire.schema.Location; +import com.squareup.wire.schema.internal.parser.ProtoParser; +import org.apache.avro.Schema; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterContextService; import org.apache.jmeter.threads.JMeterVariables; @@ -73,9 +74,8 @@ void testFlatPropertiesListWithAVRO() throws IOException { final File testFile = fileHelper.getFile("/avro-files/embedded-avros-example-test.avsc"); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.APICURIO.toString()); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); - final var baseParsedSchema = new BaseParsedSchema<>(ApicurioAbstractParsedSchemaMetadata.parse(parsedSchema)); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + final var parsedSchema = new AvroParsedSchema("test", new Schema.Parser().parse(testFile)); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); final var result = SchemaExtractor.flatPropertiesList("avroSubject"); @@ -86,13 +86,12 @@ void testFlatPropertiesListWithAVRO() throws IOException { @DisplayName("Test flatPropertiesList with Json") void testFlatPropertiesListWithJson() throws IOException { - final File testFile = fileHelper.getFile("/jsonschema/basic.jcs"); + final var testFile = fileHelper.getContent("/jsonschema/basic.jcs"); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.CONFLUENT.toString()); - final var parsedSchema = new ParsedSchema(testFile, "JSON"); - final var baseParsedSchema = new BaseParsedSchema<>(ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema)); + final var parsedSchema = new JsonParsedSchema("JSON", testFile); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); final var result = SchemaExtractor.flatPropertiesList("jsonSubject"); Assertions.assertThat(result).isNotNull(); @@ -102,13 +101,12 @@ void testFlatPropertiesListWithJson() throws IOException { @DisplayName("Test flatPropertiesList with Protobuf") void testFlatPropertiesListWithProtobuf() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/easyTest.proto"); + final var testFile = fileHelper.getContent("/proto-files/easyTest.proto"); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.CONFLUENT.toString()); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "PROTOBUF"); - final BaseParsedSchema baseParsedSchema = new BaseParsedSchema<>(ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema)); + final var parsedSchema = new ProtobufParsedSchema("test", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); final var result = SchemaExtractor.flatPropertiesList("protobufSubject"); Assertions.assertThat(result).isNotNull(); } @@ -126,13 +124,12 @@ void testReadSchemaFile() throws IOException { @DisplayName("Test flatPropertiesList throws exception schema type not supported") void testFlatPropertiesListWithException() { - final var parsedSchema = new ParsedSchemaUtil(); - final var baseParsedSchema = new BaseParsedSchema<>(ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema)); + final var parsedSchema = new FakeParsedSchema("Test", "TestType", null); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.CONFLUENT.toString()); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); Assertions.assertThatExceptionOfType(KLoadGenException.class) .isThrownBy(() -> SchemaExtractor.flatPropertiesList("exceptionSubject") ).withMessage(String.format("Schema type not supported %s", parsedSchema.schemaType())); @@ -142,12 +139,11 @@ void testFlatPropertiesListWithException() { @Test @DisplayName("Test flatPropertiesList with AVRO and CONFLUENT") void testSchemaTypeIsCorrectWhenAvroConfluent() throws IOException { - final File testFile = fileHelper.getFile("/avro-files/embedded-avros-example-test.avsc"); + final var testFile = fileHelper.getContent("/avro-files/embedded-avros-example-test.avsc"); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.CONFLUENT.toString()); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); - final var baseParsedSchema = new BaseParsedSchema<>(ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema)); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + final var parsedSchema = new AvroParsedSchema("test", new Schema.Parser().parse(testFile)); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); final var result = SchemaExtractor.flatPropertiesList("avroSubject"); diff --git a/src/test/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImplTest.java b/src/test/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImplTest.java new file mode 100644 index 00000000..6aa74dfb --- /dev/null +++ b/src/test/java/com/sngular/kloadgen/extractor/asyncapi/AsyncApiExtractorImplTest.java @@ -0,0 +1,63 @@ +package com.sngular.kloadgen.extractor.asyncapi; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.testutil.FileHelper; +import org.apache.jmeter.threads.JMeterContext; +import org.apache.jmeter.threads.JMeterContextService; +import org.apache.jmeter.threads.JMeterVariables; +import org.apache.jmeter.util.JMeterUtils; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class AsyncApiExtractorImplTest { + + private final ObjectMapper om = new ObjectMapper(new YAMLFactory()); + + private final FileHelper fileHelper = new FileHelper(); + + @BeforeEach + public final void setUp() { + final File file = new File("src/test/resources"); + final String absolutePath = file.getAbsolutePath(); + JMeterUtils.loadJMeterProperties(absolutePath + "/kloadgen.properties"); + final JMeterContext jmcx = JMeterContextService.getContext(); + jmcx.setVariables(new JMeterVariables()); + JMeterUtils.setLocale(Locale.ENGLISH); + } + + @Test + @DisplayName("Should extract asyncapi file") + void testExtractFile() { + final File testFile = fileHelper.getFile("/asyncapi/event-api.yml"); + final AsyncApiFile asapfle = new AsyncApiExtractorImpl().processFile(testFile); + + Assertions.assertThat(asapfle).isNotNull(); + Assertions.assertThat(asapfle.getApiSchemaList().toString()).isEqualTo("{user_signedup=user_signedup}"); + Assertions.assertThat(asapfle.getApiServerMap().toString()).isEqualTo("{production=AsyncApiServer(name=production," + + " url=mqtt://test.mosquitto.org, protocol=mqtt," + + " description=Test MQTT broker)}"); + } + + @Test + @DisplayName("Should extract basic asyncapi schema") + void testExtractAsyncapiSchema() throws IOException { + final File testFile = fileHelper.getFile("/asyncapi/event-api.yml"); + final JsonNode openApi = om.readTree(testFile); + final AsyncApiFile asapfle = new AsyncApiExtractorImpl().processNode(openApi); + final JsonNode propertiesSchema = asapfle.getAsyncApiFileNode().path("components").path("schemas").path("userSignedUpPayload").path("properties"); + Assertions.assertThat(asapfle).isNotNull(); + Assertions.assertThat(propertiesSchema) + .hasSize(4) + .isSubsetOf(openApi.get("components").get("schemas").get("userSignedUpPayload").get("properties")); + } + +} \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactoryTest.java b/src/test/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactoryTest.java index 9c8797b7..76734fc9 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactoryTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/extractors/ExtractorFactoryTest.java @@ -13,9 +13,7 @@ import com.sngular.kloadgen.extractor.extractors.json.JsonExtractor; import com.sngular.kloadgen.extractor.extractors.protobuf.ProtobufExtractor; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; -import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseParsedSchema; -import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentAbstractParsedSchemaMetadata; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.testutil.FileHelper; import com.sngular.kloadgen.util.JMeterHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; @@ -35,17 +33,16 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; - @SuppressWarnings("checkstyle:ClassDataAbstractionCoupling") class ExtractorFactoryTest { - @Captor - private ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Schema.class); - private final Properties properties = new Properties(); private final Extractor avroConfluentExtractor = new AvroConfluentExtractor(); + @Captor + private ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Schema.class); + private MockedStatic jmeterHelperMockedStatic; private MockedStatic jmeterContextServiceMockedStatic; @@ -76,19 +73,19 @@ void flatPropertiesList() throws IOException { final AvroExtractor avroExtractor = Mockito.mock(AvroExtractor.class); ExtractorFactory.configExtractorFactory(avroExtractor, new JsonExtractor(), new ProtobufExtractor()); - final File testFile = new FileHelper().getFile("/avro-files/embedded-avros-example-test.avsc"); + final var testFile = new FileHelper().getContent("/avro-files/embedded-avros-example-test.avsc"); properties.setProperty(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, SchemaRegistryEnum.CONFLUENT.toString()); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); - final var baseParsedSchema = new BaseParsedSchema<>(ConfluentAbstractParsedSchemaMetadata.parse(parsedSchema)); + final var parsedSchema = new AvroParsedSchema("test", new Schema.Parser().parse(testFile)); - jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(baseParsedSchema); + jmeterHelperMockedStatic.when(() -> JMeterHelper.getParsedSchema(Mockito.anyString(), Mockito.any(Properties.class))).thenReturn(parsedSchema); jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); final Schema schema = new Schema.Parser().parse(testFile); final List fieldValueMappingList = avroConfluentExtractor.processSchema(schema); - Mockito.when(avroExtractor.processSchema(new ParsedSchema(argumentCaptor.capture(), ""), ArgumentMatchers.isA(SchemaRegistryEnum.class))).thenReturn(fieldValueMappingList); + Mockito.when(avroExtractor.processSchema(new AvroParsedSchema("test", argumentCaptor.capture()), ArgumentMatchers.isA(SchemaRegistryEnum.class))) + .thenReturn(fieldValueMappingList); final var result = SchemaExtractor.flatPropertiesList(schema.getName()); Assertions.assertThat(result).isNotNull(); diff --git a/src/test/java/com/sngular/kloadgen/extractor/extractors/avro/AvroConfluentExtractorTest.java b/src/test/java/com/sngular/kloadgen/extractor/extractors/avro/AvroConfluentExtractorTest.java index 87df8637..5a21bcf7 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/extractors/avro/AvroConfluentExtractorTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/extractors/avro/AvroConfluentExtractorTest.java @@ -12,15 +12,12 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mockito; - class AvroConfluentExtractorTest { - private final FileHelper fileHelper = new FileHelper(); private final Extractor avroConfluentExtractor = new AvroConfluentExtractor(); - @Test @DisplayName("Should extract Embedded Record") void testFlatPropertiesEmbeddedAvros() throws Exception { diff --git a/src/test/java/com/sngular/kloadgen/extractor/extractors/json/JsonDefaultTest.java b/src/test/java/com/sngular/kloadgen/extractor/extractors/json/JsonDefaultTest.java index dccd6efb..d176e41c 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/extractors/json/JsonDefaultTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/extractors/json/JsonDefaultTest.java @@ -22,24 +22,6 @@ class JsonDefaultTest { private final Extractor jsonDefaultExtractor = new JsonDefaultExtractor(); - @Test - @DisplayName("Should extract basic types") - void testBasic() throws Exception { - final String testFile = fileHelper.getContent("/jsonschema/basic.jcs"); - - final Map constraints = Map.of(ConstraintTypeEnum.MINIMUM_VALUE, "0", ConstraintTypeEnum.MAXIMUM_VALUE, "0"); - final JSONObject jsonObject = new JSONObject(testFile); - final Schema schema = SchemaLoader.load(jsonObject); - final List fieldValueMappingList = jsonDefaultExtractor.processSchema(schema.toString()); - - Assertions.assertThat(fieldValueMappingList) - .hasSize(3) - .containsExactlyInAnyOrder( - FieldValueMapping.builder().fieldName("firstName").fieldType("string").constraints(constraints).required(false).isAncestorRequired(false).build(), - FieldValueMapping.builder().fieldName("lastName").fieldType("string").constraints(constraints).required(true).isAncestorRequired(false).build(), - FieldValueMapping.builder().fieldName("age").fieldType("number").required(true).isAncestorRequired(false).build()); - } - @Test @DisplayName("Should extract a basic array") void testBasicArray() throws Exception { diff --git a/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufApicurioExtractorTest.java b/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufApicurioExtractorTest.java index 0d63c161..263a52c7 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufApicurioExtractorTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufApicurioExtractorTest.java @@ -37,7 +37,6 @@ public void setUp() { JMeterUtils.setLocale(Locale.ENGLISH); } - @Test @DisplayName("Test Extractor with simple proto file") void testFlatProperties() throws Exception { @@ -54,7 +53,6 @@ void testFlatProperties() throws Exception { ); } - @Test @DisplayName("Test Extractor with data structure map and array") void testEmbeddedTypes() throws Exception { diff --git a/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufConfluentExtractorTest.java b/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufConfluentExtractorTest.java index ac5418ad..844b2d75 100644 --- a/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufConfluentExtractorTest.java +++ b/src/test/java/com/sngular/kloadgen/extractor/extractors/protobuf/ProtobufConfluentExtractorTest.java @@ -6,8 +6,12 @@ import com.sngular.kloadgen.extractor.extractors.Extractor; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.testutil.FileHelper; +import com.squareup.wire.schema.Location; +import com.squareup.wire.schema.internal.parser.ProtoFileElement; +import com.squareup.wire.schema.internal.parser.ProtoParser; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterContextService; import org.apache.jmeter.threads.JMeterVariables; @@ -21,7 +25,7 @@ class ProtobufConfluentExtractorTest { private final FileHelper fileHelper = new FileHelper(); - private final Extractor protoBufConfluentExtractor = new ProtoBufConfluentExtractor(); + private final Extractor> protoBufConfluentExtractor = new ProtoBufConfluentExtractor(); @BeforeEach public void setUp() { @@ -33,12 +37,11 @@ public void setUp() { JMeterUtils.setLocale(Locale.ENGLISH); } - @Test @DisplayName("Test Extractor with simple proto file") void testFlatProperties() throws Exception { final String testFile = fileHelper.getContent("/proto-files/easyTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(3) @@ -53,7 +56,7 @@ void testFlatProperties() throws Exception { @DisplayName("Test Extractor with data structure map and array") void testEmbeddedTypes() throws Exception { final String testFile = fileHelper.getContent("/proto-files/embeddedTypeTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(2) @@ -68,7 +71,7 @@ void testEmbeddedTypes() throws Exception { @DisplayName("Test Extractor with data structure enums and collections") void testEnumType() throws Exception { final String testFile = fileHelper.getContent("/proto-files/enumTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(3) @@ -86,7 +89,7 @@ void testEnumType() throws Exception { @DisplayName("Test Extractor with data structure Any of") void testOneOfsType() throws Exception { final String testFile = fileHelper.getContent("/proto-files/oneOfTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(4) @@ -106,7 +109,7 @@ void testOneOfsType() throws Exception { @DisplayName("Test Extractor with complex structure") void testComplexProto() throws Exception { final String testFile = fileHelper.getContent("/proto-files/complexTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(13) @@ -131,7 +134,7 @@ void testComplexProto() throws Exception { @DisplayName("Test Extractor with real proto") void testProvided() throws Exception { final String testFile = fileHelper.getContent("/proto-files/providedTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(32) @@ -175,7 +178,7 @@ void testProvided() throws Exception { @DisplayName("Test Extractor with data structure maps") void testMap() throws Exception { final String testFile = fileHelper.getContent("/proto-files/mapTest.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(7) @@ -194,7 +197,7 @@ void testMap() throws Exception { @DisplayName("Test Extractor with multi types") void completeTest() throws Exception { final String testFile = fileHelper.getContent("/proto-files/completeProto.proto"); - final ParsedSchema schema = new ParsedSchema(testFile, "PROTOBUF"); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); final List fieldValueMappingList = protoBufConfluentExtractor.processSchema(schema); Assertions.assertThat(fieldValueMappingList) .hasSize(11) diff --git a/src/test/java/com/sngular/kloadgen/loadgen/impl/AvroSRLoadGeneratorTest.java b/src/test/java/com/sngular/kloadgen/loadgen/impl/AvroSRLoadGeneratorTest.java index cff6bd0d..f9dc9730 100644 --- a/src/test/java/com/sngular/kloadgen/loadgen/impl/AvroSRLoadGeneratorTest.java +++ b/src/test/java/com/sngular/kloadgen/loadgen/impl/AvroSRLoadGeneratorTest.java @@ -21,7 +21,6 @@ import com.sngular.kloadgen.schemaregistry.SchemaRegistryAdapter; import com.sngular.kloadgen.schemaregistry.SchemaRegistryManagerFactory; import com.sngular.kloadgen.serializer.EnrichedRecord; -import com.sngular.kloadgen.testutil.FileHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterContextService; @@ -34,8 +33,6 @@ @WireMockTest class AvroSRLoadGeneratorTest { - private final FileHelper fileHelper = new FileHelper(); - @BeforeEach public void setUp(final WireMockRuntimeInfo wmRuntimeInfo) throws IOException { final File file = new File("src/test/resources"); @@ -47,7 +44,7 @@ public void setUp(final WireMockRuntimeInfo wmRuntimeInfo) throws IOException { } @Test - void testAvroLoadGeneratorApicurio(final WireMockRuntimeInfo wmRuntimeInfo) throws KLoadGenException, IOException { + void testAvroLoadGeneratorApicurio(final WireMockRuntimeInfo wmRuntimeInfo) throws KLoadGenException { final List fieldValueMappingList = Arrays.asList( FieldValueMapping.builder().fieldName("Name").fieldType("string").valueLength(0).fieldValueList("Jose").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("Age").fieldType("int").valueLength(0).fieldValueList("43").required(true).isAncestorRequired(true).build()); @@ -67,11 +64,11 @@ void testAvroLoadGeneratorApicurio(final WireMockRuntimeInfo wmRuntimeInfo) thro } @Test - void testAvroLoadGeneratorConfluent(final WireMockRuntimeInfo wmRuntimeInfo) throws KLoadGenException, IOException { + void testAvroLoadGeneratorConfluent(final WireMockRuntimeInfo wmRuntimeInfo) throws KLoadGenException { final List fieldValueMappingList = Arrays.asList( - FieldValueMapping.builder().fieldName("Name").fieldType("string").valueLength(0).fieldValueList("Jose").required(true).isAncestorRequired(true).build(), - FieldValueMapping.builder().fieldName("Age").fieldType("int").valueLength(0).fieldValueList("43").required(true).isAncestorRequired(true).build()); + FieldValueMapping.builder().fieldName("Name").fieldType("string").valueLength(0).fieldValueList("Jose").required(true).isAncestorRequired(true).build(), + FieldValueMapping.builder().fieldName("Age").fieldType("int").valueLength(0).fieldValueList("43").required(true).isAncestorRequired(true).build()); final Map originals = new HashMap<>(); final SchemaRegistryAdapter schemaRegistryManager = SchemaRegistryManagerFactory.getSchemaRegistry("confluent"); diff --git a/src/test/java/com/sngular/kloadgen/loadgen/impl/ProtobufSRLoadGeneratorTest.java b/src/test/java/com/sngular/kloadgen/loadgen/impl/ProtobufSRLoadGeneratorTest.java index 55a2c7c5..40e1154a 100644 --- a/src/test/java/com/sngular/kloadgen/loadgen/impl/ProtobufSRLoadGeneratorTest.java +++ b/src/test/java/com/sngular/kloadgen/loadgen/impl/ProtobufSRLoadGeneratorTest.java @@ -20,7 +20,6 @@ import com.sngular.kloadgen.model.FieldValueMapping; import com.sngular.kloadgen.schemaregistry.SchemaRegistryManagerFactory; import com.sngular.kloadgen.serializer.EnrichedRecord; -import com.sngular.kloadgen.testutil.FileHelper; import com.sngular.kloadgen.util.ProducerKeysHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; import io.confluent.kafka.schemaregistry.client.SchemaRegistryClientConfig; @@ -35,8 +34,6 @@ @WireMockTest class ProtobufSRLoadGeneratorTest { - private FileHelper fileHelper = new FileHelper(); - @BeforeEach public void setUp(final WireMockRuntimeInfo wmRuntimeInfo) throws IOException { final File file = new File("src/test/resources"); diff --git a/src/test/java/com/sngular/kloadgen/model/FieldValueMappingTest.java b/src/test/java/com/sngular/kloadgen/model/FieldValueMappingTest.java index 8215ae03..ece11c0f 100644 --- a/src/test/java/com/sngular/kloadgen/model/FieldValueMappingTest.java +++ b/src/test/java/com/sngular/kloadgen/model/FieldValueMappingTest.java @@ -19,15 +19,33 @@ class FieldValueMappingTest { @BeforeAll static void setUpTest() { fieldValueMapping = FieldValueMapping - .builder() - .fieldName("value") - .fieldType("String") - .valueLength(30) - .fieldValueList( - "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"\",\"action\":\"\"}]}]}," - + "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"\",\"action\":\"\"}]}]}") - .constraint(ConstraintTypeEnum.MAXIMUM_VALUE, "5") - .build(); + .builder() + .fieldName("value") + .fieldType("String") + .valueLength(30) + .fieldValueList( + """ + {"client_code":"ABC", + "market_codes":["popfa","popfa"], + "permissions":[ + {"app_code":"TEAA", + "resource_codes":[ + {"code":"", + "action":""}] + }] + }, + {"client_code":"ABC", + "market_codes":["popfa","popfa"], + "permissions":[ + {"app_code":"TEAA", + "resource_codes":[ + {"code":"", + "action":""} + ] + }] + }""") + .constraint(ConstraintTypeEnum.MAXIMUM_VALUE, "5") + .build(); } @Test @@ -50,17 +68,23 @@ void getFieldValuesList() { Assertions.assertThat(fieldValueMapping.getFieldValuesList()) .hasSize(2) .containsExactlyElementsOf(List.of( - "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"\",\"action\":\"\"}]}]}", - "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"\",\"action\":\"\"}]}]}")); + """ + {"client_code":"ABC","market_codes":["popfa","popfa"],"permissions":[{"app_code":"TEAA","resource_codes":[{"code":"","action":""}]}]}""", + """ + {"client_code":"ABC","market_codes":["popfa","popfa"],"permissions":[{"app_code":"TEAA","resource_codes":[{"code":"","action":""}]}]}""")); } @Test void getFieldValuesListSingleJson() { fieldValueMapping.setFieldValuesList( - "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"jj\",\"action\":\"kk\"}]}]}"); + """ + {"client_code":"ABC", + "market_codes":["popfa","popfa"], + "permissions":[{"app_code":"TEAA","resource_codes":[{"code":"jj","action":"kk"}]}]}"""); Assertions.assertThat(fieldValueMapping.getFieldValuesList()) .hasSize(1) .containsExactlyElementsOf(List.of( - "{\"client_code\":\"ABC\",\"market_codes\":[\"popfa\",\"popfa\"],\"permissions\":[{\"app_code\":\"TEAA\",\"resource_codes\":[{\"code\":\"jj\",\"action\":\"kk\"}]}]}")); + """ + {"client_code":"ABC","market_codes":["popfa","popfa"],"permissions":[{"app_code":"TEAA","resource_codes":[{"code":"jj","action":"kk"}]}]}""")); } } \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/model/HeaderMappingTest.java b/src/test/java/com/sngular/kloadgen/model/HeaderMappingTest.java index 84d17c9b..c6075c5e 100644 --- a/src/test/java/com/sngular/kloadgen/model/HeaderMappingTest.java +++ b/src/test/java/com/sngular/kloadgen/model/HeaderMappingTest.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.model; import org.assertj.core.api.Assertions; @@ -11,10 +17,10 @@ public class HeaderMappingTest { @BeforeAll static void setUpTest() { headerMapping = HeaderMapping - .builder() - .headerName("value") - .headerValue("String") - .build(); + .builder() + .headerName("value") + .headerValue("String") + .build(); } @Test diff --git a/src/test/java/com/sngular/kloadgen/model/PropertyMappingTest.java b/src/test/java/com/sngular/kloadgen/model/PropertyMappingTest.java index 18c4af37..0288aca2 100644 --- a/src/test/java/com/sngular/kloadgen/model/PropertyMappingTest.java +++ b/src/test/java/com/sngular/kloadgen/model/PropertyMappingTest.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.model; import org.assertj.core.api.Assertions; @@ -5,15 +11,16 @@ import org.junit.jupiter.api.Test; public class PropertyMappingTest { + private static PropertyMapping propertyMapping; @BeforeAll static void setUpTest() { propertyMapping = PropertyMapping - .builder() - .propertyName("value") - .propertyValue("String") - .build(); + .builder() + .propertyName("value") + .propertyValue("String") + .build(); } @Test diff --git a/src/test/java/com/sngular/kloadgen/processor/AvroSchemaProcessorTest.java b/src/test/java/com/sngular/kloadgen/processor/AvroSchemaProcessorTest.java index 40e4c251..ef804513 100644 --- a/src/test/java/com/sngular/kloadgen/processor/AvroSchemaProcessorTest.java +++ b/src/test/java/com/sngular/kloadgen/processor/AvroSchemaProcessorTest.java @@ -21,7 +21,8 @@ import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.exception.KLoadGenException; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AbstractParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.processor.fixture.AvroSchemaFixturesConstants; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; @@ -80,7 +81,7 @@ void testAvroSchemaProcessorWithSubEntitySimpleArray() throws IOException { FieldValueMapping.builder().fieldName("topLevelIntArray[3]").fieldType("int-array").valueLength(0).fieldValueList("[2]").required(true).isAncestorRequired(true).build()); final File testFile = fileHelper.getFile("/avro-files/avros-example-with-sub-entity-array-test.avsc"); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); + final var parsedSchema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(testFile)); final SchemaProcessor avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final GenericRecord entity = setUpEntityForAvroTestWithSubEntitySimpleArray(parsedSchema); @@ -91,8 +92,8 @@ void testAvroSchemaProcessorWithSubEntitySimpleArray() throws IOException { Assertions.assertThat(message.getGenericRecord()).isEqualTo(entity); } - private GenericRecord setUpEntityForAvroTestWithSubEntitySimpleArray(final ParsedSchema parsedSchema) { - final var entity = new GenericData.Record((Schema) parsedSchema.rawSchema()); + private GenericRecord setUpEntityForAvroTestWithSubEntitySimpleArray(final AbstractParsedSchema parsedSchema) { + final var entity = new GenericData.Record((Schema) parsedSchema.getRawSchema()); final var subEntitySchema = entity.getSchema().getField("subEntity").schema(); final var subEntityRecord = new GenericData.Record(subEntitySchema); final var anotherLevelSchema = subEntitySchema.getField("anotherLevel").schema(); @@ -129,8 +130,8 @@ void testAvroSchemaProcessorWithSubEntityArray() throws IOException { .isAncestorRequired(true) .build()); - final var testFile = fileHelper.getFile("/avro-files/avros-example-with-sub-entity-array-test.avsc"); - final var parsedSchema = new ParsedSchema(testFile, "AVRO"); + final var testFile = fileHelper.getContent("/avro-files/avros-example-with-sub-entity-array-test.avsc"); + final var parsedSchema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(testFile)); final var avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final var entity = setUpEntityForAvroTestWithSubEntityArray(parsedSchema); @@ -141,8 +142,8 @@ void testAvroSchemaProcessorWithSubEntityArray() throws IOException { Assertions.assertThat(message.getGenericRecord()).isEqualTo(entity); } - private GenericRecord setUpEntityForAvroTestWithSubEntityArray(final ParsedSchema parsedSchema) { - final var entity = new GenericData.Record((Schema) parsedSchema.rawSchema()); + private GenericRecord setUpEntityForAvroTestWithSubEntityArray(final AbstractParsedSchema parsedSchema) { + final var entity = new GenericData.Record((Schema) parsedSchema.getRawSchema()); final var subEntitySchema = entity.getSchema().getField("subEntity").schema(); final var subEntityRecord = new GenericData.Record(subEntitySchema); final var anotherLevelSchema = subEntitySchema.getField("anotherLevel").schema(); @@ -173,8 +174,8 @@ void testEmbeddedAvroSchemaProcessor() throws IOException { .build(), FieldValueMapping.builder().fieldName("timestamp").fieldType("long").valueLength(0).fieldValueList("5").required(true).isAncestorRequired(true).build() ); - final var testFile = fileHelper.getFile("/avro-files/embedded-avros-example-test.avsc"); - final var parsedSchema = new ParsedSchema(testFile, "AVRO"); + final var testFile = fileHelper.getContent("/avro-files/embedded-avros-example-test.avsc"); + final var parsedSchema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(testFile)); final var avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final var message = (EnrichedRecord) avroSchemaProcessor.next(); @@ -185,11 +186,10 @@ void testEmbeddedAvroSchemaProcessor() throws IOException { Assertions.assertThat(message.getGenericRecord()).isEqualTo(entity); } - private GenericRecord setUpEntityForEmbeddedAvroTest(final ParsedSchema parsedSchema) { - GenericData.Record entity = null; //TODO HERE + private GenericRecord setUpEntityForEmbeddedAvroTest(final AbstractParsedSchema parsedSchema) { + GenericData.Record entity = null; - if (parsedSchema.rawSchema() instanceof Schema) { - final Schema schema = (Schema) parsedSchema.rawSchema(); + if (parsedSchema.getRawSchema() instanceof final Schema schema) { if (Schema.Type.UNION.equals(schema.getType())) { entity = new GenericData.Record(schema.getTypes().get(schema.getTypes().size() - 1)); } else { @@ -255,38 +255,38 @@ void textAvroSchemaProcessorArrayMap() throws KLoadGenException { final var avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, SchemaBuilder - .builder() - .record("arrayMap") - .fields() - .name("values") - .type() - .array() - .items() - .type(SchemaBuilder - .builder() - .map() - .values() - .stringType() - .getValueType()) - .noDefault() - .name("topLevelRecord") - .type() - .record("subvalues") - .fields() - .name("subvalues") - .type() - .array() - .items() - .type(SchemaBuilder - .builder() - .map() - .values() - .stringType() - .getValueType()) - .noDefault() - .endRecord() - .noDefault() - .endRecord(), + .builder() + .record("arrayMap") + .fields() + .name("values") + .type() + .array() + .items() + .type(SchemaBuilder + .builder() + .map() + .values() + .stringType() + .getValueType()) + .noDefault() + .name("topLevelRecord") + .type() + .record("subvalues") + .fields() + .name("subvalues") + .type() + .array() + .items() + .type(SchemaBuilder + .builder() + .map() + .values() + .stringType() + .getValueType()) + .noDefault() + .endRecord() + .noDefault() + .endRecord(), confluentBaseSchemaMetadata, fieldValueMappingList); @@ -303,8 +303,8 @@ void textAvroSchemaProcessorArrayMap() throws KLoadGenException { .hasSize(1); final List> valuesElement = (List>) ((GenericRecord) message.getGenericRecord()).get("values"); Assertions.assertThat(valuesElement).hasSize(2).containsExactlyInAnyOrder(Maps.of("n", "1", "t", "2"), Maps.of("n", "1", "t", "2")); - final List> subvaluesElement = (List>) ((GenericRecord) ((GenericRecord) message.getGenericRecord()).get("topLevelRecord")).get( - "subvalues"); + final List> subvaluesElement = (List>) ((GenericRecord) ((GenericRecord) message.getGenericRecord()).get("topLevelRecord")) + .get("subvalues"); Assertions.assertThat(subvaluesElement).hasSize(2).containsExactlyInAnyOrder(Maps.of("n", "1", "t", "2"), Maps.of("n", "1", "t", "2")); } @@ -317,22 +317,22 @@ void textAvroSchemaProcessorArrayRecord() throws KLoadGenException { final var avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, SchemaBuilder - .builder() - .record("array") - .fields() - .name("values") - .type() - .array() - .items() - .type(SchemaBuilder - .builder() - .record("test") - .fields() - .requiredString("name") - .requiredFloat("amount") - .endRecord()) - .noDefault() - .endRecord(), + .builder() + .record("array") + .fields() + .name("values") + .type() + .array() + .items() + .type(SchemaBuilder + .builder() + .record("test") + .fields() + .requiredString("name") + .requiredFloat("amount") + .endRecord()) + .noDefault() + .endRecord(), confluentBaseSchemaMetadata, fieldValueMappingList); @@ -357,21 +357,21 @@ void textAvroSchemaProcessorMap() throws KLoadGenException { final var avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, SchemaBuilder - .builder() - .record("arrayMap") - .fields() - .name("values") - .type() - .array() - .items() - .type(SchemaBuilder - .builder() - .map() - .values() - .stringType() - .getValueType()) - .noDefault() - .endRecord(), + .builder() + .record("arrayMap") + .fields() + .name("values") + .type() + .array() + .items() + .type(SchemaBuilder + .builder() + .map() + .values() + .stringType() + .getValueType()) + .noDefault() + .endRecord(), confluentBaseSchemaMetadata, fieldValueMappingList); @@ -393,10 +393,9 @@ void textAvroSchemaProcessorMap() throws KLoadGenException { @ParameterizedTest @MethodSource("parametersForTestNullOnOptionalField") void testNullOnOptionalField(final Schema schema, final List fieldValueMapping) { - final var metadata = confluentBaseSchemaMetadata; final var avroSchemaProcessor = new SchemaProcessor(); - avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schema, metadata, fieldValueMapping); + avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schema, confluentBaseSchemaMetadata, fieldValueMapping); final var message = (EnrichedRecord) avroSchemaProcessor.next(); Assertions.assertThat(message) @@ -407,7 +406,6 @@ void testNullOnOptionalField(final Schema schema, final List final var genericRecord = (GenericRecord) message.getGenericRecord(); Assertions.assertThat(genericRecord.get(0)).isNotNull(); Assertions.assertThat(genericRecord.get(1)).isNull(); - } @Test @@ -419,25 +417,25 @@ void testCustomSequenceOfValuesWithSameStartingValue() { final var avroSchemaProcessor = new SchemaProcessor(); final var schemaWithTwoSequencesWithSameStartingValue = SchemaBuilder - .builder() - .record("Root") - .fields() - .name("values") - .type() - .array() - .items() - .type(SchemaBuilder.builder() - .record("valuesData") - .fields() - .name("id") - .type(Schema.Type.STRING.getName()) - .noDefault() - .name("otherId") - .type(Schema.Type.LONG.getName()) - .noDefault() - .endRecord()) - .noDefault() - .endRecord(); + .builder() + .record("Root") + .fields() + .name("values") + .type() + .array() + .items() + .type(SchemaBuilder.builder() + .record("valuesData") + .fields() + .name("id") + .type(Schema.Type.STRING.getName()) + .noDefault() + .name("otherId") + .type(Schema.Type.LONG.getName()) + .noDefault() + .endRecord()) + .noDefault() + .endRecord(); final var entity = entityForCustomSequenceOfValuesWithSameStartingStartingValue(schemaWithTwoSequencesWithSameStartingValue, Arrays.asList("1", "2", "1"), Arrays.asList("1", "3", "1")); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schemaWithTwoSequencesWithSameStartingValue, @@ -454,13 +452,13 @@ private GenericRecord entityForCustomSequenceOfValuesWithSameStartingStartingVal final var valuesSchema = entity.getSchema().getField("values").schema(); final var valuesDataSchema = valuesSchema.getElementType(); final var valuesData = IntStream - .range(0, Math.min(idValues.size(), otherIdValues.size())) - .mapToObj(idx -> { - final var valuesDataRecord = new GenericData.Record(valuesDataSchema); - valuesDataRecord.put("id", idValues.get(idx)); - valuesDataRecord.put("otherId", Long.valueOf(otherIdValues.get(idx))); - return valuesDataRecord; - }).collect(Collectors.toList()); + .range(0, Math.min(idValues.size(), otherIdValues.size())) + .mapToObj(idx -> { + final var valuesDataRecord = new GenericData.Record(valuesDataSchema); + valuesDataRecord.put("id", idValues.get(idx)); + valuesDataRecord.put("otherId", Long.valueOf(otherIdValues.get(idx))); + return valuesDataRecord; + }).collect(Collectors.toList()); entity.put("values", valuesData); return entity; @@ -477,34 +475,34 @@ void testCustomIteratorOfValuesWithSameFieldNameInDifferentMappings() { final var avroSchemaProcessor = new SchemaProcessor(); final var schemaWithTwoIteratorsWithSameStartingValue = SchemaBuilder - .builder() - .record("Root") - .fields() - .name("values") - .type() - .array() - .items() - .type(SchemaBuilder.builder() - .record("valuesData") - .fields() - .name("id") - .type(idSchema) - .noDefault() - .endRecord()) - .noDefault() - .name("otherValues") - .type() - .array() - .items() - .type(SchemaBuilder.builder() - .record("otherValuesData") - .fields() - .name("id") - .type(idSchema) - .noDefault() - .endRecord()) - .noDefault() - .endRecord(); + .builder() + .record("Root") + .fields() + .name("values") + .type() + .array() + .items() + .type(SchemaBuilder.builder() + .record("valuesData") + .fields() + .name("id") + .type(idSchema) + .noDefault() + .endRecord()) + .noDefault() + .name("otherValues") + .type() + .array() + .items() + .type(SchemaBuilder.builder() + .record("otherValuesData") + .fields() + .name("id") + .type(idSchema) + .noDefault() + .endRecord()) + .noDefault() + .endRecord(); final var entity = entityForCustomIteratorOfValuesWithSameFieldNameInDifferentMappings(schemaWithTwoIteratorsWithSameStartingValue, Arrays.asList("1", "2.44", "3.6", "1"), Arrays.asList("1", "3.02", "4.98", "1")); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schemaWithTwoIteratorsWithSameStartingValue, @@ -536,7 +534,6 @@ private List getIdRecordsList(final GenericRecord entity, final S }).collect(Collectors.toList()); } - @Test @DisplayName("Should process Embedded Avro Schema Processor") void testEnumProcessor() throws IOException { @@ -552,12 +549,12 @@ void testEnumProcessor() throws IOException { .build() ); final File testFile = fileHelper.getFile("/avro-files/optionalEnum.avsc"); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); + final var parsedSchema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(testFile)); final SchemaProcessor avroSchemaProcessor = new SchemaProcessor(); avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final EnrichedRecord message = (EnrichedRecord) avroSchemaProcessor.next(); - final var entity = entityForEnumMappings((Schema) parsedSchema.rawSchema()); + final var entity = entityForEnumMappings(parsedSchema.getRawSchema()); Assertions.assertThat(message).isNotNull().isInstanceOf(EnrichedRecord.class); Assertions.assertThat(message.getGenericRecord()).isNotNull().isEqualTo(entity); } diff --git a/src/test/java/com/sngular/kloadgen/processor/JsonSchemaProcessorTest.java b/src/test/java/com/sngular/kloadgen/processor/JsonSchemaProcessorTest.java index b5dc8620..dfdc6c76 100644 --- a/src/test/java/com/sngular/kloadgen/processor/JsonSchemaProcessorTest.java +++ b/src/test/java/com/sngular/kloadgen/processor/JsonSchemaProcessorTest.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.processor; import java.io.File; @@ -15,6 +21,7 @@ import org.apache.jmeter.util.JMeterUtils; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -32,6 +39,10 @@ private static Stream parametersForTestBasicStructure() { return Stream.of(Arguments.of(JsonSchemaFixturesConstants.SIMPLE_SCHEMA_REQUIRED, JsonSchemaFixturesConstants.SIMPLE_SCHEMA_REQUIRED_EXPECTED)); } + private static Stream parametersForTestOptionalFieldNonEmpty() { + return Stream.of(Arguments.of(JsonSchemaFixturesConstants.SIMPLE_SCHEMA_NONREQUIRED, JsonSchemaFixturesConstants.SIMPLE_SCHEMA_NONREQUIRED_EXPECTED)); + } + @BeforeEach public final void setUp() { final File file = new File("src/test/resources"); @@ -63,7 +74,7 @@ final void testNullOnMapWithChildren() { final ObjectNode message = (ObjectNode) jsonSchemaProcessor.next(); Assertions.assertThat(message.toString()).contains("lastName\":\"García") - .contains("itemTipo\":{").contains("itemType\":{"); + .contains("itemTipo\":{").contains("itemType\":{"); } @Test @@ -87,11 +98,11 @@ final void testNullOnComplexCollections() { final ObjectNode message = (ObjectNode) jsonSchemaProcessor.next(); Assertions.assertThat(message.toString()).contains("{\"fruits\":{\"tropical\":[]},\"vegetables\":{\"trees\":{}}") - .contains("\"birds\":[[{\"nameBird\":") - .contains("\"animals\":{").contains("nameAnimal\":"); + .contains("\"birds\":[[{\"nameBird\":") + .contains("\"animals\":{").contains("nameAnimal\":"); } - + @ParameterizedTest @MethodSource("parametersForTestBasicStructure") final void testBasicStructure(final List schemaAsJson, final String expected) { @@ -117,4 +128,18 @@ final void testNestedComplexLevels() { ".*\\\"bush\":\\{\"\\w+\":\\{\"maxHeight\":(\\[(\\{(\"\\w+\":\\d+,?)+},?)+],?)*\"leafs\":(\\[\\{(\"\\w+\":\\[(\"oval\",?)+],?)+}+],+)*.*$"); } + @ParameterizedTest + @DisplayName("Should process non-required fields if it is not empty") + @MethodSource("parametersForTestOptionalFieldNonEmpty") + final void testOptionalFieldNonEmpty(final List schemaAsJson, final String expected) { + + final SchemaProcessor jsonSchemaProcessor = new SchemaProcessor(); + + jsonSchemaProcessor.processSchema(SchemaTypeEnum.JSON, null, null, schemaAsJson); + final ObjectNode message = (ObjectNode) jsonSchemaProcessor.next(); + + Assertions.assertThat(message.toString()).isEqualTo(expected); + + } + } diff --git a/src/test/java/com/sngular/kloadgen/processor/ProtobufSchemaProcessorTest.java b/src/test/java/com/sngular/kloadgen/processor/ProtobufSchemaProcessorTest.java index c5bcead9..912e8f56 100644 --- a/src/test/java/com/sngular/kloadgen/processor/ProtobufSchemaProcessorTest.java +++ b/src/test/java/com/sngular/kloadgen/processor/ProtobufSchemaProcessorTest.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.processor; import java.io.File; @@ -14,7 +20,7 @@ import com.sngular.kloadgen.exception.KLoadGenException; import com.sngular.kloadgen.extractor.SchemaExtractor; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.schemaregistry.SchemaRegistryAdapter; import com.sngular.kloadgen.schemaregistry.SchemaRegistryManagerFactory; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; @@ -22,6 +28,8 @@ import com.sngular.kloadgen.serializer.EnrichedRecord; import com.sngular.kloadgen.testutil.FileHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; +import com.squareup.wire.schema.Location; +import com.squareup.wire.schema.internal.parser.ProtoParser; import org.apache.commons.collections.MapUtils; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterContextService; @@ -36,8 +44,6 @@ class ProtobufSchemaProcessorTest { private final FileHelper fileHelper = new FileHelper(); - private final SchemaExtractor schemaExtractor = new SchemaExtractor(); - private final BaseSchemaMetadata confluentBaseSchemaMetadata = new BaseSchemaMetadata<>( ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, ""))); @@ -56,14 +62,13 @@ public void setUp() { @Test @DisplayName("Be able to process embedded schema") void textEmbeddedTypeTestSchemaProcessor() throws KLoadGenException, IOException { - final File testFile = fileHelper.getFile("/proto-files/embeddedTypeTest.proto"); final List fieldValueMappingList = List.of( FieldValueMapping.builder().fieldName("phones.addressesPhone[1:].id[1]").fieldType("string-array").fieldValueList("Pablo").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("phones.phoneType").fieldType("enum").fieldValueList("[MOBILE, HOME, WORK]").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, readSchemaFile("/proto-files/embeddedTypeTest.proto"), + confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final Map map = genericRecord.getAllFields(); @@ -80,9 +85,14 @@ void textEmbeddedTypeTestSchemaProcessor() throws KLoadGenException, IOException Assertions.assertThat(idField).isEqualTo("[Pablo]"); } + private ProtobufParsedSchema readSchemaFile(final String fileToRead) throws IOException { + final String testFile = fileHelper.getContent(fileToRead); + return new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); + } + private String getIdFieldForEmbeddedTypeTest(final List assertValues) { final DynamicMessage dynamicMessage = (DynamicMessage) assertValues.get(0); - final DynamicMessage firstMap = (DynamicMessage) ((List) dynamicMessage.getField(dynamicMessage.getDescriptorForType().findFieldByName("addressesPhone"))).get(0); + final DynamicMessage firstMap = (DynamicMessage) ((List) dynamicMessage.getField(dynamicMessage.getDescriptorForType().findFieldByName("addressesPhone"))).get(0); final DynamicMessage secondMapAsDynamicField = (DynamicMessage) firstMap.getField(firstMap.getDescriptorForType().findFieldByName("value")); return secondMapAsDynamicField.getField(secondMapAsDynamicField.getDescriptorForType().findFieldByName("id")).toString(); } @@ -90,14 +100,13 @@ private String getIdFieldForEmbeddedTypeTest(final List assertValues) { @Test @DisplayName("Be able to process complex types like StringValue or Int32Value and get values by default") void testProtobufGoogleTypes() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/googleTypesTest.proto"); final List fieldValueMappingList = List.of( FieldValueMapping.builder().fieldName("id").fieldType("Int32Value").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("occurrence_id").fieldType("StringValue").fieldValueList("Isabel").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("load_number").fieldType("Int32Value").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, readSchemaFile("/proto-files/googleTypesTest.proto"), + confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final Map map = genericRecord.getAllFields(); @@ -120,12 +129,11 @@ void testProtobufGoogleTypes() throws IOException { @Test @DisplayName("Be able to process enum in the schema") void testProtoBufEnumSchemaProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/enumTest.proto"); - final List fieldValueMappingList = schemaExtractor.flatPropertiesList(new ParsedSchema(testFile, "PROTOBUF")); + final var parsedSchema = readSchemaFile("/proto-files/enumTest.proto"); + final List fieldValueMappingList = SchemaExtractor.flatPropertiesList(readSchemaFile("/proto-files/enumTest.proto")); fieldValueMappingList.get(0).setFieldValuesList("HOME, WORK"); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final Map map = genericRecord.getAllFields(); @@ -136,8 +144,8 @@ void testProtoBufEnumSchemaProcessor() throws IOException { assertValues.add(value); }); final String firstValue = assertValues.get(0).toString(); - final List secondValue = (List) assertValues.get(1); - final List thirdValueMap = (List) assertValues.get(2); + final var secondValue = (List) assertValues.get(1); + final var thirdValueMap = (List) assertValues.get(2); final DynamicMessage dynamicMessage = (DynamicMessage) thirdValueMap.get(0); final Object thirdValue = dynamicMessage.getField(dynamicMessage.getDescriptorForType().findFieldByName("value")); Assertions.assertThat(message).isNotNull().isInstanceOf(EnrichedRecord.class); @@ -159,11 +167,10 @@ void testProtoBufEnumSchemaProcessor() throws IOException { @Test @DisplayName("Be able to process easy schema") void testProtoBufEasyTestProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/easyTest.proto"); - final List fieldValueMappingList = schemaExtractor.flatPropertiesList(new ParsedSchema(testFile, "PROTOBUF")); + final var parsedSchema = readSchemaFile("/proto-files/easyTest.proto"); + final List fieldValueMappingList = SchemaExtractor.flatPropertiesList(parsedSchema); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -189,12 +196,11 @@ void testProtoBufEasyTestProcessor() throws IOException { @Test @DisplayName("Be able to process oneOf fields") void testProtoBufOneOfProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/oneOfTest.proto"); + final var parsedSchema = readSchemaFile("/proto-files/oneOfTest.proto"); - final List fieldValueMappingList = schemaExtractor.flatPropertiesList(new ParsedSchema(testFile, "PROTOBUF")); + final List fieldValueMappingList = SchemaExtractor.flatPropertiesList(parsedSchema); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -212,6 +218,7 @@ void testProtoBufOneOfProcessor() throws IOException { .hasSize(2) .containsAnyOf("tutorial.Address.type", "tutorial.Address.optionInt", "tutorial.Address.optionLong", "tutorial.Address.optionString") .element(0) + .isInstanceOf(String.class) .isEqualTo("tutorial.Address.type"); Assertions.assertThat(assertValues).hasSize(2); @@ -220,7 +227,7 @@ void testProtoBufOneOfProcessor() throws IOException { @Test @DisplayName("Be able to process map in schema") void testProtoBufMapTestProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/mapTest.proto"); + final var testFile = readSchemaFile("/proto-files/mapTest.proto"); final List fieldValueMappingList = Arrays.asList( FieldValueMapping.builder().fieldName("name[:]").fieldType("string-map").fieldValueList("Pablo").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("addresses[:].street").fieldType("string").fieldValueList("Sor Joaquina").required(true).isAncestorRequired(true).build(), @@ -230,8 +237,7 @@ void testProtoBufMapTestProcessor() throws IOException { FieldValueMapping.builder().fieldName("addressesNoDot[:].number").fieldType("int").fieldValueList("6").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("addressesNoDot[:].zipcode").fieldType("int").fieldValueList("15011").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, testFile, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -276,7 +282,7 @@ private Object getSubFieldForMapTestProcessor(final DynamicMessage dynamicMessag @Test @DisplayName("Be able to process complex schema") void testProtoBufComplexTestProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/complexTest.proto"); + final var testFile = fileHelper.getContent("/proto-files/complexTest.proto"); final SchemaRegistryAdapter schemaRegistryManager = SchemaRegistryManagerFactory.getSchemaRegistry("CONFLUENT"); schemaRegistryManager.setSchemaRegistryClient("http://localhost:8080", MapUtils.EMPTY_MAP); @@ -295,8 +301,9 @@ void testProtoBufComplexTestProcessor() throws IOException { FieldValueMapping.builder().fieldName("response").fieldType("string").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("presents[:].options[]").fieldType("string-array").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), - confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, + new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()), + confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -329,7 +336,7 @@ void testProtoBufComplexTestProcessor() throws IOException { @Test @DisplayName("Be able to process provided complex schema") void testProtoBufProvidedComplexTestProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/providedTest.proto"); + final var testFile = readSchemaFile("/proto-files/providedTest.proto"); final List fieldValueMappingList = Arrays.asList( FieldValueMapping.builder().fieldName("id").fieldType("int").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("occurrence_id").fieldType("string").required(true).isAncestorRequired(true).build(), @@ -364,8 +371,7 @@ void testProtoBufProvidedComplexTestProcessor() throws IOException { FieldValueMapping.builder().fieldName("report_by_name").fieldType("string").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("create_user_id").fieldType("string").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, new ParsedSchema(testFile, - SchemaTypeEnum.PROTOBUF.name()), confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, testFile, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -410,7 +416,7 @@ void testProtoBufProvidedComplexTestProcessor() throws IOException { @Test void testFailing() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/deveTest.proto"); + final var testFile = readSchemaFile("/proto-files/deveTest.proto"); final List fieldValueMappingList = Arrays.asList( FieldValueMapping.builder().fieldName("load_type").fieldType("string").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("shipment.carrier_identifier.type").fieldType("enum") @@ -471,8 +477,7 @@ void testFailing() throws IOException { ); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, - new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, testFile, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -495,7 +500,7 @@ void testFailing() throws IOException { @Test @DisplayName("Be able to process provided schema with not nested type") void testProtoBufProvidedWithNotNestedTypeProcessor() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/issue311Test.proto"); + final var testFile = readSchemaFile("/proto-files/issue311Test.proto"); final List fieldValueMappingList = Arrays.asList( FieldValueMapping.builder().fieldName("order_id").fieldType("int").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("order_number").fieldType("string").required(true).isAncestorRequired(true).build(), @@ -503,8 +508,7 @@ void testProtoBufProvidedWithNotNestedTypeProcessor() throws IOException { FieldValueMapping.builder().fieldName("customer_account.billing_party.address.address_line_one").fieldType("string").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("customer_account.billing_party.address.address_line_two").fieldType("string").required(true).isAncestorRequired(true).build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, - new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, testFile, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final List assertKeys = new ArrayList<>(); @@ -531,14 +535,13 @@ void testProtoBufProvidedWithNotNestedTypeProcessor() throws IOException { @Test @DisplayName("Be able to process Date and TimeOfDay types") void testDateTimeTypes() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/dateTimeTest.proto"); + final var testFile = readSchemaFile("/proto-files/dateTimeTest.proto"); final List fieldValueMappingList = List.of( FieldValueMapping.builder().fieldName("incident_date").fieldType(".google.type.Date").fieldValueList("2022-05-30").required(true).isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("incident_time").fieldType(".google.type.TimeOfDay").fieldValueList("14:20:30-05:00").required(true).isAncestorRequired(true) .build()); final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, - new ParsedSchema(testFile, SchemaTypeEnum.PROTOBUF.name()), confluentBaseSchemaMetadata, fieldValueMappingList); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, testFile, confluentBaseSchemaMetadata, fieldValueMappingList); final EnrichedRecord message = (EnrichedRecord) protobufSchemaProcessor.next(); final DynamicMessage genericRecord = (DynamicMessage) message.getGenericRecord(); final Map map = genericRecord.getAllFields(); diff --git a/src/test/java/com/sngular/kloadgen/processor/fixture/JsonSchemaFixturesConstants.java b/src/test/java/com/sngular/kloadgen/processor/fixture/JsonSchemaFixturesConstants.java index 37fecb87..829c59ad 100644 --- a/src/test/java/com/sngular/kloadgen/processor/fixture/JsonSchemaFixturesConstants.java +++ b/src/test/java/com/sngular/kloadgen/processor/fixture/JsonSchemaFixturesConstants.java @@ -11,7 +11,7 @@ public class JsonSchemaFixturesConstants { - public static final List SIMPLE_SCHEMA = new ArrayList(Arrays.asList( + public static final List SIMPLE_SCHEMA = new ArrayList<>(Arrays.asList( FieldValueMapping.builder() .fieldName("firstName") .fieldType("string") @@ -41,6 +41,36 @@ public class JsonSchemaFixturesConstants { public static final String SIMPLE_SCHEMA_EXPECTED = "{\"lastName\":\"García\"}"; + public static final List SIMPLE_SCHEMA_NONREQUIRED = new ArrayList<>(Arrays.asList( + FieldValueMapping.builder() + .fieldName("firstName") + .fieldType("string") + .valueLength(0) + .fieldValueList("Graciela") + .required(false) + .isAncestorRequired(false) + .constraints(Map.of(ConstraintTypeEnum.MINIMUM_VALUE, "0", ConstraintTypeEnum.MAXIMUM_VALUE, "0")) + .build(), + FieldValueMapping.builder() + .fieldName("lastName") + .fieldType("string") + .valueLength(0) + .fieldValueList("null") + .required(false) + .constraints(Map.of(ConstraintTypeEnum.MINIMUM_VALUE, "0", ConstraintTypeEnum.MAXIMUM_VALUE, "0")) + .build(), + FieldValueMapping.builder() + .fieldName("age") + .fieldType("number") + .valueLength(0) + .fieldValueList("21") + .required(false) + .constraints(Collections.emptyMap()) + .build() + )); + + public static final String SIMPLE_SCHEMA_NONREQUIRED_EXPECTED = "{\"firstName\":\"Graciela\",\"age\":21.0}"; + public static final List SIMPLE_SCHEMA_MAP = new ArrayList<>(Arrays.asList( FieldValueMapping.builder() .fieldName("firstName") @@ -163,7 +193,7 @@ public class JsonSchemaFixturesConstants { .build() )); - public static final List SIMPLE_SCHEMA_REQUIRED = new ArrayList(Arrays.asList( + public static final List SIMPLE_SCHEMA_REQUIRED = new ArrayList<>(Arrays.asList( FieldValueMapping.builder() .fieldName("firstName") .fieldType("string") diff --git a/src/test/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditorTest.java b/src/test/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditorTest.java index 97c04e55..1125a057 100644 --- a/src/test/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditorTest.java +++ b/src/test/java/com/sngular/kloadgen/property/editor/FileSubjectPropertyEditorTest.java @@ -11,8 +11,9 @@ import java.util.List; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.testutil.FileHelper; +import org.apache.avro.Schema; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -27,7 +28,7 @@ class FileSubjectPropertyEditorTest { @DisplayName("File Subject Property Editor extract AVRO") void extractEmbeddedAvroTest() throws IOException { final File testFile = fileHelper.getFile("/avro-files/embedded-avros-example-test.avsc"); - final ParsedSchema schema = new ParsedSchema(testFile, "AVRO"); + final var schema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(testFile)); final List fieldValueMappingList = editor.getAttributeList(schema); Assertions.assertThat(fieldValueMappingList) diff --git a/src/test/java/com/sngular/kloadgen/property/editor/SerialisedSubjectPropertyEditorTest.java b/src/test/java/com/sngular/kloadgen/property/editor/SerialisedSubjectPropertyEditorTest.java index 5639d4cd..a41b9f54 100644 --- a/src/test/java/com/sngular/kloadgen/property/editor/SerialisedSubjectPropertyEditorTest.java +++ b/src/test/java/com/sngular/kloadgen/property/editor/SerialisedSubjectPropertyEditorTest.java @@ -82,7 +82,7 @@ public void setUp() { void iterationStart() { final var valueSerializedConfigElement = new ValueSerializedConfigElement("avroSubject", Collections.emptyList(), "AVRO", - AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); + AvroSerializer.class.getSimpleName(), TopicNameStrategy.class.getSimpleName()); final var variables = JMeterContextService.getContext().getVariables(); valueSerializedConfigElement.iterationStart(null); diff --git a/src/test/java/com/sngular/kloadgen/randomtool/generator/AvroGeneratorToolTest.java b/src/test/java/com/sngular/kloadgen/randomtool/generator/AvroGeneratorToolTest.java index 2fc68b21..a6a1b0e0 100644 --- a/src/test/java/com/sngular/kloadgen/randomtool/generator/AvroGeneratorToolTest.java +++ b/src/test/java/com/sngular/kloadgen/randomtool/generator/AvroGeneratorToolTest.java @@ -38,10 +38,15 @@ class AvroGeneratorToolTest { private static final LocalDateTime FIXED_TIMESTAMP = LocalDateTime.of(2019, 12, 6, 10, 15, 30); + private static final LocalDate FIXED_DATE = LocalDate.of(2019, 12, 6); + private static final LocalTime FIXED_TIME = LocalTime.of(10, 15, 30); + private static final String TIMESTAMP_STRING = "2019-12-06T10:15:30"; + private static final String DATE_STRING = "2019-12-06"; + private static final String TIME_STRING = "10:15:30"; private static Stream parametersForGenerateRandomValueForField() { @@ -109,38 +114,6 @@ private static Stream parametersForGenerateRandomValueForFieldLogical ); } - @ParameterizedTest - @DisplayName("Testing Random Value for Field") - @MethodSource("parametersForGenerateRandomValueForField") - void testGenerateRandomValueForField(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, final Object expected) { - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList(String.join(",", fieldValuesList)) - .required(true) - .isAncestorRequired(true) - .build(); - Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).isEqualTo(expected); - } - - @ParameterizedTest - @DisplayName("Testing Random Value for Field with Logical Types") - @MethodSource("parametersForGenerateRandomValueForFieldLogicalTypes") - void testGenerateRandomValueForFieldLogicalTypes(final String fieldType, final Integer valueLength, final List fieldValuesList, - final Field field, final Object expected, - final Map constraints) { - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList(String.join(",", fieldValuesList)) - .required(true) - .isAncestorRequired(true) - .build(); - Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, constraints)).isEqualTo(expected); - } - private static Stream parametersForGenerateRandomValue() { return Stream.of( Arguments.of("int", 5, Collections.emptyList(), new Field("name", SchemaBuilder.builder().intType())), @@ -149,24 +122,6 @@ private static Stream parametersForGenerateRandomValue() { Arguments.of("double", 6, Collections.emptyList(), new Field("name", SchemaBuilder.builder().doubleType()))); } - @Disabled("Test failure sometimes") - @ParameterizedTest - @DisplayName("Testing Generate a Random Value") - @MethodSource("parametersForGenerateRandomValue") - void testGenerateRandomValue(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field) { - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList(String.join(",", fieldValuesList)) - .required(true) - .isAncestorRequired(true) - .build(); - final Object number = new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap()); - Assertions.assertThat(number).isInstanceOfAny(Long.class, Integer.class, Double.class, Float.class); - Assertions.assertThat(String.valueOf(number)).hasSize(valueLength); - } - private static Stream parametersForGenerateFieldValuesListIterator() { return Stream.of( Arguments.of(18, @@ -183,47 +138,12 @@ private static Stream parametersForGenerateFieldValuesListIterator() List.of("first", "second", "third", "first", "second"))); } - @ParameterizedTest - @DisplayName("Testing generate an iterator of a list of values") - @MethodSource("parametersForGenerateFieldValuesListIterator") - void testGenerateFieldValuesListSequence(final int size, final List fieldValuesList, final String fieldType, final List expected) { - final var intList = new ArrayList<>(); - final Schema schema = fieldType.equals(ValidTypeConstants.INT) ? SchemaBuilder.builder().intType() : SchemaBuilder.builder().stringType(); - final Field field = new Field("name", schema); - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType("it") - .valueLength(0) - .fieldValueList(String.join(",", fieldValuesList)) - .build(); - final var avroGeneratorTool = new AvroGeneratorTool(); - for (int i = 0; i <= size; i++) { - intList.add(avroGeneratorTool.generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())); - } - Assertions.assertThat(intList).containsExactlyElementsOf(expected); - } - private static Stream parametersForGenerateRandomValueForEnums() { return Stream.of( Arguments.of("enum", 1, Collections.singletonList("RED"), new Field("name", SchemaBuilder.builder().enumeration("ENUM1").symbols("RED", "BLUE", "GREEN")), "RED")); } - @ParameterizedTest - @DisplayName("Testing Generate a Random Value for Enums") - @MethodSource("parametersForGenerateRandomValueForEnums") - void testGenerateRandomValueForEnums(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, final Object expected) { - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList(String.join(",", fieldValuesList)) - .required(true) - .isAncestorRequired(true) - .build(); - Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).hasFieldOrPropertyWithValue("symbol", expected); - } - private static Stream parametersForGenerateSequenceValueForField() { return Stream.of( Arguments.of("seq", 1, Collections.singletonList("0"), new Field("name", SchemaBuilder.builder().intType()), 0), @@ -234,22 +154,6 @@ private static Stream parametersForGenerateSequenceValueForField() { Arguments.of("it", 1, Collections.singletonList("2"), new Field("name", SchemaBuilder.builder().intType()), 2)); } - @ParameterizedTest - @DisplayName("Testing Generate a Random Value for Field") - @MethodSource("parametersForGenerateSequenceValueForField") - void testGenerateSequenceValueForField(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, - final Object expectedTyped) { - final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList(String.join(",", fieldValuesList)) - .required(true) - .isAncestorRequired(true) - .build(); - Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).isEqualTo(expectedTyped); - } - private static Stream parametersForShouldRecoverVariableFromContext() { return Stream.of( Arguments.of("string", 1, "testString", new Field("name", SchemaBuilder.builder().stringType()), "testString"), @@ -301,6 +205,109 @@ private static Stream parametersForShouldRecoverVariableFromContextLo ); } + @ParameterizedTest + @DisplayName("Testing Random Value for Field") + @MethodSource("parametersForGenerateRandomValueForField") + void testGenerateRandomValueForField(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, final Object expected) { + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList(String.join(",", fieldValuesList)) + .required(true) + .isAncestorRequired(true) + .build(); + Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).isEqualTo(expected); + } + + @ParameterizedTest + @DisplayName("Testing Random Value for Field with Logical Types") + @MethodSource("parametersForGenerateRandomValueForFieldLogicalTypes") + void testGenerateRandomValueForFieldLogicalTypes( + final String fieldType, final Integer valueLength, final List fieldValuesList, + final Field field, final Object expected, + final Map constraints) { + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList(String.join(",", fieldValuesList)) + .required(true) + .isAncestorRequired(true) + .build(); + Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, constraints)).isEqualTo(expected); + } + + @Disabled("Test failure sometimes") + @ParameterizedTest + @DisplayName("Testing Generate a Random Value") + @MethodSource("parametersForGenerateRandomValue") + void testGenerateRandomValue(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field) { + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList(String.join(",", fieldValuesList)) + .required(true) + .isAncestorRequired(true) + .build(); + final Object number = new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap()); + Assertions.assertThat(number).isInstanceOfAny(Long.class, Integer.class, Double.class, Float.class); + Assertions.assertThat(String.valueOf(number)).hasSize(valueLength); + } + + @ParameterizedTest + @DisplayName("Testing generate an iterator of a list of values") + @MethodSource("parametersForGenerateFieldValuesListIterator") + void testGenerateFieldValuesListSequence(final int size, final List fieldValuesList, final String fieldType, final List expected) { + final var intList = new ArrayList<>(); + final Schema schema = fieldType.equals(ValidTypeConstants.INT) ? SchemaBuilder.builder().intType() : SchemaBuilder.builder().stringType(); + final Field field = new Field("name", schema); + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType("it") + .valueLength(0) + .fieldValueList(String.join(",", fieldValuesList)) + .build(); + final var avroGeneratorTool = new AvroGeneratorTool(); + for (int i = 0; i <= size; i++) { + intList.add(avroGeneratorTool.generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())); + } + Assertions.assertThat(intList).containsExactlyElementsOf(expected); + } + + @ParameterizedTest + @DisplayName("Testing Generate a Random Value for Enums") + @MethodSource("parametersForGenerateRandomValueForEnums") + void testGenerateRandomValueForEnums(final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, final Object expected) { + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList(String.join(",", fieldValuesList)) + .required(true) + .isAncestorRequired(true) + .build(); + Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).hasFieldOrPropertyWithValue("symbol", expected); + } + + @ParameterizedTest + @DisplayName("Testing Generate a Random Value for Field") + @MethodSource("parametersForGenerateSequenceValueForField") + void testGenerateSequenceValueForField( + final String fieldType, final Integer valueLength, final List fieldValuesList, final Field field, + final Object expectedTyped) { + final var fieldValueMapping = FieldValueMapping.builder() + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList(String.join(",", fieldValuesList)) + .required(true) + .isAncestorRequired(true) + .build(); + Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).isEqualTo(expectedTyped); + } + @ParameterizedTest @DisplayName("Testing Recover Variable from Context") @MethodSource("parametersForShouldRecoverVariableFromContext") @@ -309,32 +316,33 @@ void shouldRecoverVariableFromContext(final String fieldType, final Integer valu variables.put("VARIABLE", value); JMeterContextService.getContext().setVariables(variables); final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList("${VARIABLE}") - .required(true) - .isAncestorRequired(true) - .build(); + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList("${VARIABLE}") + .required(true) + .isAncestorRequired(true) + .build(); Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, Collections.emptyMap())).isEqualTo(expected); } @ParameterizedTest @DisplayName("Testing Recover Variable from Context Logical Types") @MethodSource("parametersForShouldRecoverVariableFromContextLogicalTypes") - void shouldRecoverVariableFromContext(final String fieldType, final Integer valueLength, final String value, final Field field, + void shouldRecoverVariableFromContext( + final String fieldType, final Integer valueLength, final String value, final Field field, final Object expected, final Map constraints) { final var variables = new JMeterVariables(); variables.put("VARIABLE", value); JMeterContextService.getContext().setVariables(variables); final var fieldValueMapping = FieldValueMapping.builder() - .fieldName(field.name()) - .fieldType(fieldType) - .valueLength(valueLength) - .fieldValueList("${VARIABLE}") - .required(true) - .isAncestorRequired(true) - .build(); + .fieldName(field.name()) + .fieldType(fieldType) + .valueLength(valueLength) + .fieldValueList("${VARIABLE}") + .required(true) + .isAncestorRequired(true) + .build(); Assertions.assertThat(new AvroGeneratorTool().generateObject(field.schema(), fieldValueMapping, constraints)).isEqualTo(expected); } } \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/randomtool/random/RandomIteratorTest.java b/src/test/java/com/sngular/kloadgen/randomtool/random/RandomIteratorTest.java index d9261475..596a8399 100644 --- a/src/test/java/com/sngular/kloadgen/randomtool/random/RandomIteratorTest.java +++ b/src/test/java/com/sngular/kloadgen/randomtool/random/RandomIteratorTest.java @@ -26,17 +26,28 @@ class RandomIteratorTest { private static Stream parametersForGenerateIteratorValueForField() { return Stream.of( - Arguments.of("name", "int", Collections.emptyList(), new HashMap<>(), null), - Arguments.of("name", "float", Collections.singletonList("1"), new HashMap<>(), 1f), - Arguments.of("name", "long", Collections.singletonList("2"), new HashMap<>(), 2L), - Arguments.of("name", "bytes_decimal", Collections.singletonList("1"), new HashMap<>(Maps.of("name", new BigDecimal("15"))), new BigDecimal("1")), - Arguments.of("name15", "bytes_decimal", Collections.emptyList(), new HashMap<>(Maps.of("name15", new BigDecimal("15"))), null)); + Arguments.of("name", "int", Collections.emptyList(), new HashMap<>(), null), + Arguments.of("name", "float", Collections.singletonList("1"), new HashMap<>(), 1f), + Arguments.of("name", "long", Collections.singletonList("2"), new HashMap<>(), 2L), + Arguments.of("name", "bytes_decimal", Collections.singletonList("1"), new HashMap<>(Maps.of("name", new BigDecimal("15"))), new BigDecimal("1")), + Arguments.of("name15", "bytes_decimal", Collections.emptyList(), new HashMap<>(Maps.of("name15", new BigDecimal("15"))), null)); + } + + private static Stream parametersForGenerateValueWithList() { + return Stream.of( + Arguments.of(10, + List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10"), + List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10")), + Arguments.of(12, + List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10"), + List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "1", "2"))); } @ParameterizedTest @DisplayName("Testing Generate an Iterator With an empty list or a list with one value") @MethodSource("parametersForGenerateIteratorValueForField") - void testGenerateIteratorValueForField(final String fieldName, final String fieldType, final List fieldValuesList, final Map context, + void testGenerateIteratorValueForField( + final String fieldName, final String fieldType, final List fieldValuesList, final Map context, final Object expectedStored) { Assertions.assertThat(RandomIterator.generateIt(fieldName, fieldType, fieldValuesList, context)).isEqualTo(expectedStored); if (Objects.isNull(expectedStored)) { @@ -46,16 +57,6 @@ void testGenerateIteratorValueForField(final String fieldName, final String fiel } } - private static Stream parametersForGenerateValueWithList() { - return Stream.of( - Arguments.of(10, - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10"), - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10")), - Arguments.of(12, - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10"), - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "1", "2"))); - } - @ParameterizedTest @DisplayName("Testing Generate an Iterator With a List of Values") @MethodSource("parametersForGenerateValueWithList") diff --git a/src/test/java/com/sngular/kloadgen/randomtool/random/RandomMapTest.java b/src/test/java/com/sngular/kloadgen/randomtool/random/RandomMapTest.java index 686bb88c..0f20d957 100644 --- a/src/test/java/com/sngular/kloadgen/randomtool/random/RandomMapTest.java +++ b/src/test/java/com/sngular/kloadgen/randomtool/random/RandomMapTest.java @@ -29,7 +29,7 @@ private static Stream parametersForGenerateMapRandomValueFromList() { Arguments.of("short-map", 1, Collections.singletonList("testString:1"), Maps.of("testString", (short) 1), 1), Arguments.of("double-map", 1, Collections.singletonList("testString:1.0"), Maps.of("testString", 1.0), 1), Arguments.of("uuid-map", 1, Collections.singletonList("testString:0177f035-e51c-4a46-8b82-5b157371c2a5"), - Maps.of("testString", UUID.fromString("0177f035-e51c-4a46-8b82-5b157371c2a5")), 1 + Maps.of("testString", UUID.fromString("0177f035-e51c-4a46-8b82-5b157371c2a5")), 1 ) ); } @@ -38,7 +38,7 @@ private static Stream parametersForGenerateMapArrayRandomValueFromLis //The name of this type is due to: SchemaProcessorUtils.getOneDimensionValueType (this remove the last -map) return Stream.of(Arguments.of("string-array", 5, List.of("key1:[value1,value2,value3]", "key2:[valueB1,valueB2]"), - Map.of("key1", List.of("value1", "value2", "value3"), "key2", List.of("valueB1", "valueB2")), 1) + Map.of("key1", List.of("value1", "value2", "value3"), "key2", List.of("valueB1", "valueB2")), 1) ); } @@ -53,11 +53,11 @@ private static Stream parametersForGenerateMapFixedKeyRandomValue() { ); } - @ParameterizedTest + @ParameterizedTest(name = "test for {0}") @MethodSource("parametersForGenerateMapRandomValueFromList") void generateMapRandomValueFromList( final String fieldType, final Integer valueLength, final List fieldValuesList, final Map expected, final Integer size) { - final Entry[] expectedMap = expected.entrySet().toArray(new Entry[1]); + final Entry[] expectedMap = expected.entrySet().toArray(new Entry[1]); final Map result = (Map) new RandomMap().generateMap(fieldType, valueLength, fieldValuesList, size, Collections.emptyMap()); Assertions.assertThat(result).containsExactly(expectedMap); diff --git a/src/test/java/com/sngular/kloadgen/sampler/AsyncApiSamplerTest.java b/src/test/java/com/sngular/kloadgen/sampler/AsyncApiSamplerTest.java new file mode 100644 index 00000000..bb1056a4 --- /dev/null +++ b/src/test/java/com/sngular/kloadgen/sampler/AsyncApiSamplerTest.java @@ -0,0 +1,163 @@ +/* + * 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 com.sngular.kloadgen.sampler; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Properties; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.sngular.kloadgen.extractor.asyncapi.AsyncApiExtractorImpl; +import com.sngular.kloadgen.extractor.model.AsyncApiFile; +import com.sngular.kloadgen.model.FieldValueMapping; +import com.sngular.kloadgen.model.PropertyMapping; +import com.sngular.kloadgen.testutil.FileHelper; +import org.apache.jmeter.samplers.Entry; +import org.apache.jmeter.threads.JMeterContext; +import org.apache.jmeter.threads.JMeterContextService; +import org.apache.jmeter.threads.JMeterVariables; +import org.apache.jmeter.util.JMeterUtils; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Answers; +import org.mockito.MockedStatic; +import org.mockito.Mockito; + +class AsyncApiSamplerTest { + + private static AsyncApiFile asyncApiFileNode; + + private final FileHelper fileHelper = new FileHelper(); + + private final Properties properties = new Properties(); + + private final KafkaProducer kafkaProducer = Mockito.mock(KafkaProducer.class); + + private final Entry entry = new Entry(); + + private final ObjectMapper om = new ObjectMapper(new YAMLFactory()); + + private JMeterContext jmcx; + + private AsyncApiSampler sampler = new AsyncApiSampler(); + + //@Captor + //private ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Schema.class); + + private MockedStatic jmeterContextServiceMockedStatic; + + @BeforeEach + public final void setUp() throws IOException { + final File file = new File("src/test/resources"); + final String absolutePath = file.getAbsolutePath(); + JMeterUtils.loadJMeterProperties(absolutePath + "/kloadgen.properties"); + jmcx = JMeterContextService.getContext(); + jmcx.setVariables(new JMeterVariables()); + JMeterUtils.setLocale(Locale.ENGLISH); + sampler = new AsyncapiSamplerWrapper(kafkaProducer); + final var testFile = fileHelper.getContent("/asyncapi/event-api.yml"); + final JsonNode openApi = om.readTree(testFile); + asyncApiFileNode = new AsyncApiExtractorImpl().processNode(openApi); + jmeterContextServiceMockedStatic = Mockito.mockStatic(JMeterContextService.class, Answers.RETURNS_DEEP_STUBS); + + } + + @AfterEach + public void tearDown() { + properties.clear(); + kafkaProducer.close(); + jmeterContextServiceMockedStatic.close(); + } + + /*@Test + void testAsyncApiSampleBasic() { + sampler.setAsyncApiSchemaName(asyncApiFileNode.getAsyncApiFileNode().path("channels").toString().split("\"")[1]); + sampler.setBrokerConfiguration(getMappings()); + sampler.setSchemaFieldConfiguration(getListFieldValueMapping()); + sampler.setAsyncApiFileNode(asyncApiFileNode.getAsyncApiFileNode()); + + Mockito.when(kafkaProducer.send(new ProducerRecord<>("user_signup", Mockito.any()))).thenCallRealMethod(); + jmeterContextServiceMockedStatic.when(() -> JMeterContextService.getContext().getProperties()).thenReturn(properties); + //Aquí no sé como relacionar lo que hace el when con el método sample + SampleResult samp = sampler.sample(entry); + + Assertions.assertThat(samp).isNotNull() + .isEqualTo(" "); + }*/ + + public static List getMappings() { + + final List mappings = new ArrayList<>(); + final JsonNode serversNode = asyncApiFileNode.getAsyncApiFileNode().path("servers"); + if (serversNode != null) { + final Iterator serverNodes = serversNode.elements(); + while (serverNodes.hasNext()) { + final JsonNode serverNode = serverNodes.next(); + final String serverUrl = serverNode.get("url").asText(); + final String serverProtocol = serverNode.get("protocol").asText(); + final String serverDescription = serverNode.get("description").asText(); + + mappings.add(new PropertyMapping("url", serverUrl)); + mappings.add(new PropertyMapping("protocol", serverProtocol)); + mappings.add(new PropertyMapping("description", serverDescription)); + } + } + return mappings; + } + + public static List getListFieldValueMapping() { + + int i = 0; + String field = null; + final List fieldValueMappings = new ArrayList<>(); + final JsonNode valueFields = asyncApiFileNode.getAsyncApiFileNode().path("components") + .path("schemas") + .path("userSignedUpPayload") + .path("properties"); + if (valueFields != null) { + final Iterator fieldValuesNodes = valueFields.elements(); + while (fieldValuesNodes.hasNext()) { + final JsonNode fieldValuesNode = fieldValuesNodes.next(); + String type = fieldValuesNode.get("type").toString().replaceAll("\"", ""); + type = type.replaceAll("'", ""); + String value = fieldValuesNode.get("description").toString().replaceAll("\"", ""); + value = "[" + value.replaceAll("'", "") + "]"; + + switch (i) { + case 0: + field = "firstName"; + break; + case 1: + field = "lastName"; + break; + case 2: + field = "email"; + break; + case 3: + field = "date"; + break; + default: + break; + } + + fieldValueMappings.add(new FieldValueMapping(field, type, 0, value, null, null, null)); + + i++; + } + } + return fieldValueMappings; + } + + +} \ No newline at end of file diff --git a/src/test/java/com/sngular/kloadgen/sampler/AsyncapiSamplerWrapper.java b/src/test/java/com/sngular/kloadgen/sampler/AsyncapiSamplerWrapper.java new file mode 100644 index 00000000..f71127dc --- /dev/null +++ b/src/test/java/com/sngular/kloadgen/sampler/AsyncapiSamplerWrapper.java @@ -0,0 +1,17 @@ +package com.sngular.kloadgen.sampler; + +import org.apache.kafka.clients.producer.KafkaProducer; + +public class AsyncapiSamplerWrapper extends AsyncApiSampler { + + private KafkaProducer kafkaProducer; + + protected AsyncapiSamplerWrapper(final KafkaProducer kafkaProducer) { + this.kafkaProducer = kafkaProducer; + } + + @Override + public final KafkaProducer getKafkaProducer() { + return kafkaProducer; + } +} diff --git a/src/test/java/com/sngular/kloadgen/sampler/SamplerUtilTest.java b/src/test/java/com/sngular/kloadgen/sampler/SamplerUtilTest.java index 7b4024bf..be6377c3 100644 --- a/src/test/java/com/sngular/kloadgen/sampler/SamplerUtilTest.java +++ b/src/test/java/com/sngular/kloadgen/sampler/SamplerUtilTest.java @@ -14,10 +14,10 @@ import java.util.stream.Stream; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; import com.sngular.kloadgen.processor.fixture.JsonSchemaFixturesConstants; import com.sngular.kloadgen.serializer.SerializerTestFixture; import com.sngular.kloadgen.testutil.FileHelper; +import com.sngular.kloadgen.util.ProducerKeysHelper; import com.sngular.kloadgen.util.PropsKeysHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; import org.apache.jmeter.threads.JMeterContext; @@ -64,20 +64,20 @@ void configureValueGeneratorTest(final String jmeterProps) throws IOException { } public JMeterVariables getVariablesAvro() throws IOException { - final File testFile = fileHelper.getFile("/avro-files/avros-example-with-sub-entity-array-test.avsc"); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "AVRO"); + final var testFile = fileHelper.getContent("/avro-files/avros-example-with-sub-entity-array-test.avsc"); final var variables = new JMeterVariables(); variables.put(PropsKeysHelper.KEY_SCHEMA_TYPE, "avro"); variables.put(PropsKeysHelper.VALUE_SUBJECT_NAME, "test"); variables.put(PropsKeysHelper.KEY_SUBJECT_NAME, "test"); - variables.put(PropsKeysHelper.VALUE_SCHEMA, String.valueOf(parsedSchema.rawSchema())); + variables.put(PropsKeysHelper.VALUE_SCHEMA, testFile); variables.put(PropsKeysHelper.VALUE_SCHEMA_TYPE, "avro"); - variables.put(PropsKeysHelper.KEY_SCHEMA, String.valueOf(parsedSchema.rawSchema())); + variables.put(PropsKeysHelper.KEY_SCHEMA, testFile); variables.putObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES, Arrays.asList( FieldValueMapping.builder().fieldName("subEntity.anotherLevel.subEntityIntArray[2]").fieldType("int-array").valueLength(0).fieldValueList("[1]").required(true) .isAncestorRequired(true).build(), FieldValueMapping.builder().fieldName("topLevelIntArray[3]").fieldType("int-array").valueLength(0).fieldValueList("[2]").required(true).isAncestorRequired(true).build()) ); + variables.put(ProducerKeysHelper.KEY_NAME_STRATEGY, "theStrategy"); return variables; } @@ -105,29 +105,28 @@ void configureKeyGeneratorTest(final String jmeterProps) throws IOException { public JMeterVariables getVariablesJsonSchema() throws IOException { - final File testFile = fileHelper.getFile("/jsonschema/basic.jcs"); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "JSON"); + final var testFile = fileHelper.getContent("/jsonschema/basic.jcs"); final var variables = new JMeterVariables(); variables.put(PropsKeysHelper.KEY_SCHEMA_TYPE, "JSON"); variables.put(PropsKeysHelper.VALUE_SUBJECT_NAME, "jsonSubject"); variables.put(PropsKeysHelper.KEY_SUBJECT_NAME, "jsonSubject"); - variables.put(PropsKeysHelper.VALUE_SCHEMA, String.valueOf(parsedSchema.rawSchema())); - variables.put(PropsKeysHelper.KEY_SCHEMA, String.valueOf(parsedSchema.rawSchema())); + variables.put(PropsKeysHelper.VALUE_SCHEMA, testFile); + variables.put(PropsKeysHelper.KEY_SCHEMA, testFile); variables.putObject(PropsKeysHelper.VALUE_SCHEMA_PROPERTIES, JsonSchemaFixturesConstants.SIMPLE_SCHEMA); + variables.put(ProducerKeysHelper.KEY_NAME_STRATEGY, "theStrategy"); return variables; } public JMeterVariables getVariablesProtobuf() throws IOException { - final File testFile = fileHelper.getFile("/proto-files/easyTest.proto"); - final ParsedSchema parsedSchema = new ParsedSchema(testFile, "PROTOBUF"); + final var testFile = fileHelper.getContent("/proto-files/easyTest.proto"); final var variables = new JMeterVariables(); variables.put(PropsKeysHelper.KEY_SCHEMA_TYPE, "protobuf"); variables.put(PropsKeysHelper.VALUE_SUBJECT_NAME, "protobufSubject"); - variables.put(PropsKeysHelper.VALUE_SCHEMA, String.valueOf(parsedSchema.schema())); + variables.put(PropsKeysHelper.VALUE_SCHEMA, String.valueOf(testFile)); variables.put(PropsKeysHelper.VALUE_SCHEMA_TYPE, "protobuf"); - variables.put(PropsKeysHelper.KEY_SCHEMA, String.valueOf(parsedSchema.schema())); + variables.put(PropsKeysHelper.KEY_SCHEMA, String.valueOf(testFile)); variables.put(PropsKeysHelper.KEY_SUBJECT_NAME, "protobufSubject"); variables.putObject(PropsKeysHelper.KEY_SCHEMA_PROPERTIES, Arrays.asList( SerializerTestFixture.createFieldValueMapping("street", "string"), @@ -137,6 +136,7 @@ public JMeterVariables getVariablesProtobuf() throws IOException { SerializerTestFixture.createFieldValueMapping("street", "string"), SerializerTestFixture.createFieldValueMapping("number[]", "int-array"), SerializerTestFixture.createFieldValueMapping("zipcode", "long"))); + variables.put(ProducerKeysHelper.KEY_NAME_STRATEGY, "theStrategy"); return variables; } diff --git a/src/test/java/com/sngular/kloadgen/serializer/AvroDeserializerTest.java b/src/test/java/com/sngular/kloadgen/serializer/AvroDeserializerTest.java index 3379c028..52779a4a 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/AvroDeserializerTest.java +++ b/src/test/java/com/sngular/kloadgen/serializer/AvroDeserializerTest.java @@ -10,12 +10,13 @@ import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.processor.SchemaProcessor; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; import com.sngular.kloadgen.util.PropsKeysHelper; import lombok.extern.slf4j.Slf4j; +import org.apache.avro.Schema; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Named; @@ -32,12 +33,6 @@ class AvroDeserializerTest { private AvroSerializer avroSerializer; - @BeforeEach - void setUp() { - avroDeserializer = new AvroDeserializer(); - avroSerializer = new AvroSerializer(); - } - private static Stream getSchemaToTest() { final Builder builder = Stream.builder(); @@ -69,18 +64,22 @@ private static Stream getSchemaToTest() { return builder.build(); } + @BeforeEach + void setUp() { + avroDeserializer = new AvroDeserializer(); + avroSerializer = new AvroSerializer(); + } + @ParameterizedTest @MethodSource("getSchemaToTest") void deserialize(final File schemaFile, final List fieldValueMappings) throws Exception { final var schemaStr = SerializerTestFixture.readSchema(schemaFile); - final BaseSchemaMetadata confluentBaseSchemaMetadata = - new BaseSchemaMetadata<>( - ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, - schemaStr))); + final var confluentBaseSchemaMetadata = new BaseSchemaMetadata<>(ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, + schemaStr))); avroDeserializer.configure(Map.of(PropsKeysHelper.VALUE_SCHEMA, schemaStr), false); - final ParsedSchema parsedSchema = new ParsedSchema(schemaFile, "AVRO"); + final var parsedSchema = new AvroParsedSchema("TEST", new Schema.Parser().parse(schemaFile)); AVRO_SCHEMA_PROCESSOR.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final var generatedRecord = AVRO_SCHEMA_PROCESSOR.next(); diff --git a/src/test/java/com/sngular/kloadgen/serializer/AvroSerializersTestFixture.java b/src/test/java/com/sngular/kloadgen/serializer/AvroSerializersTestFixture.java index db88d04d..0b1e4aa1 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/AvroSerializersTestFixture.java +++ b/src/test/java/com/sngular/kloadgen/serializer/AvroSerializersTestFixture.java @@ -2,6 +2,7 @@ import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.List; import com.sngular.kloadgen.model.FieldValueMapping; @@ -13,8 +14,8 @@ public final class AvroSerializersTestFixture { static final List> SERIALIZER_LIST = List.of( - new GenericAvroRecordSerializer<>(), - new GenericAvroRecordBinarySerializer<>() + new GenericAvroRecordSerializer<>(), + new GenericAvroRecordBinarySerializer<>() ); static final Pair> TEST_SUBENTITY_ARRAY = new Pair<>( @@ -45,7 +46,7 @@ public final class AvroSerializersTestFixture { static final Pair> TEST_OPTIONAL_ENUM = new Pair<>( new FileHelper().getFile("/avro-files/optionalEnum.avsc"), - Arrays.asList(SerializerTestFixture.createFieldValueMapping("aggregateAttribute.fruitList.fruits[].fruitType", "enum")) + Collections.singletonList(SerializerTestFixture.createFieldValueMapping("aggregateAttribute.fruitList.fruits[].fruitType", "enum")) ); static final Pair> TEST_FILE_ISSUE = new Pair<>( diff --git a/src/test/java/com/sngular/kloadgen/serializer/GenericRecordAvroSerializersTest.java b/src/test/java/com/sngular/kloadgen/serializer/GenericRecordAvroSerializersTest.java index 3be6ef98..eb0f2f72 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/GenericRecordAvroSerializersTest.java +++ b/src/test/java/com/sngular/kloadgen/serializer/GenericRecordAvroSerializersTest.java @@ -7,10 +7,11 @@ import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.AvroParsedSchema; import com.sngular.kloadgen.processor.SchemaProcessor; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; +import org.apache.avro.Schema; import org.apache.avro.generic.GenericRecord; import org.apache.kafka.common.serialization.Serializer; import org.assertj.core.api.Assertions; @@ -67,12 +68,12 @@ private static void extracted(final Serializer serializer, final @MethodSource("getSerializerAndSchemaToTest") void genericAvroRecordSerializerTest(final Serializer serializer, final File schemaFile, final List fieldValueMappings) throws Exception { final var schemaStr = SerializerTestFixture.readSchema(schemaFile); - final BaseSchemaMetadata confluentBaseSchemaMetadata = + final BaseSchemaMetadata confluentBaseSchemaMetadata = new BaseSchemaMetadata<>( ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, schemaStr))); - final ParsedSchema parsedSchema = new ParsedSchema(schemaFile, "AVRO"); + final var parsedSchema = new AvroParsedSchema("AVRO", new Schema.Parser().parse(schemaFile)); AVRO_SCHEMA_PROCESSOR.processSchema(SchemaTypeEnum.AVRO, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final var generatedRecord = AVRO_SCHEMA_PROCESSOR.next(); diff --git a/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTest.java b/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTest.java index 4a698e9f..391701ae 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTest.java +++ b/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTest.java @@ -8,10 +8,11 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.JsonParsedSchema; import com.sngular.kloadgen.processor.SchemaProcessor; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; +import com.sngular.kloadgen.testutil.FileHelper; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Named; import org.junit.jupiter.params.ParameterizedTest; @@ -56,13 +57,16 @@ private static Stream getSchemaToTest() { @ParameterizedTest @MethodSource("getSchemaToTest") final void recordSerializersTestLogicalTypes(final File schemaFile, final List fieldValueMappings) throws Exception { + + final var fileContent = FileHelper.readFile(schemaFile); final var schemaStr = SerializerTestFixture.readSchema(schemaFile); + final BaseSchemaMetadata confluentBaseSchemaMetadata = new BaseSchemaMetadata<>( ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, schemaStr))); - final ParsedSchema parsedSchema = new ParsedSchema(schemaFile, "JSON"); + final var parsedSchema = new JsonParsedSchema("JSON", fileContent); JSON_SCHEMA_PROCESSOR.processSchema(SchemaTypeEnum.JSON, parsedSchema, confluentBaseSchemaMetadata, fieldValueMappings); final var objectNode = JSON_SCHEMA_PROCESSOR.next(); diff --git a/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTestFixture.java b/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTestFixture.java index 9e3da2ac..01c491af 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTestFixture.java +++ b/src/test/java/com/sngular/kloadgen/serializer/JsonSerializerTestFixture.java @@ -2,6 +2,7 @@ import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.List; import com.sngular.kloadgen.model.FieldValueMapping; @@ -229,7 +230,7 @@ final class JsonSerializerTestFixture { static final Pair> TEST_MULTIPLE_TYPE_SINGLE = new Pair<>( new FileHelper().getFile("/jsonschema/multiple-type-single.jcs"), - Arrays.asList( + Collections.singletonList( SerializerTestFixture.createFieldValueMapping("id", "number")) ); diff --git a/src/test/java/com/sngular/kloadgen/serializer/ProtobufSerializerTest.java b/src/test/java/com/sngular/kloadgen/serializer/ProtobufSerializerTest.java index 492b16c9..38571455 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/ProtobufSerializerTest.java +++ b/src/test/java/com/sngular/kloadgen/serializer/ProtobufSerializerTest.java @@ -9,11 +9,14 @@ import com.sngular.kloadgen.common.SchemaTypeEnum; import com.sngular.kloadgen.model.FieldValueMapping; -import com.sngular.kloadgen.parsedschema.ParsedSchema; +import com.sngular.kloadgen.parsedschema.ProtobufParsedSchema; import com.sngular.kloadgen.processor.SchemaProcessor; import com.sngular.kloadgen.schemaregistry.adapter.impl.BaseSchemaMetadata; import com.sngular.kloadgen.schemaregistry.adapter.impl.ConfluentSchemaMetadata; +import com.sngular.kloadgen.testutil.FileHelper; import com.sngular.kloadgen.util.SchemaRegistryKeyHelper; +import com.squareup.wire.schema.Location; +import com.squareup.wire.schema.internal.parser.ProtoParser; import lombok.extern.slf4j.Slf4j; import org.apache.jmeter.threads.JMeterContext; import org.apache.jmeter.threads.JMeterContextService; @@ -29,19 +32,9 @@ @Slf4j class ProtobufSerializerTest { - private ProtobufSerializer protobufSerializer; + private final FileHelper fileHelper = new FileHelper(); - @BeforeEach - void setUp() { - protobufSerializer = new ProtobufSerializer(); - final File file = new File("src/test/resources"); - final String absolutePath = file.getAbsolutePath(); - JMeterUtils.loadJMeterProperties(absolutePath + "/kloadgen.properties"); - final JMeterContext jmcx = JMeterContextService.getContext(); - jmcx.setVariables(new JMeterVariables()); - JMeterUtils.setLocale(Locale.ENGLISH); - JMeterContextService.getContext().getProperties().put(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, "CONFLUENT"); - } + private ProtobufSerializer protobufSerializer; private static Stream getSchemaToTest() { final Builder builder = Stream.builder(); @@ -74,15 +67,29 @@ private static Stream getSchemaToTest() { return builder.build(); } + @BeforeEach + void setUp() { + protobufSerializer = new ProtobufSerializer(); + final File file = new File("src/test/resources"); + final String absolutePath = file.getAbsolutePath(); + JMeterUtils.loadJMeterProperties(absolutePath + "/kloadgen.properties"); + final JMeterContext jmcx = JMeterContextService.getContext(); + jmcx.setVariables(new JMeterVariables()); + JMeterUtils.setLocale(Locale.ENGLISH); + JMeterContextService.getContext().getProperties().put(SchemaRegistryKeyHelper.SCHEMA_REGISTRY_NAME, "CONFLUENT"); + } + @ParameterizedTest @MethodSource("getSchemaToTest") void serialize(final File schemaFile, final List fieldValueMappings) throws IOException { - final ParsedSchema parsedSchema = new ParsedSchema(schemaFile, "PROTOBUF"); + final String testFile = FileHelper.readFile(schemaFile); + final var schema = new ProtobufParsedSchema("PROTOBUF", new ProtoParser(Location.get("/"), testFile.toCharArray()).readProtoFile()); + final SchemaProcessor protobufSchemaProcessor = new SchemaProcessor(); - final BaseSchemaMetadata confluentBaseSchemaMetadata = + final var confluentBaseSchemaMetadata = new BaseSchemaMetadata<>( ConfluentSchemaMetadata.parse(new io.confluent.kafka.schemaregistry.client.SchemaMetadata(1, 1, ""))); - protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, parsedSchema.rawSchema(), confluentBaseSchemaMetadata, fieldValueMappings); + protobufSchemaProcessor.processSchema(SchemaTypeEnum.PROTOBUF, schema.getRawSchema(), confluentBaseSchemaMetadata, fieldValueMappings); final var generatedRecord = protobufSchemaProcessor.next(); diff --git a/src/test/java/com/sngular/kloadgen/serializer/SerializerTestFixture.java b/src/test/java/com/sngular/kloadgen/serializer/SerializerTestFixture.java index ae6827a7..12100776 100644 --- a/src/test/java/com/sngular/kloadgen/serializer/SerializerTestFixture.java +++ b/src/test/java/com/sngular/kloadgen/serializer/SerializerTestFixture.java @@ -1,3 +1,9 @@ +/* + * 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 com.sngular.kloadgen.serializer; import java.io.File; diff --git a/src/test/java/com/sngular/kloadgen/testutil/FileHelper.java b/src/test/java/com/sngular/kloadgen/testutil/FileHelper.java index 1e8b7f06..3b5ba16c 100644 --- a/src/test/java/com/sngular/kloadgen/testutil/FileHelper.java +++ b/src/test/java/com/sngular/kloadgen/testutil/FileHelper.java @@ -7,14 +7,20 @@ package com.sngular.kloadgen.testutil; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.net.URL; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; public final class FileHelper { + public static String readFile(final File fileToRead) throws IOException { + return IOUtils.toString(new FileInputStream(fileToRead), Charset.defaultCharset()); + } + public File getFile(final String fileName) { final URL url = this.getClass().getResource(fileName); return new File(url.getFile()); diff --git a/src/test/java/com/sngular/kloadgen/testutil/ParsedSchemaUtil.java b/src/test/java/com/sngular/kloadgen/testutil/ParsedSchemaUtil.java deleted file mode 100644 index 7469ba29..00000000 --- a/src/test/java/com/sngular/kloadgen/testutil/ParsedSchemaUtil.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.sngular.kloadgen.testutil; - -import com.sngular.kloadgen.parsedschema.IParsedSchema; - -public final class ParsedSchemaUtil implements IParsedSchema { - - @Override - public String schemaType() { - return null; - } - - @Override - public String name() { - return null; - } - - @Override - public String canonicalString() { - return null; - } - - @Override - public Object rawSchema() { - return null; - } - -} diff --git a/src/test/resources/asyncapi/event-api.yml b/src/test/resources/asyncapi/event-api.yml new file mode 100644 index 00000000..a568870c --- /dev/null +++ b/src/test/resources/asyncapi/event-api.yml @@ -0,0 +1,51 @@ +asyncapi: 2.0.0 +info: + title: Email Service + version: '1.0.0' + description: | + Sends emails upon certain events + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: mqtt://test.mosquitto.org + protocol: mqtt + description: Test MQTT broker + +channels: + user_signedup: + publish: + operationId: onUserSignUp + message: + $ref : '#/components/messages/UserSignedUp' + +components: + messages: + UserSignedUp: + name: userSignedUp + title: User signed up event + summary: Inform about a new user registration in the system + contentType: application/json + payload: + $ref: '#/components/schemas/userSignedUpPayload' + + schemas: + userSignedUpPayload: + type: object + properties: + firstName: + type: string + description: "foo" + lastName: + type: string + description: "bar" + email: + type: string + format: email + description: "baz" + createdAt: + type: string + format: date-time + description: "foo" \ No newline at end of file