summaryrefslogtreecommitdiffstats
path: root/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java')
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java294
1 files changed, 294 insertions, 0 deletions
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
new file mode 100644
index 00000000000..1b53fc8869d
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
@@ -0,0 +1,294 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.container.xml;
+
+import com.yahoo.component.ComponentId;
+import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
+import com.yahoo.container.core.ChainsConfig;
+import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig;
+import com.yahoo.container.jdisc.JdiscBindingsConfig;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.ContainerCluster;
+import com.yahoo.vespa.model.container.component.Handler;
+import com.yahoo.vespa.model.container.search.GUIHandler;
+import com.yahoo.vespa.model.test.utils.ApplicationPackageUtils;
+import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
+import org.junit.Test;
+import org.w3c.dom.Element;
+
+import static com.yahoo.config.model.api.container.ContainerServiceType.CONTAINER;
+import static com.yahoo.test.Matchers.hasItemWithMethod;
+import static com.yahoo.vespa.model.container.search.ContainerSearch.QUERY_PROFILE_REGISTRY_CLASS;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author gjoranv
+ */
+public class SearchBuilderTest extends ContainerModelBuilderTestBase {
+
+ private ChainsConfig chainsConfig() {
+ return root.getConfig(ChainsConfig.class, "default/component/com.yahoo.search.handler.SearchHandler");
+ }
+
+ @Test
+ public void gui_search_handler_is_always_included_when_search_is_specified() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search />",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
+ assertTrue(discBindingsConfig.contains(GUIHandler.BINDING_PATH));
+
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
+
+ GUIHandler guiHandler = null;
+ for (Handler<?> handler : cluster.getHandlers()) {
+ if (handler instanceof GUIHandler) {
+ guiHandler = (GUIHandler) handler;
+ }
+ }
+ assertNotNull(guiHandler);
+ }
+
+ @Test
+ public void search_handler_bindings_can_be_overridden() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search>",
+ " <binding>http://*/binding0</binding>",
+ " <binding>http://*/binding1</binding>",
+ " </search>",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
+ assertTrue(discBindingsConfig.contains(".serverBindings[0] \"http://*/binding0\""));
+ assertTrue(discBindingsConfig.contains(".serverBindings[1] \"http://*/binding1\""));
+ assertFalse(discBindingsConfig.contains("/search/*"));
+ }
+
+ @Test
+ public void search_handler_bindings_can_be_disabled() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search>",
+ " <binding/>",
+ " </search>",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ String discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default").toString();
+ assertFalse(discBindingsConfig.contains("/search/*"));
+ }
+
+ @Test
+ public void search_handler_binding_can_be_stolen_by_user_configured_handler() {
+ var myHandler = "replaces_search_handler";
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search />",
+ " <handler id='" + myHandler + "'>",
+ " <binding>" + SearchHandler.DEFAULT_BINDING.patternString() + "</binding>",
+ " </handler>",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ var discBindingsConfig = root.getConfig(JdiscBindingsConfig.class, "default");
+ assertEquals(SearchHandler.DEFAULT_BINDING.patternString(), discBindingsConfig.handlers(myHandler).serverBindings(0));
+ assertNull(discBindingsConfig.handlers(SearchHandler.HANDLER_CLASS));
+ }
+
+ // TODO: remove test when all containers are named 'container'
+ @Test
+ public void cluster_with_only_search_gets_qrserver_as_service_name() {
+ createClusterWithOnlyDefaultChains();
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
+ assertEquals(CONTAINER.serviceName, cluster.getContainers().get(0).getServiceName());
+ }
+
+ @Test
+ public void empty_search_element_gives_default_chains() {
+ createClusterWithOnlyDefaultChains();
+ assertThat(chainsConfig().chains(), hasItemWithMethod("vespaPhases", "id"));
+ assertThat(chainsConfig().chains(), hasItemWithMethod("native", "id"));
+ assertThat(chainsConfig().chains(), hasItemWithMethod("vespa", "id"));
+ }
+
+ @Test
+ public void query_profiles_registry_component_is_added() {
+ createClusterWithOnlyDefaultChains();
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
+ var queryProfileRegistryId = ComponentId.fromString(QUERY_PROFILE_REGISTRY_CLASS);
+ assertTrue(cluster.getComponentsMap().containsKey(queryProfileRegistryId));
+ }
+
+ private void createClusterWithOnlyDefaultChains() {
+ Element containerElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search/>",
+ " <nodes>",
+ " <node hostalias='mockhost' />",
+ " </nodes>",
+ "</container>");
+
+ createModel(root, containerElem);
+ }
+
+ @Test
+ public void manually_setting_up_search_handler_is_forbidden() {
+ try {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <handler id='com.yahoo.search.handler.SearchHandler' />",
+ nodesXml,
+ " </container>");
+
+
+ createModel(root, clusterElem);
+ fail("Expected exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("Setting up com.yahoo.search.handler.SearchHandler manually is not supported"));
+ }
+ }
+
+ @Test
+ public void cluster_is_connected_to_content_clusters() {
+ String hosts = hostsXml();
+
+ String services = "" +
+ "<services>"+
+ " <admin version='2.0'>" +
+ " <adminserver hostalias='mockhost'/>" +
+ " </admin>" +
+ " <container version='1.0' id='container'>"+
+ " <search>" +
+ " <chain id='mychain' inherits='vespa'/>" +
+ " </search>" +
+ " <nodes>"+
+ " <node hostalias=\"mockhost\" />"+
+ " </nodes>"+
+ " </container>"+
+ contentXml() +
+ "</services>";
+
+ VespaModel model = getVespaModelWithMusic(hosts, services);
+
+ ContainerCluster cluster = model.getContainerClusters().get("container");
+ assertFalse(cluster.getSearchChains().localProviders().isEmpty());
+ }
+
+ @Test
+ public void cluster_is_connected_to_search_clusters() {
+ String hosts = hostsXml();
+
+ String services = "" +
+ "<services>"+
+ " <admin version='2.0'>" +
+ " <adminserver hostalias='mockhost'/>" +
+ " </admin>" +
+ " <container version='1.0' id='container'>"+
+ " <search>" +
+ " <chain id='mychain' inherits='vespa'/>" +
+ " </search>" +
+ " <nodes>"+
+ " <node hostalias=\"mockhost\" />"+
+ " </nodes>"+
+ " </container>"+
+ contentXml() +
+ "</services>";
+
+ VespaModel model = getVespaModelWithMusic(hosts, services);
+
+ ContainerCluster cluster = model.getContainerClusters().get("container");
+ assertFalse(cluster.getSearchChains().localProviders().isEmpty());
+ }
+
+ @Test
+ public void search_handler_has_dedicated_threadpool() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search />",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
+ Handler<?> searchHandler = cluster.getHandlers().stream()
+ .filter(h -> h.getComponentId().toString().equals(SearchHandler.HANDLER_CLASS))
+ .findAny()
+ .get();
+
+ assertTrue(searchHandler.getInjectedComponentIds().contains("threadpool@search-handler"));
+
+ ContainerThreadpoolConfig config = root.getConfig(
+ ContainerThreadpoolConfig.class, "default/component/" + SearchHandler.HANDLER_CLASS + "/threadpool@search-handler");
+ assertEquals(-2, config.maxThreads());
+ assertEquals(-2, config.minThreads());
+ assertEquals(-40, config.queueSize());
+ }
+
+ @Test
+ public void threadpool_configuration_can_be_overridden() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search>",
+ " <threadpool>",
+ " <max-threads>100</max-threads>",
+ " <min-threads>80</min-threads>",
+ " <queue-size>10</queue-size>",
+ " </threadpool>",
+ " </search>",
+ nodesXml,
+ "</container>");
+ createModel(root, clusterElem);
+ ContainerThreadpoolConfig config = root.getConfig(
+ ContainerThreadpoolConfig.class, "default/component/" + SearchHandler.HANDLER_CLASS + "/threadpool@search-handler");
+ assertEquals(100, config.maxThreads());
+ assertEquals(80, config.minThreads());
+ assertEquals(10, config.queueSize());
+ }
+
+ private VespaModel getVespaModelWithMusic(String hosts, String services) {
+ return new VespaModelCreatorWithMockPkg(hosts, services, ApplicationPackageUtils.generateSchemas("music")).create();
+ }
+
+ private String hostsXml() {
+ return "" +
+ "<hosts> " +
+ " <host name=\"node0\">" +
+ " <alias>mockhost</alias>" +
+ " </host>" +
+ "</hosts>";
+ }
+
+ private String contentXml() {
+ return " <content version=\"1.0\" id='content'>"+
+ " <documents>\n" +
+ " <document type=\"music\" mode='index'/>\n" +
+ " </documents>\n" +
+ " <redundancy>3</redundancy>"+
+ " <group>"+
+ " <node hostalias=\"mockhost\" distribution-key=\"0\"/>"+
+ " </group>"+
+ " </content>";
+ }
+
+}