[CORDA-1482] Make boolean config variables case insensitive (#3622)

* Make boolean config variables case insensitive

* Address review comments
This commit is contained in:
Anthony Keenan 2018-07-21 11:54:02 +01:00 committed by GitHub
parent d2446be69e
commit 7853cfe003
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 17 deletions

View File

@ -121,7 +121,7 @@ private fun Config.getSingleValue(path: String, type: KType, onUnknownKeys: (Set
Int::class -> getInt(path) Int::class -> getInt(path)
Long::class -> getLong(path) Long::class -> getLong(path)
Double::class -> getDouble(path) Double::class -> getDouble(path)
Boolean::class -> getBoolean(path) Boolean::class -> getBooleanCaseInsensitive(path)
LocalDate::class -> LocalDate.parse(getString(path)) LocalDate::class -> LocalDate.parse(getString(path))
Duration::class -> getDuration(path) Duration::class -> getDuration(path)
Instant::class -> Instant.parse(getString(path)) Instant::class -> Instant.parse(getString(path))
@ -276,6 +276,19 @@ private fun Iterable<*>.toConfigIterable(field: Field): Iterable<Any?> {
} }
} }
// The typesafe .getBoolean function is case sensitive, this is a case insensitive version
fun Config.getBooleanCaseInsensitive(path: String): Boolean {
try {
return getBoolean(path)
} catch(e:Exception) {
val stringVal = getString(path).toLowerCase()
if (stringVal == "true" || stringVal == "false") {
return stringVal.toBoolean()
}
throw e
}
}
private val logger = LoggerFactory.getLogger("net.corda.nodeapi.internal.config") private val logger = LoggerFactory.getLogger("net.corda.nodeapi.internal.config")
enum class UnknownConfigKeysPolicy(private val handle: (Set<String>, logger: Logger) -> Unit) { enum class UnknownConfigKeysPolicy(private val handle: (Set<String>, logger: Logger) -> Unit) {

View File

@ -21,6 +21,7 @@ import net.corda.core.utilities.days
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.* import net.corda.nodeapi.internal.*
import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX import net.corda.nodeapi.internal.network.NodeInfoFilesCopier.Companion.NODE_INFO_FILE_NAME_PREFIX
import net.corda.serialization.internal.AMQP_P2P_CONTEXT import net.corda.serialization.internal.AMQP_P2P_CONTEXT
import net.corda.serialization.internal.CordaSerializationMagic import net.corda.serialization.internal.CordaSerializationMagic
@ -289,7 +290,7 @@ class NetworkBootstrapper
// The config contains the notary type // The config contains the notary type
val nodeConfig = configs[nodeInfoFile.parent]!! val nodeConfig = configs[nodeInfoFile.parent]!!
if (nodeConfig.hasPath("notary")) { if (nodeConfig.hasPath("notary")) {
val validating = nodeConfig.getBoolean("notary.validating") val validating = nodeConfig.getBooleanCaseInsensitive("notary.validating")
// And the node-info file contains the notary's identity // And the node-info file contains the notary's identity
val nodeInfo = nodeInfoFile.readObject<SignedNodeInfo>().verified() val nodeInfo = nodeInfoFile.readObject<SignedNodeInfo>().verified()
NotaryInfo(nodeInfo.notaryIdentity(), validating) NotaryInfo(nodeInfo.notaryIdentity(), validating)

View File

@ -1,6 +1,7 @@
package net.corda.nodeapi.internal.config package net.corda.nodeapi.internal.config
import com.typesafe.config.Config import com.typesafe.config.Config
import com.typesafe.config.ConfigException
import com.typesafe.config.ConfigFactory.empty import com.typesafe.config.ConfigFactory.empty
import com.typesafe.config.ConfigRenderOptions.defaults import com.typesafe.config.ConfigRenderOptions.defaults
import com.typesafe.config.ConfigValueFactory import com.typesafe.config.ConfigValueFactory
@ -8,6 +9,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import org.assertj.core.api.Assertions.* import org.assertj.core.api.Assertions.*
import org.hibernate.exception.DataException
import org.junit.Test import org.junit.Test
import java.net.URL import java.net.URL
import java.nio.file.Path import java.nio.file.Path
@ -41,8 +43,16 @@ class ConfigParsingTest {
@Test @Test
fun Boolean() { fun Boolean() {
testPropertyType<BooleanData, BooleanListData, Boolean>(true, false) testPropertyType<BooleanData, BooleanListData, Boolean>(true, false)
assertThat(config(Pair("value", "false")).parseAs<BooleanData>().value).isEqualTo(false)
assertThat(config(Pair("value", "False")).parseAs<BooleanData>().value).isEqualTo(false)
assertThat(config(Pair("value", "FALSE")).parseAs<BooleanData>().value).isEqualTo(false)
assertThat(config(Pair("value", "true")).parseAs<BooleanData>().value).isEqualTo(true)
assertThat(config(Pair("value", "True")).parseAs<BooleanData>().value).isEqualTo(true)
assertThat(config(Pair("value", "TRUE")).parseAs<BooleanData>().value).isEqualTo(true)
assertThatThrownBy { config(Pair("value", "stilton")).parseAs<BooleanData>().value }
.isInstanceOf(ConfigException.WrongType::class.java)
.hasMessageContaining("hardcoded value: value has type STRING rather than BOOLEAN")
} }
@Test @Test
fun Enum() { fun Enum() {
testPropertyType<EnumData, EnumListData, TestEnum>(TestEnum.Value2, TestEnum.Value1, valuesToString = true) testPropertyType<EnumData, EnumListData, TestEnum>(TestEnum.Value2, TestEnum.Value1, valuesToString = true)

View File

@ -4,6 +4,7 @@ import com.typesafe.config.Config
import com.typesafe.config.ConfigException import com.typesafe.config.ConfigException
import net.corda.core.cordapp.CordappConfig import net.corda.core.cordapp.CordappConfig
import net.corda.core.cordapp.CordappConfigException import net.corda.core.cordapp.CordappConfigException
import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive
/** /**
* Provides configuration from a typesafe config source * Provides configuration from a typesafe config source
@ -71,7 +72,7 @@ class TypesafeCordappConfig(private val cordappConfig: Config) : CordappConfig {
override fun getBoolean(path: String): Boolean { override fun getBoolean(path: String): Boolean {
try { try {
return cordappConfig.getBoolean(path) return cordappConfig.getBooleanCaseInsensitive(path)
} catch (e: ConfigException) { } catch (e: ConfigException) {
throw CordappConfigException("Cordapp configuration is incorrect due to exception", e) throw CordappConfigException("Cordapp configuration is incorrect due to exception", e)
} }

View File

@ -4,6 +4,7 @@ import com.typesafe.config.*
import net.corda.core.internal.toPath import net.corda.core.internal.toPath
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.tools.shell.SSHDConfiguration import net.corda.tools.shell.SSHDConfiguration
@ -67,16 +68,16 @@ class NodeConfigurationImplTest {
val os = System.getProperty("os.name") val os = System.getProperty("os.name")
setSystemOs("Windows 98") setSystemOs("Windows 98")
assertTrue(getConfig("test-config-empty.conf").getBoolean("devMode")) assertTrue(getConfig("test-config-empty.conf").getBooleanCaseInsensitive("devMode"))
setSystemOs("Mac Sierra") setSystemOs("Mac Sierra")
assertTrue(getConfig("test-config-empty.conf").getBoolean("devMode")) assertTrue(getConfig("test-config-empty.conf").getBooleanCaseInsensitive("devMode"))
setSystemOs("Windows server 2008") setSystemOs("Windows server 2008")
assertFalse(getConfig("test-config-empty.conf").getBoolean("devMode")) assertFalse(getConfig("test-config-empty.conf").getBooleanCaseInsensitive("devMode"))
setSystemOs("Linux") setSystemOs("Linux")
assertFalse(getConfig("test-config-empty.conf").getBoolean("devMode")) assertFalse(getConfig("test-config-empty.conf").getBooleanCaseInsensitive("devMode"))
setSystemOs(os) setSystemOs(os)
} }
@ -87,22 +88,22 @@ class NodeConfigurationImplTest {
@Test @Test
fun `Dev mode is read from the config over the autodetect logic`() { fun `Dev mode is read from the config over the autodetect logic`() {
assertTrue(getConfig("test-config-DevMode.conf").getBoolean("devMode")) assertTrue(getConfig("test-config-DevMode.conf").getBooleanCaseInsensitive("devMode"))
assertFalse(getConfig("test-config-noDevMode.conf").getBoolean("devMode")) assertFalse(getConfig("test-config-noDevMode.conf").getBooleanCaseInsensitive("devMode"))
} }
@Test @Test
fun `Dev mode is true if overriden`() { fun `Dev mode is true if overriden`() {
assertTrue(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) assertTrue(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBooleanCaseInsensitive("devMode"))
assertTrue(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) assertTrue(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBooleanCaseInsensitive("devMode"))
assertTrue(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBoolean("devMode")) assertTrue(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to true))).getBooleanCaseInsensitive("devMode"))
} }
@Test @Test
fun `Dev mode is false if overriden`() { fun `Dev mode is false if overriden`() {
assertFalse(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) assertFalse(getConfig("test-config-DevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBooleanCaseInsensitive("devMode"))
assertFalse(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) assertFalse(getConfig("test-config-noDevMode.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBooleanCaseInsensitive("devMode"))
assertFalse(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBoolean("devMode")) assertFalse(getConfig("test-config-empty.conf", ConfigFactory.parseMap(mapOf("devMode" to false))).getBooleanCaseInsensitive("devMode"))
} }
private fun getConfig(cfgName: String, overrides: Config = ConfigFactory.empty()): Config { private fun getConfig(cfgName: String, overrides: Config = ConfigFactory.empty()): Config {

View File

@ -9,6 +9,7 @@ import net.corda.core.node.NotaryInfo
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.nodeapi.internal.DEV_ROOT_CA import net.corda.nodeapi.internal.DEV_ROOT_CA
import net.corda.nodeapi.internal.SignedNodeInfo import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.nodeapi.internal.config.getBooleanCaseInsensitive
import net.corda.nodeapi.internal.createDevNetworkMapCa import net.corda.nodeapi.internal.createDevNetworkMapCa
import java.io.File import java.io.File
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
@ -36,7 +37,7 @@ interface Volume {
fun convertNodeIntoToNetworkParams(notaryFiles: List<Pair<File, File>>): NetworkParameters { fun convertNodeIntoToNetworkParams(notaryFiles: List<Pair<File, File>>): NetworkParameters {
val notaryInfos = notaryFiles.map { (configFile, nodeInfoFile) -> val notaryInfos = notaryFiles.map { (configFile, nodeInfoFile) ->
val validating = ConfigFactory.parseFile(configFile).getConfig("notary").getBoolean("validating") val validating = ConfigFactory.parseFile(configFile).getConfig("notary").getBooleanCaseInsensitive("validating")
nodeInfoFile.readBytes().deserialize<SignedNodeInfo>().verified().let { NotaryInfo(it.legalIdentities.first(), validating) } nodeInfoFile.readBytes().deserialize<SignedNodeInfo>().verified().let { NotaryInfo(it.legalIdentities.first(), validating) }
} }