CORDA-2176 - test that logging is not broken. (#5224)

* Initial commit with a test that can detect a logger that isn't initialised with by lazy that gets called during startup.

* Test improvement. Test fix for api stability.

* Added explanatory comment for the test.

* Changes according to PR review. Added empty file check to make test more robust.
This commit is contained in:
Stefan Iliev 2019-06-25 14:35:39 +01:00 committed by Anthony Keenan
parent 48b0de5e57
commit d1e7850dd1
4 changed files with 125 additions and 4 deletions

View File

@ -6,7 +6,9 @@ import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.messaging.FlowHandle import net.corda.core.messaging.FlowHandle
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
@ -28,6 +30,30 @@ class ErrorCodeLoggingTests {
} }
} }
// This is used to detect broken logging which can be caused by loggers being initialized
// before the initLogging() call is made
@Test
fun `When logging is set to error level, there are no other levels logged after node startup`() {
driver(DriverParameters(notarySpecs = emptyList())) {
val node = startNode(startInSameProcess = false, logLevelOverride = "ERROR").getOrThrow()
node.rpc.startFlow(::MyFlow).waitForCompletion()
val logFile = node.logFile()
assertThat(logFile.length()).isGreaterThan(0)
val linesWithoutError = logFile.useLines { lines ->
lines.filterNot {
it.contains("[ERROR")
}.filter{
it.contains("[INFO")
.or(it.contains("[WARN"))
.or(it.contains("[DEBUG"))
.or(it.contains("[TRACE"))
}.toList()
}
assertThat(linesWithoutError.isEmpty()).isTrue()
}
}
@StartableByRPC @StartableByRPC
@InitiatingFlow @InitiatingFlow
class MyFlow : FlowLogic<String>() { class MyFlow : FlowLogic<String>() {

View File

@ -89,8 +89,51 @@ interface DriverDSL {
* @param maximumHeapSize The maximum JVM heap size to use for the node as a [String]. By default a number is interpreted * @param maximumHeapSize The maximum JVM heap size to use for the node as a [String]. By default a number is interpreted
* as being in bytes. Append the letter 'k' or 'K' to the value to indicate Kilobytes, 'm' or 'M' to indicate * as being in bytes. Append the letter 'k' or 'K' to the value to indicate Kilobytes, 'm' or 'M' to indicate
* megabytes, and 'g' or 'G' to indicate gigabytes. The default value is "512m" = 512 megabytes. * megabytes, and 'g' or 'G' to indicate gigabytes. The default value is "512m" = 512 megabytes.
* @param logLevelOverride log4j log level used to override the default value of info.
* @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and * @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and
* it sees all previously started nodes, including the notaries. * it sees all previously started nodes, including the notaries.
*/
fun startNode(
defaultParameters: NodeParameters = NodeParameters(),
providedName: CordaX500Name? = defaultParameters.providedName,
rpcUsers: List<User> = defaultParameters.rpcUsers,
verifierType: VerifierType = defaultParameters.verifierType,
customOverrides: Map<String, Any?> = defaultParameters.customOverrides,
startInSameProcess: Boolean? = defaultParameters.startInSameProcess,
maximumHeapSize: String = defaultParameters.maximumHeapSize,
logLevelOverride: String? = defaultParameters.logLevelOverride
): CordaFuture<NodeHandle> {
return startNode(defaultParameters.copy(
providedName = providedName,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = customOverrides,
startInSameProcess = startInSameProcess,
maximumHeapSize = maximumHeapSize,
logLevelOverride = logLevelOverride
))
}
/**
* Start a node.
*
* NOTE: This method does not provide all the node parameters that are available and only exists for backwards compatibility. It is
* recommended you use [NodeParameters].
*
* @param defaultParameters The default parameters for the node. If any of the remaining parameters to this method are specified then
* their values are taken instead of the corresponding value in [defaultParameters].
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to empty list.
* @param verifierType The type of transaction verifier to use. See: [VerifierType].
* @param customOverrides A map of custom node configuration overrides.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @param maximumHeapSize The maximum JVM heap size to use for the node as a [String]. By default a number is interpreted
* as being in bytes. Append the letter 'k' or 'K' to the value to indicate Kilobytes, 'm' or 'M' to indicate
* megabytes, and 'g' or 'G' to indicate gigabytes. The default value is "512m" = 512 megabytes.
* @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and
* it sees all previously started nodes, including the notaries.
*/ */
fun startNode( fun startNode(
defaultParameters: NodeParameters = NodeParameters(), defaultParameters: NodeParameters = NodeParameters(),

View File

@ -20,6 +20,8 @@ import net.corda.testing.node.User
* @property maximumHeapSize The maximum JVM heap size to use for the node. Defaults to 512 MB. * @property maximumHeapSize The maximum JVM heap size to use for the node. Defaults to 512 MB.
* @property additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes * @property additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes
* managed by the [DriverDSL]. * managed by the [DriverDSL].
* @property logLevelOverride log level to be passed as parameter to an out of process node. ERROR, WARN, INFO, DEBUG, TRACE. This overrides debug port
* log level argument.
*/ */
@Suppress("unused") @Suppress("unused")
data class NodeParameters( data class NodeParameters(
@ -30,7 +32,8 @@ data class NodeParameters(
val startInSameProcess: Boolean? = null, val startInSameProcess: Boolean? = null,
val maximumHeapSize: String = "512m", val maximumHeapSize: String = "512m",
val additionalCordapps: Collection<TestCordapp> = emptySet(), val additionalCordapps: Collection<TestCordapp> = emptySet(),
val flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = emptyMap() val flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = emptyMap(),
val logLevelOverride : String? = null
) { ) {
/** /**
* Create a new node parameters object with default values. Each parameter can be specified with its wither method which returns a copy * Create a new node parameters object with default values. Each parameter can be specified with its wither method which returns a copy
@ -46,6 +49,7 @@ data class NodeParameters(
fun withMaximumHeapSize(maximumHeapSize: String): NodeParameters = copy(maximumHeapSize = maximumHeapSize) fun withMaximumHeapSize(maximumHeapSize: String): NodeParameters = copy(maximumHeapSize = maximumHeapSize)
fun withAdditionalCordapps(additionalCordapps: Set<TestCordapp>): NodeParameters = copy(additionalCordapps = additionalCordapps) fun withAdditionalCordapps(additionalCordapps: Set<TestCordapp>): NodeParameters = copy(additionalCordapps = additionalCordapps)
fun withFlowOverrides(flowOverrides: Map<Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>): NodeParameters = copy(flowOverrides = flowOverrides) fun withFlowOverrides(flowOverrides: Map<Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>): NodeParameters = copy(flowOverrides = flowOverrides)
fun withLogLevelOverride(logLevelOverride : String?) : NodeParameters = copy(logLevelOverride = logLevelOverride)
constructor( constructor(
providedName: CordaX500Name?, providedName: CordaX500Name?,
@ -79,4 +83,44 @@ data class NodeParameters(
maximumHeapSize = maximumHeapSize, maximumHeapSize = maximumHeapSize,
additionalCordapps = additionalCordapps additionalCordapps = additionalCordapps
) )
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
additionalCordapps: Collection<TestCordapp> = emptySet(),
flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>
) : this(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
additionalCordapps,
flowOverrides,
logLevelOverride = null)
fun copy(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
additionalCordapps: Collection<TestCordapp> = emptySet(),
flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>
) = this.copy(
providedName = providedName,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = customOverrides,
startInSameProcess = startInSameProcess,
maximumHeapSize = maximumHeapSize,
additionalCordapps = additionalCordapps,
flowOverrides = flowOverrides,
logLevelOverride = logLevelOverride)
} }

View File

@ -548,6 +548,7 @@ class DriverDSLImpl(
debugPort, debugPort,
systemProperties, systemProperties,
"512m", "512m",
null,
*extraCmdLineFlag *extraCmdLineFlag
) )
@ -605,7 +606,7 @@ class DriverDSLImpl(
nodeFuture nodeFuture
} else { } else {
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val process = startOutOfProcessNode(config, quasarJarPath, debugPort, systemProperties, parameters.maximumHeapSize) val process = startOutOfProcessNode(config, quasarJarPath, debugPort, systemProperties, parameters.maximumHeapSize, parameters.logLevelOverride)
// Destroy the child process when the parent exits.This is needed even when `waitForAllNodesToFinish` is // Destroy the child process when the parent exits.This is needed even when `waitForAllNodesToFinish` is
// true because we don't want orphaned processes in the case that the parent process is terminated by the // true because we don't want orphaned processes in the case that the parent process is terminated by the
@ -732,6 +733,7 @@ class DriverDSLImpl(
debugPort: Int?, debugPort: Int?,
overriddenSystemProperties: Map<String, String>, overriddenSystemProperties: Map<String, String>,
maximumHeapSize: String, maximumHeapSize: String,
logLevelOverride: String?,
vararg extraCmdLineFlag: String vararg extraCmdLineFlag: String
): Process { ): Process {
log.info("Starting out-of-process Node ${config.corda.myLegalName.organisation}, debug port is " + (debugPort ?: "not enabled")) log.info("Starting out-of-process Node ${config.corda.myLegalName.organisation}, debug port is " + (debugPort ?: "not enabled"))
@ -761,7 +763,13 @@ class DriverDSLImpl(
"com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;)" "com.lmax**;picocli**;liquibase**;com.github.benmanes**;org.json**;org.postgresql**;nonapi.io.github.classgraph**;)"
val extraJvmArguments = systemProperties.removeResolvedClasspath().map { "-D${it.key}=${it.value}" } + val extraJvmArguments = systemProperties.removeResolvedClasspath().map { "-D${it.key}=${it.value}" } +
"-javaagent:$quasarJarPath=$excludePattern" "-javaagent:$quasarJarPath=$excludePattern"
val loggingLevel = if (debugPort == null) "INFO" else "DEBUG"
val loggingLevel = when {
logLevelOverride != null -> logLevelOverride
debugPort == null -> "INFO"
else -> "DEBUG"
}
val arguments = mutableListOf( val arguments = mutableListOf(
"--base-directory=${config.corda.baseDirectory}", "--base-directory=${config.corda.baseDirectory}",