// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.api.ads.common.lib.conf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import com.google.api.ads.common.lib.conf.ConfigurationHelper.ConfigurationInfo;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.configuration.AbstractConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.SystemConfiguration;
import org.apache.commons.lang.SystemUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* Test for {@link ConfigurationHelper}.
*/
@RunWith(JUnit4.class)
public class ConfigurationHelperTest {
private ConfigurationHelper configurationHelper;
private Map<String, String> test1Properties;
private Map<String, String> test3Properties;
private String[] allPropertyKeys = {"a.b.c", "a.b.d", "e.f.g", "e.f.h", "i.j.k", "testProperty"};
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() {
AbstractConfiguration.setDefaultListDelimiter(',');
clearSystemProperties();
this.configurationHelper = new ConfigurationHelper();
this.test1Properties = new HashMap<String, String>() {{
this.put("a.b.c", "efgh");
this.put("a.b.d", "1234");
}};
this.test3Properties = new HashMap<String, String>() {{
this.put("a.b.c", "jklm");
this.put("e.f.h", "90123");
// The value in the file is "foo,bar" but AbstractConfiguration.getString(key) only returns
// the first item in a collection.
this.put("i.j.k", "foo");
}};
}
@Test
public void testUnsupportedConfigurationInfo() {
thrown.expect(IllegalArgumentException.class);
new ConfigurationInfo<Long>(1234L, false);
}
@Test
public void testSupportedConfigurationInfo() throws Exception {
new ConfigurationInfo<String>("1234", false);
new ConfigurationInfo<URL>(new URL("http://google.com"), false);
}
@Test
public void testNewConfigurationInfoList_optional() throws Exception {
List<ConfigurationInfo<URL>> configurationInfos =
ConfigurationHelper.newList(
Lists.newArrayList(new URL("http://google.com"), new URL("https://google.com")), true);
assertEquals(2, configurationInfos.size());
assertEquals(new URL("http://google.com"), configurationInfos.get(0).getLocation());
assertTrue(configurationInfos.get(0).isOptional());
assertEquals(new URL("https://google.com"), configurationInfos.get(1).getLocation());
assertTrue(configurationInfos.get(1).isOptional());
}
@Test
public void testNewConfigurationInfoList_required() {
List<ConfigurationInfo<String>> configurationInfos =
ConfigurationHelper.newList(Lists.newArrayList("1234", "5678"), false);
assertEquals(2, configurationInfos.size());
assertEquals("1234", configurationInfos.get(0).getLocation());
assertFalse(configurationInfos.get(0).isOptional());
assertEquals("5678", configurationInfos.get(1).getLocation());
assertFalse(configurationInfos.get(1).isOptional());
}
@Test
public void testNewConfigurationInfoList_null() throws Exception {
assertNull(ConfigurationHelper.newList(null, true));
}
@Test
public void testNewConfigurationInfoList_nullArguments() throws Exception {
thrown.expect(IllegalArgumentException.class);
ConfigurationHelper.newList(true, (Object[]) null);
}
@Test
public void testFromFile_stringExists() throws Exception {
Configuration configuration =
configurationHelper.fromFile(createPropertiesFile(test1Properties).toString());
assertPropertiesEquals(test1Properties, configuration);
}
@Test
public void testFromFile_stringDoesNotExist() throws Exception {
thrown.expect(ConfigurationLoadException.class);
configurationHelper.fromFile("/" + System.currentTimeMillis());
}
@Test
public void testFromFile_fileExists() throws Exception {
Configuration configuration =
configurationHelper.fromFile(createPropertiesFile(test1Properties));
assertPropertiesEquals(test1Properties, configuration);
}
@Test
public void testFromFile_urlExists() throws Exception {
Configuration configuration =
configurationHelper.fromFile(createPropertiesFile(test1Properties).toURI().toURL());
assertPropertiesEquals(test1Properties, configuration);
}
@Test
public void testFromFile_urlDoesNotExist() throws Exception {
thrown.expect(ConfigurationLoadException.class);
configurationHelper.fromFile(new URL("file:///" + System.currentTimeMillis()));
}
@Test
public void testFromFile_urlClasspathExists() throws Exception {
Configuration configuration =
configurationHelper.fromFile(ConfigurationHelperTest.class
.getResource("props/test1.properties"));
assertPropertiesEquals(test1Properties, configuration);
}
/**
* Asserts that reading list values from a properties file works properly when the default
* list delimiter is not modified.
*/
@Test
public void testFromFile_listValuesWithDefaultDelimiterUnchanged() throws Exception {
Configuration configuration = configurationHelper.fromFile(ConfigurationHelperTest.class
.getResource("props/test3.properties"));
assertPropertiesEquals(test3Properties, configuration);
String[] stringArray = configuration.getStringArray("i.j.k");
assertArrayEquals(new String[]{"foo", "bar"}, stringArray);
}
/**
* Asserts that reading list values from a properties file works properly when the default
* list delimiter is modified.
*/
@Test
public void testFromFile_listValuesWithDefaultDelimiterChanged() throws Exception {
AbstractConfiguration.setDefaultListDelimiter('|');
Configuration configuration = configurationHelper.fromFile(
ConfigurationHelperTest.class.getResource("props/test3.properties"));
assertPropertiesEquals(test3Properties, configuration);
String[] stringArray = configuration.getStringArray("i.j.k");
assertArrayEquals(new String[] {"foo", "bar"}, stringArray);
}
@Test
public void testFromSystem() throws Exception {
for (Map.Entry<String, String> entry : test3Properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
assertContains(test3Properties, configurationHelper.fromSystem());
}
@Test
public void testFromSystem_containsListValues() throws Exception {
AbstractConfiguration.setDefaultListDelimiter('|');
Map<String, String> properties = Maps.newHashMap();
properties.put("testProperty", "b,bee");
for (Entry<String, String> entry : properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
Splitter splitter = Splitter.on(',');
Configuration systemConfiguration = configurationHelper.fromSystem();
for (Entry<String, String> entry : properties.entrySet()) {
String[] actualValues = systemConfiguration.getStringArray(entry.getKey());
String[] expectedValues;
if ("line.separator".equals(entry.getKey())) {
expectedValues = new String[] {SystemUtils.LINE_SEPARATOR};
} else {
expectedValues = splitter.splitToList(entry.getValue()).toArray(new String[0]);
}
assertArrayEquals(String.format("Values for key %s do not match", entry.getKey()),
expectedValues, actualValues);
}
}
@Test
public void testCreateCombinedConfiguration_justSystem() throws Exception {
SystemConfiguration systemConfig = new SystemConfiguration();
systemConfig.setTrimmingDisabled(true);
assertContains(systemConfig,
configurationHelper.createCombinedConfiguration(null, null));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlOverride() throws Exception {
for (Map.Entry<String, String> entry : test1Properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(null,
Lists.<ConfigurationInfo<URL>>newArrayList(new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test3.properties"), true)));
assertEquals("efgh", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("testValue", configuration.getString("testProperty"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlNoOverride() throws Exception {
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(null,
Lists.<ConfigurationInfo<URL>>newArrayList(new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test3.properties"), true)));
assertEquals("jklm", configuration.getString("a.b.c"));
assertEquals("testValue", configuration.getString("testProperty"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_optionalUrlOverride() throws Exception {
for (Map.Entry<String, String> entry : test1Properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(null,
Lists.<ConfigurationInfo<URL>>newArrayList(new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test3.properties"), true)));
assertEquals("efgh", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("testValue", configuration.getString("testProperty"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_optionalUrlNotFound() throws Exception {
for (Map.Entry<String, String> entry : test1Properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(null,
Lists.<ConfigurationInfo<URL>>newArrayList(new ConfigurationInfo<URL>(
new URL("file:///does/not/exist" + System.currentTimeMillis()), true)));
assertEquals("efgh", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("testValue", configuration.getString("testProperty"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlNotFound() throws Exception {
for (Map.Entry<String, String> entry : test1Properties.entrySet()) {
System.setProperty(entry.getKey(), entry.getValue());
}
System.setProperty("testProperty", "testValue");
thrown.expect(ConfigurationLoadException.class);
configurationHelper.createCombinedConfiguration(null,
Lists.<ConfigurationInfo<URL>>newArrayList(new ConfigurationInfo<URL>(
new URL("file:///does/not/exist" + System.currentTimeMillis()), false)));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlOptionalPathOverride() throws Exception {
System.setProperty("e.f.h", "5678");
Configuration configuration = configurationHelper.createCombinedConfiguration(
Lists.<ConfigurationInfo<String>>newArrayList(
new ConfigurationInfo<String>(
createPropertiesFile(test3Properties).toString(), false)),
Lists.<ConfigurationInfo<URL>>newArrayList(
new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test1.properties"), true)));
assertEquals("jklm", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("5678", configuration.getString("e.f.h"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlrequiredPathNoOverride() throws Exception {
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(
Lists.<ConfigurationInfo<String>>newArrayList(
new ConfigurationInfo<String>(
createPropertiesFile(test1Properties).toString(), false)),
Lists.<ConfigurationInfo<URL>>newArrayList(
new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test2.properties"), false)));
assertEquals("testValue", configuration.getString("testProperty"));
assertEquals("efgh", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("xyz", configuration.getString("e.f.g"));
assertEquals("5678", configuration.getString("e.f.h"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredUrlrequiredPathOptionalNotExist()
throws Exception {
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(
Lists.<ConfigurationInfo<String>>newArrayList(
new ConfigurationInfo<String>("test4.properties", true)),
Lists.<ConfigurationInfo<URL>>newArrayList(
new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test2.properties"), false)));
assertEquals("testValue", configuration.getString("testProperty"));
assertEquals("xyz", configuration.getString("e.f.g"));
assertEquals("5678", configuration.getString("e.f.h"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredPathsOverride()
throws Exception {
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(
Lists.<ConfigurationInfo<String>>newArrayList(
new ConfigurationInfo<String>(
createPropertiesFile(test3Properties).toString(), false),
new ConfigurationInfo<String>(
createPropertiesFile(test1Properties).toString(), false)), null);
assertEquals("testValue", configuration.getString("testProperty"));
assertEquals("jklm", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("90123", configuration.getString("e.f.h"));
}
@Test
@SuppressWarnings("unchecked")
public void testCreateCombinedConfiguration_requiredPathsOverrideUrl()
throws Exception {
System.setProperty("testProperty", "testValue");
Configuration configuration = configurationHelper.createCombinedConfiguration(
Lists.<ConfigurationInfo<String>>newArrayList(
new ConfigurationInfo<String>(
createPropertiesFile(test3Properties).toString(), false),
new ConfigurationInfo<String>(
createPropertiesFile(test1Properties).toString(), false)),
Lists.<ConfigurationInfo<URL>>newArrayList(
new ConfigurationInfo<URL>(
ConfigurationHelperTest.class.getResource("props/test2.properties"), false)));
assertEquals("testValue", configuration.getString("testProperty"));
assertEquals("jklm", configuration.getString("a.b.c"));
assertEquals("1234", configuration.getString("a.b.d"));
assertEquals("90123", configuration.getString("e.f.h"));
assertEquals("xyz", configuration.getString("e.f.g"));
}
/**
* Creates a properties file from the map.
*/
private static File createPropertiesFile(Map<String, String> properties) throws IOException {
File file = File.createTempFile("javalibtest", "properties");
FileWriter fileWriter = new FileWriter(file);
for (Map.Entry<String, String> entry : properties.entrySet()) {
fileWriter.write(String.format("%s=%s\n", entry.getKey(), entry.getValue()));
}
fileWriter.flush();
fileWriter.close();
return file;
}
/**
* Asserts that the configuration matches the properties and that they have
* the same number of entries. If the value for a key contains the list delimiter
* then this method will only confirm that the <em>first</em> value in the delimited
* list matches the key's value in <code>properties</code>.
*/
private static void assertPropertiesEquals(Map<String, String> properties,
Configuration configuration) {
int count = 0;
@SuppressWarnings("rawtypes")
Iterator keys = configuration.getKeys();
while (keys.hasNext()) {
String key = (String) keys.next();
assertPropertyEquals(key, properties.get(key), configuration.getString(key));
count++;
}
assertEquals("Configuration does not have the same number of properties",
properties.size(), count);
}
/**
* Asserts that the actual configuration contains the expected ones.
*/
private static void assertContains(Configuration expected, Configuration actual) {
@SuppressWarnings("rawtypes")
Iterator keys = expected.getKeys();
while (keys.hasNext()) {
String key = (String) keys.next();
assertPropertyEquals(key, expected.getString(key), actual.getString(key));
}
}
/**
* Asserts that the configuration contains the properties.
*/
private static void assertContains(Map<String, String> properties, Configuration configuration) {
for (Map.Entry<String, String> entry : properties.entrySet()) {
String key = entry.getKey();
assertPropertyEquals(key, properties.get(key), configuration.getString(key));
}
}
private static void assertPropertyEquals(String key, Object expectedValue,
Object actualValue) {
assertEquals(String.format("Unexpected value for key: %s", key),
expectedValue, actualValue);
}
/**
* Clears the tested properties from the System.
*/
private void clearSystemProperties() {
for (String key : allPropertyKeys) {
System.clearProperty(key);
}
}
}