From 0136ea2884e93c380bb6d715f4cd80688eb0785b Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Tue, 11 Nov 2014 19:24:18 +0100 Subject: [PATCH] Polish and test BitsquareEnvironment - Introduce a test-time dependency on spring-test module for access to MockPropertySource and friends. - Add BitsquareEnvironmentTests and test that property source precedence works as expected, i.e. that properties supplied on the command line have highest precedence, overriding those picked up via environment variables, system properties, the bitsquare.properties file or any of the other available property sources. --- build.gradle | 1 + .../bitsquare/app/BitsquareEnvironment.java | 77 +++++++++---------- .../bitsquare/app/gui/BitsquareAppMain.java | 2 +- .../app/BitsquareEnvironmentTests.java | 34 +++++++- 4 files changed, 70 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index d7126cc9e4..afe21cc5e8 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,7 @@ dependencies { compile 'org.jetbrains:annotations:13.0' compile 'eu.hansolo.enzo:Enzo:0.1.5' testCompile 'junit:junit:4.11' + testCompile 'org.springframework:spring-test:4.1.1.RELEASE' } task packageNative(type: Exec, dependsOn: shadowJar) { diff --git a/src/main/java/io/bitsquare/app/BitsquareEnvironment.java b/src/main/java/io/bitsquare/app/BitsquareEnvironment.java index 47e56d0a73..daa5f15680 100644 --- a/src/main/java/io/bitsquare/app/BitsquareEnvironment.java +++ b/src/main/java/io/bitsquare/app/BitsquareEnvironment.java @@ -23,10 +23,6 @@ import io.bitsquare.btc.WalletFacade; import io.bitsquare.gui.ViewCB; import io.bitsquare.persistence.Persistence; -import com.google.common.base.Preconditions; - -import java.io.IOException; - import java.nio.file.Paths; import java.util.Properties; @@ -42,51 +38,59 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePropertySource; -public class BitsquareEnvironment extends StandardEnvironment { +import static com.google.common.base.Preconditions.checkNotNull; - public static final String APP_NAME_KEY = "app.name"; - public static final String DEFAULT_APP_NAME = "Bitsquare"; +public class BitsquareEnvironment extends StandardEnvironment { public static final String USER_DATA_DIR_KEY = "user.data.dir"; public static final String DEFAULT_USER_DATA_DIR = defaultUserDataDir(); + public static final String APP_NAME_KEY = "app.name"; + public static final String DEFAULT_APP_NAME = "Bitsquare"; + public static final String APP_DATA_DIR_KEY = "app.data.dir"; public static final String DEFAULT_APP_DATA_DIR = appDataDir(DEFAULT_USER_DATA_DIR, DEFAULT_APP_NAME); - private static final String BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME = "bitsquareDefaultProperties"; - private static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties"; - private static final String BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME = "bitsquareFilesystemProperties"; - private static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties"; + static final String BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME = "bitsquareDefaultProperties"; + static final String BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME = "bitsquareClasspathProperties"; + static final String BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME = "bitsquareFilesystemProperties"; + static final String BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME = "bitsquareCommandLineProperties"; private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private final String appName; + private final String appDataDir; + public BitsquareEnvironment(OptionSet options) { - Preconditions.checkArgument(options != null, "Options must not be null"); - - PropertySource commandLineProperties = - new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, options); - - String appName = commandLineProperties.containsProperty(APP_NAME_KEY) ? - (String) commandLineProperties.getProperty(APP_NAME_KEY) : - DEFAULT_APP_NAME; + this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(options))); + } + BitsquareEnvironment(PropertySource commandLineProperties) { String userDataDir = commandLineProperties.containsProperty(USER_DATA_DIR_KEY) ? (String) commandLineProperties.getProperty(USER_DATA_DIR_KEY) : DEFAULT_USER_DATA_DIR; - String appDataDir = commandLineProperties.containsProperty(APP_DATA_DIR_KEY) ? + this.appName = commandLineProperties.containsProperty(APP_NAME_KEY) ? + (String) commandLineProperties.getProperty(APP_NAME_KEY) : + DEFAULT_APP_NAME; + + this.appDataDir = commandLineProperties.containsProperty(APP_DATA_DIR_KEY) ? (String) commandLineProperties.getProperty(APP_DATA_DIR_KEY) : appDataDir(userDataDir, appName); MutablePropertySources propertySources = this.getPropertySources(); - propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, defaultProperties(appDataDir, appName)); - propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, classpathProperties()); - propertySources.addBefore(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, filesystemProperties(appDataDir)); - propertySources.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, commandLineProperties); + propertySources.addFirst(commandLineProperties); + try { + propertySources.addLast(filesystemProperties()); + propertySources.addLast(classpathProperties()); + propertySources.addLast(defaultProperties()); + } catch (Exception ex) { + throw new BitsquareException(ex); + } } - private PropertySource defaultProperties(String appDataDir, String appName) { + PropertySource defaultProperties() throws Exception { return new PropertiesPropertySource(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME, new Properties() {{ setProperty(APP_DATA_DIR_KEY, appDataDir); setProperty(APP_NAME_KEY, appName); @@ -104,28 +108,19 @@ public class BitsquareEnvironment extends StandardEnvironment { }}); } - private PropertySource classpathProperties() { - try { - Resource resource = resourceLoader.getResource("classpath:bitsquare.properties"); - return new ResourcePropertySource(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME, resource); - } catch (IOException ex) { - throw new BitsquareException(ex); - } + PropertySource classpathProperties() throws Exception { + Resource resource = resourceLoader.getResource("classpath:bitsquare.properties"); + return new ResourcePropertySource(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME, resource); } - private PropertySource filesystemProperties(String appDir) { - String location = String.format("file:%s/bitsquare.conf", appDir); + PropertySource filesystemProperties() throws Exception { + String location = String.format("file:%s/bitsquare.conf", appDataDir); Resource resource = resourceLoader.getResource(location); - if (!resource.exists()) { + if (!resource.exists()) return new PropertySource.StubPropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME); - } - try { - return new ResourcePropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME, resource); - } catch (IOException ex) { - throw new BitsquareException(ex); - } + return new ResourcePropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME, resource); } diff --git a/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java b/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java index dffb8d87eb..da72226152 100644 --- a/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java +++ b/src/main/java/io/bitsquare/app/gui/BitsquareAppMain.java @@ -39,8 +39,8 @@ public class BitsquareAppMain extends BitsquareExecutable { @Override protected void customizeOptionParsing(OptionParser parser) { - parser.accepts(APP_NAME_KEY, "Application name").withRequiredArg().defaultsTo(DEFAULT_APP_NAME); parser.accepts(USER_DATA_DIR_KEY, "User data directory").withRequiredArg().defaultsTo(DEFAULT_USER_DATA_DIR); + parser.accepts(APP_NAME_KEY, "Application name").withRequiredArg().defaultsTo(DEFAULT_APP_NAME); parser.accepts(APP_DATA_DIR_KEY, "Application data directory").withRequiredArg().defaultsTo(DEFAULT_APP_DATA_DIR); parser.accepts(NAME_KEY, "Network name").withRequiredArg(); parser.accepts(PORT_KEY, "Port to listen on").withRequiredArg().defaultsTo(String.valueOf(Node.DEFAULT_PORT)); diff --git a/src/test/java/io/bitsquare/app/BitsquareEnvironmentTests.java b/src/test/java/io/bitsquare/app/BitsquareEnvironmentTests.java index fa54068a39..e9c94fbf4c 100644 --- a/src/test/java/io/bitsquare/app/BitsquareEnvironmentTests.java +++ b/src/test/java/io/bitsquare/app/BitsquareEnvironmentTests.java @@ -19,13 +19,43 @@ package io.bitsquare.app; import org.junit.Test; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.mock.env.MockPropertySource; + +import static io.bitsquare.app.BitsquareEnvironment.*; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.*; +import static org.springframework.core.env.PropertySource.named; +import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; +import static org.springframework.core.env.StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME; public class BitsquareEnvironmentTests { @Test - public void test() { - assertThat(1, equalTo(1)); + public void testPropertySourcePrecedence() { + PropertySource commandlineProps = new MockPropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME) + .withProperty("key.x", "x.commandline"); + + PropertySource filesystemProps = new MockPropertySource(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME) + .withProperty("key.x", "x.env") + .withProperty("key.y", "y.env"); + + ConfigurableEnvironment env = new BitsquareEnvironment(commandlineProps) { + @Override PropertySource filesystemProperties() { return filesystemProps; } + }; + MutablePropertySources propertySources = env.getPropertySources(); + + assertThat(propertySources.precedenceOf(named(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME)), equalTo(0)); + assertThat(propertySources.precedenceOf(named(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), equalTo(1)); + assertThat(propertySources.precedenceOf(named(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)), equalTo(2)); + assertThat(propertySources.precedenceOf(named(BITSQUARE_FILESYSTEM_PROPERTY_SOURCE_NAME)), equalTo(3)); + assertThat(propertySources.precedenceOf(named(BITSQUARE_CLASSPATH_PROPERTY_SOURCE_NAME)), equalTo(4)); + assertThat(propertySources.precedenceOf(named(BITSQUARE_DEFAULT_PROPERTY_SOURCE_NAME)), equalTo(5)); + assertThat(propertySources.size(), equalTo(6)); + + assertThat(env.getProperty("key.x"), equalTo("x.commandline")); // commandline value wins due to precedence + assertThat(env.getProperty("key.y"), equalTo("y.env")); // env value wins because it's the only one available } } \ No newline at end of file