diff --git a/docs/schemas.md b/docs/schemas.md index 495919fc..baeeaea9 100644 --- a/docs/schemas.md +++ b/docs/schemas.md @@ -86,13 +86,15 @@ A special type has also been created, `seq`, to allow creating a custom sequence In order to create a sequence, you need to specify `seq` as **Field Type**. -> In previous versions (up to 4.0.0), typing `{` in **Field Value List** was another requirement in order to create sequences. This is no longer required or supported. +> In previous versions (up to 4.0.0), typing `{` in **Field Values List** was another requirement in order to create sequences. This is no longer required or supported. | Type | Details | Returns | |----------|-------------------------------------------------------------------------------|--------| | seq | Generates a numeric sequence starting in 1. Will cast to the AVRO Field Type. | Returns a sequence starting in 1 | -**Note:** If you want to specify a starting value, put it in the first position in the **Field Values List** field. The other values within the field will be considered constants for this field and converted to the corresponding field type. +**Note:** If you want to specify a starting value, put it in the **Field Values List** field. + +> Sequences don't accept more than one value in the **Field Values List** field. > Keep in mind to avoid Cast exceptions. diff --git a/pom-maven-central.xml b/pom-maven-central.xml index b2456530..1869621e 100644 --- a/pom-maven-central.xml +++ b/pom-maven-central.xml @@ -7,7 +7,7 @@ kloadgen - 4.13.1 + 5.0.0 KLoadGen Load Generation Jmeter plugin for Kafka Cluster. Supporting AVRO, JSON Schema and Protobuf schema types. Generate Artificial data based on Data specification https://corunet.github.io/kloadgen/ diff --git a/pom.xml b/pom.xml index 057adf32..1fc19156 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ kloadgen - 4.13.1 + 5.0.0 KLoadGen Load Generation Jmeter plugin for Kafka Cluster. Supporting AVRO, JSON Schema and Protobuf schema types. Generate Artificial data base on Data specification https://corunet.github.io/kloadgen/ diff --git a/src/main/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorTool.java b/src/main/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorTool.java index 42b20c5e..96a637b0 100644 --- a/src/main/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorTool.java +++ b/src/main/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorTool.java @@ -70,11 +70,8 @@ public final Object generateObject(final Schema schema, final String fieldName, } else if ("seq".equalsIgnoreCase(fieldType)) { final String type = Type.UNION.getName().equals(ValueUtils.getValidTypeFromSchema(schema)) ? getRecordUnion(schema.getTypes()).getName() : ValueUtils.getValidTypeFromSchema(schema); - if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomSequence.isTypeNotSupported(type))) { - value = RandomSequence.generateSequenceForFieldValueList(fieldName, type, fieldValuesList, context); - } else { - value = RandomSequence.generateSeq(fieldName, type, parameterList, context); - } + value = RandomSequence.generateSeq(fieldName, type, parameterList, context); + } else if ("it".equalsIgnoreCase(fieldType)) { final String type = Type.UNION.getName().equals(ValueUtils.getValidTypeFromSchema(schema)) ? getRecordUnion(schema.getTypes()).getName() : ValueUtils.getValidTypeFromSchema(schema); @@ -104,7 +101,7 @@ private Object getEnumOrGenerate(final String fieldName, final String fieldType, value = new GenericData.EnumSymbol(schema, enumValueList.get(RandomUtils.nextInt(0, enumValueList.size()))); } else { if ("Seq".equalsIgnoreCase(fieldType)) { - value = new GenericData.EnumSymbol(schema, RandomSequence.generateSequenceForFieldValueList(fieldName, fieldValueMappingType, parameterList, context)); + value = new GenericData.EnumSymbol(schema, RandomSequence.generateSeq(fieldName, fieldValueMappingType, parameterList, context)); } else if ("It".equalsIgnoreCase(fieldType)) { value = new GenericData.EnumSymbol(schema, RandomIterator.generateIteratorForFieldValueList(fieldName, fieldValueMappingType, parameterList, context)); } else { @@ -201,7 +198,7 @@ public final Object generateArray( final List value = new ArrayList<>(valueLength); if ("seq".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomSequence.isTypeNotSupported(fieldType))) { - value.add(RandomSequence.generateSequenceForFieldValueList(fieldName, fieldType, parameterList, context)); + value.add(RandomSequence.generateSeq(fieldName, fieldType, parameterList, context)); } else if ("it".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomIterator.isTypeNotSupported(fieldType))) { value.add(RandomIterator.generateIteratorForFieldValueList(fieldName, fieldType, parameterList, context)); @@ -233,7 +230,7 @@ public final Object generateMap( if ("seq".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomSequence.isTypeNotSupported(fieldType))) { value.put(RANDOM_OBJECT.generateRandom("string", valueLength, Collections.emptyList(), Collections.emptyMap()), - RandomSequence.generateSequenceForFieldValueList(fieldName, fieldType, parameterList, context)); + RandomSequence.generateSeq(fieldName, fieldType, parameterList, context)); } else if ("it".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomIterator.isTypeNotSupported(fieldType))) { value.put(RANDOM_OBJECT.generateRandom("string", valueLength, Collections.emptyList(), Collections.emptyMap()), diff --git a/src/main/java/net/coru/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java b/src/main/java/net/coru/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java index d3eaf91e..358a14b6 100644 --- a/src/main/java/net/coru/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java +++ b/src/main/java/net/coru/kloadgen/randomtool/generator/ProtoBufGeneratorTool.java @@ -34,7 +34,7 @@ public final Object generateArray(final String fieldName, final String fieldType final List value = new ArrayList<>(arraySize); if ("seq".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomSequence.isTypeNotSupported(fieldType))) { - value.add(RandomSequence.generateSequenceForFieldValueList(fieldName, fieldType, parameterList, context)); + value.add(RandomSequence.generateSeq(fieldName, fieldType, parameterList, context)); } else { for (int i = arraySize; i > 0; i--) { value.add(RandomSequence.generateSeq(fieldName, fieldType, parameterList, context)); diff --git a/src/main/java/net/coru/kloadgen/randomtool/generator/StatelessGeneratorTool.java b/src/main/java/net/coru/kloadgen/randomtool/generator/StatelessGeneratorTool.java index 4eda9896..994b3df2 100644 --- a/src/main/java/net/coru/kloadgen/randomtool/generator/StatelessGeneratorTool.java +++ b/src/main/java/net/coru/kloadgen/randomtool/generator/StatelessGeneratorTool.java @@ -40,11 +40,7 @@ public final Object generateObject(final String fieldName, final String fieldTyp final Object value; if ("seq".equals(fieldType)) { - if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomSequence.isTypeNotSupported(fieldType))) { - value = RandomSequence.generateSequenceForFieldValueList(fieldName, fieldType, fieldValuesList, context); - } else { - value = RandomSequence.generateSeq(fieldName, fieldType, parameterList, context); - } + value = RandomSequence.generateSeq(fieldName, fieldType, parameterList, context); } else if ("it".equals(fieldType)) { if (!fieldValuesList.isEmpty() && (fieldValuesList.size() > 1 || RandomIterator.isTypeNotSupported(fieldType))) { value = RandomIterator.generateIteratorForFieldValueList(fieldName, fieldType, fieldValuesList, context); diff --git a/src/main/java/net/coru/kloadgen/randomtool/random/RandomSequence.java b/src/main/java/net/coru/kloadgen/randomtool/random/RandomSequence.java index 1f613cf0..7bdc536e 100644 --- a/src/main/java/net/coru/kloadgen/randomtool/random/RandomSequence.java +++ b/src/main/java/net/coru/kloadgen/randomtool/random/RandomSequence.java @@ -35,22 +35,17 @@ public static boolean isTypeNotSupported(final String fieldType) { } public static Object generateSeq(final String fieldName, final String fieldType, final List fieldValueList, final Map context) { + if (!fieldValueList.isEmpty() && fieldValueList.size() > 1) { + throw new IllegalArgumentException("Sequences do not accept more than one option as initial value"); + } return context.compute(fieldName, (fieldNameMap, seqObject) -> seqObject == null ? getFirstValueOrDefaultForType(fieldValueList, fieldType) : addOneCasted(seqObject, fieldType)); } - public static Object generateSequenceForFieldValueList(final String fieldName, final String fieldType, final List fieldValueList, final Map context) { - final var index = (Integer) context.compute(fieldName, (fieldNameMap, seqObject) -> seqObject == null ? 0 : (((Integer) seqObject) + 1) % fieldValueList.size()); - return ValueUtils.castValue(fieldValueList.get(index), fieldType); - } - private static Object getFirstValueOrDefaultForType(final List fieldValueList, final String fieldType) { - Object result = null; - if (isTypeNotSupported(fieldType)) { - throw new IllegalArgumentException("Field type is not supported for sequences"); - } + final Object result; if (!fieldValueList.isEmpty()) { result = ValueUtils.castValue(fieldValueList.get(0), fieldType); } else { diff --git a/src/test/java/net/coru/kloadgen/processor/AvroSchemaProcessorTest.java b/src/test/java/net/coru/kloadgen/processor/AvroSchemaProcessorTest.java index a59e4487..c7c5bc51 100644 --- a/src/test/java/net/coru/kloadgen/processor/AvroSchemaProcessorTest.java +++ b/src/test/java/net/coru/kloadgen/processor/AvroSchemaProcessorTest.java @@ -417,11 +417,11 @@ private GenericRecord entityForCustomSequenceOfValuesWithSameStartingStartingVal } @Test - @DisplayName("Should process Custom Sequence Of Values With Same Starting Starting Value") - void testCustomSequenceOfValuesWithSameStartingStartingValue() { + @DisplayName("Should process Custom Iterator Of Values With Same Starting Value") + void testCustomSequenceOfValuesWithSameStartingValue() { final var fieldValueMappingList = asList( - FieldValueMapping.builder().fieldName("values[3].id").fieldType("seq").valueLength(0).fieldValueList("[1,2]").required(true).isAncestorRequired(true).build(), - FieldValueMapping.builder().fieldName("values[3].otherId").fieldType("seq").valueLength(0).fieldValueList("[1,3]").required(true).isAncestorRequired(true).build()); + FieldValueMapping.builder().fieldName("values[3].id").fieldType("it").valueLength(0).fieldValueList("[1,2]").required(true).isAncestorRequired(true).build(), + FieldValueMapping.builder().fieldName("values[3].otherId").fieldType("it").valueLength(0).fieldValueList("[1,3]").required(true).isAncestorRequired(true).build()); final var avroSchemaProcessor = new SchemaProcessor(); final var schemaWithTwoSequencesWithSameStartingValue = SchemaBuilder @@ -454,7 +454,7 @@ void testCustomSequenceOfValuesWithSameStartingStartingValue() { Assertions.assertThat(message.getGenericRecord()).isEqualTo(entity); } - private GenericRecord entityForCustomSequenceOfValuesWithSameFieldNameInDifferentMappings(final Schema schema, final List idValues, final List idOtherValues) { + private GenericRecord entityForCustomIteratorOfValuesWithSameFieldNameInDifferentMappings(final Schema schema, final List idValues, final List idOtherValues) { final var entity = new GenericData.Record(schema); final var valuesData = getIdRecordsList(entity, "values", idValues); final var otherValuesData = getIdRecordsList(entity, "otherValues", idOtherValues); @@ -475,16 +475,16 @@ private List getIdRecordsList(final GenericRecord entity, final S } @Test - @DisplayName("Should process Custom Sequence Of Values With Same FieldName In Different Mappings") - void testCustomSequenceOfValuesWithSameFieldNameInDifferentMappings() { + @DisplayName("Should process Custom Iterator Of Values With Same FieldName In Different Mappings") + void testCustomIteratorOfValuesWithSameFieldNameInDifferentMappings() { final var fieldValueMappingList = asList( - FieldValueMapping.builder().fieldName("values[4].id").fieldType("seq").valueLength(0).fieldValueList("[1,2.44,3.6]").required(true).isAncestorRequired(true).build(), - FieldValueMapping.builder().fieldName("otherValues[4].id").fieldType("seq").valueLength(0).fieldValueList("[1,3.02,4.98]").required(true).isAncestorRequired(true).build()); + FieldValueMapping.builder().fieldName("values[4].id").fieldType("it").valueLength(0).fieldValueList("[1,2.44,3.6]").required(true).isAncestorRequired(true).build(), + FieldValueMapping.builder().fieldName("otherValues[4].id").fieldType("it").valueLength(0).fieldValueList("[1,3.02,4.98]").required(true).isAncestorRequired(true).build()); final var idSchema = LogicalTypes.decimal(5, 2).addToSchema(SchemaBuilder.builder().bytesBuilder().endBytes()); final var avroSchemaProcessor = new SchemaProcessor(); - final var schemaWithTwoSequencesWithSameStartingValue = SchemaBuilder + final var schemaWithTwoIteratorsWithSameStartingValue = SchemaBuilder .builder() .record("Root") .fields() @@ -513,8 +513,8 @@ void testCustomSequenceOfValuesWithSameFieldNameInDifferentMappings() { .endRecord()) .noDefault() .endRecord(); - final var entity = entityForCustomSequenceOfValuesWithSameFieldNameInDifferentMappings(schemaWithTwoSequencesWithSameStartingValue, asList("1", "2.44", "3.6", "1"), asList("1", "3.02", "4.98", "1")); - avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schemaWithTwoSequencesWithSameStartingValue, + final var entity = entityForCustomIteratorOfValuesWithSameFieldNameInDifferentMappings(schemaWithTwoIteratorsWithSameStartingValue, asList("1", "2.44", "3.6", "1"), asList("1", "3.02", "4.98", "1")); + avroSchemaProcessor.processSchema(SchemaTypeEnum.AVRO, schemaWithTwoIteratorsWithSameStartingValue, new SchemaMetadata(1, 1, ""), fieldValueMappingList); diff --git a/src/test/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorToolTest.java b/src/test/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorToolTest.java index 4555dcdb..9f8a39c1 100644 --- a/src/test/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorToolTest.java +++ b/src/test/java/net/coru/kloadgen/randomtool/generator/AvroGeneratorToolTest.java @@ -169,7 +169,7 @@ void testGenerateRandomValue(String fieldType, Integer valueLength, List assertThat(String.valueOf(number)).hasSize(valueLength); } - private static Stream parametersForGenerateFieldValuesListSequence() { + private static Stream parametersForGenerateFieldValuesListIterator() { return Stream.of( Arguments.of(18, List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20"), @@ -186,15 +186,15 @@ private static Stream parametersForGenerateFieldValuesListSequence() } @ParameterizedTest - @DisplayName("Testing generate a sequence of a list of values") - @MethodSource("parametersForGenerateFieldValuesListSequence") + @DisplayName("Testing generate an iterator of a list of values") + @MethodSource("parametersForGenerateFieldValuesListIterator") void testGenerateFieldValuesListSequence(int size, List fieldValuesList, String fieldType, List expected) { var intList = new ArrayList<>(); Schema schema = fieldType.equals(ValidTypeConstants.INT) ? SchemaBuilder.builder().intType() : SchemaBuilder.builder().stringType(); Field field = new Field("name", schema); FieldValueMapping fieldValueMapping = FieldValueMapping.builder() .fieldName(field.name()) - .fieldType("seq") + .fieldType("it") .valueLength(0) .fieldValueList(String.join(",", fieldValuesList)) .build(); @@ -229,7 +229,7 @@ void testGenerateRandomValueForEnums(String fieldType, Integer valueLength, List private static Stream parametersForGenerateSequenceValueForField() { return Stream.of( - Arguments.of("seq", 1, Collections.singletonList("0"), new Field("name", SchemaBuilder.builder().stringType()), "0"), + Arguments.of("seq", 1, Collections.singletonList("0"), new Field("name", SchemaBuilder.builder().intType()), 0), Arguments.of("seq", 1, Collections.singletonList("1"), new Field("name", SchemaBuilder.builder().intType()), 1), Arguments.of("seq", 1, Collections.singletonList("2"), new Field("name", SchemaBuilder.builder().intType()), 2), Arguments.of("it", 1, Collections.singletonList("0"), new Field("name", SchemaBuilder.builder().stringType()), "0"), diff --git a/src/test/java/net/coru/kloadgen/randomtool/random/RandomSequenceTest.java b/src/test/java/net/coru/kloadgen/randomtool/random/RandomSequenceTest.java index 2dafc2fe..0878f988 100644 --- a/src/test/java/net/coru/kloadgen/randomtool/random/RandomSequenceTest.java +++ b/src/test/java/net/coru/kloadgen/randomtool/random/RandomSequenceTest.java @@ -19,6 +19,7 @@ import java.util.stream.Stream; import org.apache.groovy.util.Maps; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -45,22 +46,24 @@ void testGenerateSequenceValueForField(String fieldName, String fieldType, List< private static Stream parametersForGenerateRandomValueWithList() { return Stream.of( Arguments.of(18, - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20"), - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20")), - Arguments.of(20, - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20"), - List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20", "1", "2"))); + List.of("1", "2", "3", "5", "6", "7", "7", "9", "9", "9", "10", "14", "17", "17", "17", "17", "18", "19", "20"))); } @ParameterizedTest @DisplayName("Testing Generate a Random Value With a List of Values") @MethodSource("parametersForGenerateRandomValueWithList") - void testGenerateRandomValueWithList(final int size, final List values, final List expected) { - final var intList = new ArrayList<>(); - final var context = new HashMap(); - for (int i=0; i <= size; i++) { - intList.add(RandomSequence.generateSequenceForFieldValueList("ClientCode", "seq", values, context)); - } - assertThat(intList).containsExactlyElementsOf(expected); + void testGenerateRandomValueWithList(final int size, final List values) { + final Exception exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { + final var intList = new ArrayList<>(); + final var context = new HashMap(); + for (int i=0; i <= size; i++) { + intList.add(RandomSequence.generateSeq("ClientCode", "seq", values, context)); + } + }); + + final String expectedMessage = "Sequences do not accept more than one option as initial value"; + final String actualMessage = exception.getMessage(); + + Assertions.assertTrue(actualMessage.contains(expectedMessage)); } } \ No newline at end of file