summaryrefslogtreecommitdiffstats
path: root/config-proxy/src/test
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /config-proxy/src/test
Publish
Diffstat (limited to 'config-proxy/src/test')
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CacheTest.java77
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CheckDelayedResponsesTest.java45
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ClientUpdaterTest.java113
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServerTest.java253
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyStatisticsTest.java46
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java49
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponseTest.java83
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponsesTest.java32
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/Helper.java58
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheConfigClientTest.java29
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java65
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockConnection.java86
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockRpcServer.java23
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ModeTest.java61
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java184
-rw-r--r--config-proxy/src/test/java/com/yahoo/vespa/config/proxy/UpstreamConfigSubscriberTest.java173
16 files changed, 1377 insertions, 0 deletions
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CacheTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CacheTest.java
new file mode 100644
index 00000000000..e4ddee9da97
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CacheTest.java
@@ -0,0 +1,77 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.config.ConfigCacheKey;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.config.ConfigPayload;
+import com.yahoo.vespa.config.RawConfig;
+import com.yahoo.vespa.config.protocol.Payload;
+import org.junit.Before;
+
+import java.util.ArrayList;
+import java.util.Optional;
+
+/**
+ * Helper class for memory and disk cache unit tests
+ *
+ * @author musum
+ * @since 5.1.10
+ */
+public class CacheTest {
+ String defName = "foo";
+ String configId = "id";
+ String namespace = "bar";
+ String defMd5 = "a";
+
+ long generation = 1L;
+ String defName2 = "baz-quux";
+ String namespace2 = "search.config";
+ // Test with a config id with / in it
+ String configId2 = "clients/gateways/gateway/component/com.yahoo.feedhandler.VespaFeedHandlerRemoveLocation";
+ String defMd52 = "a2";
+ String differentDefMd5 = "09ef";
+ String configMd5 = "b";
+ ConfigKey<?> configKey = new ConfigKey<>(defName, configId, namespace);
+ ConfigKey<?> configKey2 = new ConfigKey<>(defName2, configId2, namespace2);
+ ConfigCacheKey cacheKey;
+ ConfigCacheKey cacheKeyDifferentMd5;
+ ConfigCacheKey cacheKey2;
+ RawConfig config;
+ RawConfig config2;
+ RawConfig configDifferentMd5;
+ RawConfig unknown;
+ Payload payload;
+ Payload payload2;
+ Payload payloadDifferentMd5;
+
+ public CacheTest() {
+ }
+
+ @Before
+ public void setup() {
+ ArrayList<String> defContent = new ArrayList<>();
+ defContent.add("bar string");
+
+ Slime slime = new Slime();
+ slime.setString("bar \"value\"");
+ payload = Payload.from(new ConfigPayload(slime));
+
+ slime = new Slime();
+ slime.setString("bar \"baz\"");
+ payload2 = Payload.from(new ConfigPayload(slime));
+
+ slime = new Slime();
+ slime.setString("bar \"value2\"");
+ payloadDifferentMd5 = Payload.from(new ConfigPayload(slime));
+
+ config = new RawConfig(configKey, defMd5, payload, configMd5, generation, defContent, Optional.empty());
+ config2 = new RawConfig(configKey2, defMd52, payload2, configMd5, generation, defContent, Optional.empty());
+ unknown = new RawConfig(new ConfigKey<>("unknown", configId, namespace), defMd5, payload, configMd5, generation, defContent, Optional.empty());
+ configDifferentMd5 = new RawConfig(configKey, differentDefMd5, payloadDifferentMd5, configMd5, generation, defContent, Optional.empty());
+
+ cacheKey = new ConfigCacheKey(configKey, config.getDefMd5());
+ cacheKey2 = new ConfigCacheKey(configKey2, config2.getDefMd5());
+ cacheKeyDifferentMd5 = new ConfigCacheKey(configKey, differentDefMd5);
+ }
+} \ No newline at end of file
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CheckDelayedResponsesTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CheckDelayedResponsesTest.java
new file mode 100644
index 00000000000..f96f584f257
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/CheckDelayedResponsesTest.java
@@ -0,0 +1,45 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author musum
+ */
+public class CheckDelayedResponsesTest {
+
+ private final MapBackedConfigSource source = new MapBackedConfigSource(UpstreamConfigSubscriberTest.MockClientUpdater.create());
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setup() {
+ source.clear();
+ source.put(ProxyServerTest.fooConfig.getKey(), ProxyServerTest.createConfigWithNextConfigGeneration(ProxyServerTest.fooConfig, 0));
+ }
+
+ @Test
+ public void basic() {
+ ConfigTester tester = new ConfigTester();
+ ConfigProxyStatistics statistics = new ConfigProxyStatistics();
+ DelayedResponses delayedResponses = new DelayedResponses(statistics);
+ final MockRpcServer mockRpcServer = new MockRpcServer();
+ final MemoryCache memoryCache = new MemoryCache();
+ memoryCache.put(ProxyServerTest.fooConfig);
+ final CheckDelayedResponses checkDelayedResponses = new CheckDelayedResponses(delayedResponses, memoryCache, mockRpcServer);
+ delayedResponses.add(new DelayedResponse(tester.createRequest(ProxyServerTest.fooConfig, 0)));
+ delayedResponses.add(new DelayedResponse(tester.createRequest(ProxyServerTest.fooConfig, 1200000))); // should not be returned yet
+ delayedResponses.add(new DelayedResponse(tester.createRequest(ProxyServerTest.errorConfig, 0))); // will not give a config when resolving
+ checkDelayedResponses.checkDelayedResponses();
+
+ assertThat(mockRpcServer.responses, is(1L));
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ClientUpdaterTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ClientUpdaterTest.java
new file mode 100644
index 00000000000..7aca5990a12
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ClientUpdaterTest.java
@@ -0,0 +1,113 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.vespa.config.ConfigCacheKey;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.config.RawConfig;
+import com.yahoo.vespa.config.protocol.JRTConfigRequestFactory;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequestV3;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import static junit.framework.TestCase.assertNull;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author musum
+ */
+public class ClientUpdaterTest {
+ private MockRpcServer rpcServer;
+ private ConfigProxyStatistics statistics;
+ private DelayedResponses delayedResponses;
+ private Mode mode;
+ private MemoryCache memoryCache;
+ private ClientUpdater clientUpdater;
+
+ @Rule
+ public TemporaryFolder tempFolder = new TemporaryFolder();
+
+
+ @Before
+ public void setup() {
+ rpcServer = new MockRpcServer();
+ statistics = new ConfigProxyStatistics();
+ delayedResponses = new DelayedResponses(statistics);
+ mode = new Mode();
+ memoryCache = new MemoryCache();
+ clientUpdater = new ClientUpdater(CacheManager.createTestCacheManager(memoryCache),
+ rpcServer,
+ statistics,
+ delayedResponses,
+ mode);
+ }
+
+ @Test
+ public void basic() {
+ assertThat(rpcServer.responses, is(0L));
+
+ final RawConfig fooConfig = ProxyServerTest.fooConfig;
+ clientUpdater.updateSubscribers(fooConfig);
+
+ // No delayed response, so not returned
+ assertResponseAndCache(rpcServer, memoryCache, fooConfig, 0, 1);
+
+ delayedResponses.add(new DelayedResponse(JRTServerConfigRequestV3.createFromRequest(JRTConfigRequestFactory.createFromRaw(fooConfig, -10L).getRequest())));
+ clientUpdater.updateSubscribers(fooConfig);
+ assertResponseAndCache(rpcServer, memoryCache, fooConfig, 1, 1);
+
+ // Will not find bar config in delayed responses
+ RawConfig barConfig = new RawConfig(new ConfigKey<>("bar", "id", "namespace"), fooConfig.getDefMd5());
+ clientUpdater.updateSubscribers(barConfig);
+ assertResponseAndCache(rpcServer, memoryCache, barConfig, 1, 2);
+
+
+ mode = new Mode(Mode.ModeName.MEMORYCACHE.name());
+ // Nothing should be returned, so still 1 response
+ assertResponseAndCache(rpcServer, memoryCache, fooConfig, 1, 2);
+ assertThat(statistics.errors(), is(0L));
+ }
+
+ @Test
+ public void memoryCacheMode() {
+ final RawConfig fooConfig = ProxyServerTest.fooConfig;
+ mode = new Mode(Mode.ModeName.MEMORYCACHE.name());
+ clientUpdater = new ClientUpdater(CacheManager.createTestCacheManager(memoryCache),
+ rpcServer,
+ statistics,
+ delayedResponses,
+ mode);
+ memoryCache.clear();
+ assertThat(rpcServer.responses, is(0L));
+
+ clientUpdater.updateSubscribers(fooConfig);
+ assertNull(memoryCache.get(new ConfigCacheKey(fooConfig.getKey(), fooConfig.getDefMd5())));
+ assertThat(memoryCache.size(), is(0));
+ assertThat(rpcServer.responses, is(0L));
+ }
+
+ @Test
+ public void errorResponse() {
+ assertThat(rpcServer.responses, is(0L));
+
+ final RawConfig errorConfig = ProxyServerTest.errorConfig;
+
+ clientUpdater.updateSubscribers(errorConfig);
+ // Error response, so not put into cache
+ assertNull(memoryCache.get(new ConfigCacheKey(errorConfig.getKey(), errorConfig.getDefMd5())));
+ assertThat(rpcServer.responses, is(0L));
+ assertThat(statistics.errors(), is(1L));
+ }
+
+ private static void assertResponseAndCache(MockRpcServer rpcServer,
+ MemoryCache memoryCache,
+ RawConfig expectedConfig,
+ long expectedResponses,
+ int cacheSize) {
+ assertThat(rpcServer.responses, is(expectedResponses));
+ assertThat(memoryCache.size(), is(cacheSize));
+ assertThat(memoryCache.get(new ConfigCacheKey(expectedConfig.getKey(), expectedConfig.getDefMd5())), is(expectedConfig));
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServerTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServerTest.java
new file mode 100644
index 00000000000..fbef9cf1d17
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyRpcServerTest.java
@@ -0,0 +1,253 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.config.subscription.ConfigSourceSet;
+import com.yahoo.jrt.Request;
+import com.yahoo.jrt.Spec;
+import com.yahoo.jrt.StringValue;
+import com.yahoo.vespa.config.RawConfig;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class ConfigProxyRpcServerTest {
+ private static final String hostname = "localhost";
+ private static final int port = 12345;
+ private static final String address = "tcp/" + hostname + ":" + port;
+ ProxyServer proxyServer;
+ private ConfigProxyRpcServer rpcServer;
+
+ @Before
+ public void setup() {
+ proxyServer = ProxyServer.createTestServer(new ConfigSourceSet(address));
+ rpcServer = new ConfigProxyRpcServer(proxyServer, null);
+ }
+
+ @After
+ public void teardown() {
+ rpcServer.shutdown();
+ }
+
+ @Test
+ public void basic() {
+ ConfigSourceSet configSources = new ConfigSourceSet();
+ ProxyServer proxy = ProxyServer.createTestServer(configSources);
+ Spec spec = new Spec("localhost", 12345);
+ ConfigProxyRpcServer server = new ConfigProxyRpcServer(proxy, spec);
+ assertThat(server.getSpec(), is(spec));
+ }
+
+ /**
+ * Tests ping RPC command
+ */
+ @Test
+ public void testRpcMethodPing() {
+ Request req = new Request("ping");
+ rpcServer.ping(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asInt32(), is(0));
+ }
+
+ /**
+ * Tests listCachedConfig RPC command
+ */
+ @Test
+ public void testRpcMethodListCachedConfig() {
+ Request req = new Request("listCachedConfig");
+ rpcServer.listCachedConfig(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(ret.length, is(0));
+
+ final RawConfig config = ProxyServerTest.fooConfig;
+ proxyServer.getCacheManager().putInCache(config);
+ req = new Request("listCachedConfig");
+ rpcServer.listCachedConfig(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(1));
+ assertThat(ret[0], is(config.getNamespace() + "." + config.getName() + "," +
+ config.getConfigId() + "," +
+ config.getGeneration() + "," +
+ config.getConfigMd5()));
+ }
+
+ /**
+ * Tests listCachedConfig RPC command
+ */
+ @Test
+ public void testRpcMethodListCachedConfigFull() {
+ Request req = new Request("listCachedConfigFull");
+ rpcServer.listCachedConfigFull(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(0));
+
+ final RawConfig config = ProxyServerTest.fooConfig;
+ proxyServer.getCacheManager().putInCache(config);
+ req = new Request("listCachedConfigFull");
+ rpcServer.listCachedConfigFull(req);
+ assertFalse(req.errorMessage(), req.isError());
+ ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(1));
+ assertThat(ret[0], is(config.getNamespace() + "." + config.getName() + "," +
+ config.getConfigId() + "," +
+ config.getGeneration() + "," +
+ config.getConfigMd5() + "," +
+ config.getPayload().getData()));
+ }
+
+ /**
+ * Tests printStatistics RPC command
+ */
+ @Test
+ public void testRpcMethodListSourceConnections() {
+ Request req = new Request("listSourceConnections");
+ rpcServer.listSourceConnections(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ final String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(2));
+ assertThat(ret[0], is("Current source: " + address));
+ assertThat(ret[1], is("All sources:\n" + address + "\n"));
+ }
+
+ /**
+ * Tests printStatistics RPC command
+ */
+ @Test
+ public void testRpcMethodPrintStatistics() {
+ Request req = new Request("printStatistics");
+ rpcServer.printStatistics(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is("\n" +
+ "Delayed responses queue size: 0\n" +
+ "Contents: "));
+ }
+
+ /**
+ * Tests invalidateCache RPC command
+ */
+ @Test
+ public void testRpcMethodInvalidateCache() {
+ Request req = new Request("invalidateCache");
+ rpcServer.invalidateCache(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ final String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(2));
+ assertThat(ret[0], is("0"));
+ assertThat(ret[1], is("success"));
+ }
+
+ /**
+ * Tests getMode and setMode RPC commands
+ */
+ @Test
+ public void testRpcMethodGetModeAndSetMode() {
+ Request req = new Request("getMode");
+ rpcServer.getMode(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is("default"));
+
+ req = new Request("setMode");
+ String mode = "memorycache";
+ req.parameters().add(new StringValue(mode));
+ rpcServer.setMode(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(2));
+ assertThat(ret[0], is("0"));
+ assertThat(ret[1], is("success"));
+ assertThat(proxyServer.getMode().name(), is(mode));
+
+ req = new Request("getMode");
+ rpcServer.getMode(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is(mode));
+
+ req = new Request("setMode");
+ String oldMode = mode;
+ mode = "invalid";
+ req.parameters().add(new StringValue(mode));
+ rpcServer.setMode(req);
+
+ assertFalse(req.errorMessage(), req.isError());
+ ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(2));
+ assertThat(ret[0], is("1"));
+ assertThat(ret[1], is("Could not set mode to '" + mode + "'. Legal modes are '" + Mode.modes() + "'"));
+ assertThat(proxyServer.getMode().name(), is(oldMode));
+ }
+
+ /**
+ * Tests updateSources RPC command
+ */
+ @Test
+ public void testRpcMethodUpdateSources() {
+ Request req = new Request("updateSources");
+ String spec1 = "tcp/a:19070";
+ String spec2 = "tcp/b:19070";
+ req.parameters().add(new StringValue(spec1 + "," + spec2));
+ rpcServer.updateSources(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is("Updated config sources to: " + spec1 + "," + spec2));
+
+
+ proxyServer.setMode(Mode.ModeName.MEMORYCACHE.name());
+
+ req = new Request("updateSources");
+ req.parameters().add(new StringValue(spec1 + "," + spec2));
+ rpcServer.updateSources(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is("Cannot update sources when in '" + Mode.ModeName.MEMORYCACHE.name().toLowerCase() + "' mode"));
+
+ // TODO source connections needs to have deterministic order to work
+ /*req = new Request("listSourceConnections");
+ rpcServer.listSourceConnections(req);
+ assertFalse(req.errorMessage(), req.isError());
+ final String[] ret = req.returnValues().get(0).asStringArray();
+ assertThat(ret.length, is(2));
+ assertThat(ret[0], is("Current source: " + spec1));
+ assertThat(ret[1], is("All sources:\n" + spec2 + "\n" + spec1 + "\n"));
+ */
+ }
+
+ /**
+ * Tests dumpCache RPC command
+ */
+ @Test
+ public void testRpcMethodDumpCache() {
+ Request req = new Request("dumpCache");
+ String path = "/tmp";
+ req.parameters().add(new StringValue(path));
+ rpcServer.dumpCache(req);
+ assertFalse(req.errorMessage(), req.isError());
+ assertThat(req.returnValues().size(), is(1));
+ assertThat(req.returnValues().get(0).asString(), is("success"));
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyStatisticsTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyStatisticsTest.java
new file mode 100644
index 00000000000..8f1529142af
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigProxyStatisticsTest.java
@@ -0,0 +1,46 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class ConfigProxyStatisticsTest {
+
+ @Test
+ public void basic() {
+ ConfigProxyStatistics statistics = new ConfigProxyStatistics();
+ assertThat(statistics.getEventInterval(), is(ConfigProxyStatistics.defaultEventInterval));
+ assertThat(statistics.processedRequests(), is(0L));
+ assertThat(statistics.errors(), is(0L));
+ assertThat(statistics.delayedResponses(), is(0L));
+
+ statistics.delayedResponses(1);
+ statistics.incProcessedRequests();
+ statistics.incRpcRequests();
+ statistics.incErrorCount();
+
+ assertThat(statistics.processedRequests(), is(1L));
+ assertThat(statistics.rpcRequests(), is(1L));
+ assertThat(statistics.errors(), is(1L));
+ assertThat(statistics.delayedResponses(), is(1L));
+
+ statistics.decDelayedResponses();
+ assertThat(statistics.delayedResponses(), is(0L));
+
+
+ Long eventInterval = 1L;
+ statistics = new ConfigProxyStatistics(eventInterval);
+ assertThat(statistics.getEventInterval(), is(eventInterval));
+
+ Thread t = new Thread(statistics);
+ t.start();
+
+ statistics.stop();
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java
new file mode 100644
index 00000000000..187a9f0726f
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ConfigTester.java
@@ -0,0 +1,49 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.jrt.Request;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.config.RawConfig;
+import com.yahoo.vespa.config.protocol.CompressionType;
+import com.yahoo.vespa.config.protocol.DefContent;
+import com.yahoo.vespa.config.protocol.JRTClientConfigRequestV3;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequestV3;
+import com.yahoo.vespa.config.protocol.Trace;
+
+import java.util.Collections;
+import java.util.Optional;
+
+/**
+ * @author bratseth
+ */
+public class ConfigTester {
+
+ private final long defaultTimeout = 10000;
+
+ public JRTServerConfigRequest createRequest(RawConfig config) {
+ return createRequest(config, defaultTimeout);
+ }
+
+ public JRTServerConfigRequest createRequest(RawConfig config, long timeout) {
+ return createRequest(config.getName(), config.getConfigId(), config.getNamespace(),
+ config.getConfigMd5(), config.getDefMd5(), config.getGeneration(), timeout);
+ }
+
+ public JRTServerConfigRequest createRequest(String configName, String configId, String namespace) {
+ return createRequest(configName, configId, namespace, defaultTimeout);
+ }
+
+ public JRTServerConfigRequest createRequest(String configName, String configId, String namespace, long timeout) {
+ return createRequest(configName, configId, namespace, "", null, 0, timeout);
+ }
+
+ public JRTServerConfigRequest createRequest(String configName, String configId, String namespace, String md5, String defMd5, long generation, long timeout) {
+ Request request = JRTClientConfigRequestV3.
+ createWithParams(new ConfigKey<>(configName, configId, namespace, defMd5, null), DefContent.fromList(Collections.emptyList()),
+ "fromHost", md5, generation, timeout, Trace.createDummy(), CompressionType.UNCOMPRESSED,
+ Optional.empty()).getRequest();
+ return JRTServerConfigRequestV3.createFromRequest(request);
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponseTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponseTest.java
new file mode 100644
index 00000000000..c81846d78d8
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponseTest.java
@@ -0,0 +1,83 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
+import org.junit.Test;
+
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.11
+ */
+public class DelayedResponseTest {
+
+ private static final String configId = "id";
+ private static final String namespace = "bar";
+
+ @Test
+ public void basic() {
+ ConfigTester tester = new ConfigTester();
+ final long returnTime = System.currentTimeMillis();
+ final long timeout = 1;
+ final String configName = "foo";
+ final JRTServerConfigRequest request = tester.createRequest(configName, configId, namespace, timeout);
+ DelayedResponse delayedResponse = new DelayedResponse(request, returnTime);
+ assertThat(delayedResponse.getRequest(), is(request));
+ assertThat(delayedResponse.getReturnTime(), is(returnTime));
+ assertTrue(delayedResponse.getDelay(TimeUnit.SECONDS) < returnTime);
+
+ DelayedResponse before = new DelayedResponse(request, returnTime - 1000L);
+ DelayedResponse after = new DelayedResponse(request, returnTime + 1000L);
+
+ assertThat(delayedResponse.compareTo(delayedResponse), is(0));
+ assertThat(delayedResponse.compareTo(before), is(1));
+ assertThat(delayedResponse.compareTo(after), is(-1));
+ assertThat(delayedResponse.compareTo(new Delayed() {
+ @Override
+ public long getDelay(TimeUnit unit) {
+ return 0;
+ }
+
+ @Override
+ public int compareTo(Delayed o) {
+ return 0;
+ }
+ }), is(0));
+ }
+
+ @Test
+ public void testDelayedResponse() {
+ ConfigTester tester = new ConfigTester();
+ final long timeout = 20000;
+ JRTServerConfigRequest request1 = tester.createRequest("baz", configId, namespace, timeout);
+ DelayedResponse delayed1 = new DelayedResponse(request1);
+ assertTrue(delayed1.getReturnTime() > System.currentTimeMillis());
+ assertTrue(delayed1.getDelay(TimeUnit.MILLISECONDS) > 0);
+ assertTrue(delayed1.getDelay(TimeUnit.MILLISECONDS) <= timeout);
+
+ // Just to make sure we do not get requests within the same millisecond
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ // New request, should have larger delay than the first
+ JRTServerConfigRequest request2 = tester.createRequest("baz", configId, namespace, timeout);
+ DelayedResponse delayed2 = new DelayedResponse(request2);
+ assertTrue("delayed1=" + delayed1.getReturnTime() + ", delayed2=" +
+ delayed2.getReturnTime() + ": delayed2 should be greater than delayed1",
+ delayed2.getReturnTime() > delayed1.getReturnTime());
+
+ // Test compareTo() method
+ assertThat(delayed1.compareTo(delayed1), is(0));
+ assertThat(delayed1.compareTo(delayed2), is(-1));
+ assertThat(delayed2.compareTo(delayed1), is(1));
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponsesTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponsesTest.java
new file mode 100644
index 00000000000..701ca959ee8
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/DelayedResponsesTest.java
@@ -0,0 +1,32 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class DelayedResponsesTest {
+
+ @Test
+ public void basic() throws InterruptedException {
+ ConfigTester tester = new ConfigTester();
+ DelayedResponses responses = new DelayedResponses(new ConfigProxyStatistics());
+ DelayedResponse delayedResponse = new DelayedResponse(tester.createRequest("foo", "id", "bar"));
+ responses.add(delayedResponse);
+
+ assertThat(responses.size(), is(1));
+ assertThat(responses.responses().take(), is(delayedResponse));
+ assertThat(responses.size(), is(0));
+
+ responses.add(delayedResponse);
+ assertThat(responses.size(), is(1));
+ responses.remove(delayedResponse);
+ assertThat(responses.size(), is(0));
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/Helper.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/Helper.java
new file mode 100644
index 00000000000..dc2b667f823
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/Helper.java
@@ -0,0 +1,58 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.config.*;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
+import com.yahoo.vespa.config.protocol.Payload;
+import com.yahoo.vespa.config.util.ConfigUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class Helper {
+
+ static final long serverTimeout = 100000;
+ static RawConfig fooConfig;
+ static RawConfig fooConfigV2;
+ static RawConfig barConfig;
+ static Payload fooConfigPayload;
+
+ static JRTServerConfigRequest fooConfigRequest;
+ static JRTServerConfigRequest barConfigRequest;
+
+ static ConfigCacheKey fooConfigConfigCacheKey;
+ static ConfigCacheKey barConfigConfigCacheKey;
+
+ static {
+ ConfigTester tester = new ConfigTester();
+ String defName = "foo";
+ String configId = "id";
+ String namespace = "bar";
+ ConfigKey<?> configKey = new ConfigKey<>(defName, configId, namespace);
+ Payload payloadV1 = Payload.from("bar \"value\"");
+ Slime slime = new Slime();
+ slime.setString("bar \"value\"");
+ fooConfigPayload = Payload.from(new ConfigPayload(slime));
+
+ List<String> defContent = Collections.singletonList("bar string");
+ long generation = 1;
+ String defMd5 = ConfigUtils.getDefMd5(defContent);
+ String configMd5 = "5752ad0f757d7e711e32037f29940b73";
+ fooConfig = new RawConfig(configKey, defMd5, payloadV1, configMd5, generation, defContent, Optional.empty());
+ fooConfigV2 = new RawConfig(configKey, defMd5, fooConfigPayload, configMd5, generation, defContent, Optional.empty());
+ fooConfigRequest = tester.createRequest(defName, configId, namespace, serverTimeout);
+ fooConfigConfigCacheKey = new ConfigCacheKey(fooConfig.getKey(), fooConfig.getDefMd5());
+
+ String defName2 = "bar";
+ barConfig = new RawConfig(new ConfigKey<>(defName2, configId, namespace), defMd5, payloadV1, configMd5, generation, defContent, Optional.empty());
+ barConfigRequest = tester.createRequest(defName2, configId, namespace, serverTimeout);
+ barConfigConfigCacheKey = new ConfigCacheKey(barConfig.getKey(), barConfig.getDefMd5());
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheConfigClientTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheConfigClientTest.java
new file mode 100644
index 00000000000..b59d8710f36
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheConfigClientTest.java
@@ -0,0 +1,29 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import org.junit.Test;
+
+import java.util.Collections;
+
+import static junit.framework.TestCase.assertNull;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class MemoryCacheConfigClientTest {
+
+ @Test
+ public void basic() {
+ MemoryCache cache = new MemoryCache();
+ cache.put(Helper.fooConfig);
+ MemoryCacheConfigClient client = new MemoryCacheConfigClient(cache);
+ assertThat(client.getConfig(Helper.fooConfig, null), is(Helper.fooConfig));
+ assertNull(client.getConfig(Helper.barConfig, null));
+
+ assertThat(client.getActiveSourceConnection(), is("N/A"));
+ assertThat(client.getSourceConnections(), is(Collections.singletonList("N/A")));
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java
new file mode 100644
index 00000000000..3707217b9c6
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MemoryCacheTest.java
@@ -0,0 +1,65 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.vespa.config.RawConfig;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class MemoryCacheTest extends CacheTest {
+
+ @Test
+ public void basic() {
+ MemoryCache cache = new MemoryCache();
+
+ cache.put(config);
+ cache.put(config2);
+ assertThat(cache.size(), is(2));
+ assertTrue(cache.containsKey(cacheKey));
+ assertTrue(cache.containsKey(cacheKey2));
+
+ RawConfig response = cache.get(cacheKey);
+ assertNotNull(response);
+ assertThat(response.getName(), is(defName));
+ assertThat(response.getPayload().toString(), is(payload.toString()));
+ assertThat(response.getGeneration(), is(generation));
+
+ response = cache.get(cacheKey2);
+ assertNotNull(response);
+ assertThat(response.getName(), is(defName2));
+ assertThat(response.getPayload().toString(), is(payload2.toString()));
+ assertThat(response.getGeneration(), is(generation));
+
+ cache.clear();
+ }
+
+ @Test
+ public void testSameConfigNameDifferentMd5() {
+ MemoryCache cache = new MemoryCache();
+
+ cache.put(config);
+ cache.put(configDifferentMd5); // same name, different defMd5
+ assertThat(cache.size(), is(2));
+ assertTrue(cache.containsKey(cacheKey));
+
+ RawConfig response = cache.get(cacheKey);
+ assertNotNull(response);
+ assertThat(response.getName(), is(defName));
+ assertThat(response.getPayload().getData(), is(payload.getData()));
+ assertThat(response.getGeneration(), is(generation));
+
+ response = cache.get(cacheKeyDifferentMd5);
+ assertNotNull(response);
+ assertThat(response.getName(), is(defName));
+ assertThat(response.getPayload().getData(), is(payloadDifferentMd5.getData()));
+ assertThat(response.getGeneration(), is(generation));
+
+ cache.clear();
+ assertThat(cache.size(), is(0));
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockConnection.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockConnection.java
new file mode 100644
index 00000000000..15f00cea18a
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockConnection.java
@@ -0,0 +1,86 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.jrt.Request;
+import com.yahoo.jrt.RequestWaiter;
+import com.yahoo.vespa.config.RawConfig;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequestV3;
+import com.yahoo.vespa.config.protocol.Payload;
+import com.yahoo.vespa.config.util.ConfigUtils;
+
+/**
+ * For unit testing
+ *
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.11
+ */
+public class MockConnection extends com.yahoo.config.subscription.impl.MockConnection {
+
+ public MockConnection(MapBackedConfigSource configSource) {
+ this(new ProxyResponseHandler(configSource));
+ }
+
+ public MockConnection(ResponseHandler responseHandler) {
+ super(responseHandler);
+ }
+
+ static class ProxyResponseHandler implements ResponseHandler {
+ private RequestWaiter requestWaiter;
+ private Request request;
+ private final MapBackedConfigSource configSource;
+
+ protected ProxyResponseHandler(MapBackedConfigSource configSource) {
+ this.configSource = configSource;
+ }
+
+ @Override
+ public RequestWaiter requestWaiter() {
+ return requestWaiter;
+ }
+
+ @Override
+ public Request request() {
+ return request;
+ }
+
+ @Override
+ public ResponseHandler requestWaiter(RequestWaiter requestWaiter) {
+ this.requestWaiter = requestWaiter;
+ return this;
+ }
+
+ @Override
+ public ResponseHandler request(Request request) {
+ this.request = request;
+ return this;
+ }
+
+ @Override
+ public void run() {
+ if (request.isError()) {
+ System.out.println("Returning error response");
+ createErrorResponse();
+ } else {
+ System.out.println("Returning OK response");
+ createOkResponse();
+ }
+ requestWaiter.handleRequestDone(request);
+ }
+
+ protected void createOkResponse() {
+ JRTServerConfigRequestV3 jrtReq = JRTServerConfigRequestV3.createFromRequest(request);
+ long generation = 1;
+ RawConfig config = configSource.getConfig(jrtReq.getConfigKey());
+ if (config == null || config.getPayload() == null) {
+ throw new RuntimeException("No config for " + jrtReq.getConfigKey() + " found");
+ }
+ Payload payload = config.getPayload();
+ jrtReq.addOkResponse(payload, generation, ConfigUtils.getMd5(payload.getData()));
+ }
+
+ protected void createErrorResponse() {
+ JRTServerConfigRequestV3 jrtReq = JRTServerConfigRequestV3.createFromRequest(request);
+ jrtReq.addErrorResponse(request.errorCode(), request.errorMessage());
+ }
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockRpcServer.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockRpcServer.java
new file mode 100644
index 00000000000..ed41fbf0e26
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/MockRpcServer.java
@@ -0,0 +1,23 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.vespa.config.RawConfig;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
+
+/**
+ * @author musum
+ */
+public class MockRpcServer implements RpcServer {
+
+ volatile long responses = 0;
+ volatile long errorResponses = 0;
+
+ public void returnOkResponse(JRTServerConfigRequest request, RawConfig config) {
+ responses++;
+ }
+
+ public void returnErrorResponse(JRTServerConfigRequest request, int errorCode, String message) {
+ responses++;
+ errorResponses++;
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ModeTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ModeTest.java
new file mode 100644
index 00000000000..c068a531a80
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ModeTest.java
@@ -0,0 +1,61 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author musum
+ */
+public class ModeTest {
+
+ @Test
+ public void basic() {
+ Mode mode = new Mode();
+ assertModeName(Mode.ModeName.DEFAULT, mode);
+ assertTrue(mode.isDefault());
+
+ mode = new Mode("");
+ assertModeName(Mode.ModeName.DEFAULT, mode);
+ assertTrue(mode.isDefault());
+
+ mode = new Mode(Mode.ModeName.DEFAULT.name());
+ assertModeName(Mode.ModeName.DEFAULT, mode);
+ assertTrue(mode.isDefault());
+
+ mode = new Mode(Mode.ModeName.MEMORYCACHE.name());
+ assertModeName(Mode.ModeName.MEMORYCACHE, mode);
+ assertTrue(mode.isMemoryCache());
+
+ assertTrue(new Mode(Mode.ModeName.DEFAULT.name()).requiresConfigSource());
+
+ assertFalse(new Mode(Mode.ModeName.MEMORYCACHE.name()).requiresConfigSource());
+
+ Set<String> modes = new HashSet<>();
+ for (Mode.ModeName modeName : Mode.ModeName.values()) {
+ modes.add(modeName.name().toLowerCase());
+ }
+
+ assertThat(Mode.modes(), is(modes));
+
+ assertFalse(Mode.validModeName("foo"));
+
+ assertThat(mode.toString(), is(Mode.ModeName.MEMORYCACHE.name().toLowerCase()));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void failWhenInvalidMode() {
+ new Mode("invalid_mode");
+ }
+
+ private void assertModeName(Mode.ModeName expected, Mode actual) {
+ assertThat(actual.name(), is(expected.name().toLowerCase()));
+ }
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java
new file mode 100644
index 00000000000..3ed876d547f
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/ProxyServerTest.java
@@ -0,0 +1,184 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.config.subscription.ConfigSourceSet;
+import com.yahoo.config.subscription.RawSource;
+import com.yahoo.vespa.config.*;
+import com.yahoo.vespa.config.protocol.JRTServerConfigRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.*;
+
+/**
+ * @author <a href="mailto:musum@yahoo-inc.com">Harald Musum</a>
+ * @since 5.1.9
+ */
+public class ProxyServerTest {
+
+ private final MapBackedConfigSource source = new MapBackedConfigSource(UpstreamConfigSubscriberTest.MockClientUpdater.create());
+ private ProxyServer proxy = ProxyServer.createTestServer(source);
+
+ static final RawConfig fooConfig = Helper.fooConfigV2;
+
+ // errorConfig based on fooConfig
+ static final ConfigKey<?> errorConfigKey = new ConfigKey<>("error", fooConfig.getConfigId(), fooConfig.getNamespace());
+ static final RawConfig errorConfig = new RawConfig(errorConfigKey, fooConfig.getDefMd5(),
+ fooConfig.getPayload(), fooConfig.getConfigMd5(),
+ fooConfig.getGeneration(), ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty());
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setup() {
+ source.clear();
+ source.put(fooConfig.getKey(), createConfigWithNextConfigGeneration(fooConfig, 0));
+ source.put(errorConfigKey, createConfigWithNextConfigGeneration(fooConfig, ErrorCode.UNKNOWN_DEFINITION));
+ proxy = ProxyServer.createTestServer(source);
+ }
+
+ @After
+ public void shutdown() {
+ proxy.stop();
+ }
+
+ @Test
+ public void basic() {
+ assertTrue(proxy.getMode().isDefault());
+ assertThat(proxy.getCacheManager().getMemoryCache().size(), is(0));
+ assertThat(proxy.getTimingValues(), is(ProxyServer.defaultTimingValues()));
+ }
+
+ /**
+ * Tests that the proxy server RPC commands for setting and getting mode works..
+ */
+ @Test
+ public void testModeSwitch() {
+ ConfigSourceSet source = new ConfigSourceSet(); // Need to use a ConfigSourceSet to test modes
+ ProxyServer proxy = ProxyServer.createTestServer(source);
+ assertTrue(proxy.getMode().isDefault());
+
+ for (String mode : Mode.modes()) {
+ proxy.setMode(mode);
+ assertThat(proxy.getMode().name(), is(mode));
+ }
+
+ // Also switch to DEFAULT mode, as that is not covered above
+ proxy.setMode("default");
+ assertTrue(proxy.getMode().isDefault());
+
+ // Set mode to the same as the current mode
+ proxy.setMode(proxy.getMode().name());
+ assertTrue(proxy.getMode().isDefault());
+
+ proxy.stop();
+ }
+
+ /**
+ * Tests that the proxy server can be tested with a MapBackedConfigSource,
+ * which is a simple hash map with configs
+ */
+ @Test
+ public void testRawConfigSetBasics() {
+ ConfigTester tester = new ConfigTester();
+ JRTServerConfigRequest errorConfigRequest = tester.createRequest(errorConfig);
+
+ assertTrue(proxy.getMode().isDefault());
+ RawConfig config = proxy.resolveConfig(Helper.fooConfigRequest);
+ assertThat(config, is(createConfigWithNextConfigGeneration(Helper.fooConfig, 0)));
+
+ config = proxy.resolveConfig(Helper.barConfigRequest);
+ assertNull(config);
+
+ config = proxy.resolveConfig(errorConfigRequest);
+ assertThat(config.errorCode(), is(ErrorCode.UNKNOWN_DEFINITION));
+ }
+
+ /**
+ * Verifies that config is retrieved from the real server when it is not found in the cache,
+ * that the cache is populated with the config and that the entry in the cache is used
+ * when it is found there.
+ */
+ @Test
+ public void testGetConfigAndCaching() {
+ ConfigTester tester = new ConfigTester();
+ final CacheManager cacheManager = proxy.getCacheManager();
+ assertEquals(0, cacheManager.getCacheSize());
+ RawConfig res = proxy.resolveConfig(tester.createRequest(fooConfig));
+ assertNotNull(res);
+ assertThat(res.getPayload().toString(), is(Helper.fooConfigPayload.toString()));
+ assertEquals(1, cacheManager.getCacheSize());
+ assertThat(cacheManager.getMemoryCache().get(new ConfigCacheKey(fooConfig.getKey(), fooConfig.getDefMd5())), is(res));
+
+ // Trying same config again
+ JRTServerConfigRequest newRequestBasedOnResponse = tester.createRequest(res);
+ RawConfig res2 = proxy.resolveConfig(newRequestBasedOnResponse);
+ assertFalse(ProxyServer.configOrGenerationHasChanged(res2, newRequestBasedOnResponse));
+ assertEquals(1, cacheManager.getCacheSize());
+ }
+
+ /**
+ * Verifies that error responses are not cached. When the config has been successfully retrieved,
+ * it must be put in the cache.
+ */
+ @Test
+ public void testNoCachingOfErrorRequests() {
+ ConfigTester tester = new ConfigTester();
+ // Simulate an error response
+ source.put(fooConfig.getKey(), createConfigWithNextConfigGeneration(fooConfig, ErrorCode.INTERNAL_ERROR));
+
+ final CacheManager cacheManager = proxy.getCacheManager();
+ assertEquals(0, cacheManager.getCacheSize());
+
+ RawConfig res = proxy.resolveConfig(tester.createRequest(fooConfig));
+ assertNotNull(res);
+ assertNotNull(res.getPayload());
+ assertTrue(res.isError());
+ assertEquals(0, cacheManager.getCacheSize());
+
+ // Put a version of the same config into backend without error and see that it now works (i.e. we are
+ // not getting a cached response (of the error in the previous request)
+ source.put(fooConfig.getKey(), createConfigWithNextConfigGeneration(fooConfig, 0));
+
+ // Verify that we get the config now and that it is cached
+ res = proxy.resolveConfig(tester.createRequest(fooConfig));
+ assertNotNull(res);
+ assertNotNull(res.getPayload().getData());
+ assertThat(res.getPayload().toString(), is(Helper.fooConfigPayload.toString()));
+ assertEquals(1, cacheManager.getCacheSize());
+
+ JRTServerConfigRequest newRequestBasedOnResponse = tester.createRequest(res);
+ RawConfig res2 = proxy.resolveConfig(newRequestBasedOnResponse);
+ assertFalse(ProxyServer.configOrGenerationHasChanged(res2, newRequestBasedOnResponse));
+ assertEquals(1, cacheManager.getCacheSize());
+ }
+
+ @Test
+ public void testReadingSystemProperties() {
+ ProxyServer.Properties properties = ProxyServer.getSystemProperties();
+ assertThat(properties.eventInterval, is(ConfigProxyStatistics.defaultEventInterval));
+ assertThat(properties.mode, is(Mode.ModeName.DEFAULT.name()));
+ assertThat(properties.configSources.length, is(1));
+ assertThat(properties.configSources[0], is(ProxyServer.DEFAULT_PROXY_CONFIG_SOURCES));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testIllegalConfigSource() {
+ RawSource source = new RawSource("bar 1");
+ proxy = ProxyServer.createTestServer(source);
+ }
+
+ static RawConfig createConfigWithNextConfigGeneration(RawConfig config, int errorCode) {
+ return new RawConfig(config.getKey(), config.getDefMd5(),
+ config.getPayload(), config.getConfigMd5(),
+ config.getGeneration() + 1, errorCode, config.getDefContent(), Optional.empty());
+ }
+
+}
diff --git a/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/UpstreamConfigSubscriberTest.java b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/UpstreamConfigSubscriberTest.java
new file mode 100644
index 00000000000..695c4068155
--- /dev/null
+++ b/config-proxy/src/test/java/com/yahoo/vespa/config/proxy/UpstreamConfigSubscriberTest.java
@@ -0,0 +1,173 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.proxy;
+
+import com.yahoo.config.subscription.ConfigSourceSet;
+import com.yahoo.config.subscription.impl.JRTConfigRequester;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.config.*;
+import com.yahoo.vespa.config.protocol.*;
+import com.yahoo.vespa.config.util.ConfigUtils;
+import org.junit.*;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.fail;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertThat;
+
+/**
+ * @author musum
+ */
+public class UpstreamConfigSubscriberTest {
+ private final ConfigSourceSet sourceSet = new ConfigSourceSet("tcp/foo:78");
+ private final TimingValues timingValues = ProxyServer.defaultTimingValues();
+
+ private MapBackedConfigSource sourceResponses;
+ private MockClientUpdater clientUpdater;
+ private MockConnection mockConnection;
+ static RawConfig fooConfig;
+ static RawConfig errorConfig;
+ static ConfigKey<?> errorConfigKey;
+ static Payload fooPayload;
+ static Payload errorPayload;
+ long generation = 1;
+
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void setup() {
+ clientUpdater = MockClientUpdater.create();
+ sourceResponses = new MapBackedConfigSource(clientUpdater);
+
+ ConfigPayload payload = getConfigPayload("bar", "value");
+ fooPayload = Payload.from(payload);
+ fooConfig = new RawConfig(Helper.fooConfig.getKey(), Helper.fooConfig.getDefMd5(), fooPayload, ConfigUtils.getMd5(payload), generation, 0, Helper.fooConfig.getDefContent(), Optional.empty());
+
+ payload = new ConfigPayload(new Slime());
+ errorPayload = Payload.from(payload);
+ errorConfigKey = new ConfigKey<>("error", fooConfig.getConfigId(), fooConfig.getNamespace());
+ errorConfig = new RawConfig(errorConfigKey, fooConfig.getDefMd5(), errorPayload, ConfigUtils.getMd5(payload), generation, ErrorCode.UNKNOWN_DEFINITION, fooConfig.getDefContent(), Optional.empty());
+
+ sourceResponses.clear();
+ sourceResponses.put(fooConfig.getKey(), fooConfig);
+
+ mockConnection = new MockConnection(sourceResponses);
+ }
+
+ private ConfigPayload getConfigPayload(String key, String value) {
+ Slime slime = new Slime();
+ slime.setObject().setString(key, value);
+ return new ConfigPayload(slime);
+ }
+
+ @Test
+ public void basic() {
+ final UpstreamConfigSubscriber subscriber = createUpstreamConfigSubscriber(fooConfig);
+ new Thread(subscriber).start();
+ waitForConfigGeneration(clientUpdater, generation);
+ assertThat(clientUpdater.getLastConfig(), is(fooConfig));
+ subscriber.cancel();
+ }
+
+ @Test
+ public void require_that_reconfiguration_works() {
+ final UpstreamConfigSubscriber subscriber = createUpstreamConfigSubscriber(fooConfig);
+
+ new Thread(subscriber).start();
+ waitForConfigGeneration(clientUpdater, generation);
+ assertThat(clientUpdater.getLastConfig(), is(fooConfig));
+
+ // Add updated config
+ generation++;
+ final ConfigPayload payload = getConfigPayload("bar", "value2");
+ fooPayload = Payload.from(payload);
+ RawConfig fooConfig2 = new RawConfig(fooConfig.getKey(), fooConfig.getDefMd5(), fooPayload, ConfigUtils.getMd5(payload), generation, fooConfig.getDefContent(), Optional.empty());
+ sourceResponses.put(fooConfig2.getKey(), fooConfig2);
+
+ waitForConfigGeneration(clientUpdater, generation);
+ assertThat(clientUpdater.getLastConfig(), is(not(fooConfig)));
+ subscriber.cancel();
+ }
+
+ @Test
+ public void require_that_error_response_is_handled() {
+ sourceResponses.put(errorConfigKey, errorConfig);
+ final UpstreamConfigSubscriber subscriber = createUpstreamConfigSubscriber(fooConfig);
+
+ new Thread(subscriber).start();
+ waitForConfigGeneration(clientUpdater, generation);
+ RawConfig lastConfig = clientUpdater.getLastConfig();
+ assertThat(lastConfig, is(errorConfig));
+ assertThat(lastConfig.errorCode(), is(ErrorCode.UNKNOWN_DEFINITION));
+ subscriber.cancel();
+ }
+
+ private UpstreamConfigSubscriber createUpstreamConfigSubscriber(RawConfig config) {
+ return new UpstreamConfigSubscriber(config, clientUpdater, sourceSet, timingValues, createRequesterPool());
+ }
+
+ private Map<ConfigSourceSet, JRTConfigRequester> createRequesterPool() {
+ JRTConfigRequester request = JRTConfigRequester.get(mockConnection, timingValues);
+
+ Map<ConfigSourceSet, JRTConfigRequester> requesterPool = new LinkedHashMap<>();
+ requesterPool.put(sourceSet, request);
+ return requesterPool;
+ }
+
+ private void waitForConfigGeneration(MockClientUpdater clientUpdater, long expectedGeneration) {
+ int i = 0;
+ RawConfig lastConfig;
+ do {
+ lastConfig = clientUpdater.getLastConfig();
+ if (lastConfig != null) {
+ System.out.println("i=" + i + ", config=" + lastConfig + ",generation=" + lastConfig.getGeneration());
+ }
+ if (lastConfig != null && lastConfig.getGeneration() == expectedGeneration) {
+ break;
+ } else {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+ i++;
+ } while (i < 1000);
+ assertNotNull(lastConfig);
+ assertThat(lastConfig.getGeneration(), is(expectedGeneration));
+ }
+
+ static class MockClientUpdater extends ClientUpdater {
+ private RawConfig lastConfig;
+
+ private MockClientUpdater(ConfigProxyStatistics statistics, Mode mode) {
+ super(CacheManager.createTestCacheManager(),
+ new MockRpcServer(),
+ statistics,
+ new DelayedResponses(statistics),
+ mode);
+ }
+
+ public static MockClientUpdater create() {
+ Mode mode = new Mode();
+ ConfigProxyStatistics statistics = new ConfigProxyStatistics();
+ return new MockClientUpdater(statistics, mode);
+ }
+
+ @Override
+ public void updateSubscribers(RawConfig newConfig) {
+ lastConfig = newConfig;
+ }
+
+ RawConfig getLastConfig() {
+ return lastConfig;
+ }
+ }
+}