blob: 1b4ecc326d5fc963732c5ebc3801b598e010cdd2 [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.client.solrj.request;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
import com.codahale.metrics.MetricRegistry;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.LuceneTestCase;
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.embedded.AbstractEmbeddedSolrServerTestCase;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.request.CoreAdminRequest.Create;
import org.apache.solr.client.solrj.request.CoreAdminRequest.RequestRecovery;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import org.apache.solr.metrics.SolrCoreMetricManager;
import org.apache.solr.metrics.SolrMetricManager;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.Is.is;
public class TestCoreAdmin extends AbstractEmbeddedSolrServerTestCase {
private static String tempDirProp;
@Rule
public TestRule testRule = RuleChain.outerRule(new SystemPropertiesRestoreRule());
/*
@Override
protected File getSolrXml() throws Exception {
// This test writes on the directory where the solr.xml is located. Better
// to copy the solr.xml to
// the temporary directory where we store the index
File origSolrXml = new File(SOLR_HOME, SOLR_XML);
File solrXml = new File(tempDir, SOLR_XML);
FileUtils.copyFile(origSolrXml, solrXml);
return solrXml;
}
*/
protected SolrClient getSolrAdmin() {
return new EmbeddedSolrServer(cores, null);
}
@Test
public void testConfigSet() throws Exception {
SolrClient client = getSolrAdmin();
File testDir = createTempDir(LuceneTestCase.getTestClass().getSimpleName()).toFile();
File newCoreInstanceDir = new File(testDir, "newcore");
cores.getAllowPaths().add(testDir.toPath()); // Allow the test dir
CoreAdminRequest.Create req = new CoreAdminRequest.Create();
req.setCoreName("corewithconfigset");
req.setInstanceDir(newCoreInstanceDir.getAbsolutePath());
req.setConfigSet("configset-2");
CoreAdminResponse response = req.process(client);
assertThat((String) response.getResponse().get("core"), is("corewithconfigset"));
try (SolrCore core = cores.getCore("corewithconfigset")) {
assertThat(core, is(notNullValue()));
}
}
@Test
public void testCustomUlogDir() throws Exception {
try (SolrClient client = getSolrAdmin()) {
File dataDir = createTempDir("data").toFile();
File newCoreInstanceDir = createTempDir("instance").toFile();
cores.getAllowPaths().add(dataDir.toPath()); // Allow the test dir
cores.getAllowPaths().add(newCoreInstanceDir.toPath()); // Allow the test dir
File instanceDir = new File(cores.getSolrHome());
FileUtils.copyDirectory(instanceDir, new File(newCoreInstanceDir,
"newcore"));
CoreAdminRequest.Create req = new CoreAdminRequest.Create();
req.setCoreName("newcore");
req.setInstanceDir(newCoreInstanceDir.getAbsolutePath() + File.separator + "newcore");
req.setDataDir(dataDir.getAbsolutePath());
req.setUlogDir(new File(dataDir, "ulog").getAbsolutePath());
req.setConfigSet("shared");
// These should be the inverse of defaults.
req.setIsLoadOnStartup(false);
req.setIsTransient(true);
req.process(client);
// Show that the newly-created core has values for load on startup and transient different than defaults due to the
// above.
File logDir;
try (SolrCore coreProveIt = cores.getCore("collection1");
SolrCore core = cores.getCore("newcore")) {
assertTrue(core.getCoreDescriptor().isTransient());
assertFalse(coreProveIt.getCoreDescriptor().isTransient());
assertFalse(core.getCoreDescriptor().isLoadOnStartup());
assertTrue(coreProveIt.getCoreDescriptor().isLoadOnStartup());
logDir = new File(core.getUpdateHandler().getUpdateLog().getLogDir());
}
assertEquals(new File(dataDir, "ulog" + File.separator + "tlog").getAbsolutePath(), logDir.getAbsolutePath());
}
}
@Test
public void testErrorCases() throws Exception {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("action", "BADACTION");
String collectionName = "badactioncollection";
params.set("name", collectionName);
QueryRequest request = new QueryRequest(params);
request.setPath("/admin/cores");
expectThrows(SolrException.class, () -> getSolrAdmin().request(request));
}
@Test
public void testInvalidCoreNamesAreRejectedWhenCreatingCore() {
final Create createRequest = new Create();
SolrException e = expectThrows(SolrException.class, () -> createRequest.setCoreName("invalid$core@name"));
final String exceptionMessage = e.getMessage();
assertTrue(exceptionMessage.contains("Invalid core"));
assertTrue(exceptionMessage.contains("invalid$core@name"));
assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics"));
}
@Test
public void testInvalidCoreNamesAreRejectedWhenRenamingExistingCore() throws Exception {
SolrException e = expectThrows(SolrException.class,
() -> CoreAdminRequest.renameCore("validExistingCoreName", "invalid$core@name", null));
final String exceptionMessage = e.getMessage();
assertTrue(e.getMessage(), exceptionMessage.contains("Invalid core"));
assertTrue(exceptionMessage.contains("invalid$core@name"));
assertTrue(exceptionMessage.contains("must consist entirely of periods, underscores, hyphens, and alphanumerics"));
}
@Test
public void testValidCoreRename() throws Exception {
Collection<String> names = cores.getAllCoreNames();
assertFalse(names.toString(), names.contains("coreRenamed"));
assertTrue(names.toString(), names.contains("core1"));
CoreAdminRequest.renameCore("core1", "coreRenamed", getSolrAdmin());
names = cores.getAllCoreNames();
assertTrue(names.toString(), names.contains("coreRenamed"));
assertFalse(names.toString(), names.contains("core1"));
// rename it back
CoreAdminRequest.renameCore("coreRenamed", "core1", getSolrAdmin());
names = cores.getAllCoreNames();
assertFalse(names.toString(), names.contains("coreRenamed"));
assertTrue(names.toString(), names.contains("core1"));
assertEquals(names.size(), cores.getNumAllCores());
}
@Test
public void testCoreSwap() throws Exception {
// index marker docs to core0
SolrClient cli0 = getSolrCore0();
SolrInputDocument d = new SolrInputDocument("id", "core0-0");
cli0.add(d);
d = new SolrInputDocument("id", "core0-1");
cli0.add(d);
cli0.commit();
// index a marker doc to core1
SolrClient cli1 = getSolrCore1();
d = new SolrInputDocument("id", "core1-0");
cli1.add(d);
cli1.commit();
// initial state assertions
SolrQuery q = new SolrQuery("*:*");
QueryResponse rsp = cli0.query(q);
SolrDocumentList docs = rsp.getResults();
assertEquals(2, docs.size());
docs.forEach(doc -> {
assertTrue(doc.toString(), doc.getFieldValue("id").toString().startsWith("core0-"));
});
rsp = cli1.query(q);
docs = rsp.getResults();
assertEquals(1, docs.size());
docs.forEach(doc -> {
assertTrue(doc.toString(), doc.getFieldValue("id").toString().startsWith("core1-"));
});
// assert initial metrics
SolrMetricManager metricManager = cores.getMetricManager();
String core0RegistryName = SolrCoreMetricManager.createRegistryName(false, null, null, null, "core0");
String core1RegistryName = SolrCoreMetricManager.createRegistryName(false, null, null,null, "core1");
MetricRegistry core0Registry = metricManager.registry(core0RegistryName);
MetricRegistry core1Registry = metricManager.registry(core1RegistryName);
// 2 docs + 1 commit
assertEquals(3, core0Registry.counter("UPDATE./update.requests").getCount());
// 1 doc + 1 commit
assertEquals(2, core1Registry.counter("UPDATE./update.requests").getCount());
// swap
CoreAdminRequest.swapCore("core0", "core1", getSolrAdmin());
// assert state after swap
cli0 = getSolrCore0();
cli1 = getSolrCore1();
rsp = cli0.query(q);
docs = rsp.getResults();
assertEquals(1, docs.size());
docs.forEach(doc -> {
assertTrue(doc.toString(), doc.getFieldValue("id").toString().startsWith("core1-"));
});
rsp = cli1.query(q);
docs = rsp.getResults();
assertEquals(2, docs.size());
docs.forEach(doc -> {
assertTrue(doc.toString(), doc.getFieldValue("id").toString().startsWith("core0-"));
});
core0Registry = metricManager.registry(core0RegistryName);
core1Registry = metricManager.registry(core1RegistryName);
assertEquals(2, core0Registry.counter("UPDATE./update.requests").getCount());
assertEquals(3, core1Registry.counter("UPDATE./update.requests").getCount());
}
@Test
public void testInvalidRequestRecovery() throws SolrServerException, IOException {
RequestRecovery recoverRequestCmd = new RequestRecovery();
recoverRequestCmd.setCoreName("non_existing_core");
expectThrows(SolrException.class, () -> recoverRequestCmd.process(getSolrAdmin()));
}
@Test
public void testReloadCoreAfterFailure() throws Exception {
cores.shutdown();
useFactory(null); // use FS factory
try {
cores = CoreContainer.createAndLoad(SOLR_HOME, getSolrXml());
String ddir = CoreAdminRequest.getCoreStatus("core0", getSolrCore0()).getDataDirectory();
Path data = Paths.get(ddir, "index");
assumeTrue("test can't handle relative data directory paths (yet?)", data.isAbsolute());
getSolrCore0().add(new SolrInputDocument("id", "core0-1"));
getSolrCore0().commit();
cores.shutdown();
// destroy the index
Files.move(data.resolve("_0.si"), data.resolve("backup"));
cores = CoreContainer.createAndLoad(SOLR_HOME, getSolrXml());
// Need to run a query to confirm that the core couldn't load
expectThrows(SolrException.class, () -> getSolrCore0().query(new SolrQuery("*:*")));
// We didn't fix anything, so should still throw
expectThrows(SolrException.class, () -> CoreAdminRequest.reloadCore("core0", getSolrCore0()));
Files.move(data.resolve("backup"), data.resolve("_0.si"));
CoreAdminRequest.reloadCore("core0", getSolrCore0());
assertEquals(1, getSolrCore0().query(new SolrQuery("*:*")).getResults().getNumFound());
} finally {
resetFactory();
}
}
@BeforeClass
public static void before() {
// wtf?
if (System.getProperty("tempDir") != null)
tempDirProp = System.getProperty("tempDir");
}
@After
public void after() {
// wtf?
if (tempDirProp != null) {
System.setProperty("tempDir", tempDirProp);
} else {
System.clearProperty("tempDir");
}
System.clearProperty("solr.solr.home");
}
}