package com.linkedin.databus.core.util;
/*
*
* Copyright 2013 LinkedIn Corp. 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.
*
*/
import static org.testng.AssertJUnit.assertEquals;
import java.beans.PropertyDescriptor;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class TestConfigManager
{
static
{
LogFactory.getFactory().setAttribute("org.apache.commons.logging.Log", Log4JLogger.class.getName());
//Logger.getRootLogger().setLevel(Level.TRACE);
Logger.getRootLogger().setLevel(Level.ERROR);
}
private DynamicConfigBuilder _configBuilder;
private MyConfigManager _configManager;
@BeforeMethod
public void setUp() throws Exception
{
_configBuilder = new DynamicConfigBuilder();
_configManager = new MyConfigManager(_configBuilder);
}
@AfterMethod
public void tearDown() throws Exception
{
}
@Test
public void testLoadConfig_HappyPath() throws Exception
{
Properties props = new Properties();
props.setProperty("com.linkedin.databus2.intSetting", "1");
props.setProperty("com.linkedin.databus2.nestedConfig.stringSetting", "Hello");
props.setProperty("com.linkedin.databus2.listSetting[0].stringSetting", "item0");
props.setProperty("com.linkedin.databus2.listSetting[1].stringSetting", "item1");
props.setProperty("com.linkedin.databus.intSetting", "2");
_configManager.loadConfig(props);
DynamicConfig dynConfig = _configManager.getReadOnlyConfig();
assertEquals("intSetting correct", 1, dynConfig.getIntSetting());
assertEquals("nestedConfig.stringSetting correct", "Hello",
dynConfig.getNestedConfig().getStringSetting());
assertEquals("listSetting size correct", 2, dynConfig.getListSetting().size());
assertEquals("listSetting[0].stringSetting", "item0",
dynConfig.getListSetting(0).getStringSetting());
assertEquals("listSetting[1].stringSetting", "item1",
dynConfig.getListSetting(1).getStringSetting());
_configManager.setSetting("com.linkedin.databus2.intSetting", 3);
_configManager.setSetting("com.linkedin.databus2.listSetting[2].stringSetting", "item2");
assertEquals("old intSetting correct", 1, dynConfig.getIntSetting());
assertEquals("listSetting size correct", 2, dynConfig.getListSetting().size());
DynamicConfig newDynConfig = _configManager.getReadOnlyConfig();
assertEquals("new intSetting correct", 3, newDynConfig.getIntSetting());
assertEquals("nestedConfig.stringSetting correct", "Hello",
newDynConfig.getNestedConfig().getStringSetting());
assertEquals("listSetting size correct", 3, newDynConfig.getListSetting().size());
assertEquals("listSetting[0].stringSetting", "item0",
newDynConfig.getListSetting(0).getStringSetting());
assertEquals("listSetting[1].stringSetting", "item1",
newDynConfig.getListSetting(1).getStringSetting());
assertEquals("listSetting[2].stringSetting", "item2",
newDynConfig.getListSetting(2).getStringSetting());
}
@Test(expectedExceptions=InvalidConfigException.class)
public void testInvalidSimpleProperty() throws InvalidConfigException
{
_configManager.setSetting("com.linkedin.databus2.inSetting", 3);
}
@Test(expectedExceptions=InvalidConfigException.class)
public void testInvalidNestedProperty1() throws InvalidConfigException
{
Properties props = new Properties();
props.setProperty("com.linkedin.databus2.nestedConfig.inSetting", "1");
_configManager.loadConfig(props);
}
@Test(expectedExceptions=InvalidConfigException.class)
public void testInvalidNestedProperty2() throws InvalidConfigException
{
Properties props = new Properties();
props.setProperty("com.linkedin.databus2.nestdConfig.stringSetting", "1");
_configManager.loadConfig(props);
}
@Test(expectedExceptions=InvalidConfigException.class)
public void testInvalidNestedProperty3() throws InvalidConfigException
{
Properties props = new Properties();
props.setProperty("com.linkedin.databus2.lstConfig[1].stringSetting", "1");
_configManager.loadConfig(props);
}
@Test(expectedExceptions=InvalidConfigException.class)
public void testInvalidNestedProperty4() throws InvalidConfigException
{
Properties props = new Properties();
props.setProperty("com.linkedin.databus2.listSetting[1].inSetting", "1");
_configManager.loadConfig(props);
}
@Test
public void testIgnoreSetting() throws InvalidConfigException
{
Properties props = new Properties();
props.setProperty("com.linkedin.databs2.listSetting[1].stringSetting", "1");
_configManager.loadConfig(props);
}
@Test
public void testLoadConfigFromJson_HappyPath() throws Exception
{
String json = "{\"intSetting\": 1,\"nestedConfig\":{\"stringSetting\":\"Hello\"},\"listSetting\":[{\"stringSetting\":\"item0\"},{\"stringSetting\":\"item1\"}]}";
StringReader jsonReader = new StringReader(json);
_configManager.loadConfigFromJson(jsonReader);
DynamicConfig dynConfig = _configManager.getReadOnlyConfig();
assertEquals("intSetting correct", 1, dynConfig.getIntSetting());
assertEquals("nestedConfig.stringSetting correct", "Hello",
dynConfig.getNestedConfig().getStringSetting());
assertEquals("listSetting size correct", 2, dynConfig.getListSetting().size());
assertEquals("listSetting[0].stringSetting", "item0",
dynConfig.getListSetting(0).getStringSetting());
assertEquals("listSetting[1].stringSetting", "item1",
dynConfig.getListSetting(1).getStringSetting());
}
@Test
public void testPaddedInt() throws Exception
{
ConvertUtilsBean convertUtils = new ConvertUtilsBean();
Integer intValue = (Integer)convertUtils.convert("456", int.class);
assertEquals("correct int value", 456, intValue.intValue());
BeanUtilsBean beanUtils = new BeanUtilsBean();
PropertyDescriptor propDesc = beanUtils.getPropertyUtils().getPropertyDescriptor(_configBuilder,
"intSetting");
assertEquals("correct setting type", int.class, propDesc.getPropertyType());
_configManager.setSetting("com.linkedin.databus2.intSetting", " 123 ");
DynamicConfig config = _configManager.getReadOnlyConfig();
assertEquals("correct int value", 123, config.getIntSetting());
}
@Test
public void testStringPropertyTrimming() throws Exception
{
DynamicConfig config =
_configManager.setSetting("com.linkedin.databus2.nestedConfig.stringSetting", " text to trim ");
assertEquals("trimmed value", "text to trim", config.getNestedConfig().getStringSetting());
}
public static class NestedDynamicConfig implements ConfigApplier<NestedDynamicConfig>
{
private final String _stringSetting;
public NestedDynamicConfig(String stringSetting)
{
_stringSetting = stringSetting;
}
public String getStringSetting()
{
return _stringSetting;
}
@Override
public void applyNewConfig(NestedDynamicConfig oldConfig)
{
// TODO Auto-generated method stub
}
@Override
public boolean equals(Object otherConfig)
{
if (null == otherConfig || !(otherConfig instanceof NestedDynamicConfig)) return false;
return equalsConfig((NestedDynamicConfig)otherConfig);
}
@Override
public boolean equalsConfig(NestedDynamicConfig otherConfig)
{
if (null == otherConfig) return false;
return getStringSetting().equals(otherConfig.getStringSetting());
}
@Override
public int hashCode()
{
return _stringSetting.hashCode();
}
}
public static class NestedDynamicConfigBuilder implements ConfigBuilder<NestedDynamicConfig>
{
private String _stringSetting;
public NestedDynamicConfigBuilder()
{
super();
_stringSetting = "default";
}
public String getStringSetting()
{
return _stringSetting;
}
public void setStringSetting(String stringSetting)
{
_stringSetting = stringSetting;
}
@Override
public NestedDynamicConfig build() throws InvalidConfigException
{
if (null == _stringSetting)
{
throw new InvalidConfigException("Null string setting");
}
else
{
return new NestedDynamicConfig(_stringSetting);
}
}
}
public static class DynamicConfig implements ConfigApplier<DynamicConfig>
{
private final int _intSetting;
private final NestedDynamicConfig _nestedBean;
private final ArrayList<NestedDynamicConfig> _listSetting;
public DynamicConfig(int intSetting, NestedDynamicConfig nestedBean,
ArrayList<NestedDynamicConfig> listSetting)
{
_intSetting = intSetting;
_nestedBean = nestedBean;
_listSetting = listSetting;
}
public int getIntSetting()
{
return _intSetting;
}
public NestedDynamicConfig getNestedConfig()
{
return _nestedBean;
}
public NestedDynamicConfig getListSetting(int i)
{
return _listSetting.get(i);
}
public List<NestedDynamicConfig> getListSetting()
{
return _listSetting;
}
@Override
public void applyNewConfig(DynamicConfig oldConfig)
{
if (null != getNestedConfig())
{
getNestedConfig().applyNewConfig(null != oldConfig ? oldConfig.getNestedConfig() : null);
}
// FIXME Auto-generated method stub
}
@Override
public boolean equals(Object otherConfig)
{
if (null == otherConfig || !(otherConfig instanceof DynamicConfig)) return false;
return equalsConfig((DynamicConfig)otherConfig);
}
@Override
public boolean equalsConfig(DynamicConfig otherConfig)
{
if (null == otherConfig) return false;
return (getIntSetting() == otherConfig.getIntSetting()) &&
(getListSetting().equals(otherConfig.getListSetting())) &&
((null == getNestedConfig() && null == otherConfig.getNestedConfig()) ||
(null != getNestedConfig() && getNestedConfig().equals(otherConfig.getNestedConfig()))) ;
}
@Override
public int hashCode()
{
return _intSetting ^ _listSetting.hashCode();
}
}
public static class DynamicConfigBuilder implements ConfigBuilder<DynamicConfig>
{
private int _intSetting;
private NestedDynamicConfigBuilder _nestedConfig;
private ArrayList<NestedDynamicConfigBuilder> _listSetting;
public DynamicConfigBuilder()
{
super();
_intSetting = 0;
_nestedConfig = new NestedDynamicConfigBuilder();
_listSetting = new ArrayList<NestedDynamicConfigBuilder>();
}
public int getIntSetting()
{
return _intSetting;
}
public void setIntSetting(int intSetting)
{
_intSetting = intSetting;
}
public NestedDynamicConfigBuilder getNestedConfig()
{
return _nestedConfig;
}
public DynamicConfigBuilder setNestedConfig(NestedDynamicConfigBuilder nestedBean)
{
_nestedConfig = nestedBean;
return this;
}
public NestedDynamicConfigBuilder getListSetting(int idx)
{
if (idx >= _listSetting.size())
{
setListSetting(idx, new NestedDynamicConfigBuilder());
}
return _listSetting.get(idx);
}
public void setListSetting(int idx, NestedDynamicConfigBuilder value)
{
if (idx < _listSetting.size())
{
_listSetting.set(idx, value);
}
else
{
for (int i = _listSetting.size(); i < idx; ++i) _listSetting.add(new NestedDynamicConfigBuilder());
_listSetting.add(value);
}
}
@Override
public DynamicConfig build() throws InvalidConfigException
{
if (_listSetting.size() >= 5) throw new InvalidConfigException("Big list");
if (_intSetting < 0) throw new InvalidConfigException("Negative int setting");
ArrayList<NestedDynamicConfig> beanList = new ArrayList<NestedDynamicConfig>(_listSetting.size());
for (NestedDynamicConfigBuilder builder: _listSetting) beanList.add(builder.build());
return new DynamicConfig(_intSetting, _nestedConfig.build(), beanList);
}
}
public static class MyConfigManager extends ConfigManager<DynamicConfig>
{
public MyConfigManager(DynamicConfigBuilder dynConfigBuilder) throws InvalidConfigException
{
super("com.linkedin.databus2.", dynConfigBuilder);
}
}
}