diff --git a/build.gradle.kts b/build.gradle.kts index d9d368e..20280f7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { implementation("com.squareup.okhttp3:okhttp:4.11.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") implementation("org.yaml:snakeyaml:2.2") + implementation("com.google.code.gson:gson:2.10.1") } // Apply a specific Java toolchain to ease working on different environments. diff --git a/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt b/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt index b2513b3..910a73f 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt @@ -34,7 +34,6 @@ private fun String.runCommand(workingDir: File): String? = .redirectOutput(ProcessBuilder.Redirect.PIPE) .redirectError(ProcessBuilder.Redirect.PIPE) .start() - process.waitFor(60, TimeUnit.MINUTES) process.inputStream.bufferedReader().readText() } catch (e: IOException) { printMessageInRedColor("Exception while executing command -> ${e.message}") diff --git a/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt b/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt index ab3e82d..136145b 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/Matrix.kt @@ -6,8 +6,8 @@ fun generateCombinations( keys: List, matrix: AssertionMatrix, idx: Int, - prev: MutableMap, - combinations: MutableList> + prev: MutableMap, + combinations: MutableList> ) { val key = keys[idx] val values = matrix[key] ?: emptyList() @@ -23,19 +23,19 @@ fun generateCombinations( } } -fun getMatrixCombinations(matrix: AssertionMatrix): List> { +fun getMatrixCombinations(matrix: AssertionMatrix): List> { val keys = matrix.keys.toList() if (keys.isEmpty()) { return emptyList() } - val combinations = mutableListOf>() + val combinations = mutableListOf>() generateCombinations(keys, matrix, 0, mutableMapOf(), combinations) return combinations } -fun applyCombinationToValue(value: Any?, combination: Map): Any? { +fun applyCombinationToValue(value: Any?, combination: Map): Any? { if (value is String) { val variableKeysInValue = Regex("""\$\{\{\s*([^\s}]+)\s*}}""").findAll(value) @@ -46,14 +46,14 @@ fun applyCombinationToValue(value: Any?, combination: Map): Any? { return variableKeysInValue.fold(value) { acc, result -> val key = result.groupValues[1].trim() val regex = Regex("""\$\{\{\s*([^\s}]+)\s*}}""") - acc.replace(regex, combination[key].toString()) + acc.replace(regex, getContextValues(combination[key]).toString()) } } return value } fun applyCombinationToFeatureAssertion( - combination: Map, + combination: Map, assertion: FeatureAssertion ): FeatureAssertion { val flattenedAssertion = assertion.copy() @@ -92,9 +92,8 @@ fun getFeatureAssertionsFromMatrix( ): List { if (assertionWithMatrix.matrix == null) { val assertion = assertionWithMatrix.copy() - assertion.description = "Assertion #${aIndex + 1}: (${assertion.environment}) ${ - assertion.description ?: "at ${getAtValue(assertion.at)}%" - }" + assertion.description = + "Assertion #${aIndex + 1}: (${assertion.environment}) ${assertion.description ?: "at ${getAtValue(assertion.at)}%"}" return listOf(assertion) } @@ -103,9 +102,8 @@ fun getFeatureAssertionsFromMatrix( for (combination in combinations) { val assertion = applyCombinationToFeatureAssertion(combination, assertionWithMatrix) - assertion.description = "Assertion #${aIndex + 1}: (${assertion.environment}) ${ - assertion.description ?: "at ${getAtValue(assertion.at)}%" - }" + assertion.description = + "Assertion #${aIndex + 1}: (${assertion.environment}) ${assertion.description ?: "at ${getAtValue(assertion.at)}%"}" assertions.add(assertion) } @@ -128,7 +126,7 @@ fun getAtValue(at: WeightType) = when (at) { } fun applyCombinationToSegmentAssertion( - combination: Map, + combination: Map, assertion: SegmentAssertion ): SegmentAssertion { val flattenedAssertion = assertion.copy() diff --git a/src/main/kotlin/com/featurevisor/testRunner/Parser.kt b/src/main/kotlin/com/featurevisor/testRunner/Parser.kt index 9d4a8d7..7b4b062 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/Parser.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/Parser.kt @@ -3,9 +3,7 @@ package com.featurevisor.testRunner import com.featurevisor.sdk.serializers.isValidJson import com.featurevisor.sdk.serializers.mapOperator import com.featurevisor.types.* -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.builtins.serializer -import kotlinx.serialization.json.Json +import com.google.gson.Gson import org.yaml.snakeyaml.Yaml import java.io.File import java.util.* @@ -26,7 +24,11 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) = description = assertionMap["description"] as? String, context = (assertionMap["context"] as Map).mapValues { parseAttributeValue(it.value) }, expectedToMatch = assertionMap["expectedToMatch"] as Boolean, - matrix = assertionMap["matrix"] as? AssertionMatrix + matrix = (assertionMap["matrix"] as? Map>)?.mapValues { + it.value.map { item -> + mapMatrixValues(item) + } + } ) } val testSegment = TestSegment(key = segment, assertions = segmentAssertion) @@ -45,7 +47,11 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) = ) }, expectedVariation = assertionMap["expectedVariation"] as? String, - matrix = assertionMap["matrix"] as? AssertionMatrix + matrix = (assertionMap["matrix"] as? Map>)?.mapValues { + it.value.map { item -> + mapMatrixValues(item) + } + } ) } @@ -55,10 +61,35 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) = null } } catch (e: Exception) { - printMessageInRedColor("Exception while parsing Yaml Assertion File --> ${e.message}") + printMessageInRedColor("Exception while parsing Yaml Assertion File -- $yamlFilePath --> ${e.message}") null } +private fun mapMatrixValues(value: Any) = + when(value){ + is Boolean -> { + if (value){ + AttributeValue.StringValue("yes") + }else{ + AttributeValue.StringValue("no") + } + } + is Int -> { + AttributeValue.IntValue(value) + } + is Double -> { + AttributeValue.DoubleValue(value) + } + is String -> { + AttributeValue.StringValue(value) + } + is Date -> { + AttributeValue.DateValue(value) + } + + else -> { AttributeValue.StringValue("")} + } + private fun parseWeightValue(value: Any): WeightType { return when (value) { is Int -> WeightType.IntType(value) @@ -87,9 +118,8 @@ private fun parseVariableValue(value: Any?): VariableValue { } is Map<*, *> -> { - val mapData = value as Map - val json1 = Json.encodeToString(MapSerializer(String.serializer(), String.serializer()), mapData) - VariableValue.JsonValue(json1) + val json = Gson().toJson(value) + VariableValue.JsonValue(json) } else -> throw IllegalArgumentException("Unsupported variable value type") @@ -121,8 +151,17 @@ private fun parseAttributeValue(value: Any?): AttributeValue { AttributeValue.DateValue(value) } + is List<*> -> { + AttributeValue.StringValue(value.toString()) + } + + is Map<*, *> -> { + val json = Gson().toJson(value) + AttributeValue.StringValue(json) + } + else -> { - throw IllegalArgumentException("Unsupported attribute value type") + throw IllegalArgumentException("Unsupported attribute value type $value") } } } @@ -199,7 +238,13 @@ private fun parseConditionValue(value: Any?): ConditionValue { } return when (value) { - is String -> ConditionValue.StringValue(value) + is String -> { + value.toIntOrNull()?.let { + ConditionValue.IntValue(value.toInt()) + } ?: value.toDoubleOrNull()?.let { + ConditionValue.DoubleValue(value.toDouble()) + } ?: ConditionValue.StringValue(value) + } is Int -> ConditionValue.IntValue(value) is Double -> ConditionValue.DoubleValue(value) is Boolean -> ConditionValue.BooleanValue(value) diff --git a/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt b/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt index 86dae0f..c8a3dac 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt @@ -131,19 +131,6 @@ private fun executeTest(filePath: String, dataFile: DataFile, option: TestProjec return executionResult } -fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) = - try { - getJsonForFeatureUsingCommand( - featureName = featureName, - environment = environment, - projectRootPath = projectRootPath - )?.run { - convertToDataClass() - } - } catch (e: Exception) { - printMessageInRedColor("Exception while parsing data file --> ${e.message}") - null - } diff --git a/src/main/kotlin/com/featurevisor/testRunner/Utils.kt b/src/main/kotlin/com/featurevisor/testRunner/Utils.kt index cc48df0..a5dce63 100644 --- a/src/main/kotlin/com/featurevisor/testRunner/Utils.kt +++ b/src/main/kotlin/com/featurevisor/testRunner/Utils.kt @@ -134,13 +134,14 @@ fun getContextValue(contextValue: Any?) = else -> throw Exception("Unsupported context value") } -fun getContextValues(contextValue: AttributeValue) = +fun getContextValues(contextValue: AttributeValue?) = when (contextValue) { is AttributeValue.IntValue -> contextValue.value is AttributeValue.DoubleValue -> contextValue.value is AttributeValue.StringValue -> contextValue.value is AttributeValue.BooleanValue -> contextValue.value is AttributeValue.DateValue -> contextValue.value + null -> null } fun checkIfArraysAreEqual(a: Array, b: Array): Boolean { @@ -230,4 +231,18 @@ fun buildDataFileForBothEnvironments(projectRootPath: String): DataFile { ) } +fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) = + try { + getJsonForFeatureUsingCommand( + featureName = featureName, + environment = environment, + projectRootPath = projectRootPath + )?.run { + convertToDataClass() + } + } catch (e: Exception) { + printMessageInRedColor("Exception while parsing data file --> ${e.message}") + null + } +