/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 gobblin.util;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import org.jasypt.util.text.BasicTextEncryptor;
import org.testng.Assert;
import org.testng.annotations.Test;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import com.typesafe.config.ConfigValueFactory;
import gobblin.configuration.ConfigurationKeys;
import gobblin.configuration.State;
public class ConfigUtilsTest {
@Test
public void testPropertiesToConfig() {
Properties properties = new Properties();
properties.setProperty("k1.kk1", "v1");
properties.setProperty("k1.kk2", "v2");
properties.setProperty("k2.kk", "v3");
properties.setProperty("k3", "v4");
properties.setProperty("k3.kk1", "v5");
properties.setProperty("k3.kk1.kkk1", "v6");
Config conf = ConfigUtils.propertiesToConfig(properties);
Assert.assertEquals(conf.getString("k1.kk1"), "v1");
Assert.assertEquals(conf.getString("k1.kk2"), "v2");
Assert.assertEquals(conf.getString("k2.kk"), "v3");
Assert.assertEquals(conf.getString(ConfigUtils.sanitizeFullPrefixKey("k3")), "v4");
Assert.assertEquals(conf.getString(ConfigUtils.sanitizeFullPrefixKey("k3.kk1")), "v5");
Assert.assertEquals(conf.getString("k3.kk1.kkk1"), "v6");
}
@Test
public void testPropertiesToConfigWithPrefix() {
Properties properties = new Properties();
properties.setProperty("k1.kk1", "v1");
properties.setProperty("k1.kk2", "v2");
properties.setProperty("k2.kk", "v3");
Config conf = ConfigUtils.propertiesToConfig(properties, Optional.of("k1"));
Assert.assertEquals(conf.getString("k1.kk1"), "v1");
Assert.assertEquals(conf.getString("k1.kk2"), "v2");
Assert.assertFalse(conf.hasPath("k2.kk"), "Should not contain key k2.kk");
}
@Test
public void testHasNonEmptyPath() throws Exception {
Assert.assertTrue(ConfigUtils.hasNonEmptyPath(ConfigFactory.parseMap(ImmutableMap.of("key1", "value1")), "key1"));
Assert.assertFalse(ConfigUtils.hasNonEmptyPath(ConfigFactory.parseMap(ImmutableMap.of("key2", "value1")), "key1"));
Assert.assertFalse(ConfigUtils.hasNonEmptyPath(ConfigFactory.parseMap(ImmutableMap.of("key1", "")), "key1"));
}
@Test
public void testGetStringList() throws Exception {
// values as comma separated strings
Assert.assertEquals(ConfigUtils.getStringList(ConfigFactory.parseMap(ImmutableMap.of("a.b", "1,2,3")), "a.b"),
ImmutableList.of("1", "2", "3"));
// values as quoted comma separated strings
Assert.assertEquals(ConfigUtils.getStringList(ConfigFactory.parseMap(ImmutableMap.of("a.b", "\"1\",\"2\",\"3\"")), "a.b"),
ImmutableList.of("1", "2", "3"));
// values as quoted comma separated strings (Multiple values)
Assert.assertEquals(ConfigUtils.getStringList(ConfigFactory.parseMap(ImmutableMap.of("a.b", "\"1\",\"2,3\"")), "a.b"),
ImmutableList.of("1", "2,3"));
// values as Type safe list
Assert.assertEquals(ConfigUtils.getStringList(
ConfigFactory.empty().withValue("a.b",
ConfigValueFactory.fromIterable(ImmutableList.of("1", "2","3"))), "a.b"),
ImmutableList.of("1", "2", "3"));
// values as quoted Type safe list
Assert.assertEquals(ConfigUtils.getStringList(
ConfigFactory.empty().withValue("a.b",
ConfigValueFactory.fromIterable(ImmutableList.of("\"1\"", "\"2\"","\"3\""))), "a.b"),
ImmutableList.of("1", "2", "3"));
// values as quoted Type safe list (Multiple values)
Assert.assertEquals(ConfigUtils.getStringList(
ConfigFactory.empty().withValue("a.b",
ConfigValueFactory.fromIterable(ImmutableList.of("\"1\"", "\"2,3\""))), "a.b"),
ImmutableList.of("1", "2,3"));
// Empty list if path does not exist
Assert.assertEquals(ConfigUtils.getStringList(ConfigFactory.parseMap(ImmutableMap.of("key1", "value1,value2")), "key2"), ImmutableList.of());
// Empty list of path is null
Map<String,String> configMap = Maps.newHashMap();
configMap.put("key1", null);
Assert.assertEquals(ConfigUtils.getStringList(ConfigFactory.parseMap(configMap), "key1"), ImmutableList.of());
}
@Test
public void testConfigToProperties() {
Config cfg = ConfigFactory.parseMap(ImmutableMap.<String, Object>builder()
.put("key1", 1)
.put("key2", "sTring")
.put("key3", true)
.build());
Properties props = ConfigUtils.configToProperties(cfg);
Assert.assertEquals(props.getProperty("key1"), "1");
Assert.assertEquals(props.getProperty("key2"), "sTring");
Assert.assertEquals(props.getProperty("key3"), "true");
}
@Test
public void testPropertiesToConfigToState() {
Properties properties = new Properties();
properties.setProperty("k1.kk1", "v1");
properties.setProperty("k1.kk2", "v2");
properties.setProperty("k2.kk", "v3");
properties.setProperty("k3", "v4");
properties.setProperty("k3.kk1", "v5");
properties.setProperty("k3.kk1.kkk1", "v6");
Config conf = ConfigUtils.propertiesToConfig(properties);
State state = ConfigUtils.configToState(conf);
Assert.assertEquals(state.getProp("k1.kk1"), "v1");
Assert.assertEquals(state.getProp("k1.kk2"), "v2");
Assert.assertEquals(state.getProp("k2.kk"), "v3");
Assert.assertEquals(state.getProp("k3"), "v4");
Assert.assertEquals(state.getProp("k3.kk1"), "v5");
Assert.assertEquals(state.getProp("k3.kk1.kkk1"), "v6");
}
@Test
public void testConfigToPropertiesWithPrefix() {
Config cfg = ConfigFactory.parseMap(ImmutableMap.<String, Object>builder()
.put("a.key1", 1)
.put("b.key2", "sTring")
.put("a.key3", true)
.build());
Properties props = ConfigUtils.configToProperties(cfg, "a.");
Assert.assertEquals(props.getProperty("a.key1"), "1");
Assert.assertNull(props.getProperty("b.key2"));
Assert.assertEquals(props.getProperty("a.key3"), "true");
}
/**
* Test that you can go from properties to Config and back without changing.
* Specifically tests prefixed paths and numeric key-parts.
*/
@Test
public void testPropertiesToConfigAndBack() {
Properties props = new Properties();
props.setProperty("writer.staging.dir", "foobar");
props.setProperty("writer.staging.dir.0", "foobar-0");
Config config = ConfigUtils.propertiesToConfig(props);
Properties configProps = ConfigUtils.configToProperties(config);
Assert.assertEquals(configProps, props);
}
@Test
public void testFindFullPrefixKeys() {
Properties props = new Properties();
props.setProperty("a.b", "123");
props.setProperty("a.b1", "123");
props.setProperty("b", "123");
props.setProperty("b_a", "123");
props.setProperty("a.b.c", "123");
props.setProperty("a.b.c.d.e", "123");
props.setProperty("b.a", "123");
Set<String> fullPrefixKeys =
ConfigUtils.findFullPrefixKeys(props, Optional.<String>absent());
Assert.assertEquals(fullPrefixKeys, new HashSet<>(Arrays.asList("a.b", "a.b.c", "b")));
fullPrefixKeys =
ConfigUtils.findFullPrefixKeys(props, Optional.of("a."));
Assert.assertEquals(fullPrefixKeys, new HashSet<>(Arrays.asList("a.b", "a.b.c")));
fullPrefixKeys =
ConfigUtils.findFullPrefixKeys(props, Optional.of("c."));
Assert.assertTrue(fullPrefixKeys.isEmpty());
props = new Properties();
props.setProperty("a.b", "123");
props.setProperty("a.b1", "123");
props.setProperty("b", "123");
props.setProperty("b_a", "123");
fullPrefixKeys =
ConfigUtils.findFullPrefixKeys(props, Optional.<String>absent());
Assert.assertTrue(fullPrefixKeys.isEmpty());
}
@Test
public void testConfigResolveEncrypted() throws IOException {
Map<String, String> vals = Maps.newHashMap();
vals.put("test.key1", "test_val1");
vals.put("test.key2", "test_val2");
State state = new State();
for (Map.Entry<String, String> entry : vals.entrySet()) {
state.setProp(entry.getKey(), entry.getValue());
}
String key = UUID.randomUUID().toString();
File keyFile = newKeyFile(key);
state.setProp(ConfigurationKeys.ENCRYPT_KEY_LOC, keyFile.getAbsolutePath());
Map<String, String> encryptedVals = Maps.newHashMap();
encryptedVals.put("my.nested.key1", "val1");
encryptedVals.put("my.nested.key2", "val2");
String encPrefix = "testenc";
for (Map.Entry<String, String> entry : encryptedVals.entrySet()) {
BasicTextEncryptor encryptor = new BasicTextEncryptor();
encryptor.setPassword(key);
String encrypted = "ENC(" + encryptor.encrypt(entry.getValue()) + ")";
state.setProp(encPrefix + "." + entry.getKey(), encrypted);
}
Config config = ConfigUtils.resolveEncrypted(ConfigUtils.propertiesToConfig(state.getProperties()), Optional.of(encPrefix));
Map<String, String> expected = ImmutableMap.<String, String>builder()
.putAll(vals)
.putAll(encryptedVals)
.build();
for (Map.Entry<String, String> entry : expected.entrySet()) {
String val = config.getString(entry.getKey());
Assert.assertEquals(val, entry.getValue());
}
keyFile.delete();
}
private File newKeyFile(String masterPwd) throws IOException {
File masterPwdFile = File.createTempFile("masterPassword", null);
masterPwdFile.deleteOnExit();
Files.write(masterPwd, masterPwdFile, Charset.defaultCharset());
return masterPwdFile;
}
}