Skip to content

Commit

Permalink
Merge pull request #118 from cfg4j/integration-tests
Browse files Browse the repository at this point in the history
Integration tests
  • Loading branch information
norbertpotocki committed Aug 30, 2015
2 parents 4be456c + b7d8c8b commit 4a2e321
Show file tree
Hide file tree
Showing 8 changed files with 382 additions and 4 deletions.
Expand Up @@ -64,8 +64,8 @@ public MockResponse dispatch(RecordedRequest request) throws InterruptedExceptio
return new MockResponse()
.setResponseCode(200)
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("[{\"CreateIndex\":1,\"ModifyIndex\":1,\"LockIndex\":0,\"Key\":\"us-west-1/featureA/toggle\",\"Flags\":0,\"Value\":\"ZGlzYWJsZWQ=\"},"
+ "{\"CreateIndex\":2,\"ModifyIndex\":2,\"LockIndex\":0,\"Key\":\"us-west-2/featureA/toggle\",\"Flags\":0,\"Value\":\""
.setBody("[{\"CreateIndex\":1,\"ModifyIndex\":1,\"LockIndex\":0,\"Key\":\"us-west-1/featureA.toggle\",\"Flags\":0,\"Value\":\"ZGlzYWJsZWQ=\"},"
+ "{\"CreateIndex\":2,\"ModifyIndex\":2,\"LockIndex\":0,\"Key\":\"us-west-2/featureA.toggle\",\"Flags\":0,\"Value\":\""
+ (usWest2Toggle ? enabledBase64 : disabledBase64) + "\"}]");
}
return new MockResponse().setResponseCode(404);
Expand Down
@@ -0,0 +1,93 @@
/*
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl)
*
* 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 org.cfg4j.source.consul;

import static org.assertj.core.api.Assertions.assertThat;

import com.squareup.okhttp.mockwebserver.Dispatcher;
import com.squareup.okhttp.mockwebserver.MockResponse;
import com.squareup.okhttp.mockwebserver.MockWebServer;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
import org.cfg4j.provider.ConfigurationProvider;
import org.cfg4j.provider.ConfigurationProviderBuilder;
import org.cfg4j.source.ConfigurationSource;
import org.cfg4j.source.context.environment.ImmutableEnvironment;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

public class SimpleConfigurationProviderIntegrationTest {

private static final String PING_RESPONSE = "\n" +
"{\"Config\":{\"Bootstrap\":true,\"BootstrapExpect\":0,\"Server\":true,\"Datacenter\":\"dc1\",\"DataDir\":\"/tmp/consul\",\"DNSRecursor\":\"\",\"DNSRecursors\":[],\"DNSConfig\":{\"NodeTTL\":0,\"ServiceTTL\":null,\"AllowStale\":false,\"EnableTruncate\":false,\"MaxStale\":5000000000,\"OnlyPassing\":false},\"Domain\":\"consul.\",\"LogLevel\":\"INFO\",\"NodeName\":\"receivehead-lm\",\"ClientAddr\":\"127.0.0.1\",\"BindAddr\":\"0.0.0.0\",\"AdvertiseAddr\":\"192.168.0.4\",\"Ports\":{\"DNS\":8600,\"HTTP\":8500,\"HTTPS\":-1,\"RPC\":8400,\"SerfLan\":8301,\"SerfWan\":8302,\"Server\":8300},\"Addresses\":{\"DNS\":\"\",\"HTTP\":\"\",\"HTTPS\":\"\",\"RPC\":\"\"},\"LeaveOnTerm\":false,\"SkipLeaveOnInt\":false,\"StatsiteAddr\":\"\",\"StatsdAddr\":\"\",\"Protocol\":2,\"EnableDebug\":false,\"VerifyIncoming\":false,\"VerifyOutgoing\":false,\"CAFile\":\"\",\"CertFile\":\"\",\"KeyFile\":\"\",\"ServerName\":\"\",\"StartJoin\":[],\"StartJoinWan\":[],\"RetryJoin\":[],\"RetryMaxAttempts\":0,\"RetryIntervalRaw\":\"\",\"RetryJoinWan\":[],\"RetryMaxAttemptsWan\":0,\"RetryIntervalWanRaw\":\"\",\"UiDir\":\"\",\"PidFile\":\"\",\"EnableSyslog\":false,\"SyslogFacility\":\"LOCAL0\",\"RejoinAfterLeave\":false,\"CheckUpdateInterval\":300000000000,\"ACLDatacenter\":\"\",\"ACLTTL\":30000000000,\"ACLTTLRaw\":\"\",\"ACLDefaultPolicy\":\"allow\",\"ACLDownPolicy\":\"extend-cache\",\"Watches\":null,\"DisableRemoteExec\":false,\"DisableUpdateCheck\":false,\"DisableAnonymousSignature\":false,\"HTTPAPIResponseHeaders\":null,\"AtlasInfrastructure\":\"\",\"AtlasJoin\":false,\"Revision\":\"0c7ca91c74587d0a378831f63e189ac6bf7bab3f+CHANGES\",\"Version\":\"0.5.0\",\"VersionPrerelease\":\"\",\"UnixSockets\":{\"Usr\":\"\",\"Grp\":\"\",\"Perms\":\"\"}},\"Member\":{\"Name\":\"receivehead-lm\",\"Addr\":\"192.168.0.4\",\"Port\":8301,\"Tags\":{\"bootstrap\":\"1\",\"build\":\"0.5.0:0c7ca91c\",\"dc\":\"dc1\",\"port\":\"8300\",\"role\":\"consul\",\"vsn\":\"2\",\"vsn_max\":\"2\",\"vsn_min\":\"1\"},\"Status\":1,\"ProtocolMin\":1,\"ProtocolMax\":2,\"ProtocolCur\":2,\"DelegateMin\":2,\"DelegateMax\":4,\"DelegateCur\":4}}";

private class ModifiableDispatcher extends Dispatcher {

@Override
public MockResponse dispatch(RecordedRequest request) throws InterruptedException {

switch (request.getPath()) {
case "/v1/agent/self":
return new MockResponse().setResponseCode(200).setBody(PING_RESPONSE);
case "/v1/kv/?recurse=true":
return new MockResponse()
.setResponseCode(200)
.addHeader("Content-Type", "application/json; charset=utf-8")
.setBody("[{\"CreateIndex\":1,\"ModifyIndex\":1,\"LockIndex\":0,\"Key\":\"us-west-1/featureA.toggle\",\"Flags\":0,\"Value\":\"ZGlzYWJsZWQ=\"}]");
}
return new MockResponse().setResponseCode(404);
}
}

private MockWebServer server;
private ModifiableDispatcher dispatcher;

@Before
public void setUp() throws Exception {
dispatcher = new ModifiableDispatcher();
runMockServer();
}

@After
public void tearDown() throws Exception {
server.shutdown();
}

@Test
public void shouldReadConfigsFromConsulConfigurationSource() throws Exception {
ConfigurationSource source = new ConsulConfigurationSourceBuilder()
.withHost(server.getHostName())
.withPort(server.getPort())
.build();

ConfigurationProvider provider = new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withEnvironment(new ImmutableEnvironment("us-west-1"))
.build();

assertThat(provider.getProperty("featureA.toggle", String.class)).isEqualTo("disabled");
}


private void runMockServer() throws IOException {
server = new MockWebServer();
server.setDispatcher(dispatcher);
server.start(0);
}
}
Expand Up @@ -18,6 +18,7 @@
import static java.util.Objects.requireNonNull;

import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import org.cfg4j.source.ConfigurationSource;
import org.cfg4j.source.context.environment.DefaultEnvironment;
import org.cfg4j.source.context.environment.Environment;
Expand Down Expand Up @@ -99,7 +100,21 @@ public ConfigurationProviderBuilder withEnvironment(Environment environment) {

/**
* Enable metrics emission for {@link ConfigurationProvider}s built by this builder. All metrics will be registered
* with {@code metricRegistry} and prefixed by {@code prefix}.
* with {@code metricRegistry} and prefixed by {@code prefix}. Provider built by this builder will emit the following metrics:
* <p>Provider-level metrics:</p>
* <ul>
* <li>allConfigurationAsProperties</li>
* <li>getProperty</li>
* <li>getPropertyGeneric</li>
* <li>bind</li>
* </ul>
* <p>Source-level metrics</p>
* <ul>
* <li>source.getConfiguration</li>
* <li>source.init</li>
* <li>source.reload</li>
* </ul>
* Each of those metrics is of {@link Timer} type (i.e. includes execution time percentiles, execution count, etc.)
*
* @param metricRegistry metric registry for registering metrics
* @param prefix prefix for metric names
Expand Down Expand Up @@ -127,6 +142,8 @@ public ConfigurationProvider build() {
configurationSource = new MeteredConfigurationSource(metricRegistry.get(), prefix, configurationSource);
}

configurationSource.init();

reloadStrategy.register(configurationSource);

SimpleConfigurationProvider configurationProvider = new SimpleConfigurationProvider(configurationSource, environment);
Expand Down
@@ -0,0 +1,66 @@
/*
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl)
*
* 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 org.cfg4j.source.inmemory;

import static java.util.Objects.requireNonNull;

import org.cfg4j.source.ConfigurationSource;
import org.cfg4j.source.context.environment.Environment;

import java.util.Properties;

/**
* Simple in-memory {@link ConfigurationSource}. A reference to the properties object is being kept allowing this source to sync up
* on {@link #reload()} call.
*/
public class InMemoryConfigurationSource implements ConfigurationSource {

private Properties properties;
private final Properties sourceProperties;

/**
* Create in-memory configuration source with given {@code properties}. A reference to the properties object is being kept allowing
* this source to sync up on {@link #reload()} call.
*
* @param properties properties to seed source.
*/
public InMemoryConfigurationSource(Properties properties) {
this.sourceProperties = requireNonNull(properties);
this.properties = (Properties) properties.clone();
}

@Override
public Properties getConfiguration(Environment environment) {
return (Properties) properties.clone();
}

@Override
public void init() {
// NOP
}

@Override
public void reload() {
properties = (Properties) sourceProperties.clone();
}

@Override
public String toString() {
return "InMemoryConfigurationSource{" +
"properties=" + properties +
'}';
}
}
Expand Up @@ -31,7 +31,7 @@


