Skip to content

Commit 9ecae26

Browse files
authored
Test Runnner Improvement (#23)
1.handle assertion count in case of matrix combination 2.handle parsing when context value is map 3.handle parsing when no or wrong reference is passed to matrix
1 parent 58e1b8a commit 9ecae26

File tree

6 files changed

+85
-40
lines changed

6 files changed

+85
-40
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ dependencies {
6565
implementation("com.squareup.okhttp3:okhttp:4.11.0")
6666
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
6767
implementation("org.yaml:snakeyaml:2.2")
68+
implementation("com.google.code.gson:gson:2.10.1")
6869
}
6970

7071
// Apply a specific Java toolchain to ease working on different environments.

src/main/kotlin/com/featurevisor/testRunner/CommandExecuter.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ private fun String.runCommand(workingDir: File): String? =
3434
.redirectOutput(ProcessBuilder.Redirect.PIPE)
3535
.redirectError(ProcessBuilder.Redirect.PIPE)
3636
.start()
37-
process.waitFor(60, TimeUnit.MINUTES)
3837
process.inputStream.bufferedReader().readText()
3938
} catch (e: IOException) {
4039
printMessageInRedColor("Exception while executing command -> ${e.message}")

src/main/kotlin/com/featurevisor/testRunner/Matrix.kt

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ fun generateCombinations(
66
keys: List<String>,
77
matrix: AssertionMatrix,
88
idx: Int,
9-
prev: MutableMap<String, Any>,
10-
combinations: MutableList<MutableMap<String, Any>>
9+
prev: MutableMap<String, AttributeValue>,
10+
combinations: MutableList<MutableMap<String, AttributeValue>>
1111
) {
1212
val key = keys[idx]
1313
val values = matrix[key] ?: emptyList()
@@ -23,19 +23,19 @@ fun generateCombinations(
2323
}
2424
}
2525

26-
fun getMatrixCombinations(matrix: AssertionMatrix): List<MutableMap<String, Any>> {
26+
fun getMatrixCombinations(matrix: AssertionMatrix): List<MutableMap<String, AttributeValue>> {
2727
val keys = matrix.keys.toList()
2828

2929
if (keys.isEmpty()) {
3030
return emptyList()
3131
}
3232

33-
val combinations = mutableListOf<MutableMap<String, Any>>()
33+
val combinations = mutableListOf<MutableMap<String, AttributeValue>>()
3434
generateCombinations(keys, matrix, 0, mutableMapOf(), combinations)
3535
return combinations
3636
}
3737

38-
fun applyCombinationToValue(value: Any?, combination: Map<String, Any>): Any? {
38+
fun applyCombinationToValue(value: Any?, combination: Map<String, AttributeValue>): Any? {
3939
if (value is String) {
4040
val variableKeysInValue = Regex("""\$\{\{\s*([^\s}]+)\s*}}""").findAll(value)
4141

@@ -46,14 +46,14 @@ fun applyCombinationToValue(value: Any?, combination: Map<String, Any>): Any? {
4646
return variableKeysInValue.fold(value) { acc, result ->
4747
val key = result.groupValues[1].trim()
4848
val regex = Regex("""\$\{\{\s*([^\s}]+)\s*}}""")
49-
acc.replace(regex, combination[key].toString())
49+
acc.replace(regex, getContextValues(combination[key]).toString())
5050
}
5151
}
5252
return value
5353
}
5454

5555
fun applyCombinationToFeatureAssertion(
56-
combination: Map<String, Any>,
56+
combination: Map<String, AttributeValue>,
5757
assertion: FeatureAssertion
5858
): FeatureAssertion {
5959
val flattenedAssertion = assertion.copy()
@@ -92,9 +92,8 @@ fun getFeatureAssertionsFromMatrix(
9292
): List<FeatureAssertion> {
9393
if (assertionWithMatrix.matrix == null) {
9494
val assertion = assertionWithMatrix.copy()
95-
assertion.description = "Assertion #${aIndex + 1}: (${assertion.environment}) ${
96-
assertion.description ?: "at ${getAtValue(assertion.at)}%"
97-
}"
95+
assertion.description =
96+
"Assertion #${aIndex + 1}: (${assertion.environment}) ${assertion.description ?: "at ${getAtValue(assertion.at)}%"}"
9897
return listOf(assertion)
9998
}
10099

@@ -103,9 +102,8 @@ fun getFeatureAssertionsFromMatrix(
103102

104103
for (combination in combinations) {
105104
val assertion = applyCombinationToFeatureAssertion(combination, assertionWithMatrix)
106-
assertion.description = "Assertion #${aIndex + 1}: (${assertion.environment}) ${
107-
assertion.description ?: "at ${getAtValue(assertion.at)}%"
108-
}"
105+
assertion.description =
106+
"Assertion #${aIndex + 1}: (${assertion.environment}) ${assertion.description ?: "at ${getAtValue(assertion.at)}%"}"
109107
assertions.add(assertion)
110108
}
111109

@@ -128,7 +126,7 @@ fun getAtValue(at: WeightType) = when (at) {
128126
}
129127

130128
fun applyCombinationToSegmentAssertion(
131-
combination: Map<String, Any>,
129+
combination: Map<String, AttributeValue>,
132130
assertion: SegmentAssertion
133131
): SegmentAssertion {
134132
val flattenedAssertion = assertion.copy()

src/main/kotlin/com/featurevisor/testRunner/Parser.kt

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ package com.featurevisor.testRunner
33
import com.featurevisor.sdk.serializers.isValidJson
44
import com.featurevisor.sdk.serializers.mapOperator
55
import com.featurevisor.types.*
6-
import kotlinx.serialization.builtins.MapSerializer
7-
import kotlinx.serialization.builtins.serializer
8-
import kotlinx.serialization.json.Json
6+
import com.google.gson.Gson
97
import org.yaml.snakeyaml.Yaml
108
import java.io.File
119
import java.util.*
@@ -26,7 +24,11 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) =
2624
description = assertionMap["description"] as? String,
2725
context = (assertionMap["context"] as Map<AttributeKey, Any?>).mapValues { parseAttributeValue(it.value) },
2826
expectedToMatch = assertionMap["expectedToMatch"] as Boolean,
29-
matrix = assertionMap["matrix"] as? AssertionMatrix
27+
matrix = (assertionMap["matrix"] as? Map<String, List<Any>>)?.mapValues {
28+
it.value.map { item ->
29+
mapMatrixValues(item)
30+
}
31+
}
3032
)
3133
}
3234
val testSegment = TestSegment(key = segment, assertions = segmentAssertion)
@@ -45,7 +47,11 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) =
4547
)
4648
},
4749
expectedVariation = assertionMap["expectedVariation"] as? String,
48-
matrix = assertionMap["matrix"] as? AssertionMatrix
50+
matrix = (assertionMap["matrix"] as? Map<String, List<Any>>)?.mapValues {
51+
it.value.map { item ->
52+
mapMatrixValues(item)
53+
}
54+
}
4955
)
5056
}
5157

