/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.solr.client.solrj; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters; import junit.framework.Assert; import org.apache.commons.io.FileUtils; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.lucene.util.IOUtils; import org.apache.lucene.util.LuceneTestCase.Slow; import org.apache.lucene.util.QuickPatchThreadsFilter; import org.apache.solr.SolrIgnoredThreadsFilter; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.embedded.JettyConfig; import org.apache.solr.client.solrj.embedded.JettySolrRunner; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.impl.LBHttpSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.client.solrj.response.SolrResponseBase; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.util.TimeOut; import org.junit.AfterClass; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; /** * Test for LBHttpSolrClient * * @since solr 1.4 */ @Slow @ThreadLeakFilters(defaultFilters = true, filters = { SolrIgnoredThreadsFilter.class, QuickPatchThreadsFilter.class }) public class TestLBHttpSolrClient extends SolrTestCaseJ4 { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); SolrInstance[] solr = new SolrInstance[3]; CloseableHttpClient httpClient; // TODO: fix this test to not require FSDirectory static String savedFactory; @BeforeClass public static void beforeClass() { savedFactory = System.getProperty("solr.DirectoryFactory"); System.setProperty("solr.directoryFactory", "org.apache.solr.core.MockFSDirectoryFactory"); System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong())); } @AfterClass public static void afterClass() { if (savedFactory == null) { System.clearProperty("solr.directoryFactory"); } else { System.setProperty("solr.directoryFactory", savedFactory); } System.clearProperty("tests.shardhandler.randomSeed"); } @Override public void setUp() throws Exception { super.setUp(); httpClient = HttpClientUtil.createClient(null); for (int i = 0; i < solr.length; i++) { solr[i] = new SolrInstance("solr/collection1" + i, createTempDir("instance-" + i).toFile(), 0); solr[i].setUp(); solr[i].startJetty(); addDocs(solr[i]); } } private void addDocs(SolrInstance solrInstance) throws IOException, SolrServerException { List<SolrInputDocument> docs = new ArrayList<>(); for (int i = 0; i < 10; i++) { SolrInputDocument doc = new SolrInputDocument(); doc.addField("id", i); doc.addField("name", solrInstance.name); docs.add(doc); } SolrResponseBase resp; try (HttpSolrClient client = getHttpSolrClient(solrInstance.getUrl(), httpClient)) { resp = client.add(docs); assertEquals(0, resp.getStatus()); resp = client.commit(); assertEquals(0, resp.getStatus()); } } @Override public void tearDown() throws Exception { for (SolrInstance aSolr : solr) { if (aSolr != null) { aSolr.tearDown(); } } HttpClientUtil.close(httpClient); super.tearDown(); } public void testSimple() throws Exception { String[] s = new String[solr.length]; for (int i = 0; i < solr.length; i++) { s[i] = solr[i].getUrl(); } LBHttpSolrClient client = getLBHttpSolrClient(httpClient, s); client.setAliveCheckInterval(500); SolrQuery solrQuery = new SolrQuery("*:*"); Set<String> names = new HashSet<>(); QueryResponse resp = null; for (String value : s) { resp = client.query(solrQuery); assertEquals(10, resp.getResults().getNumFound()); names.add(resp.getResults().get(0).getFieldValue("name").toString()); } assertEquals(3, names.size()); // Kill a server and test again solr[1].jetty.stop(); solr[1].jetty = null; names.clear(); for (String value : s) { resp = client.query(solrQuery); assertEquals(10, resp.getResults().getNumFound()); names.add(resp.getResults().get(0).getFieldValue("name").toString()); } assertEquals(2, names.size()); assertFalse(names.contains("solr1")); // Start the killed server once again solr[1].startJetty(); // Wait for the alive check to complete Thread.sleep(1200); names.clear(); for (String value : s) { resp = client.query(solrQuery); assertEquals(10, resp.getResults().getNumFound()); names.add(resp.getResults().get(0).getFieldValue("name").toString()); } assertEquals(3, names.size()); } public void testTwoServers() throws Exception { LBHttpSolrClient client = getLBHttpSolrClient(httpClient, solr[0].getUrl(), solr[1].getUrl()); client.setAliveCheckInterval(500); SolrQuery solrQuery = new SolrQuery("*:*"); QueryResponse resp = null; solr[0].jetty.stop(); solr[0].jetty = null; resp = client.query(solrQuery); String name = resp.getResults().get(0).getFieldValue("name").toString(); Assert.assertEquals("solr/collection11", name); resp = client.query(solrQuery); name = resp.getResults().get(0).getFieldValue("name").toString(); Assert.assertEquals("solr/collection11", name); solr[1].jetty.stop(); solr[1].jetty = null; solr[0].startJetty(); Thread.sleep(1200); try { resp = client.query(solrQuery); } catch(SolrServerException e) { // try again after a pause in case the error is lack of time to start server Thread.sleep(3000); resp = client.query(solrQuery); } name = resp.getResults().get(0).getFieldValue("name").toString(); Assert.assertEquals("solr/collection10", name); } public void testReliability() throws Exception { String[] s = new String[solr.length]; for (int i = 0; i < solr.length; i++) { s[i] = solr[i].getUrl(); } CloseableHttpClient myHttpClient = HttpClientUtil.createClient(null); try { LBHttpSolrClient client = getLBHttpSolrClient(myHttpClient, s); client.setConnectionTimeout(500); client.setSoTimeout(500); client.setAliveCheckInterval(500); // Kill a server and test again solr[1].jetty.stop(); solr[1].jetty = null; // query the servers for (String value : s) client.query(new SolrQuery("*:*")); // Start the killed server once again solr[1].startJetty(); // Wait for the alive check to complete waitForServer(30, client, 3, "solr1"); } finally { HttpClientUtil.close(myHttpClient); } } // wait maximum ms for serverName to come back up private void waitForServer(int maxSeconds, LBHttpSolrClient client, int nServers, String serverName) throws Exception { final TimeOut timeout = new TimeOut(maxSeconds, TimeUnit.SECONDS); while (! timeout.hasTimedOut()) { QueryResponse resp; try { resp = client.query(new SolrQuery("*:*")); } catch (Exception e) { log.warn("", e); continue; } String name = resp.getResults().get(0).getFieldValue("name").toString(); if (name.equals(serverName)) return; Thread.sleep(500); } } private static class SolrInstance { String name; File homeDir; File dataDir; File confDir; int port; JettySolrRunner jetty; public SolrInstance(String name, File homeDir, int port) { this.name = name; this.homeDir = homeDir; this.port = port; dataDir = new File(homeDir + "/collection1", "data"); confDir = new File(homeDir + "/collection1", "conf"); } public String getHomeDir() { return homeDir.toString(); } public String getUrl() { return buildUrl(port, "/solr/collection1"); } public String getSchemaFile() { return "solrj/solr/collection1/conf/schema-replication1.xml"; } public String getConfDir() { return confDir.toString(); } public String getDataDir() { return dataDir.toString(); } public String getSolrConfigFile() { return "solrj/solr/collection1/conf/solrconfig-slave1.xml"; } public String getSolrXmlFile() { return "solrj/solr/solr.xml"; } public void setUp() throws Exception { homeDir.mkdirs(); dataDir.mkdirs(); confDir.mkdirs(); FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrXmlFile()), new File(homeDir, "solr.xml")); File f = new File(confDir, "solrconfig.xml"); FileUtils.copyFile(SolrTestCaseJ4.getFile(getSolrConfigFile()), f); f = new File(confDir, "schema.xml"); FileUtils.copyFile(SolrTestCaseJ4.getFile(getSchemaFile()), f); Files.createFile(homeDir.toPath().resolve("collection1/core.properties")); } public void tearDown() throws Exception { if (jetty != null) jetty.stop(); IOUtils.rm(homeDir.toPath()); } public void startJetty() throws Exception { Properties props = new Properties(); props.setProperty("solrconfig", "bad_solrconfig.xml"); props.setProperty("solr.data.dir", getDataDir()); JettyConfig jettyConfig = JettyConfig.builder(buildJettyConfig("/solr")).setPort(port).build(); jetty = new JettySolrRunner(getHomeDir(), props, jettyConfig); jetty.start(); int newPort = jetty.getLocalPort(); if (port != 0 && newPort != port) { fail("TESTING FAILURE: could not grab requested port."); } this.port = newPort; // System.out.println("waiting........."); // Thread.sleep(5000); } } }