From da05e9a96a6a06f9d33dd4b6eca78ffda3a2683a Mon Sep 17 00:00:00 2001 From: Noble Paul Date: Thu, 3 Sep 2015 16:39:53 +0000 Subject: [PATCH] SOLR-8006: Test failures in BasicAuthIntegrationTest git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1701066 13f79535-47bb-0310-9956-ffa450edef68 --- .../solr/cloud/TestMiniSolrCloudCluster.java | 4 - .../cloud/TestMiniSolrCloudClusterBase.java | 209 ++++++++++++++++++ .../security/BasicAuthIntegrationTest.java | 32 +-- 3 files changed, 221 insertions(+), 24 deletions(-) create mode 100644 solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java diff --git a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java index 686bca4901e..9e9e06539d3 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java @@ -205,7 +205,6 @@ public class TestMiniSolrCloudCluster extends LuceneTestCase { assertTrue(e.code() >= 500 && e.code() < 600); } - doExtraTests(miniCluster, zkClient, zkStateReader,cloudSolrClient, collectionName); // delete the collection we created earlier miniCluster.deleteCollection(collectionName); AbstractDistribZkTestBase.waitForCollectionToDisappear(collectionName, zkStateReader, true, true, 330); @@ -216,9 +215,6 @@ public class TestMiniSolrCloudCluster extends LuceneTestCase { } } - protected void doExtraTests(MiniSolrCloudCluster miniCluster, SolrZkClient zkClient, ZkStateReader zkStateReader, CloudSolrClient cloudSolrClient, - String defaultCollName) throws Exception { /*do nothing*/ } - @Test public void testErrorsInStartup() throws Exception { diff --git a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java new file mode 100644 index 00000000000..475157e26d8 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java @@ -0,0 +1,209 @@ +package org.apache.solr.cloud; + +/* + * 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. + */ + + +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.client.solrj.SolrQuery; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.embedded.JettyConfig; +import org.apache.solr.client.solrj.embedded.JettySolrRunner; +import org.apache.solr.client.solrj.impl.CloudSolrClient; +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.cloud.ClusterState; +import org.apache.solr.common.cloud.Replica; +import org.apache.solr.common.cloud.Slice; +import org.apache.solr.common.cloud.SolrZkClient; +import org.apache.solr.common.cloud.ZkStateReader; +import org.apache.solr.core.CoreDescriptor; +import org.apache.solr.util.RevertDefaultThreadHandlerRule; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@LuceneTestCase.SuppressSysoutChecks(bugUrl = "Solr logs to JUL") +public class TestMiniSolrCloudClusterBase extends LuceneTestCase { + + private static Logger log = LoggerFactory.getLogger(MiniSolrCloudCluster.class); + protected int NUM_SERVERS = 5; + protected int NUM_SHARDS = 2; + protected int REPLICATION_FACTOR = 2; + + public TestMiniSolrCloudClusterBase () { + NUM_SERVERS = 5; + NUM_SHARDS = 2; + REPLICATION_FACTOR = 2; + } + + @Rule + public TestRule solrTestRules = RuleChain + .outerRule(new SystemPropertiesRestoreRule()); + + @ClassRule + public static TestRule solrClassRules = RuleChain.outerRule( + new SystemPropertiesRestoreRule()).around( + new RevertDefaultThreadHandlerRule()); + + @Test + public void testBasics() throws Exception { + final String collectionName = "testSolrCloudCollection"; + testCollectionCreateSearchDelete(collectionName); + } + + private MiniSolrCloudCluster createMiniSolrCloudCluster() throws Exception { + + File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml"); + JettyConfig.Builder jettyConfig = JettyConfig.builder(); + jettyConfig.waitForLoadingCoresToFinish(null); + MiniSolrCloudCluster miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir().toFile(), solrXml, jettyConfig.build()); + return miniCluster; + } + + private void createCollection(MiniSolrCloudCluster miniCluster, String collectionName, String createNodeSet, String asyncId) throws Exception { + String configName = "solrCloudCollectionConfig"; + File configDir = new File(SolrTestCaseJ4.TEST_HOME() + File.separator + "collection1" + File.separator + "conf"); + miniCluster.uploadConfigDir(configDir, configName); + + Map collectionProperties = new HashMap<>(); + collectionProperties.put(CoreDescriptor.CORE_CONFIG, "solrconfig-tlog.xml"); + collectionProperties.put("solr.tests.maxBufferedDocs", "100000"); + collectionProperties.put("solr.tests.ramBufferSizeMB", "100"); + // use non-test classes so RandomizedRunner isn't necessary + collectionProperties.put("solr.tests.mergePolicy", "org.apache.lucene.index.TieredMergePolicy"); + collectionProperties.put("solr.tests.mergeScheduler", "org.apache.lucene.index.ConcurrentMergeScheduler"); + collectionProperties.put("solr.directoryFactory", "solr.RAMDirectoryFactory"); + + miniCluster.createCollection(collectionName, NUM_SHARDS, REPLICATION_FACTOR, configName, createNodeSet, asyncId, collectionProperties); + } + + protected void testCollectionCreateSearchDelete(String collectionName) throws Exception { + + MiniSolrCloudCluster miniCluster = createMiniSolrCloudCluster(); + + final CloudSolrClient cloudSolrClient = miniCluster.getSolrClient(); + + try { + assertNotNull(miniCluster.getZkServer()); + List jettys = miniCluster.getJettySolrRunners(); + assertEquals(NUM_SERVERS, jettys.size()); + for (JettySolrRunner jetty : jettys) { + assertTrue(jetty.isRunning()); + } + + // shut down a server + JettySolrRunner stoppedServer = miniCluster.stopJettySolrRunner(0); + assertTrue(stoppedServer.isStopped()); + assertEquals(NUM_SERVERS - 1, miniCluster.getJettySolrRunners().size()); + + // create a server + JettySolrRunner startedServer = miniCluster.startJettySolrRunner(); + assertTrue(startedServer.isRunning()); + assertEquals(NUM_SERVERS, miniCluster.getJettySolrRunners().size()); + + // create collection + final String asyncId = (random().nextBoolean() ? null : "asyncId("+collectionName+".create)="+random().nextInt()); + createCollection(miniCluster, collectionName, null, asyncId); + if (asyncId != null) { + assertEquals("did not see async createCollection completion", "completed", AbstractFullDistribZkTestBase.getRequestStateAfterCompletion(asyncId, 330, cloudSolrClient)); + } + + try (SolrZkClient zkClient = new SolrZkClient + (miniCluster.getZkServer().getZkAddress(), AbstractZkTestCase.TIMEOUT, 45000, null); + ZkStateReader zkStateReader = new ZkStateReader(zkClient)) { + AbstractDistribZkTestBase.waitForRecoveriesToFinish(collectionName, zkStateReader, true, true, 330); + + // modify/query collection + cloudSolrClient.setDefaultCollection(collectionName); + SolrInputDocument doc = new SolrInputDocument(); + doc.setField("id", "1"); + cloudSolrClient.add(doc); + cloudSolrClient.commit(); + SolrQuery query = new SolrQuery(); + query.setQuery("*:*"); + QueryResponse rsp = cloudSolrClient.query(query); + assertEquals(1, rsp.getResults().getNumFound()); + + // remove a server not hosting any replicas + zkStateReader.updateClusterState(); + ClusterState clusterState = zkStateReader.getClusterState(); + HashMap jettyMap = new HashMap(); + for (JettySolrRunner jetty : miniCluster.getJettySolrRunners()) { + String key = jetty.getBaseUrl().toString().substring((jetty.getBaseUrl().getProtocol() + "://").length()); + jettyMap.put(key, jetty); + } + Collection slices = clusterState.getSlices(collectionName); + // track the servers not host repliacs + for (Slice slice : slices) { + jettyMap.remove(slice.getLeader().getNodeName().replace("_solr", "/solr")); + for (Replica replica : slice.getReplicas()) { + jettyMap.remove(replica.getNodeName().replace("_solr", "/solr")); + } + } + assertTrue("Expected to find a node without a replica", jettyMap.size() > 0); + JettySolrRunner jettyToStop = jettyMap.entrySet().iterator().next().getValue(); + jettys = miniCluster.getJettySolrRunners(); + for (int i = 0; i < jettys.size(); ++i) { + if (jettys.get(i).equals(jettyToStop)) { + miniCluster.stopJettySolrRunner(i); + assertEquals(NUM_SERVERS - 1, miniCluster.getJettySolrRunners().size()); + } + } + + // now restore the original state so that this function could be called multiple times + + // re-create a server (to restore original NUM_SERVERS count) + startedServer = miniCluster.startJettySolrRunner(); + assertTrue(startedServer.isRunning()); + assertEquals(NUM_SERVERS, miniCluster.getJettySolrRunners().size()); + Thread.sleep(15000); + try { + cloudSolrClient.query(query); + fail("Expected exception on query because collection should not be ready - we have turned on async core loading"); + } catch (SolrServerException e) { + SolrException rc = (SolrException) e.getRootCause(); + assertTrue(rc.code() >= 500 && rc.code() < 600); + } catch (SolrException e) { + assertTrue(e.code() >= 500 && e.code() < 600); + } + + doExtraTests(miniCluster, zkClient, zkStateReader,cloudSolrClient, collectionName); + } + } + finally { + miniCluster.shutdown(); + } + } + + protected void doExtraTests(MiniSolrCloudCluster miniCluster, SolrZkClient zkClient, ZkStateReader zkStateReader, CloudSolrClient cloudSolrClient, + String defaultCollName) throws Exception { /*do nothing*/ } + +} diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java index 38a0030c9ab..409ee8b42f4 100644 --- a/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java @@ -41,7 +41,7 @@ import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.cloud.MiniSolrCloudCluster; -import org.apache.solr.cloud.TestMiniSolrCloudCluster; +import org.apache.solr.cloud.TestMiniSolrCloudClusterBase; import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.cloud.Slice; @@ -62,7 +62,7 @@ import static java.util.Collections.singletonMap; import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP; -public class BasicAuthIntegrationTest extends TestMiniSolrCloudCluster { +public class BasicAuthIntegrationTest extends TestMiniSolrCloudClusterBase { private static final Logger log = LoggerFactory.getLogger(BasicAuthIntegrationTest.class); @@ -164,11 +164,18 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudCluster { } - httpPost = new HttpPost(baseUrl + "/admin/authorization"); + /* httpPost = new HttpPost(baseUrl + "/admin/authorization"); setBasicAuthHeader(httpPost, "harry", "HarryIsUberCool"); httpPost.setEntity(new ByteArrayEntity(Utils.toJSON(singletonMap("delete-permission", "collection-admin-edit")))); - r = cl.execute(httpPost);//cleanup so that the super class does not need to pass on credentials + r = cl.execute(httpPost); //cleanup so that the super class does not need to pass on credentials + for (Slice slice : zkStateReader.getClusterState().getCollection(defaultCollName).getSlices()) { + //ensure that all nodes have removed the collection-admin-edit permission + for (Replica replica : slice.getReplicas()) { + baseUrl = replica.getStr(BASE_URL_PROP); + verifySecurityStatus(cl, baseUrl + "/admin/authorization", "authorization/permissions[2]/name", null, 20); + } + }*/ } public static void verifySecurityStatus(HttpClient cl, String url, String objPath, Object expected, int count) throws Exception { @@ -187,7 +194,7 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudCluster { success = true; break; } - } else if (Objects.equals(String.valueOf(actual), expected)) { + } else if (Objects.equals(actual == null ? null : String.valueOf(actual), expected)) { success = true; break; } @@ -223,21 +230,6 @@ public class BasicAuthIntegrationTest extends TestMiniSolrCloudCluster { } }; - - @Override - public void testErrorsInStartup() throws Exception { - //don't do anything - } - - @Override - public void testErrorsInShutdown() throws Exception { - } - - - @Override - public void testCollectionCreateWithoutCoresThenDelete() throws Exception { - } - //the password is 'SolrRocks' //this could be generated everytime. But , then we will not know if there is any regression private static final String STD_CONF = "{\n" +