[EG-440] Add some error codes and the error resource generation tool (#6192)

* [EG-438] First commit of error code interface

* [EG-438] Implement error reporter and a few error codes

* [EG-438] Add unit tests and default properties files

* [EG-438] Add the error table builder

* [EG-438] Update initial properties files

* [EG-438] Add some Irish tests and the build.gradle

* [EG-438] Fall back for aliases and use different resource strategy

* [EG-438] Define the URL using a project-specific context

* [EG-438] Tidy up initialization code

* [EG-438] Add testing to generator and tidy up

* [EG-438] Remove direct dependency on core and add own logging config

* [EG-438] Fix compiler warnings and tidy up logging

* [EG-438] Fix detekt warnings

* [EG-438] Improve error messages

* [EG-438] Address first set of review comments

* [EG-438] Use enums and a builder for the reporter

* [EG-438] Address first set of review comments

* [EG-438] Use enums and a builder for the reporter

* [EG-438] Add kdocs for error resource static methods

* [EG-440] Add error code for duplicate CorDapp loading

* [EG-438] Handle enums defined with underscores

* [EG-440] Add errors for some CorDapp loading scenarios

* [EG-440] Finish adding errors for CorDapp loading

* [EG-440] Fix up errors in properties files

* [EG-440] Start change to error code definition

* [EG-440] Update error code definition and add resource generation tool

* [EG-440] Tidy up error resource generation tool frontend

* [EG-440] Small refactorings and add kdocs

* [EG-440] Generate all missing resources

* [EG-440] Some refactoring and start writing a test

* [EG-440] Update unit test for resource generator

* [EG-440] Renaming of various parts of the error tool

* [EG-440] Add testing for errors and fix an issue in resource generation

* [EG-440] Add a kdoc for context provider API

* [EG-440] Remove old code from repository

* [EG-440] Address some review comments
This commit is contained in:
James Higgs
2020-04-29 11:21:50 +01:00
committed by GitHub
parent ab43238420
commit ab95aa57a2
34 changed files with 566 additions and 85 deletions

View File

@ -43,6 +43,11 @@ class ErrorReporting private constructor(private val localeString: String,
return ErrorReporting(localeString, location, contextProvider)
}
/**
* Set the context provider to supply project-specific information about the errors.
*
* @param contextProvider The context provider to use with error reporting
*/
fun withContextProvider(contextProvider: ErrorContextProvider) : ErrorReporting {
return ErrorReporting(localeString, resourceLocation, contextProvider)
}

View File

@ -4,7 +4,8 @@ package net.corda.common.logging.errorReporting
* Namespaces for errors within the node.
*/
enum class NodeNamespaces {
DATABASE
DATABASE,
CORDAPP
}
/**
@ -17,4 +18,16 @@ enum class NodeDatabaseErrors : ErrorCodes {
PASSWORD_REQUIRED_FOR_H2;
override val namespace = NodeNamespaces.DATABASE.toString()
}
/**
* Errors related to loading of Cordapps
*/
enum class CordappErrors : ErrorCodes {
DUPLICATE_CORDAPPS_INSTALLED,
MULTIPLE_CORDAPPS_FOR_FLOW,
MISSING_VERSION_ATTRIBUTE,
INVALID_VERSION_IDENTIFIER;
override val namespace = NodeNamespaces.CORDAPP.toString()
}

View File

@ -0,0 +1,4 @@
errorTemplate = The CorDapp (name: {0}, file: {1}) is installed multiple times on the node. The following files correspond to the exact same content: {2}
shortDescription = A CorDapp has been installed multiple times on the same node.
actionsToFix = Investigate the logs to determine the files with duplicate content, and remove one of them from the cordapps directory.
aliases = iw8d4e

View File

@ -0,0 +1,3 @@
errorTemplate = The CorDapp (name: {0}, file: {1}) is installed multiple times on the node. The following files correspond to the exact same content: {2}
shortDescription = A CorDapp has been installed multiple times on the same node.
actionsToFix = Investigate the logs to determine the files with duplicate content, and remove one of them from the cordapps directory.

View File

@ -0,0 +1,4 @@
errorTemplate = Version identifier ({0}) for attribute {1} must be a whole number starting from 1.
shortDescription = A version attribute was specified in the CorDapp manifest with an invalid value. The value must be a whole number, and it must be greater than or equal to 1.
actionsToFix = Investigate the logs to find the invalid attribute, and change the attribute value to be valid (a whole number greater than or equal to 1).
aliases =

View File

@ -0,0 +1,4 @@
errorTemplate = Version identifier ({0}) for attribute {1} must be a whole number starting from 1.
shortDescription = A version attribute was specified in the CorDapp manifest with an invalid value. The value must be a whole number, and it must be greater than or equal to 1.
actionsToFix = Investigate the logs to find the invalid attribute, and change the attribute value to be valid (a whole number greater than or equal to 1).
aliases =

View File

@ -0,0 +1,4 @@
errorTemplate = Target versionId attribute {0} not specified. Please specify a whole number starting from 1.
shortDescription = A required version attribute was not specified in the manifest of the CorDapp JAR.
actionsToFix = Investigate the logs to find out which version attribute has not been specified, and add that version attribute to the CorDapp manifest.
aliases =

View File

@ -0,0 +1,3 @@
errorTemplate = Target versionId attribute {0} not specified. Please specify a whole number starting from 1.
shortDescription = A required version attribute was not specified in the manifest of the CorDapp JAR.
actionsToFix = Investigate the logs to find out which version attribute has not been specified, and add that version attribute to the CorDapp manifest.

View File

@ -0,0 +1,4 @@
errorTemplate = There are multiple CorDapp JARs on the classpath for the flow {0}: [{1}]
shortDescription = Multiple CorDapp JARs on the classpath define the same flow class. As a result, the platform will not know which version of the flow to start when the flow is invoked.
actionsToFix = Investigate the logs to find out which CorDapp JARs define the same flow classes. The developers of these apps will need to resolve the clash.
aliases =

View File

@ -0,0 +1,4 @@
errorTemplate = There are multiple CorDapp JARs on the classpath for the flow {0}: [{1}]
shortDescription = Multiple CorDapp JARs on the classpath define the same flow class. As a result, the platform will not know which version of the flow to start when the flow is invoked.
actionsToFix = Investigate the logs to find out which CorDapp JARs define the same flow classes. The developers of these apps will need to resolve the clash.
aliases =

View File

@ -0,0 +1,12 @@
package net.corda.commmon.logging.errorReporting
import net.corda.common.logging.errorReporting.CordappErrors
class CordappErrorsTest : ErrorCodeTest<CordappErrors>(CordappErrors::class.java, true) {
override val dataForCodes = mapOf(
CordappErrors.MISSING_VERSION_ATTRIBUTE to listOf("test-attribute"),
CordappErrors.INVALID_VERSION_IDENTIFIER to listOf(-1, "test-attribute"),
CordappErrors.MULTIPLE_CORDAPPS_FOR_FLOW to listOf("MyTestFlow", "Jar 1, Jar 2"),
CordappErrors.DUPLICATE_CORDAPPS_INSTALLED to listOf("TestCordapp", "testapp.jar", "testapp2.jar")
)
}

View File

@ -0,0 +1,13 @@
package net.corda.commmon.logging.errorReporting
import net.corda.common.logging.errorReporting.NodeDatabaseErrors
import java.net.InetAddress
class DatabaseErrorsTest : ErrorCodeTest<NodeDatabaseErrors>(NodeDatabaseErrors::class.java) {
override val dataForCodes = mapOf(
NodeDatabaseErrors.COULD_NOT_CONNECT to listOf<Any>(),
NodeDatabaseErrors.FAILED_STARTUP to listOf(),
NodeDatabaseErrors.MISSING_DRIVER to listOf(),
NodeDatabaseErrors.PASSWORD_REQUIRED_FOR_H2 to listOf(InetAddress.getLocalHost())
)
}

View File

@ -0,0 +1,61 @@
package net.corda.commmon.logging.errorReporting
import junit.framework.TestCase.assertFalse
import net.corda.common.logging.errorReporting.ErrorCode
import net.corda.common.logging.errorReporting.ErrorCodes
import net.corda.common.logging.errorReporting.ErrorResource
import net.corda.common.logging.errorReporting.ResourceBundleProperties
import org.junit.Test
import java.util.*
import kotlin.test.assertTrue
/**
* Utility for testing that error code resource files behave as expected.
*
* This allows for testing that error messages are printed correctly if they are provided the correct parameters. The test will fail if any
* of the parameters of the template are not filled in.
*
* To use, override the `dataForCodes` with a map from an error code enum value to a list of parameters the message template takes. If any
* are missed, the test will fail.
*
* `printProperties`, if set to true, will print the properties out the resource files, with the error message filled in. This allows the
* message to be inspected.
*/
abstract class ErrorCodeTest<T>(private val clazz: Class<T>,
private val printProperties: Boolean = false) where T: Enum<T>, T: ErrorCodes {
abstract val dataForCodes: Map<T, List<Any>>
private class TestError<T>(override val code: T,
override val parameters: List<Any>) : ErrorCode<T> where T: Enum<T>, T: ErrorCodes
@Test(timeout = 300_000)
fun `test error codes`() {
for ((code, params) in dataForCodes) {
val error = TestError(code, params)
val resource = ErrorResource.fromErrorCode(error, "error-codes", Locale.forLanguageTag("en-US"))
val message = resource.getErrorMessage(error.parameters.toTypedArray())
assertFalse(
"The error message reported for code $code contains missing parameters",
message.contains("\\{.*}".toRegex())
)
val otherProperties = Triple(resource.shortDescription, resource.actionsToFix, resource.aliases)
if (printProperties) {
println("Data for $code")
println("Error Message = $message")
println("${ResourceBundleProperties.SHORT_DESCRIPTION} = ${otherProperties.first}")
println("${ResourceBundleProperties.ACTIONS_TO_FIX} = ${otherProperties.second}")
println("${ResourceBundleProperties.ALIASES} = ${otherProperties.third}")
println("")
}
}
}
@Test(timeout = 300_000)
fun `ensure all error codes tested`() {
val expected = clazz.enumConstants.toSet()
val actual = dataForCodes.keys.toSet()
val missing = expected - actual
assertTrue(missing.isEmpty(), "The following codes have not been tested: $missing")
}
}