From 131de5be9d13d45c21305738d51204e1e2b5addc Mon Sep 17 00:00:00 2001 From: Konstantin Aksenov Date: Wed, 22 May 2024 19:42:03 +1000 Subject: [PATCH] feat(core): add filter disabling thought config --- .idea/jarRepositories.xml | 30 +++++++++++++++++ .../marathon/config/FilteringConfiguration.kt | 18 +++++++++-- .../execution/filter/AllureTestFilter.kt | 15 +++++++-- .../execution/filter/AnnotationDataFilter.kt | 10 ++++-- .../execution/filter/AnnotationFilter.kt | 32 ++++++++++++------- .../execution/filter/CompositionFilter.kt | 9 +++--- .../execution/filter/FragmentationFilter.kt | 8 +++-- .../filter/FullyQualifiedClassnameFilter.kt | 12 +++++-- .../filter/FullyQualifiedTestnameFilter.kt | 12 +++++-- .../execution/filter/SimpleClassnameFilter.kt | 11 +++++-- .../execution/filter/SimpleTestnameFilter.kt | 14 +++++--- .../execution/filter/SingleValueTestFilter.kt | 8 +++-- .../execution/filter/TestMethodFilter.kt | 11 +++++-- .../execution/filter/TestPackageFilter.kt | 31 +++++++++++------- .../execution/filter/ToggleTestFilter.kt | 13 ++++++++ 15 files changed, 175 insertions(+), 59 deletions(-) create mode 100644 .idea/jarRepositories.xml create mode 100644 core/src/main/kotlin/com/malinskiy/marathon/execution/filter/ToggleTestFilter.kt diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 000000000..bad397270 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/configuration/src/main/kotlin/com/malinskiy/marathon/config/FilteringConfiguration.kt b/configuration/src/main/kotlin/com/malinskiy/marathon/config/FilteringConfiguration.kt index 77bd0b1db..b1c47fef1 100644 --- a/configuration/src/main/kotlin/com/malinskiy/marathon/config/FilteringConfiguration.kt +++ b/configuration/src/main/kotlin/com/malinskiy/marathon/config/FilteringConfiguration.kt @@ -39,6 +39,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -75,6 +76,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -111,6 +113,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -148,6 +151,7 @@ sealed class TestFilterConfiguration { @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, @JsonProperty("subpackages") val subpackages: Boolean = false, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -184,7 +188,8 @@ sealed class TestFilterConfiguration { data class AnnotationDataFilterConfiguration( @JsonProperty("nameRegex") val nameRegex: Regex, - @JsonProperty("valueRegex") val valueRegex: Regex + @JsonProperty("valueRegex") val valueRegex: Regex, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() {} @@ -200,6 +205,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -235,6 +241,7 @@ sealed class TestFilterConfiguration { data class FragmentationFilterConfiguration( val index: Int, val count: Int, + val enabled: Boolean, ) : TestFilterConfiguration() { override fun validate() { if (index < 0) throw ConfigurationException("Fragment index [$index] should be >= 0") @@ -247,6 +254,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -283,6 +291,7 @@ sealed class TestFilterConfiguration { @JsonProperty("regex") val regex: Regex? = null, @JsonProperty("values") val values: List? = null, @JsonProperty("file") val file: File? = null, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { var i = 0 @@ -317,7 +326,8 @@ sealed class TestFilterConfiguration { data class CompositionFilterConfiguration( @JsonProperty("filters") val filters: List, - @JsonProperty("op") val op: OPERATION + @JsonProperty("op") val op: OPERATION, + @JsonProperty("enabled") val enabled: Boolean = true, ) : TestFilterConfiguration() { override fun validate() { filters.forEach { it.validate() } @@ -342,7 +352,9 @@ sealed class TestFilterConfiguration { override fun hashCode(): Int = filters.hashCode() + op.hashCode() } - object AllureFilterConfiguration : TestFilterConfiguration() { + data class AllureFilterConfiguration( + @JsonProperty("enabled") val enabled: Boolean = true, + ) : TestFilterConfiguration() { override fun validate() { } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AllureTestFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AllureTestFilter.kt index e7c6c9e0f..6f2270a1b 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AllureTestFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AllureTestFilter.kt @@ -10,7 +10,15 @@ import io.qameta.allure.testfilter.TestPlanSupplier import io.qameta.allure.testfilter.TestPlanV1_0 val ALLURE_ID_ANNOTATIONS = setOf("io.qameta.allure.AllureId", "io.qameta.allure.kotlin.AllureId") -class AllureTestFilter(val cnf: TestFilterConfiguration.AllureFilterConfiguration, private val testPlanSupplier: TestPlanSupplier = FileTestPlanSupplier()) : TestFilter { + +class AllureTestFilter( + val cnf: TestFilterConfiguration.AllureFilterConfiguration, + private val testPlanSupplier: TestPlanSupplier = FileTestPlanSupplier() +) : ToggleTestFilter { + + override val enabled: Boolean + get() = cnf.enabled + private val testPlan: TestPlan? by lazy { val optional = testPlanSupplier.supply() if (optional.isPresent) { @@ -20,7 +28,7 @@ class AllureTestFilter(val cnf: TestFilterConfiguration.AllureFilterConfiguratio } } - override fun filter(tests: List): List { + override fun filterPredicate(tests: List): List { return if (testPlan != null && testPlan is TestPlanV1_0) { val plan = testPlan as TestPlanV1_0 tests.filter { test -> @@ -31,10 +39,11 @@ class AllureTestFilter(val cnf: TestFilterConfiguration.AllureFilterConfiguratio tests } } + private fun findAllureId(test: Test) = test.metaProperties.find { ALLURE_ID_ANNOTATIONS.contains(it.name) }?.values?.get("value") as? String - override fun filterNot(tests: List): List { + override fun filterNotPredicate(tests: List): List { return if (testPlan != null && testPlan is TestPlanV1_0) { val plan = testPlan as TestPlanV1_0 tests.filterNot { test -> diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationDataFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationDataFilter.kt index 7f1f81be2..56ee46697 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationDataFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationDataFilter.kt @@ -5,14 +5,18 @@ import com.malinskiy.marathon.execution.TestFilter import com.malinskiy.marathon.test.MetaProperty import com.malinskiy.marathon.test.Test -data class AnnotationDataFilter(val cnf: TestFilterConfiguration.AnnotationDataFilterConfiguration) : TestFilter { - override fun filter(tests: List): List = tests.filter { test -> +data class AnnotationDataFilter(val cnf: TestFilterConfiguration.AnnotationDataFilterConfiguration) : ToggleTestFilter { + + override val enabled: Boolean + get() = cnf.enabled + + override fun filterPredicate(tests: List): List = tests.filter { test -> test.metaProperties.any { match(it) } } - override fun filterNot(tests: List): List = tests.filterNot { test -> + override fun filterNotPredicate(tests: List): List = tests.filterNot { test -> test.metaProperties.any { match(it) } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationFilter.kt index 2af087e59..717d431df 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/AnnotationFilter.kt @@ -3,16 +3,24 @@ package com.malinskiy.marathon.execution.filter import com.malinskiy.marathon.config.TestFilterConfiguration class AnnotationFilter(cnf: TestFilterConfiguration.AnnotationFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - when { - regex != null -> { - test.metaProperties.map { it.name }.any(regex::matches) - } - values != null -> { - test.metaProperties.map { it.name }.intersect(values).isNotEmpty() - } - else -> { - true + SingleValueTestFilter( + cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + when { + regex != null -> { + test.metaProperties.map { it.name }.any(regex::matches) + } + + values != null -> { + test.metaProperties.map { it.name }.intersect(values).isNotEmpty() + } + + else -> { + true + } } - } - }) + }, + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/CompositionFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/CompositionFilter.kt index e566c8186..402e0e948 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/CompositionFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/CompositionFilter.kt @@ -6,10 +6,11 @@ import com.malinskiy.marathon.test.Test class CompositionFilter( private val filters: List, - private val op: TestFilterConfiguration.CompositionFilterConfiguration.OPERATION -) : TestFilter { + private val op: TestFilterConfiguration.CompositionFilterConfiguration.OPERATION, + override val enabled: Boolean +) : ToggleTestFilter { - override fun filter(tests: List): List { + override fun filterPredicate(tests: List): List { return when (op) { TestFilterConfiguration.CompositionFilterConfiguration.OPERATION.UNION -> filterWithUnionOperation(tests) TestFilterConfiguration.CompositionFilterConfiguration.OPERATION.INTERSECTION -> filterWithIntersectionOperation(tests) @@ -17,7 +18,7 @@ class CompositionFilter( } } - override fun filterNot(tests: List): List { + override fun filterNotPredicate(tests: List): List { val filteredTests = filter(tests) return when (op) { TestFilterConfiguration.CompositionFilterConfiguration.OPERATION.UNION -> tests.subtract(filteredTests).toList() diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FragmentationFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FragmentationFilter.kt index 453bb5660..aa6995dd5 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FragmentationFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FragmentationFilter.kt @@ -17,9 +17,11 @@ import java.math.BigInteger * This is a dynamic programming technique, hence the results will be sub-optimal compared to connecting multiple devices to the same test * run */ -class FragmentationFilter(private val cnf: TestFilterConfiguration.FragmentationFilterConfiguration) : TestFilter { +class FragmentationFilter(private val cnf: TestFilterConfiguration.FragmentationFilterConfiguration) : ToggleTestFilter { private val power by lazy { BigInteger.valueOf(cnf.count.toLong()) } private val remainder by lazy { BigInteger.valueOf(cnf.index.toLong()) } + override val enabled: Boolean + get() = cnf.enabled private val predicate: (Test) -> Boolean = { /** * Randomizing the distribution via md5 @@ -35,7 +37,7 @@ class FragmentationFilter(private val cnf: TestFilterConfiguration.Fragmentation actualRemainder == remainder } - override fun filter(tests: List): List = tests.filter(predicate) + override fun filterPredicate(tests: List): List = tests.filter(predicate) - override fun filterNot(tests: List): List = tests.filterNot(predicate) + override fun filterNotPredicate(tests: List): List = tests.filterNot(predicate) } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedClassnameFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedClassnameFilter.kt index 758ecc296..921e8b069 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedClassnameFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedClassnameFilter.kt @@ -4,6 +4,12 @@ import com.malinskiy.marathon.config.TestFilterConfiguration import com.malinskiy.marathon.test.toClassName class FullyQualifiedClassnameFilter(cnf: TestFilterConfiguration.FullyQualifiedClassnameFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - (regex?.matches(test.toClassName()) ?: true) && (values?.contains(test.toClassName()) ?: true) - }) + SingleValueTestFilter( + cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + (regex?.matches(test.toClassName()) ?: true) && (values?.contains(test.toClassName()) ?: true) + }, + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedTestnameFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedTestnameFilter.kt index dce5eabf4..11b543c49 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedTestnameFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/FullyQualifiedTestnameFilter.kt @@ -4,6 +4,12 @@ import com.malinskiy.marathon.config.TestFilterConfiguration import com.malinskiy.marathon.test.toTestName class FullyQualifiedTestnameFilter(cnf: TestFilterConfiguration.FullyQualifiedTestnameFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - (regex?.matches(test.toTestName()) ?: true) && (values?.contains(test.toTestName()) ?: true) - }) + SingleValueTestFilter( + cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + (regex?.matches(test.toTestName()) ?: true) && (values?.contains(test.toTestName()) ?: true) + }, + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleClassnameFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleClassnameFilter.kt index 45a06c570..b588baec1 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleClassnameFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleClassnameFilter.kt @@ -3,6 +3,11 @@ package com.malinskiy.marathon.execution.filter import com.malinskiy.marathon.config.TestFilterConfiguration class SimpleClassnameFilter(cnf: TestFilterConfiguration.SimpleClassnameFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - (regex?.matches(test.clazz) ?: true) && (values?.contains(test.clazz) ?: true) - }) + SingleValueTestFilter(cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + (regex?.matches(test.clazz) ?: true) && (values?.contains(test.clazz) ?: true) + }, + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleTestnameFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleTestnameFilter.kt index 35d643328..7c2afcd14 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleTestnameFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SimpleTestnameFilter.kt @@ -4,7 +4,13 @@ import com.malinskiy.marathon.config.TestFilterConfiguration import com.malinskiy.marathon.test.toSimpleSafeTestName class SimpleTestnameFilter(cnf: TestFilterConfiguration.SimpleTestnameFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - val simpleSafeTestName = test.toSimpleSafeTestName(methodSeparator = '#') - (regex?.matches(simpleSafeTestName) ?: true) && (values?.contains(simpleSafeTestName) ?: true) - }) + SingleValueTestFilter( + cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + val simpleSafeTestName = test.toSimpleSafeTestName(methodSeparator = '#') + (regex?.matches(simpleSafeTestName) ?: true) && (values?.contains(simpleSafeTestName) ?: true) + }, + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SingleValueTestFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SingleValueTestFilter.kt index 901cff611..eca214e94 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SingleValueTestFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/SingleValueTestFilter.kt @@ -3,14 +3,16 @@ package com.malinskiy.marathon.execution.filter import com.malinskiy.marathon.execution.TestFilter import com.malinskiy.marathon.log.MarathonLogging import com.malinskiy.marathon.test.Test +import jdk.jfr.Enabled import java.io.File open class SingleValueTestFilter( val regex: Regex?, val values: List?, val file: File?, + override val enabled: Boolean, val predicate: SingleValueTestFilter.(test: Test, values: List?) -> Boolean, -) : TestFilter { +) : ToggleTestFilter { private val log = MarathonLogging.logger("SingleValueTestFilter") private val fileValuesCache: List? by lazy { @@ -28,11 +30,11 @@ open class SingleValueTestFilter( return values ?: fileValuesCache } - override fun filter(tests: List): List = with(tests) { + override fun filterPredicate(tests: List): List = with(tests) { filter { predicate(this@SingleValueTestFilter, it, readValues()) } } - override fun filterNot(tests: List): List = with(tests) { + override fun filterNotPredicate(tests: List): List = with(tests) { filterNot { predicate(this@SingleValueTestFilter, it, readValues()) } } diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestMethodFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestMethodFilter.kt index 09fb4eac9..6df84cdd7 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestMethodFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestMethodFilter.kt @@ -3,6 +3,11 @@ package com.malinskiy.marathon.execution.filter import com.malinskiy.marathon.config.TestFilterConfiguration class TestMethodFilter(cnf: TestFilterConfiguration.TestMethodFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - (regex?.matches(test.method) ?: true) && (values?.contains(test.method) ?: true) - }) + SingleValueTestFilter(cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + (regex?.matches(test.method) ?: true) && (values?.contains(test.method) ?: true) + } + ) diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestPackageFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestPackageFilter.kt index 386cf71c2..98bad5d35 100644 --- a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestPackageFilter.kt +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/TestPackageFilter.kt @@ -3,16 +3,23 @@ package com.malinskiy.marathon.execution.filter import com.malinskiy.marathon.config.TestFilterConfiguration class TestPackageFilter(cnf: TestFilterConfiguration.TestPackageFilterConfiguration) : - SingleValueTestFilter(cnf.regex, cnf.values, cnf.file, { test, values -> - (regex?.matches(test.pkg) ?: true) && when(cnf.subpackages) { - true -> (values?.any { - test.pkg == it || - test.pkg.startsWith("$it$PACKAGE_SEPARATOR") - } ?: true) - false -> (values?.contains(test.pkg) ?: true) - } - }) { - companion object { - const val PACKAGE_SEPARATOR = '.' - } + SingleValueTestFilter( + cnf.regex, + cnf.values, + cnf.file, + cnf.enabled, + { test, values -> + (regex?.matches(test.pkg) ?: true) && when (cnf.subpackages) { + true -> (values?.any { + test.pkg == it || + test.pkg.startsWith("$it$PACKAGE_SEPARATOR") + } ?: true) + + false -> (values?.contains(test.pkg) ?: true) + } + }, + ) { + companion object { + const val PACKAGE_SEPARATOR = '.' } +} diff --git a/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/ToggleTestFilter.kt b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/ToggleTestFilter.kt new file mode 100644 index 000000000..be783fbb8 --- /dev/null +++ b/core/src/main/kotlin/com/malinskiy/marathon/execution/filter/ToggleTestFilter.kt @@ -0,0 +1,13 @@ +package com.malinskiy.marathon.execution.filter + +import com.malinskiy.marathon.execution.TestFilter +import com.malinskiy.marathon.test.Test + +interface ToggleTestFilter : TestFilter { + + val enabled: Boolean + fun filterPredicate(tests: List): List + fun filterNotPredicate(tests: List): List + override fun filter(tests: List): List = if (enabled) filterPredicate(tests) else tests + override fun filterNot(tests: List): List = if (enabled) filterNotPredicate(tests) else tests +}