-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Improve error messages * No state no class, fix wrong auto formating * Add support for get full chain with properties contains '-' in name
- Loading branch information
1 parent
2b82053
commit 9eb491d
Showing
19 changed files
with
353 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
test_runner/src/main/kotlin/ftl/args/yml/MissingParameterErrorConverter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package ftl.args.yml | ||
|
||
import com.fasterxml.jackson.databind.JsonNode | ||
import ftl.args.yml.errors.ConfigurationErrorMessageBuilder | ||
import ftl.util.FlankConfigurationException | ||
|
||
fun convertConfigurationErrorExceptions(missingParameterError: Exception, yaml: JsonNode): Throwable { | ||
val errorMessageBuilder = ConfigurationErrorMessageBuilder | ||
val errorMessage = missingParameterError.message | ||
return if (errorMessage != null) { | ||
FlankConfigurationException(errorMessageBuilder(errorMessage, yaml)) | ||
} else { | ||
missingParameterError | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
test_runner/src/main/kotlin/ftl/args/yml/YamlObjectMapper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package ftl.args.yml | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper | ||
import com.fasterxml.jackson.databind.exc.MismatchedInputException | ||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory | ||
import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException | ||
|
||
class YamlObjectMapper : ObjectMapper(YAMLFactory()) { | ||
override fun <T> readValue(content: String?, valueType: Class<T>?): T { | ||
try { | ||
return readValue(content, _typeFactory.constructType(valueType)) | ||
} catch (missingParameterError: MissingKotlinParameterException) { | ||
throw convertConfigurationErrorExceptions(missingParameterError, readTree(content)) | ||
} catch (mismatchedInputException: MismatchedInputException) { | ||
throw convertConfigurationErrorExceptions(mismatchedInputException, readTree(content)) | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
test_runner/src/main/kotlin/ftl/args/yml/errors/ConfigurationErrorMessageBuilder.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package ftl.args.yml.errors | ||
|
||
import com.fasterxml.jackson.databind.JsonNode | ||
import java.lang.Exception | ||
|
||
object ConfigurationErrorMessageBuilder { | ||
|
||
private val parseMessage = ConfigurationErrorParser | ||
private val resolveErrorNode = ErrorNodeResolver | ||
|
||
//region error message elements | ||
private const val messageHeader = "Error on parse config: " | ||
private const val missingElementMessage = "Missing element or value for: '%s'" | ||
private const val atMessage = "At line: %s, column: %s" | ||
private const val errorNodeMessage = "Error node: %s" | ||
//endregion | ||
|
||
private const val exceptionTemplate = "Parse message error: %s" | ||
|
||
operator fun invoke(errorMessage: String, yamlTreeNode: JsonNode? = null) = | ||
try { | ||
val errorModel = parseMessage(errorMessage) | ||
val errorMessageBuilder = StringBuilder(messageHeader) | ||
errorMessageBuilder.appendln(createReferenceChain(errorModel.referenceChain)) | ||
if (errorModel.propertyName != "") { | ||
errorMessageBuilder.appendln(missingElementMessage.format(errorModel.propertyName)) | ||
} | ||
errorMessageBuilder.appendln(atMessage.format(errorModel.line, errorModel.column)) | ||
yamlTreeNode?.let { | ||
errorMessageBuilder.appendln(errorNodeMessage.format(resolveErrorNode(yamlTreeNode, errorModel))) | ||
} | ||
errorMessageBuilder.toString().trim() | ||
} catch (error: Exception) { | ||
exceptionTemplate.format(errorMessage) | ||
} | ||
|
||
private fun createReferenceChain(referenceChain: List<String>): String { | ||
val chainBuilder = StringBuilder() | ||
referenceChain.forEachIndexed { index, chainPart -> | ||
chainBuilder.append(appendChainElement(chainPart, index > 0)) | ||
} | ||
return chainBuilder.toString() | ||
} | ||
|
||
private fun appendChainElement(chainPart: String, withSeparator: Boolean): String = when { | ||
chainPart.toIntOrNull() != null -> "[$chainPart]" | ||
withSeparator -> "->$chainPart" | ||
else -> chainPart | ||
} | ||
} |
3 changes: 3 additions & 0 deletions
3
test_runner/src/main/kotlin/ftl/args/yml/errors/ConfigurationErrorModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package ftl.args.yml.errors | ||
|
||
internal data class ConfigurationErrorModel(val propertyName: String, val line: Int, val column: Int, val referenceChain: List<String>) |
30 changes: 30 additions & 0 deletions
30
test_runner/src/main/kotlin/ftl/args/yml/errors/ConfigurationErrorParser.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package ftl.args.yml.errors | ||
|
||
internal object ConfigurationErrorParser { | ||
|
||
//region regex patterns | ||
private val propertyNameRegex = "(?<=property\\s)[a-z]*".toRegex() | ||
private val referenceChainRegex = "(?<=chain:\\s).*(?=[)])".toRegex() | ||
private val referenceChainCleanUpRegex = "(?<=[\\[])\"?[\\w]*\"?(?=])".toRegex() | ||
private val lineAndColumnRegex = "((?<=line:\\s)\\d*), column:\\s(\\d*)".toRegex() | ||
//endregion | ||
|
||
operator fun invoke(errorMessage: String): ConfigurationErrorModel { | ||
val (line, column) = parseErrorPositionLine(errorMessage) | ||
return ConfigurationErrorModel( | ||
parsePropertyName(errorMessage), | ||
line.toInt(), | ||
column.toInt(), | ||
parseReferenceChain(errorMessage) | ||
) | ||
} | ||
|
||
private fun parsePropertyName(errorMessage: String) = propertyNameRegex.find(errorMessage)?.value ?: "" | ||
private fun parseErrorPositionLine(errorMessage: String) = lineAndColumnRegex.find(errorMessage)!!.destructured | ||
|
||
private fun parseReferenceChain(errorMessage: String) = | ||
cleanUpReferenceChain(referenceChainRegex.find(errorMessage)!!.value) | ||
|
||
private fun cleanUpReferenceChain(referenceChain: String): List<String> = | ||
referenceChainCleanUpRegex.findAll(referenceChain).map { it.value.replace("\"", "") }.toList() | ||
} |
23 changes: 23 additions & 0 deletions
23
test_runner/src/main/kotlin/ftl/args/yml/errors/ErrorNodeResolver.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package ftl.args.yml.errors | ||
|
||
import com.fasterxml.jackson.databind.JsonNode | ||
|
||
internal object ErrorNodeResolver { | ||
operator fun invoke(treeNode: JsonNode, errorModel: ConfigurationErrorModel): String { | ||
var currentNode: JsonNode = treeNode | ||
|
||
val lastNode = errorModel.referenceChain.last() | ||
for (chainNode in errorModel.referenceChain) { | ||
if (chainNode == lastNode) { | ||
break | ||
} | ||
val nodeAsIntValue = chainNode.toIntOrNull() | ||
currentNode = if (nodeAsIntValue != null) { | ||
currentNode[nodeAsIntValue] | ||
} else { | ||
currentNode[chainNode] | ||
} | ||
} | ||
return currentNode.toPrettyString() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
test_runner/src/test/kotlin/ftl/args/yml/ErrorParserTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package ftl.args.yml | ||
|
||
import ftl.args.AndroidArgs | ||
import ftl.args.yml.errors.ConfigurationErrorMessageBuilder | ||
import ftl.test.util.TestHelper | ||
import ftl.test.util.TestHelper.getThrowable | ||
import ftl.util.FlankConfigurationException | ||
import org.junit.Assert | ||
import org.junit.Test | ||
|
||
class ErrorParserTest { | ||
private val yamlWithoutDeviceVersion = | ||
TestHelper.getPath("src/test/kotlin/ftl/args/yml/test_error_yaml_cases/flank-no-device-version.yml") | ||
private val yamlNoModelName = | ||
TestHelper.getPath("src/test/kotlin/ftl/args/yml/test_error_yaml_cases/flank-no-model-name.yml") | ||
private val yamlNoModelNode = | ||
TestHelper.getPath("src/test/kotlin/ftl/args/yml/test_error_yaml_cases/flank-no-model-node.yml") | ||
|
||
@Test | ||
fun `parse json mapping error`() { | ||
val instantionError = | ||
"Instantiation of [simple type, class ftl.config.Device] value failed for JSON property version due to missing (therefore NULL) value for creator parameter version which is a non-nullable type\n" + | ||
" at [Source: (StringReader); line: 23, column: 3] (through reference chain: ftl.args.yml.AndroidGcloudYml[\"gcloud\"]->ftl.args.yml.AndroidGcloudYmlParams[\"device\"]->java.util.ArrayList[4]->ftl.config.Device[\"version\"])" | ||
|
||
val expected = """ | ||
Error on parse config: gcloud->device[4]->version | ||
Missing element or value for: 'version' | ||
At line: 23, column: 3 | ||
""".trimIndent() | ||
val buildErrorMessage = ConfigurationErrorMessageBuilder | ||
Assert.assertEquals(expected, buildErrorMessage(instantionError)) | ||
} | ||
|
||
@Test | ||
fun `return exception with inner message on parse error`() { | ||
val instantionError = | ||
"Instantiation oflParams[\"device\"]->java.util.A" | ||
val expected = "Parse message error: Instantiation oflParams[\"device\"]->java.util.A".trimIndent() | ||
val buildErrorMessage = ConfigurationErrorMessageBuilder | ||
|
||
Assert.assertEquals(expected, buildErrorMessage(instantionError)) | ||
} | ||
|
||
@Test(expected = FlankConfigurationException::class) | ||
fun `should throw FlankConfigException without device version`() { | ||
AndroidArgs.load(yamlWithoutDeviceVersion) | ||
} | ||
|
||
@Test | ||
fun `without model name should have message`() { | ||
val actualMessage = getThrowable { AndroidArgs.load(yamlNoModelName) }.message | ||
val exceptedMessage = """ | ||
Error on parse config: gcloud->device[0]->model | ||
Missing element or value for: 'model' | ||
At line: 8, column: 1 | ||
Error node: { | ||
"model" : null, | ||
"version" : "test" | ||
} | ||
""".trimIndent() | ||
Assert.assertEquals(exceptedMessage, actualMessage) | ||
} | ||
|
||
@Test | ||
fun `without model node should have message`() { | ||
val actualMessage = getThrowable { AndroidArgs.load(yamlNoModelNode) }.message | ||
val exceptedMessage = """ | ||
Error on parse config: gcloud->device | ||
At line: 6, column: 5 | ||
Error node: { | ||
"app" : "./src/test/kotlin/ftl/fixtures/tmp/apk/app-debug.apk", | ||
"test" : "./src/test/kotlin/ftl/fixtures/tmp/apk/app-single-success-debug-androidTest.apk", | ||
"device" : { | ||
"version" : "test" | ||
} | ||
} | ||
""".trimIndent() | ||
Assert.assertEquals(exceptedMessage, actualMessage) | ||
} | ||
|
||
@Test(expected = FlankConfigurationException::class) | ||
fun `should throw FlankConfigException without model name`() { | ||
AndroidArgs.load(yamlNoModelName) | ||
} | ||
|
||
@Test(expected = FlankConfigurationException::class) | ||
fun `should throw FlankConfigException without model node`() { | ||
AndroidArgs.load(yamlNoModelNode) | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
test_runner/src/test/kotlin/ftl/args/yml/test_error_yaml_cases/flank-no-device-version.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
gcloud: | ||
app: ./src/test/kotlin/ftl/fixtures/tmp/apk/app-debug.apk | ||
test: ./src/test/kotlin/ftl/fixtures/tmp/apk/app-single-success-debug-androidTest.apk | ||
device: | ||
- model: NexusLowRes | ||
version: 23 | ||
- model: NexusLowRes | ||
version: 23 | ||
orientation: landscape | ||
- model: shamu | ||
version: 22 | ||
locale: zh_CN | ||
orientation: default | ||
# Google Pixel 3 | ||
- model: blueline | ||
version: 28 | ||
locale: en | ||
orientation: portrait | ||
# Samsung Galaxy S9 SM-G9600 | ||
- model: starqltechn | ||
versxion: 28 | ||
locale: en | ||
orientation: portrait | ||
# LG Nexus 5 | ||
- model: hammerhead | ||
version: 21 | ||
locale: en | ||
orientation: portrait | ||
flank: | ||
disable-sharding: true | ||
|
Oops, something went wrong.