diff --git a/README.md b/README.md index 47a8f2c1..6d2c57ca 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# th2 check1 (3.9.1) +# th2 check1 (3.10.0) ## Overview @@ -192,6 +192,11 @@ The `th2_check1_active_tasks_number` metric separate rules with label `rule_type ## Release Notes +### 3.10.0 + +#### Added: ++ Support for disabling of order verification for simple collection + ### 3.9.1 #### Changed: diff --git a/build.gradle b/build.gradle index ec7f04ad..a4521038 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'com.palantir.docker' version '0.25.0' - id 'org.jetbrains.kotlin.jvm' version '1.5.30' + id 'org.jetbrains.kotlin.jvm' version '1.5.32' id "io.github.gradle-nexus.publish-plugin" version "1.0.0" id 'signing' id 'java-library' @@ -10,7 +10,7 @@ plugins { ext { sharedDir = file("${project.rootDir}/shared") - sailfishVersion = '3.2.1752' + sailfishVersion = '3.2.1877' } group = 'com.exactpro.th2' @@ -165,23 +165,23 @@ signing { } dependencies { - api platform('com.exactpro.th2:bom:3.0.0') - implementation 'com.exactpro.th2:grpc-check1:3.5.1' - implementation 'com.exactpro.th2:common:3.31.3' - implementation 'com.exactpro.th2:sailfish-utils:3.12.3' + api platform('com.exactpro.th2:bom:3.2.0') + implementation 'com.exactpro.th2:grpc-check1:3.6.1-dev-2918727534-SNAPSHOT' + implementation 'com.exactpro.th2:common:3.41.0-dev-2918529806-SNAPSHOT' + implementation 'com.exactpro.th2:sailfish-utils:3.12.4' implementation "org.slf4j:slf4j-log4j12" implementation "org.slf4j:slf4j-api" implementation "com.exactpro.sf:sailfish-core:${sailfishVersion}" - implementation "io.reactivex.rxjava2:rxjava:2.2.19" // https://github.com/salesforce/reactive-grpc/issues/202 + implementation "io.reactivex.rxjava2:rxjava:2.2.21" // https://github.com/salesforce/reactive-grpc/issues/202 implementation('io.prometheus:simpleclient') { because('metrics from messages and rules') } implementation 'org.jetbrains.kotlin:kotlin-reflect' - testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.9.0' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit' testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0" } diff --git a/gradle.properties b/gradle.properties index c025470a..523c08da 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -release_version = 3.9.1 +release_version = 3.10.0 description = 'th2 check1 box' diff --git a/src/main/java/com/exactpro/th2/check1/configuration/Check1Configuration.java b/src/main/java/com/exactpro/th2/check1/configuration/Check1Configuration.java deleted file mode 100644 index 469907b6..00000000 --- a/src/main/java/com/exactpro/th2/check1/configuration/Check1Configuration.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.exactpro.th2.check1.configuration; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonPropertyDescription; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer; - -import java.time.Duration; -import java.time.temporal.ChronoUnit; - -public class Check1Configuration { - - @JsonProperty(value="message-cache-size", defaultValue = "1000") - private int messageCacheSize = 1000; - - @JsonProperty(value="cleanup-older-than", defaultValue = "60") - private long cleanupOlderThan = 60L; - - @JsonProperty(value="max-event-batch-content-size", defaultValue = "1048576") - private int maxEventBatchContentSize = 1_048_576; - - @JsonProperty(value="cleanup-time-unit", defaultValue = "SECONDS") - private ChronoUnit cleanupTimeUnit = ChronoUnit.SECONDS; - - @JsonProperty(value="rule-execution-timeout", defaultValue = "5000") - private long ruleExecutionTimeout = 5000L; - - @JsonProperty("auto-silence-check-after-sequence-rule") - @JsonPropertyDescription("The default behavior in case the SequenceCheckRule does not have silenceCheck parameter specified") - private boolean autoSilenceCheckAfterSequenceRule; - - @JsonProperty(value="decimal-precision", defaultValue = "0.00001") - private double decimalPrecision = 0.00001; - - @JsonProperty(value="time-precision", defaultValue = "PT0.000000001S") - @JsonDeserialize(using = DurationDeserializer.class) - @JsonPropertyDescription("The default time precision value uses java duration format") - private Duration timePrecision = Duration.parse("PT0.000000001S"); - - @JsonProperty(value = "check-null-value-as-empty") - private boolean checkNullValueAsEmpty = false; - - public int getMessageCacheSize() { - return messageCacheSize; - } - - public long getCleanupOlderThan() { - return cleanupOlderThan; - } - - public int getMaxEventBatchContentSize() { - return maxEventBatchContentSize; - } - - public ChronoUnit getCleanupTimeUnit() { - return cleanupTimeUnit; - } - - public long getRuleExecutionTimeout() { - return ruleExecutionTimeout; - } - - public boolean isAutoSilenceCheckAfterSequenceRule() { - return autoSilenceCheckAfterSequenceRule; - } - - public double getDecimalPrecision() { - return decimalPrecision; - } - - public Duration getTimePrecision() { - return timePrecision; - } - - public boolean isCheckNullValueAsEmpty() { - return checkNullValueAsEmpty; - } -} diff --git a/src/main/kotlin/com/exactpro/th2/check1/configuration/Check1Configuration.kt b/src/main/kotlin/com/exactpro/th2/check1/configuration/Check1Configuration.kt new file mode 100644 index 00000000..d3c40552 --- /dev/null +++ b/src/main/kotlin/com/exactpro/th2/check1/configuration/Check1Configuration.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.exactpro.th2.check1.configuration + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonPropertyDescription +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.datatype.jsr310.deser.DurationDeserializer +import java.time.Duration +import java.time.temporal.ChronoUnit + +class Check1Configuration( + @field:JsonProperty(value = "message-cache-size", defaultValue = "1000") + val messageCacheSize: Int = 1000, + + @field:JsonProperty(value = "cleanup-older-than", defaultValue = "60") + val cleanupOlderThan: Long = 60L, + + @field:JsonProperty(value = "max-event-batch-content-size", defaultValue = "1048576") + val maxEventBatchContentSize: Int = 1048576, + + @field:JsonProperty(value = "cleanup-time-unit", defaultValue = "SECONDS") + val cleanupTimeUnit: ChronoUnit = ChronoUnit.SECONDS, + + @field:JsonProperty(value = "rule-execution-timeout", defaultValue = "5000") + val ruleExecutionTimeout: Long = 5000L, + + @field:JsonProperty("auto-silence-check-after-sequence-rule") + @field:JsonPropertyDescription("The default behavior in case the SequenceCheckRule does not have silenceCheck parameter specified") + val isAutoSilenceCheckAfterSequenceRule: Boolean = false, + + @field:JsonProperty(value = "decimal-precision", defaultValue = "0.00001") + val decimalPrecision: Double = 0.00001, + + @field:JsonProperty(value = "time-precision", defaultValue = "PT0.000000001S") + @field:JsonDeserialize(using = DurationDeserializer::class) + @field:JsonPropertyDescription("The default time precision value uses java duration format") + val timePrecision: Duration = Duration.parse("PT0.000000001S"), + + @field:JsonProperty(value = "check-null-value-as-empty") + val isCheckNullValueAsEmpty: Boolean = false, + + @field:JsonProperty(value = "default-check-simple-collections-order", defaultValue = "true") + val isDefaultCheckSimpleCollectionsOrder: Boolean = true +) \ No newline at end of file diff --git a/src/main/kotlin/com/exactpro/th2/check1/entities/RuleConfiguration.kt b/src/main/kotlin/com/exactpro/th2/check1/entities/RuleConfiguration.kt index 26d7a125..343f52c6 100644 --- a/src/main/kotlin/com/exactpro/th2/check1/entities/RuleConfiguration.kt +++ b/src/main/kotlin/com/exactpro/th2/check1/entities/RuleConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2021-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -21,7 +21,8 @@ data class RuleConfiguration( val timePrecision: Duration, val decimalPrecision: Double, val maxEventBatchContentSize: Int, - val isCheckNullValueAsEmpty: Boolean + val isCheckNullValueAsEmpty: Boolean, + val defaultCheckSimpleCollectionsOrder: Boolean ) { init { require(!timePrecision.isNegative) { "Time precision cannot be negative" } diff --git a/src/main/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTask.kt b/src/main/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTask.kt index ebdd121d..1e904ec4 100644 --- a/src/main/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTask.kt +++ b/src/main/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTask.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -548,6 +548,13 @@ abstract class AbstractCheckTask( ComparatorSettings().also { it.metaContainer = VerificationUtil.toMetaContainer(this.messageFilter, false) it.ignoredFields = this.comparisonSettings.ignoreFieldsList.toSet() + + it.isCheckSimpleCollectionsOrder = if (comparisonSettings.hasCheckSimpleCollectionsOrder()) { + comparisonSettings.checkSimpleCollectionsOrder.value + } else { + ruleConfiguration.defaultCheckSimpleCollectionsOrder + } + if (this.comparisonSettings.checkRepeatingGroupOrder) { it.isCheckGroupsOrder = true } else { diff --git a/src/main/kotlin/com/exactpro/th2/check1/rule/RuleFactory.kt b/src/main/kotlin/com/exactpro/th2/check1/rule/RuleFactory.kt index 30018ec0..4fc8072e 100644 --- a/src/main/kotlin/com/exactpro/th2/check1/rule/RuleFactory.kt +++ b/src/main/kotlin/com/exactpro/th2/check1/rule/RuleFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2021-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -54,6 +54,7 @@ class RuleFactory( private val timePrecision = configuration.timePrecision private val decimalPrecision = configuration.decimalPrecision private val isCheckNullValueAsEmpty = configuration.isCheckNullValueAsEmpty + private val defaultCheckSimpleCollectionsOrder = configuration.isDefaultCheckSimpleCollectionsOrder fun createCheckRule(request: CheckRuleRequest, isChainIdExist: Boolean): CheckRuleTask = ruleCreation(request.parentEventId) { @@ -79,7 +80,8 @@ class RuleFactory( timePrecision, decimalPrecision, maxEventBatchContentSize, - isCheckNullValueAsEmpty + isCheckNullValueAsEmpty, + defaultCheckSimpleCollectionsOrder ) CheckRuleTask( @@ -89,7 +91,7 @@ class RuleFactory( filter, request.parentEventId, streamObservable, - eventBatchRouter + eventBatchRouter, ) } onErrorEvent { @@ -123,7 +125,8 @@ class RuleFactory( timePrecision, decimalPrecision, maxEventBatchContentSize, - isCheckNullValueAsEmpty + isCheckNullValueAsEmpty, + defaultCheckSimpleCollectionsOrder ) SequenceCheckRuleTask( @@ -161,7 +164,8 @@ class RuleFactory( timePrecision, decimalPrecision, maxEventBatchContentSize, - isCheckNullValueAsEmpty + isCheckNullValueAsEmpty, + defaultCheckSimpleCollectionsOrder ) NoMessageCheckTask( @@ -197,7 +201,8 @@ class RuleFactory( timePrecision, decimalPrecision, maxEventBatchContentSize, - isCheckNullValueAsEmpty + isCheckNullValueAsEmpty, + defaultCheckSimpleCollectionsOrder ) SilenceCheckTask( diff --git a/src/test/kotlin/com/exactpro/th2/check1/entities/RuleConfigurationTest.kt b/src/test/kotlin/com/exactpro/th2/check1/entities/RuleConfigurationTest.kt index 355350e2..07c6c8b9 100644 --- a/src/test/kotlin/com/exactpro/th2/check1/entities/RuleConfigurationTest.kt +++ b/src/test/kotlin/com/exactpro/th2/check1/entities/RuleConfigurationTest.kt @@ -27,6 +27,7 @@ class RuleConfigurationTest { TaskTimeout(0, 0), null, Duration.ofSeconds(-1), 0.005, 1, + true, true ) } @@ -40,6 +41,7 @@ class RuleConfigurationTest { TaskTimeout(0, 0), null, Duration.ofSeconds(1), -0.005, 1, + true, true ) } @@ -57,6 +59,7 @@ class RuleConfigurationTest { Duration.ofSeconds(1), 0.005, maxEventBatchContentSize, + true, true ) } @@ -74,6 +77,7 @@ class RuleConfigurationTest { Duration.ofSeconds(1), 0.005, 1, + true, true ) } diff --git a/src/test/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTaskTest.kt b/src/test/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTaskTest.kt index 695a89f3..bdaab12d 100644 --- a/src/test/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTaskTest.kt +++ b/src/test/kotlin/com/exactpro/th2/check1/rule/AbstractCheckTaskTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2020-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -163,6 +163,7 @@ abstract class AbstractCheckTaskTest { configuration.timePrecision, configuration.decimalPrecision, maxEventBatchContentSize, + true, true ) } diff --git a/src/test/kotlin/com/exactpro/th2/check1/rule/RuleFactoryTest.kt b/src/test/kotlin/com/exactpro/th2/check1/rule/RuleFactoryTest.kt index fc29377d..49c5d438 100644 --- a/src/test/kotlin/com/exactpro/th2/check1/rule/RuleFactoryTest.kt +++ b/src/test/kotlin/com/exactpro/th2/check1/rule/RuleFactoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2021-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/src/test/kotlin/com/exactpro/th2/check1/rule/check/TestCheckRuleTask.kt b/src/test/kotlin/com/exactpro/th2/check1/rule/check/TestCheckRuleTask.kt index de2b76f8..5fc4a381 100644 --- a/src/test/kotlin/com/exactpro/th2/check1/rule/check/TestCheckRuleTask.kt +++ b/src/test/kotlin/com/exactpro/th2/check1/rule/check/TestCheckRuleTask.kt @@ -1,5 +1,5 @@ /* - * Copyright 2021-2021 Exactpro (Exactpro Systems Limited) + * Copyright 2021-2022 Exactpro (Exactpro Systems Limited) * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,11 +15,16 @@ package com.exactpro.th2.check1.rule.check import com.exactpro.th2.check1.SessionKey import com.exactpro.th2.check1.StreamContainer +import com.exactpro.th2.check1.configuration.Check1Configuration import com.exactpro.th2.check1.entities.TaskTimeout +import com.exactpro.th2.check1.grpc.ChainID +import com.exactpro.th2.check1.grpc.CheckRuleRequest import com.exactpro.th2.check1.rule.AbstractCheckTaskTest +import com.exactpro.th2.check1.rule.RuleFactory import com.exactpro.th2.check1.util.createVerificationEntry import com.exactpro.th2.check1.util.toSimpleFilter import com.exactpro.th2.common.event.bean.VerificationStatus +import com.exactpro.th2.common.grpc.ConnectionID import com.exactpro.th2.common.grpc.Direction import com.exactpro.th2.common.grpc.EventBatch import com.exactpro.th2.common.grpc.EventID @@ -27,6 +32,7 @@ import com.exactpro.th2.common.grpc.EventStatus import com.exactpro.th2.common.grpc.EventStatus.FAILED import com.exactpro.th2.common.grpc.EventStatus.SUCCESS import com.exactpro.th2.common.grpc.FilterOperation +import com.exactpro.th2.common.grpc.ListValue import com.exactpro.th2.common.grpc.ListValueFilter import com.exactpro.th2.common.grpc.MessageID import com.exactpro.th2.common.grpc.MessageMetadata @@ -41,6 +47,7 @@ import com.exactpro.th2.common.value.add import com.exactpro.th2.common.value.listValue import com.exactpro.th2.common.value.toValue import com.exactpro.th2.common.value.toValueFilter +import com.google.protobuf.BoolValue import com.google.protobuf.StringValue import io.reactivex.Observable import org.junit.jupiter.api.Assertions.assertTrue @@ -48,9 +55,12 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertAll import org.junit.jupiter.api.assertThrows import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource import org.junit.jupiter.params.provider.ValueSource import java.lang.IllegalArgumentException import java.time.Instant +import java.util.stream.Stream import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -307,6 +317,74 @@ internal class TestCheckRuleTask : AbstractCheckTaskTest() { }) } + @ParameterizedTest + @MethodSource("argsForSimpleCollectionOrderCheckingConfig") + fun `simple collection order checking config`(requestValue: Boolean?, defaultValue: Boolean) { + val expectedComparisonResult = !(requestValue ?: defaultValue) + + val streams = createStreams(SESSION_ALIAS, Direction.FIRST, listOf( + message(MESSAGE_TYPE, Direction.FIRST, SESSION_ALIAS) + .putFields("simple_list", ListValue.newBuilder().addAllValues( + listOf("C".toValue(), "A".toValue(), "B".toValue()) + ).build().toValue()) + .build() + )) + + val messageFilterForCheckOrderBuilder = rootMessageFilter(MESSAGE_TYPE).apply { + messageFilter = messageFilter().apply { + putFields( + "simple_list", + ValueFilter.newBuilder().setListFilter( + ListValueFilter.newBuilder(). + addAllValues(listOf( + "A".toValueFilter(), + "B".toValueFilter(), + "C".toValueFilter() + )) + ).build() + ).build() + }.build() + } + + if (requestValue != null) { + messageFilterForCheckOrderBuilder.setComparisonSettings( + RootComparisonSettings.newBuilder().setCheckSimpleCollectionsOrder(BoolValue.newBuilder().setValue(requestValue)) + ) + } + + val config = Check1Configuration(isDefaultCheckSimpleCollectionsOrder = defaultValue) + val ruleFactory = RuleFactory(config, streams, clientStub) + val request = CheckRuleRequest.newBuilder() + .setParentEventId(createEvent("root")) + .setConnectivityId(ConnectionID.newBuilder().setSessionAlias(SESSION_ALIAS)) + .setRootFilter(messageFilterForCheckOrderBuilder) + .setMessageTimeout(5) + .setChainId(ChainID.newBuilder().setId("test_chain_id")) + .build() + + ruleFactory.createCheckRule(request, true).begin() + + val eventBatches = awaitEventBatchRequest(1000L, 2) + val eventList = eventBatches.flatMap(EventBatch::getEventsList) + assertAll({ + assertEquals(3, eventList.size) + }, { + val verificationEvent = eventList.find { it.type == "Verification" } + assertNotNull(verificationEvent) { "Missed verification event" } + val verification = assertVerification(verificationEvent) + + val verificationEntry = createVerificationEntry(if (expectedComparisonResult) VerificationStatus.PASSED else VerificationStatus.FAILED) + + val expected = mapOf("simple_list" to createVerificationEntry( + "0" to verificationEntry, + "1" to verificationEntry, + "2" to verificationEntry, + )) + + assertVerificationByStatus(verification, expected) + }) + } + @ParameterizedTest @ValueSource(booleans = [true, false]) fun `check verification description`(includeDescription: Boolean) { @@ -522,8 +600,17 @@ internal class TestCheckRuleTask : AbstractCheckTaskTest() { }) } - companion object { private const val VERIFICATION_DESCRIPTION = "Test verification with description" + + @JvmStatic + fun argsForSimpleCollectionOrderCheckingConfig(): Stream = Stream.of( + Arguments.of(true, true), + Arguments.of(true, false), + Arguments.of(false, true), + Arguments.of(false, true), + Arguments.of(null, true), + Arguments.of(null, false) + ) } -} +} \ No newline at end of file