/* * 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.cloud; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.solr.cloud.OverseerConfigSetMessageHandler.BASE_CONFIGSET; import static org.apache.solr.common.params.CommonParams.NAME; import static org.apache.solr.core.ConfigSetProperties.DEFAULT_FILENAME; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.StringReader; import java.lang.invoke.MethodHandles; import java.net.URI; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.Deque; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.io.FileUtils; import org.apache.http.HttpEntity; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; import org.apache.lucene.util.TestUtil; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.embedded.JettySolrRunner; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create; import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Delete; import org.apache.solr.client.solrj.request.QueryRequest; import org.apache.solr.client.solrj.response.CollectionAdminResponse; import org.apache.solr.client.solrj.response.ConfigSetAdminResponse; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.cloud.ZkConfigManager; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.CollectionParams.CollectionAction; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.ConfigSetParams; import org.apache.solr.common.params.ConfigSetParams.ConfigSetAction; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.Utils; import org.apache.solr.core.ConfigSetProperties; import org.apache.solr.core.TestDynamicLoading; import org.apache.solr.security.BasicAuthIntegrationTest; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.noggit.JSONParser; import org.noggit.ObjectBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableMap; /** * Simple ConfigSets API tests on user errors and simple success cases. */ public class TestConfigSetsAPI extends SolrTestCaseJ4 { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private MiniSolrCloudCluster solrCluster; @Override @Before public void setUp() throws Exception { super.setUp(); solrCluster = new MiniSolrCloudCluster(1, createTempDir(), buildJettyConfig("/solr")); } @Override @After public void tearDown() throws Exception { solrCluster.shutdown(); super.tearDown(); } @Test public void testCreateErrors() throws Exception { final String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); final SolrClient solrClient = getHttpSolrClient(baseUrl); solrCluster.uploadConfigSet(configset("configset-2"), "configSet"); // no action CreateNoErrorChecking createNoAction = new CreateNoErrorChecking(); createNoAction.setAction(null); verifyException(solrClient, createNoAction, "action"); // no ConfigSet name CreateNoErrorChecking create = new CreateNoErrorChecking(); verifyException(solrClient, create, NAME); // no base ConfigSet name create.setConfigSetName("configSetName"); verifyException(solrClient, create, BASE_CONFIGSET); // ConfigSet already exists Create alreadyExists = new Create(); alreadyExists.setConfigSetName("configSet").setBaseConfigSetName("baseConfigSet"); verifyException(solrClient, alreadyExists, "ConfigSet already exists"); // Base ConfigSet does not exist Create baseConfigNoExists = new Create(); baseConfigNoExists.setConfigSetName("newConfigSet").setBaseConfigSetName("baseConfigSet"); verifyException(solrClient, baseConfigNoExists, "Base ConfigSet does not exist"); solrClient.close(); } @Test public void testCreate() throws Exception { // no old, no new verifyCreate("baseConfigSet1", "configSet1", null, null); // no old, new verifyCreate("baseConfigSet2", "configSet2", null, ImmutableMap.<String, String>of("immutable", "true", "key1", "value1")); // old, no new verifyCreate("baseConfigSet3", "configSet3", ImmutableMap.<String, String>of("immutable", "false", "key2", "value2"), null); // old, new verifyCreate("baseConfigSet4", "configSet4", ImmutableMap.<String, String>of("immutable", "true", "onlyOld", "onlyOldValue"), ImmutableMap.<String, String>of("immutable", "false", "onlyNew", "onlyNewValue")); } private void setupBaseConfigSet(String baseConfigSetName, Map<String, String> oldProps) throws Exception { final File configDir = getFile("solr").toPath().resolve("configsets/configset-2/conf").toFile(); final File tmpConfigDir = createTempDir().toFile(); tmpConfigDir.deleteOnExit(); FileUtils.copyDirectory(configDir, tmpConfigDir); if (oldProps != null) { FileUtils.write(new File(tmpConfigDir, ConfigSetProperties.DEFAULT_FILENAME), getConfigSetProps(oldProps), StandardCharsets.UTF_8); } solrCluster.uploadConfigSet(tmpConfigDir.toPath(), baseConfigSetName); } private void verifyCreate(String baseConfigSetName, String configSetName, Map<String, String> oldProps, Map<String, String> newProps) throws Exception { final String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); final SolrClient solrClient = getHttpSolrClient(baseUrl); setupBaseConfigSet(baseConfigSetName, oldProps); SolrZkClient zkClient = new SolrZkClient(solrCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, AbstractZkTestCase.TIMEOUT, null); try { ZkConfigManager configManager = new ZkConfigManager(zkClient); assertFalse(configManager.configExists(configSetName)); Create create = new Create(); create.setBaseConfigSetName(baseConfigSetName).setConfigSetName(configSetName); if (newProps != null) { Properties p = new Properties(); p.putAll(newProps); create.setNewConfigSetProperties(p); } ConfigSetAdminResponse response = create.process(solrClient); assertNotNull(response.getResponse()); assertTrue(configManager.configExists(configSetName)); verifyProperties(configSetName, oldProps, newProps, zkClient); } finally { zkClient.close(); } solrClient.close(); } private NamedList getConfigSetPropertiesFromZk( SolrZkClient zkClient, String path) throws Exception { byte [] oldPropsData = null; try { oldPropsData = zkClient.getData(path, null, null, true); } catch (KeeperException.NoNodeException e) { // okay, properties just don't exist } if (oldPropsData != null) { InputStreamReader reader = new InputStreamReader(new ByteArrayInputStream(oldPropsData), StandardCharsets.UTF_8); try { return ConfigSetProperties.readFromInputStream(reader); } finally { reader.close(); } } return null; } private void verifyProperties(String configSetName, Map<String, String> oldProps, Map<String, String> newProps, SolrZkClient zkClient) throws Exception { NamedList properties = getConfigSetPropertiesFromZk(zkClient, ZkConfigManager.CONFIGS_ZKNODE + "/" + configSetName + "/" + DEFAULT_FILENAME); // let's check without merging the maps, since that's what the MessageHandler does // (since we'd probably repeat any bug in the MessageHandler here) if (oldProps == null && newProps == null) { assertNull(properties); return; } assertNotNull(properties); // check all oldProps are in props if (oldProps != null) { for (Map.Entry<String, String> entry : oldProps.entrySet()) { assertNotNull(properties.get(entry.getKey())); } } // check all newProps are in props if (newProps != null) { for (Map.Entry<String, String> entry : newProps.entrySet()) { assertNotNull(properties.get(entry.getKey())); } } // check the value in properties are correct Iterator<Map.Entry<String, Object>> it = properties.iterator(); while (it.hasNext()) { Map.Entry<String, Object> entry = it.next(); String newValue = newProps != null ? newProps.get(entry.getKey()) : null; String oldValue = oldProps != null ? oldProps.get(entry.getKey()) : null; if (newValue != null) { assertTrue(newValue.equals(entry.getValue())); } else if (oldValue != null) { assertTrue(oldValue.equals(entry.getValue())); } else { // not in either assert(false); } } } @Test public void testUploadErrors() throws Exception { final SolrClient solrClient = new HttpSolrClient( solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString()); ByteBuffer emptyData = ByteBuffer.allocate(0); // Checking error when no configuration name is specified in request Map map = postDataAndGetResponse(solrCluster.getSolrClient(), solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString() + "/admin/configs?action=UPLOAD&wt=json", emptyData, null, null); assertNotNull(map); long statusCode = (long) getObjectByPath(map, false, Arrays.asList("responseHeader", "status")); assertEquals(400l, statusCode); SolrZkClient zkClient = new SolrZkClient(solrCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, 45000, null); // Create dummy config files in zookeeper zkClient.makePath("/configs/myconf", true); zkClient.create("/configs/myconf/firstDummyFile", "first dummy content".getBytes(StandardCharsets.UTF_8), CreateMode.PERSISTENT, true); zkClient.create("/configs/myconf/anotherDummyFile", "second dummy content".getBytes(StandardCharsets.UTF_8), CreateMode.PERSISTENT, true); // Checking error when configuration name specified already exists map = postDataAndGetResponse(solrCluster.getSolrClient(), solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString() + "/admin/configs?action=UPLOAD&wt=json&name=myconf", emptyData, null, null); assertNotNull(map); statusCode = (long) getObjectByPath(map, false, Arrays.asList("responseHeader", "status")); assertEquals(400l, statusCode); assertTrue("Expected file doesnt exist in zk. It's possibly overwritten", zkClient.exists("/configs/myconf/firstDummyFile", true)); assertTrue("Expected file doesnt exist in zk. It's possibly overwritten", zkClient.exists("/configs/myconf/anotherDummyFile", true)); zkClient.close(); solrClient.close(); } @Test public void testUpload() throws Exception { String suffix = "-untrusted"; uploadConfigSet("regular", suffix, null, null); // try to create a collection with the uploaded configset createCollection("newcollection", "regular" + suffix, 1, 1, solrCluster.getSolrClient()); xsltRequest("newcollection"); } @Test public void testUploadWithRunExecutableListener() throws Exception { String suffix = "-untrusted"; uploadConfigSet("with-run-executable-listener", suffix, null, null); // try to create a collection with the uploaded configset CollectionAdminResponse resp = createCollection("newcollection3", "with-run-executable-listener" + suffix, 1, 1, solrCluster.getSolrClient()); log.info("Client saw errors: "+resp.getErrorMessages()); assertTrue(resp.getErrorMessages() != null && resp.getErrorMessages().size() > 0); assertTrue(resp.getErrorMessages().getVal(0). contains("The configset for this collection was uploaded without any authentication")); } @Test public void testUploadWithScriptUpdateProcessor() throws Exception { for (boolean withAuthorization: Arrays.asList(false, true)) { String suffix; if (withAuthorization) { suffix = "-trusted"; protectConfigsHandler(); uploadConfigSet("with-script-processor", suffix, "solr", "SolrRocks"); } else { suffix = "-untrusted"; uploadConfigSet("with-script-processor", suffix, null, null); } // try to create a collection with the uploaded configset CollectionAdminResponse resp = createCollection("newcollection2", "with-script-processor"+suffix, 1, 1, solrCluster.getSolrClient()); if (withAuthorization) { scriptRequest("newcollection2"); } else { log.info("Client saw errors: "+resp.getErrorMessages()); assertTrue(resp.getErrorMessages() != null && resp.getErrorMessages().size() > 0); assertTrue(resp.getErrorMessages().getVal(0). contains("The configset for this collection was uploaded without any authentication")); } } } protected SolrZkClient zkClient() { ZkStateReader reader = solrCluster.getSolrClient().getZkStateReader(); if (reader == null) solrCluster.getSolrClient().connect(); return solrCluster.getSolrClient().getZkStateReader().getZkClient(); } private void protectConfigsHandler() throws Exception { String authcPrefix = "/admin/authentication"; String authzPrefix = "/admin/authorization"; String securityJson = "{\n" + " 'authentication':{\n" + " 'class':'solr.BasicAuthPlugin',\n" + " 'credentials':{'solr':'orwp2Ghgj39lmnrZOTm7Qtre1VqHFDfwAEzr0ApbN3Y= Ju5osoAqOX8iafhWpPP01E5P+sg8tK8tHON7rCYZRRw='}},\n" + " 'authorization':{\n" + " 'class':'solr.RuleBasedAuthorizationPlugin',\n" + " 'user-role':{'solr':'admin'},\n" + " 'permissions':[{'name':'security-edit','role':'admin'}, {'name':'config-edit','role':'admin'}]}}"; HttpClient cl = null; try { cl = HttpClientUtil.createClient(null); JettySolrRunner randomJetty = solrCluster.getRandomJetty(random()); String baseUrl = randomJetty.getBaseUrl().toString(); zkClient().setData("/security.json", securityJson.replaceAll("'", "\"").getBytes(UTF_8), true); BasicAuthIntegrationTest.verifySecurityStatus(cl, baseUrl + authcPrefix, "authentication/class", "solr.BasicAuthPlugin", 50); BasicAuthIntegrationTest.verifySecurityStatus(cl, baseUrl + authzPrefix, "authorization/class", "solr.RuleBasedAuthorizationPlugin", 50); } finally { if (cl != null) { HttpClientUtil.close(cl); } } Thread.sleep(5000); // TODO: Without a delay, the test fails. Some problem with Authc/Authz framework? } private void uploadConfigSet(String configSetName, String suffix, String username, String password) throws Exception { // Read zipped sample config ByteBuffer sampleZippedConfig = TestDynamicLoading .getFileContent( createTempZipFile("solr/configsets/upload/"+configSetName), false); SolrZkClient zkClient = new SolrZkClient(solrCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, 45000, null); try { ZkConfigManager configManager = new ZkConfigManager(zkClient); assertFalse(configManager.configExists(configSetName+suffix)); Map map = postDataAndGetResponse(solrCluster.getSolrClient(), solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString() + "/admin/configs?action=UPLOAD&wt=json&name="+configSetName+suffix, sampleZippedConfig, username, password); assertNotNull(map); long statusCode = (long) getObjectByPath(map, false, Arrays.asList("responseHeader", "status")); assertEquals(0l, statusCode); assertTrue("managed-schema file should have been uploaded", zkClient.exists("/configs/"+configSetName+suffix+"/managed-schema", true)); assertTrue("managed-schema file contents on zookeeper are not exactly same as that of the file uploaded in config", Arrays.equals(zkClient.getData("/configs/"+configSetName+suffix+"/managed-schema", null, null, true), readFile("solr/configsets/upload/"+configSetName+"/managed-schema"))); assertTrue("solrconfig.xml file should have been uploaded", zkClient.exists("/configs/"+configSetName+suffix+"/solrconfig.xml", true)); byte data[] = zkClient.getData("/configs/"+configSetName+suffix, null, null, true); //assertEquals("{\"trusted\": false}", new String(data, StandardCharsets.UTF_8)); assertTrue("solrconfig.xml file contents on zookeeper are not exactly same as that of the file uploaded in config", Arrays.equals(zkClient.getData("/configs/"+configSetName+suffix+"/solrconfig.xml", null, null, true), readFile("solr/configsets/upload/"+configSetName+"/solrconfig.xml"))); } finally { zkClient.close(); } } /** * Create a zip file (in the temp directory) containing all the files within the specified directory * and return the path for the zip file. */ private String createTempZipFile(String directoryPath) { File zipFile = new File(solrCluster.getBaseDir().toFile().getAbsolutePath() + File.separator + TestUtil.randomSimpleString(random(), 6, 8) + ".zip"); File directory = TestDynamicLoading.getFile(directoryPath); log.info("Directory: "+directory.getAbsolutePath()); try { zip (directory, zipFile); log.info("Zipfile: "+zipFile.getAbsolutePath()); return zipFile.getAbsolutePath(); } catch (IOException e) { throw new RuntimeException(e); } } private static void zip(File directory, File zipfile) throws IOException { URI base = directory.toURI(); Deque<File> queue = new LinkedList<File>(); queue.push(directory); OutputStream out = new FileOutputStream(zipfile); ZipOutputStream zout = new ZipOutputStream(out); try { while (!queue.isEmpty()) { directory = queue.pop(); for (File kid : directory.listFiles()) { String name = base.relativize(kid.toURI()).getPath(); if (kid.isDirectory()) { queue.push(kid); name = name.endsWith("/") ? name : name + "/"; zout.putNextEntry(new ZipEntry(name)); } else { zout.putNextEntry(new ZipEntry(name)); InputStream in = new FileInputStream(kid); try { byte[] buffer = new byte[1024]; while (true) { int readCount = in.read(buffer); if (readCount < 0) { break; } zout.write(buffer, 0, readCount); } } finally { in.close(); } zout.closeEntry(); } } } } finally { zout.close(); } } private void xsltRequest(String collection) throws SolrServerException, IOException { String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); try (HttpSolrClient client = new HttpSolrClient(baseUrl + "/" + collection)) { String xml = "<random>" + " <document>" + " <node name=\"id\" value=\"12345\"/>" + " <node name=\"name\" value=\"kitten\"/>" + " <node name=\"text\" enhance=\"3\" value=\"some other day\"/>" + " <node name=\"title\" enhance=\"4\" value=\"A story\"/>" + " <node name=\"timestamp\" enhance=\"5\" value=\"2011-07-01T10:31:57.140Z\"/>" + " </document>" + "</random>"; SolrQuery query = new SolrQuery(); query.setQuery( "*:*" );//for anything query.add("qt","/update"); query.add(CommonParams.TR, "xsl-update-handler-test.xsl"); query.add("stream.body", xml); query.add("commit", "true"); try { client.query(query); fail("This should've returned a 401."); } catch (SolrException ex) { assertEquals(ErrorCode.UNAUTHORIZED.code, ex.code()); } } } public void scriptRequest(String collection) throws SolrServerException, IOException { SolrClient client = solrCluster.getSolrClient(); SolrInputDocument doc = sdoc("id", "4055", "subject", "Solr"); client.add(collection, doc); client.commit(collection); assertEquals("42", client.query(collection, params("q", "*:*")).getResults().get(0).get("script_added_i")); } protected CollectionAdminResponse createCollection(String collectionName, String confSetName, int numShards, int replicationFactor, SolrClient client) throws SolrServerException, IOException { ModifiableSolrParams params = new ModifiableSolrParams(); params.set("action", CollectionAction.CREATE.toString()); params.set("collection.configName", confSetName); params.set("name", collectionName); params.set("numShards", numShards); params.set("replicationFactor", replicationFactor); SolrRequest request = new QueryRequest(params); request.setPath("/admin/collections"); CollectionAdminResponse res = new CollectionAdminResponse(); res.setResponse(client.request(request)); return res; } public static Map postDataAndGetResponse(CloudSolrClient cloudClient, String uri, ByteBuffer bytarr, String username, String password) throws IOException { HttpPost httpPost = null; HttpEntity entity; String response = null; Map m = null; try { httpPost = new HttpPost(uri); if (username != null) { String userPass = username + ":" + password; String encoded = Base64.byteArrayToBase64(userPass.getBytes(UTF_8)); BasicHeader header = new BasicHeader("Authorization", "Basic " + encoded); httpPost.setHeader(header); } httpPost.setHeader("Content-Type", "application/octet-stream"); httpPost.setEntity(new ByteArrayEntity(bytarr.array(), bytarr .arrayOffset(), bytarr.limit())); entity = cloudClient.getLbClient().getHttpClient().execute(httpPost) .getEntity(); try { response = EntityUtils.toString(entity, StandardCharsets.UTF_8); m = (Map) ObjectBuilder.getVal(new JSONParser( new StringReader(response))); } catch (JSONParser.ParseException e) { fail(e.getMessage()); } } finally { httpPost.releaseConnection(); } return m; } private static Object getObjectByPath(Map root, boolean onlyPrimitive, java.util.List<String> hierarchy) { Map obj = root; for (int i = 0; i < hierarchy.size(); i++) { String s = hierarchy.get(i); if (i < hierarchy.size() - 1) { if (!(obj.get(s) instanceof Map)) return null; obj = (Map) obj.get(s); if (obj == null) return null; } else { Object val = obj.get(s); if (onlyPrimitive && val instanceof Map) { return null; } return val; } } return false; } private byte[] readFile(String fname) throws IOException { byte[] buf = null; try (FileInputStream fis = new FileInputStream(getFile(fname))) { buf = new byte[fis.available()]; fis.read(buf); } return buf; } @Test public void testDeleteErrors() throws Exception { final String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); final SolrClient solrClient = getHttpSolrClient(baseUrl); final File configDir = getFile("solr").toPath().resolve("configsets/configset-2/conf").toFile(); final File tmpConfigDir = createTempDir().toFile(); tmpConfigDir.deleteOnExit(); // Ensure ConfigSet is immutable FileUtils.copyDirectory(configDir, tmpConfigDir); FileUtils.write(new File(tmpConfigDir, "configsetprops.json"), getConfigSetProps(ImmutableMap.<String, String>of("immutable", "true")), StandardCharsets.UTF_8); solrCluster.uploadConfigSet(tmpConfigDir.toPath(), "configSet"); // no ConfigSet name DeleteNoErrorChecking delete = new DeleteNoErrorChecking(); verifyException(solrClient, delete, NAME); // ConfigSet doesn't exist delete.setConfigSetName("configSetBogus"); verifyException(solrClient, delete, "ConfigSet does not exist"); // ConfigSet is immutable delete.setConfigSetName("configSet"); verifyException(solrClient, delete, "Requested delete of immutable ConfigSet"); solrClient.close(); } private void verifyException(SolrClient solrClient, ConfigSetAdminRequest request, String errorContains) throws Exception { try { solrClient.request(request); Assert.fail("Expected exception"); } catch (Exception e) { assertTrue("Expected exception message to contain: " + errorContains + " got: " + e.getMessage(), e.getMessage().contains(errorContains)); } } @Test public void testDelete() throws Exception { final String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); final SolrClient solrClient = getHttpSolrClient(baseUrl); final String configSet = "configSet"; solrCluster.uploadConfigSet(configset("configset-2"), configSet); SolrZkClient zkClient = new SolrZkClient(solrCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, AbstractZkTestCase.TIMEOUT, null); try { ZkConfigManager configManager = new ZkConfigManager(zkClient); assertTrue(configManager.configExists(configSet)); Delete delete = new Delete(); delete.setConfigSetName(configSet); ConfigSetAdminResponse response = delete.process(solrClient); assertNotNull(response.getResponse()); assertFalse(configManager.configExists(configSet)); } finally { zkClient.close(); } solrClient.close(); } @Test public void testList() throws Exception { final String baseUrl = solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString(); final SolrClient solrClient = getHttpSolrClient(baseUrl); SolrZkClient zkClient = new SolrZkClient(solrCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, AbstractZkTestCase.TIMEOUT, null); try { // test empty ConfigSetAdminRequest.List list = new ConfigSetAdminRequest.List(); ConfigSetAdminResponse.List response = list.process(solrClient); Collection<String> actualConfigSets = response.getConfigSets(); assertEquals(0, actualConfigSets.size()); // test multiple Set<String> configSets = new HashSet<String>(); for (int i = 0; i < 5; ++i) { String configSet = "configSet" + i; solrCluster.uploadConfigSet(configset("configset-2"), configSet); configSets.add(configSet); } response = list.process(solrClient); actualConfigSets = response.getConfigSets(); assertEquals(configSets.size(), actualConfigSets.size()); assertTrue(configSets.containsAll(actualConfigSets)); } finally { zkClient.close(); } solrClient.close(); } private StringBuilder getConfigSetProps(Map<String, String> map) { return new StringBuilder(new String(Utils.toJSON(map), StandardCharsets.UTF_8)); } public static class CreateNoErrorChecking extends ConfigSetAdminRequest.Create { public ConfigSetAdminRequest setAction(ConfigSetAction action) { return super.setAction(action); } @Override public SolrParams getParams() { ModifiableSolrParams params = new ModifiableSolrParams(); if (action != null) params.set(ConfigSetParams.ACTION, action.toString()); if (configSetName != null) params.set(NAME, configSetName); if (baseConfigSetName != null) params.set("baseConfigSet", baseConfigSetName); return params; } } public static class DeleteNoErrorChecking extends ConfigSetAdminRequest.Delete { public ConfigSetAdminRequest setAction(ConfigSetAction action) { return super.setAction(action); } @Override public SolrParams getParams() { ModifiableSolrParams params = new ModifiableSolrParams(); if (action != null) params.set(ConfigSetParams.ACTION, action.toString()); if (configSetName != null) params.set(NAME, configSetName); return params; } } }