Skip to content

Commit

Permalink
Add tests for log passing in config
Browse files Browse the repository at this point in the history
  • Loading branch information
spacecowboy committed Jan 5, 2017
1 parent 5aa85d1 commit d20b93d
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 107 deletions.
Expand Up @@ -34,7 +34,6 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;

Expand Down Expand Up @@ -70,13 +69,17 @@ public class Config implements DiagnosticsProvider, Configuration
private final ConfigurationMigrator migrator;
private final Optional<File> configFile;
private final List<ConfigurationValidator> validators = new ArrayList<>();


private ConfigValues settingsFunction;

// Messages to this log get replayed into a real logger once logging has been instantiated.
private Log log;

/**
* @return a configuration with embedded defaults
*/
public static Config empty()
{
return embeddedDefaults( Optional.empty() );
}

/**
* @return a configuration with embedded defaults
*/
Expand Down Expand Up @@ -137,15 +140,28 @@ public static Config embeddedDefaults( Optional<File> configFile, Map<String,Str
}, additionalValidators, Optional.empty() );
}

public Config( Optional<File> configFile,
private Config( Optional<File> configFile,
Map<String,String> overriddenSettings,
Consumer<Map<String,String>> settingsPostProcessor,
Collection<ConfigurationValidator> additionalValidators,
Optional<Log> log )
{
this( configFile, overriddenSettings, settingsPostProcessor, additionalValidators, log,
LoadableConfig.allConfigClasses() );
}

/**
* Only package-local to support tests of this class. Other uses should use public factory methods.
*/
Config( Optional<File> configFile,
Map<String,String> overriddenSettings,
Consumer<Map<String,String>> settingsPostProcessor,
Collection<ConfigurationValidator> additionalValidators,
Optional<Log> log,
List<LoadableConfig> settingsClasses )
{
this.log = log.orElse( new BufferingLog() );
this.configFile = configFile;
List<LoadableConfig> settingsClasses = LoadableConfig.allConfigClasses();

configOptions = settingsClasses.stream()
.map( LoadableConfig::getConfigOptions )
Expand Down Expand Up @@ -202,17 +218,7 @@ public Config withDefaults( Map<String,String> additionalDefaults )
@Override
public <T> T get( Setting<T> setting )
{
return setting.apply( settingsFunction );
}

/**
* Unlike the public {@link Setting} instances, the function passed in here has access to
* the raw setting data, meaning it can provide functionality that cross multiple settings
* and other more advanced use cases.
*/
public <T> T view( Function<ConfigValues,T> projection )
{
return projection.apply( settingsFunction );
return setting.apply( params::get );
}

/**
Expand Down Expand Up @@ -253,7 +259,6 @@ public Set<String> getConfiguredSettingKeys()
return new HashSet<>( params.keySet() );
}


/**
* @param key to lookup in the config
* @return the value or none if it doesn't exist in the config
Expand Down Expand Up @@ -344,7 +349,6 @@ private synchronized void replaceSettings( Map<String,String> newSettings )
}
params.clear();
params.putAll( validSettings );
settingsFunction = new ConfigValues( params );
}

private static Map<String,String> initSettings( @Nonnull Optional<File> configFile,
Expand Down
Expand Up @@ -21,23 +21,24 @@

import org.junit.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;

import org.neo4j.graphdb.config.Configuration;
import org.neo4j.configuration.LoadableConfig;
import org.neo4j.graphdb.config.InvalidSettingException;
import org.neo4j.graphdb.config.Setting;
import org.neo4j.logging.Log;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.neo4j.helpers.collection.MapUtil.stringMap;
import static org.neo4j.kernel.configuration.Settings.BOOLEAN;
import static org.neo4j.kernel.configuration.Settings.INTEGER;
import static org.neo4j.kernel.configuration.Settings.NO_DEFAULT;
import static org.neo4j.kernel.configuration.Settings.STRING;
import static org.neo4j.kernel.configuration.Settings.setting;

Expand All @@ -64,18 +65,30 @@ public void setValueWithOldSetting( String value, Map<String, String> rawConfigu
public static Setting<String> newer = setting( "newer", STRING, "" );
}

public static class MySettingsWithDefaults
public static class MySettingsWithDefaults implements LoadableConfig
{
public static Setting<String> hello = setting( "hello", STRING, "Hello, World!" );
public static final Setting<String> hello = setting( "hello", STRING, "Hello, World!" );

public static Setting<Boolean> boolSetting = setting( "bool_setting", BOOLEAN, Settings.TRUE );
public static final Setting<Boolean> boolSetting = setting( "bool_setting", BOOLEAN, Settings.TRUE );

}

private MySettingsWithDefaults mySettingsWithDefaults = new MySettingsWithDefaults();

static Config Config( LoadableConfig loadableConfig )
{
return Config( Collections.emptyMap(), loadableConfig );
}

static Config Config( Map<String,String> params, LoadableConfig loadableConfig ) {
return new Config( Optional.empty(), params, s -> {}, Collections.emptyList(), Optional.empty(),
Collections.singletonList( loadableConfig ) );
}

@Test
public void shouldApplyDefaults()
{
Config config = new Config( new HashMap<>(), MySettingsWithDefaults.class );
Config config = Config( mySettingsWithDefaults );

assertThat( config.get( MySettingsWithDefaults.hello ), is( "Hello, World!" ) );
}
Expand All @@ -84,7 +97,7 @@ public void shouldApplyDefaults()
public void shouldApplyMigrations()
{
// When
Config config = new Config( stringMap( "old", "hello!" ), MyMigratingSettings.class );
Config config = Config( stringMap( "old", "hello!" ), mySettingsWithDefaults );

// Then
assertThat( config.get( MyMigratingSettings.newer ), is( "hello!" ) );
Expand All @@ -93,127 +106,98 @@ public void shouldApplyMigrations()
@Test(expected = InvalidSettingException.class)
public void shouldNotAllowSettingInvalidValues()
{
new Config( stringMap( MySettingsWithDefaults.boolSetting.name(), "asd" ), MySettingsWithDefaults.class );
Config( stringMap( MySettingsWithDefaults.boolSetting.name(), "asd" ), mySettingsWithDefaults );
fail( "Expected validation to fail." );
}

@Test
public void shouldBeAbleToAugmentConfig() throws Exception
{
// Given
Config config = new Config( stringMap( "newer", "old", "non-overlapping", "huzzah" ) );
Config config = Config( mySettingsWithDefaults );

// When
config.augment( stringMap( "newer", "new", "unrelated", "hello" ) );
config.augment( stringMap( MySettingsWithDefaults.boolSetting.name(), Settings.FALSE ) );
config.augment( stringMap( MySettingsWithDefaults.hello.name(), "Bye" ) );

// Then
assertThat( config.get( setting( "newer", STRING, "" ) ), equalTo( "new" ) );
assertThat( config.get( setting( "non-overlapping", STRING, "" ) ), equalTo( "huzzah" ) );
assertThat( config.get( setting( "unrelated", STRING, "" ) ), equalTo( "hello" ) );
assertThat( config.get( MySettingsWithDefaults.boolSetting ), equalTo( false ) );
assertThat( config.get( MySettingsWithDefaults.hello ), equalTo( "Bye" ) );
}

@Test
public void shouldProvideViewOfGroups() throws Throwable
public void shouldPassOnLogInWith() throws Exception
{
// Given
Config config = new Config( stringMap(
"my.users.0.user.name", "Bob",
"my.users.0.user.age", "81",
"my.users.1.user.name", "Greta",
"my.users.1.user.age", "82" ) );

Setting<String> name = setting( "user.name", STRING, NO_DEFAULT );
Setting<Integer> age = setting( "user.age", INTEGER, NO_DEFAULT );
Log log = mock(Log.class);
Config first = Config.embeddedDefaults( stringMap( "first.jibberish", "bah" ) );

// When
List<Configuration> views = config.view( ConfigGroups.groups( "my.users" ) );
first.setLogger( log );
Config second = first.with( stringMap( "second.jibberish", "baah" ) );
second.with( stringMap( "third.jibberish", "baah" ) );

// Then
assertThat( views.size(), equalTo( 2 ) );

Configuration bob = views.get( 0 );
assertThat( bob.get( name ), equalTo( "Bob" ) );
assertThat( bob.get( age ), equalTo( 81 ) );

Configuration greta = views.get( 1 );
assertThat( greta.get( name ), equalTo( "Greta" ) );
assertThat( greta.get( age ), equalTo( 82 ) );

// however given the full name, the config could still be accessed outside the group
Setting<String> name0 = setting( "my.users.0.user.name", STRING, NO_DEFAULT );
assertThat( config.get( name0 ), equalTo( "Bob" ) );

verify( log ).warn( "Unknown config option: %s", "first.jibberish" );
verify( log ).warn( "Unknown config option: %s", "second.jibberish" );
verify( log ).warn( "Unknown config option: %s", "third.jibberish" );
verifyNoMoreInteractions( log );
}

@Test
public void shouldFindNoGroupViewWhenGroupNameIsMissing() throws Throwable
public void shouldPassOnBufferedLogInWith() throws Exception
{
// Given
Config config = new Config( stringMap(
"0.user.name", "Bob",
"0.user.age", "81",
"1.user.name", "Greta",
"1.user.age", "82" ) );

Setting<String> name = setting( "user.name", STRING, NO_DEFAULT );
Setting<Integer> age = setting( "user.age", INTEGER, NO_DEFAULT );
Log log = mock(Log.class);
Config first = Config.embeddedDefaults( stringMap( "first.jibberish", "bah" ) );

// When
List<Configuration> emptyStrViews = config.view( ConfigGroups.groups( "" ) );
List<Configuration> numViews = config.view( ConfigGroups.groups( "0" ) );
Config second = first.with( stringMap( "second.jibberish", "baah" ) );
Config third = second.with( stringMap( "third.jibberish", "baah" ) );
third.setLogger( log );

// Then
assertThat( emptyStrViews.size(), equalTo( 0 ) );
assertThat( numViews.size(), equalTo( 0 ) );
assertThat( config.get( setting( "0.user.name", STRING, NO_DEFAULT ) ), equalTo( "Bob" ) );
verify( log ).warn( "Unknown config option: %s", "first.jibberish" );
verify( log ).warn( "Unknown config option: %s", "second.jibberish" );
verify( log ).warn( "Unknown config option: %s", "third.jibberish" );
verifyNoMoreInteractions( log );
}

@Test
public void shouldFindNoGroupViewWhenGroupNameIsWrong() throws Throwable
public void shouldPassOnLogInWithDefaults() throws Exception
{
// Given
Config config = new Config( stringMap(
"my.users.0.name", "Bob",
"my.users.0.age", "81",
"my.users.1.name", "Greta",
"my.users.1.age", "82" ) );
Log log = mock(Log.class);
Config first = Config.embeddedDefaults( stringMap( "first.jibberish", "bah" ) );

// When
List<Configuration> views = config.view( ConfigGroups.groups( "my" ) );
first.setLogger( log );
Config second = first.withDefaults( stringMap( "second.jibberish", "baah" ) );
second.withDefaults( stringMap( "third.jibberish", "baah" ) );

// Then
assertThat( views.size(), equalTo( 0 ) );
verify( log ).warn( "Unknown config option: %s", "first.jibberish" );
verify( log ).warn( "Unknown config option: %s", "second.jibberish" );
verify( log ).warn( "Unknown config option: %s", "third.jibberish" );
verifyNoMoreInteractions( log );
}

@Test
public void shouldOnlyReadInsideGroupWhileAccessingSettingsInAGroup() throws Throwable
public void shouldPassOnBufferedLogInWithDefaults() throws Exception
{
// Given
Config config = new Config( stringMap(
"name", "lemon",
"my.users.0.user.name", "Bob",
"my.users.0.user.age", "81",
"my.users.1.user.name", "Greta",
"my.users.1.user.age", "82" ) );

Setting<String> name = setting( "name", STRING, "No name given to this poor user" );
Setting<Integer> age = setting( "age", INTEGER, NO_DEFAULT );
Log log = mock(Log.class);
Config first = Config.embeddedDefaults( stringMap( "first.jibberish", "bah" ) );

// When
List<Configuration> views = config.view( ConfigGroups.groups( "my.users" ) );
Config second = first.withDefaults( stringMap( "second.jibberish", "baah" ) );
Config third = second.withDefaults( stringMap( "third.jibberish", "baah" ) );
third.setLogger( log );

// Then
assertThat( views.size(), equalTo( 2 ) );

Configuration bob = views.get( 0 );
assertThat( bob.get( name ), equalTo( "No name given to this poor user" ) );
assertNull( bob.get( age ) );

Configuration greta = views.get( 1 );
assertThat( greta.get( name ), equalTo( "No name given to this poor user" ) );
assertNull( greta.get( age ) );

assertThat( config.get( name ), equalTo( "lemon" ) );
assertNull( config.get( age ) );
verify( log ).warn( "Unknown config option: %s", "first.jibberish" );
verify( log ).warn( "Unknown config option: %s", "second.jibberish" );
verify( log ).warn( "Unknown config option: %s", "third.jibberish" );
verifyNoMoreInteractions( log );
}
}
Expand Up @@ -83,7 +83,7 @@ public static DbRepresentation of( GraphDatabaseService db, boolean includeIndex

public static DbRepresentation of( File storeDir )
{
return of( storeDir, true, Config.empty() );
return of( storeDir, true, Config.embeddedDefaults() );
}

public static DbRepresentation of( File storeDir, Config config )
Expand Down

0 comments on commit d20b93d

Please sign in to comment.