@@ -55,10 +61,35 @@ internal fun parseTestFeatureAssertions(yamlFilePath: String) =
5561
null
5662
}
5763
} catch (e: Exception) {
58-
printMessageInRedColor("Exception while parsing Yaml Assertion File --> ${e.message}")
64+
printMessageInRedColor("Exception while parsing Yaml Assertion File -- $yamlFilePath --> ${e.message}")
5965
null
6066
}
6167

68+
private fun mapMatrixValues(value: Any) =
69+
when(value){
70+
is Boolean -> {
71+
if (value){
72+
AttributeValue.StringValue("yes")
73+
}else{
74+
AttributeValue.StringValue("no")
75+
}
76+
}
77+
is Int -> {
78+
AttributeValue.IntValue(value)
79+
}
80+
is Double -> {
81+
AttributeValue.DoubleValue(value)
82+
}
83+
is String -> {
84+
AttributeValue.StringValue(value)
85+
}
86+
is Date -> {
87+
AttributeValue.DateValue(value)
88+
}
89+
90+
else -> { AttributeValue.StringValue("")}
91+
}
92+
6293
private fun parseWeightValue(value: Any): WeightType {
6394
return when (value) {
6495
is Int -> WeightType.IntType(value)
@@ -87,9 +118,8 @@ private fun parseVariableValue(value: Any?): VariableValue {
87118
}
88119

89120
is Map<*, *> -> {
90-
val mapData = value as Map<String, String>
91-
val json1 = Json.encodeToString(MapSerializer(String.serializer(), String.serializer()), mapData)
92-
VariableValue.JsonValue(json1)
121+
val json = Gson().toJson(value)
122+
VariableValue.JsonValue(json)
93123
}
94124

95125
else -> throw IllegalArgumentException("Unsupported variable value type")
@@ -121,8 +151,17 @@ private fun parseAttributeValue(value: Any?): AttributeValue {
121151
AttributeValue.DateValue(value)
122152
}
123153

154+
is List<*> -> {
155+
AttributeValue.StringValue(value.toString())
156+
}
157+
158+
is Map<*, *> -> {
159+
val json = Gson().toJson(value)
160+
AttributeValue.StringValue(json)
161+
}
162+
124163
else -> {
125-
throw IllegalArgumentException("Unsupported attribute value type")
164+
throw IllegalArgumentException("Unsupported attribute value type $value")
126165
}
127166
}
128167
}
@@ -199,7 +238,13 @@ private fun parseConditionValue(value: Any?): ConditionValue {
199238
}
200239

