| /* |
| * 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 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.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.common.util.TimeSource; |
| 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 |
| 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(); |
| } |
| try (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 { |
| try (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 { |
| try (LBHttpSolrClient client = getLBHttpSolrClient(myHttpClient, 500, 500, s)) { |
| 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, solr[1].name); |
| } |
| } 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, TimeSource.NANO_TIME); |
| 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-follower1.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); |
| } |
| } |
| } |