diff --git a/src/main/java/com/iota/iri/conf/ConfigFactory.java b/src/main/java/com/iota/iri/conf/ConfigFactory.java index e776883a8e..ecde4098d2 100644 --- a/src/main/java/com/iota/iri/conf/ConfigFactory.java +++ b/src/main/java/com/iota/iri/conf/ConfigFactory.java @@ -4,9 +4,9 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; -import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.iota.iri.conf.deserializers.CustomBoolDeserializer; +import com.iota.iri.conf.deserializers.CustomStringDeserializer; import java.io.File; import java.io.FileInputStream; @@ -41,10 +41,15 @@ public static IotaConfig createFromFile(File configFile, boolean testnet) throws objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); objectMapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true); objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); + SimpleModule booleanParser = new SimpleModule("BooleanParser"); - StdDeserializer booleanDeserializer = new CustomBoolDeserializer(); - booleanParser.addDeserializer(Boolean.TYPE, booleanDeserializer); + booleanParser.addDeserializer(Boolean.TYPE, new CustomBoolDeserializer()); objectMapper.registerModule(booleanParser); + + SimpleModule stringParser = new SimpleModule("StringParser"); + stringParser.addDeserializer(String.class, new CustomStringDeserializer()); + objectMapper.registerModule(stringParser); + iotaConfig = objectMapper.convertValue(props, iotaConfigClass); } return iotaConfig; diff --git a/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java b/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java index 360bc2ad07..c76db45a9f 100644 --- a/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java +++ b/src/main/java/com/iota/iri/conf/deserializers/CustomBoolDeserializer.java @@ -8,29 +8,31 @@ import java.io.IOException; +/** + * Deserialize boolean type. + */ public class CustomBoolDeserializer extends StdDeserializer{ + /** + * Default constructor + */ public CustomBoolDeserializer() { - this(Boolean.class); - } - - protected CustomBoolDeserializer(Class vc) { - super(vc); + super(Boolean.class); } @Override public Boolean deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException { - JsonToken t = parser.getCurrentToken(); - if (t == JsonToken.VALUE_TRUE) { + JsonToken jsonToken = parser.getCurrentToken(); + if (jsonToken == JsonToken.VALUE_TRUE) { return true; } - if (t == JsonToken.VALUE_FALSE) { + if (jsonToken == JsonToken.VALUE_FALSE) { return false; } - if (t == JsonToken.VALUE_NULL) { + if (jsonToken == JsonToken.VALUE_NULL) { return parseNull(ctxt); } - if (t == JsonToken.VALUE_STRING) { + if (jsonToken == JsonToken.VALUE_STRING) { String text = parser.getText().trim(); if (StringUtils.isEmpty(text)) { return parseNull(ctxt); diff --git a/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java b/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java new file mode 100644 index 0000000000..18103692df --- /dev/null +++ b/src/main/java/com/iota/iri/conf/deserializers/CustomStringDeserializer.java @@ -0,0 +1,26 @@ +package com.iota.iri.conf.deserializers; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; + +import java.io.IOException; + +/** + * Deserialize string and trims all leading and trailing whitespaces from string. + */ +public class CustomStringDeserializer extends StdDeserializer { + + /** + * Default constructor + */ + public CustomStringDeserializer() { + super(String.class); + } + + @Override + public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + return jsonParser.getValueAsString().trim(); + } +} diff --git a/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java b/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java new file mode 100644 index 0000000000..ff705a6de8 --- /dev/null +++ b/src/test/java/com/iota/iri/conf/ConfigFactoryTest.java @@ -0,0 +1,170 @@ +package com.iota.iri.conf; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +/** + * Tests for the {@link ConfigFactory} + */ +public class ConfigFactoryTest { + @Rule + public TemporaryFolder folder = new TemporaryFolder(); + + /** + * Creates and validates a Testnet {@link IotaConfig}. + */ + @Test + public void createIotaConfigTestnet() { + IotaConfig iotaConfig = ConfigFactory.createIotaConfig(true); + assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig); + assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet()); + } + + /** + * Creates and validates a Mainnet {@link IotaConfig}. + */ + @Test + public void createIotaConfigMainnet() { + IotaConfig iotaConfig = ConfigFactory.createIotaConfig(false); + assertTrue("Expected iotaConfig as instance of MainnetConfig.", iotaConfig instanceof MainnetConfig); + assertFalse("Expected iotaConfig as Mainnet.", iotaConfig.isTestnet()); + } + + /** + * Creates and validates a Testnet {@link IotaConfig} with TESTNET=true in config file and + * testnet: false as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithTestnetTrueAndFalse() throws IOException { + // lets assume in our configFile is TESTNET=true + File configFile = createTestnetConfigFile("true"); + + // but the parameter is set to testnet=false + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, false); + assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig); + assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet()); + } + + /** + * Creates and validates a Testnet {@link IotaConfig} with TESTNET=true in config file and + * testnet: true as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithTestnetTrueAndTrue() throws IOException { + // lets assume in our configFile is TESTNET=true + File configFile = createTestnetConfigFile("true"); + + // but the parameter is set to testnet=true + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true); + assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig); + assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet()); + } + + /** + * Creates and validates a Testnet {@link IotaConfig} with TESTNET=false in config file and + * testnet: true as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithTestnetFalseAndTrue() throws IOException { + // lets assume in our configFile is TESTNET=false + File configFile = createTestnetConfigFile("false"); + + // but the parameter is set to testnet=true + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true); + assertTrue("Expected iotaConfig as instance of TestnetConfig.", iotaConfig instanceof TestnetConfig); + assertTrue("Expected iotaConfig as Testnet.", iotaConfig.isTestnet()); + } + + /** + * Creates and validates a Mainnet {@link IotaConfig} with TESTNET=false in config file and + * testnet: false as method parameter for {@link ConfigFactory#createFromFile(File, boolean)}. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithTestnetFalseAndFalse() throws IOException { + // lets assume in our configFile is TESTNET=false + File configFile = createTestnetConfigFile("false"); + + // but the parameter is set to testnet=true + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, false); + assertTrue("Expected iotaConfig as instance of MainnetConfig.", iotaConfig instanceof MainnetConfig); + assertFalse("Expected iotaConfig as Mainnet.", iotaConfig.isTestnet()); + } + + /** + * Test if leading and trailing spaces are trimmed from string in properties file. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithTrailingSpaces() throws IOException { + File configFile = createTestnetConfigFile("true"); + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true); + String expected = "NPCRMHDOMU9QHFFBKFCWFHFJNNQDRNDOGVPEVDVGWKHFUFEXLWJBHXDJFKQGYFRDZBQIFDSJMUCCQVICI"; + assertEquals("Expected that leading and trailing spaces were trimmed.", expected, iotaConfig.getCoordinator()); + } + + /** + * Test if trailing spaces are correctly trimmed from integer. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithInteger() throws IOException { + File configFile = createTestnetConfigFile("true"); + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true); + assertEquals("Expected that trailing spaces are trimmed.", 2, iotaConfig.getMilestoneStartIndex()); + } + + /** + * Test if trailing spaces are correctly trimmed from boolean. + * @throws IOException when config file not found. + */ + @Test + public void createFromFileTestnetWithBoolean() throws IOException { + File configFile = createTestnetConfigFile("true"); + IotaConfig iotaConfig = ConfigFactory.createFromFile(configFile, true); + assertTrue("Expected that ZMQ is enabled.", iotaConfig.isZmqEnabled()); + } + + /** + * Try to create an {@link IotaConfig} from a not existing configFile. + * @throws IOException when config file not found. + */ + @Test(expected = FileNotFoundException.class) + public void createFromFileTestnetWithFileNotFound() throws IOException { + File configFile = new File("doesNotExist.ini"); + ConfigFactory.createFromFile(configFile, false); + } + + private File createTestnetConfigFile(String testnet) throws IOException { + Properties properties = new Properties(); + properties.setProperty("TESTNET", testnet); + properties.setProperty("ZMQ_ENABLED", " TRUE "); + properties.setProperty("MWM", "9"); + properties.setProperty("SNAPSHOT_FILE", "conf/snapshot.txt"); + properties.setProperty("COORDINATOR", " NPCRMHDOMU9QHFFBKFCWFHFJNNQDRNDOGVPEVDVGWKHFUFEXLWJBHXDJFKQGYFRDZBQIFDSJMUCCQVICI "); + properties.setProperty("MILESTONE_START_INDEX", "2 "); + properties.setProperty("KEYS_IN_MILESTONE", "10"); + properties.setProperty("MAX_DEPTH", "1000"); + + File configFile = folder.newFile("myCustomIotaConfig.ini"); + FileOutputStream fileOutputStream = new FileOutputStream(configFile); + properties.store(fileOutputStream, "Test config file created by Unit test!"); + fileOutputStream.close(); + + return configFile; + } +} \ No newline at end of file