201240
return when (value) {
202-
is String -> ConditionValue.StringValue(value)
241+
is String -> {
242+
value.toIntOrNull()?.let {
243+
ConditionValue.IntValue(value.toInt())
244+
} ?: value.toDoubleOrNull()?.let {
245+
ConditionValue.DoubleValue(value.toDouble())
246+
} ?: ConditionValue.StringValue(value)
247+
}
203248
is Int -> ConditionValue.IntValue(value)
204249
is Double -> ConditionValue.DoubleValue(value)
205250
is Boolean -> ConditionValue.BooleanValue(value)

src/main/kotlin/com/featurevisor/testRunner/TestExecuter.kt

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,6 @@ private fun executeTest(filePath: String, dataFile: DataFile, option: TestProjec
131131
return executionResult
132132
}
133133

134-
fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) =
135-
try {
136-
getJsonForFeatureUsingCommand(
137-
featureName = featureName,
138-
environment = environment,
139-
projectRootPath = projectRootPath
140-
)?.run {
141-
convertToDataClass<DatafileContent>()
142-
}
143-
} catch (e: Exception) {
144-
printMessageInRedColor("Exception while parsing data file --> ${e.message}")
145-
null
146-
}
147134

148135

149136

src/main/kotlin/com/featurevisor/testRunner/Utils.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,14 @@ fun getContextValue(contextValue: Any?) =
134134
else -> throw Exception("Unsupported context value")
135135
}
136136

137-
fun getContextValues(contextValue: AttributeValue) =
137+
fun getContextValues(contextValue: AttributeValue?) =
138138
when (contextValue) {
139139
is AttributeValue.IntValue -> contextValue.value
140140
is AttributeValue.DoubleValue -> contextValue.value
141141
is AttributeValue.StringValue -> contextValue.value
142142
is AttributeValue.BooleanValue -> contextValue.value
143143
is AttributeValue.DateValue -> contextValue.value
144+
null -> null
144145
}
145146

146147
fun checkIfArraysAreEqual(a: Array<Any>, b: Array<Any>): Boolean {
@@ -230,4 +231,18 @@ fun buildDataFileForBothEnvironments(projectRootPath: String): DataFile {
230231
)
231232
}
232233

234+
fun getDataFileContent(featureName: String, environment: String, projectRootPath: String) =
235+
try {
236+
getJsonForFeatureUsingCommand(
237+
featureName = featureName,
238+
environment = environment,
239+
projectRootPath = projectRootPath
240+
)?.run {
241+
convertToDataClass<DatafileContent>()
242+
}
243+
} catch (e: Exception) {
244+
printMessageInRedColor("Exception while parsing data file --> ${e.message}")
245+
null
246+
}
247+
233248

0 commit comments

Comments
 (0)