@RunWith(MockitoJUnitRunner.class)
public class SimpleConfigurationProviderIntegrationTest {
public class SimpleConfigurationProviderWithClasspathIntegrationTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();
Expand Down
@@ -0,0 +1,69 @@
/*
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl)
*
* 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 org.cfg4j.provider;

import static org.assertj.core.api.Assertions.assertThat;

import com.codahale.metrics.MetricRegistry;
import org.cfg4j.source.ConfigurationSource;
import org.cfg4j.source.inmemory.InMemoryConfigurationSource;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Properties;


@RunWith(MockitoJUnitRunner.class)
public class SimpleConfigurationProviderWithMeteredSourceIntegrationTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

private MetricRegistry metricRegistry = new MetricRegistry();

@Test
public void shouldEmitMetrics() throws Exception {
ConfigurationProvider provider = getConfigurationProvider();

provider.getProperty("some.setting", Boolean.class);

assertThat(metricRegistry.getTimers()).containsOnlyKeys(
"testService.allConfigurationAsProperties",
"testService.getProperty",
"testService.getPropertyGeneric",
"testService.bind",
"testService.source.getConfiguration",
"testService.source.init",
"testService.source.reload"
);
}

private ConfigurationProvider getConfigurationProvider() {
Properties properties = new Properties();
properties.put("some.setting", "true");

ConfigurationSource source = new InMemoryConfigurationSource(properties);

return new ConfigurationProviderBuilder()
.withConfigurationSource(source)
.withMetrics(metricRegistry, "testService.")
.build();
}
}
@@ -0,0 +1,71 @@
/*
* Copyright 2015 Norbert Potocki (norbert.potocki@nort.pl)
*
* 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 org.cfg4j.source.inmemory;

import static org.assertj.core.api.Assertions.assertThat;

import org.assertj.core.data.MapEntry;
import org.cfg4j.source.context.environment.DefaultEnvironment;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Properties;


@RunWith(MockitoJUnitRunner.class)
public class InMemoryConfigurationSourceTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

private InMemoryConfigurationSource source;
private Properties properties;

@Before
public void setUp() throws Exception {
properties = new Properties();
properties.put("sample.setting", "value");

source = new InMemoryConfigurationSource(properties);
source.init();
}

@Test
public void shouldReturnSourceProperties() throws Exception {
assertThat(source.getConfiguration(new DefaultEnvironment())).isEqualTo(properties);
}

@Test
public void shouldNotReactToChangesToSourceProperties() throws Exception {
properties.put("other.setting", "hello");

assertThat(source.getConfiguration(new DefaultEnvironment())).doesNotContain(MapEntry.entry("other.setting", "hello"));
}

@Test
public void reloadShouldReactToChangesToSourceProperties() throws Exception {
properties.put("other.setting", "hello");
source.reload();

assertThat(source.getConfiguration(new DefaultEnvironment())).contains(MapEntry.entry("other.setting", "hello"));
}

}

0 comments on commit 4a2e321

Please sign in to comment.