blob: 81dd4be8e655f5ccdae7bc0384e98a49c216a460 [file] [log] [blame]
/*
* 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;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.BinaryResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.junit.AfterClass;
import org.junit.BeforeClass;
public class TestTolerantSearch extends SolrJettyTestBase {
private static SolrClient collection1;
private static SolrClient collection2;
private static String shard1;
private static String shard2;
private static File solrHome;
private static File createSolrHome() throws Exception {
File workDir = createTempDir().toFile();
setupJettyTestHome(workDir, "collection1");
FileUtils.copyFile(new File(SolrTestCaseJ4.TEST_HOME() + "/collection1/conf/solrconfig-tolerant-search.xml"), new File(workDir, "/collection1/conf/solrconfig.xml"));
FileUtils.copyDirectory(new File(workDir, "collection1"), new File(workDir, "collection2"));
return workDir;
}
@BeforeClass
public static void createThings() throws Exception {
systemSetPropertySolrDisableShardsWhitelist("true");
solrHome = createSolrHome();
createAndStartJetty(solrHome.getAbsolutePath());
String url = jetty.getBaseUrl().toString();
collection1 = getHttpSolrClient(url + "/collection1");
collection2 = getHttpSolrClient(url + "/collection2");
String urlCollection1 = jetty.getBaseUrl().toString() + "/" + "collection1";
String urlCollection2 = jetty.getBaseUrl().toString() + "/" + "collection2";
shard1 = urlCollection1.replaceAll("https?://", "");
shard2 = urlCollection2.replaceAll("https?://", "");
//create second core
try (HttpSolrClient nodeClient = getHttpSolrClient(url)) {
CoreAdminRequest.Create req = new CoreAdminRequest.Create();
req.setCoreName("collection2");
req.setConfigSet("collection1");
nodeClient.request(req);
}
SolrInputDocument doc = new SolrInputDocument();
doc.setField("id", "1");
doc.setField("subject", "batman");
doc.setField("title", "foo bar");
collection1.add(doc);
collection1.commit();
doc.setField("id", "2");
doc.setField("subject", "superman");
collection2.add(doc);
collection2.commit();
doc = new SolrInputDocument();
doc.setField("id", "3");
doc.setField("subject", "aquaman");
doc.setField("title", "foo bar");
collection1.add(doc);
collection1.commit();
}
@AfterClass
public static void destroyThings() throws Exception {
if (null != collection1) {
collection1.close();
collection1 = null;
}
if (null != collection2) {
collection2.close();
collection2 = null;
}
if (null != jetty) {
jetty.stop();
jetty=null;
}
resetExceptionIgnores();
systemClearPropertySolrDisableShardsWhitelist();
}
@SuppressWarnings("unchecked")
public void testGetFieldsPhaseError() throws SolrServerException, IOException {
BadResponseWriter.failOnGetFields = true;
BadResponseWriter.failOnGetTopIds = false;
SolrQuery query = new SolrQuery();
query.setQuery("subject:batman OR subject:superman");
query.addField("id");
query.addField("subject");
query.set("distrib", "true");
query.set("shards", shard1 + "," + shard2);
query.set(ShardParams.SHARDS_INFO, "true");
query.set("debug", "true");
query.set("stats", "true");
query.set("stats.field", "id");
query.set("mlt", "true");
query.set("mlt.fl", "title");
query.set("mlt.count", "1");
query.set("mlt.mintf", "0");
query.set("mlt.mindf", "0");
query.setHighlight(true);
query.addFacetField("id");
query.setFacet(true);
ignoreException("Dummy exception in BadResponseWriter");
expectThrows(SolrException.class, () -> collection1.query(query));
query.set(ShardParams.SHARDS_TOLERANT, "true");
QueryResponse response = collection1.query(query);
assertTrue(response.getResponseHeader().getBooleanArg(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY));
NamedList<Object> shardsInfo = ((NamedList<Object>)response.getResponse().get(ShardParams.SHARDS_INFO));
boolean foundError = false;
for (int i = 0; i < shardsInfo.size(); i++) {
if (shardsInfo.getName(i).contains("collection2")) {
assertNotNull(((NamedList<Object>)shardsInfo.getVal(i)).get("error"));
foundError = true;
break;
}
}
assertTrue(foundError);
assertEquals("1", response.getResults().get(0).getFieldValue("id"));
assertEquals("batman", response.getResults().get(0).getFirstValue("subject"));
unIgnoreException("Dummy exception in BadResponseWriter");
}
@SuppressWarnings("unchecked")
public void testGetTopIdsPhaseError() throws SolrServerException, IOException {
BadResponseWriter.failOnGetTopIds = true;
BadResponseWriter.failOnGetFields = false;
SolrQuery query = new SolrQuery();
query.setQuery("subject:batman OR subject:superman");
query.addField("id");
query.addField("subject");
query.set("distrib", "true");
query.set("shards", shard1 + "," + shard2);
query.set(ShardParams.SHARDS_INFO, "true");
query.set("debug", "true");
query.set("stats", "true");
query.set("stats.field", "id");
query.set("mlt", "true");
query.set("mlt.fl", "title");
query.set("mlt.count", "1");
query.set("mlt.mintf", "0");
query.set("mlt.mindf", "0");
query.setHighlight(true);
query.addFacetField("id");
query.setFacet(true);
ignoreException("Dummy exception in BadResponseWriter");
expectThrows(Exception.class, () -> collection1.query(query));
query.set(ShardParams.SHARDS_TOLERANT, "true");
QueryResponse response = collection1.query(query);
assertTrue(response.getResponseHeader().getBooleanArg(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY));
NamedList<Object> shardsInfo = ((NamedList<Object>)response.getResponse().get(ShardParams.SHARDS_INFO));
boolean foundError = false;
for (int i = 0; i < shardsInfo.size(); i++) {
if (shardsInfo.getName(i).contains("collection2")) {
assertNotNull(((NamedList<Object>)shardsInfo.getVal(i)).get("error"));
foundError = true;
break;
}
}
assertTrue(foundError);
assertFalse(""+response, response.getResults().isEmpty());
assertEquals("1", response.getResults().get(0).getFieldValue("id"));
assertEquals("batman", response.getResults().get(0).getFirstValue("subject"));
unIgnoreException("Dummy exception in BadResponseWriter");
}
public static class BadResponseWriter extends BinaryResponseWriter {
private static boolean failOnGetFields = false;
private static boolean failOnGetTopIds = false;
public BadResponseWriter() {
super();
}
@Override
public void write(OutputStream out, SolrQueryRequest req,
SolrQueryResponse response) throws IOException {
// I want to fail on the shard request, not the original user request, and only on the
// GET_FIELDS phase
if (failOnGetFields &&
"collection2".equals(req.getCore().getName())
&& "subject:batman OR subject:superman".equals(req.getParams().get("q", ""))
&& req.getParams().get("ids") != null) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Dummy exception in BadResponseWriter");
} else if (failOnGetTopIds
&& "collection2".equals(req.getCore().getName())
&& "subject:batman OR subject:superman".equals(req.getParams().get("q", ""))
&& req.getParams().get("ids") == null
&& req.getParams().getBool("isShard", false) == true) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Dummy exception in BadResponseWriter");
}
super.write(out, req, response);
}
}
}