You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ro...@apache.org on 2015/10/28 16:43:51 UTC

svn commit: r1711041 - in /lucene/dev/trunk/solr: ./ core/src/test/org/apache/solr/cloud/ core/src/test/org/apache/solr/handler/ core/src/test/org/apache/solr/search/stats/ core/src/test/org/apache/solr/util/ solrj/src/test/org/apache/solr/client/solrj...

Author: romseygeek
Date: Wed Oct 28 15:43:51 2015
New Revision: 1711041

URL: http://svn.apache.org/viewvc?rev=1711041&view=rev
Log:
SOLR-8221: MiniSolrCloudCluster creates subdirectories for its child nodes

Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIExclusivity.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/stats/TestDistribIDF.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestSolrCLIRunExample.java
    lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/impl/TestCloudSolrClientConnections.java
    lucene/dev/trunk/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Wed Oct 28 15:43:51 2015
@@ -396,6 +396,9 @@ Other Changes
 * SOLR-8196: TestMiniSolrCloudCluster.testStopAllStartAll case plus necessary
   MiniSolrCloudCluster tweak (Christine Poerschke)
 
+* SOLR-8221: MiniSolrCloudCluster should create subdirectories for its nodes
+  (Alan Woodward)
+
 ==================  5.3.1 ==================
 
 Bug Fixes

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/ConcurrentDeleteAndCreateCollectionTest.java Wed Oct 28 15:43:51 2015
@@ -43,8 +43,7 @@ public class ConcurrentDeleteAndCreateCo
   @Before
   public void setUp() throws Exception {
     super.setUp();
-    final File solrXml = getFile("solr").toPath().resolve("solr.xml").toFile();
-    solrCluster = new MiniSolrCloudCluster(1, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+    solrCluster = new MiniSolrCloudCluster(1, createTempDir());
   }
   
   @Override

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestAuthenticationFramework.java Wed Oct 28 15:43:51 2015
@@ -84,20 +84,17 @@ public class TestAuthenticationFramework
   }
   
   @Test
-  @Override
   public void testBasics() throws Exception {
 
-    final String collectionName = "testAuthenticationFrameworkCollection";
-
     // Should pass
-    testCollectionCreateSearchDelete(collectionName);
+    testCollectionCreateSearchDelete();
 
     MockAuthenticationPlugin.expectedUsername = "solr";
     MockAuthenticationPlugin.expectedPassword = "s0lrRocks";
     
     // Should fail with 401
     try {
-      testCollectionCreateSearchDelete(collectionName);
+      testCollectionCreateSearchDelete();
       fail("Should've returned a 401 error");
     } catch (Exception ex) {
       if (!ex.getMessage().contains("Error 401")) {

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java Wed Oct 28 15:43:51 2015
@@ -17,7 +17,6 @@
 
 package org.apache.solr.cloud;
 
-import com.google.common.collect.ImmutableMap;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.InputStreamReader;
@@ -29,6 +28,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
@@ -48,11 +48,11 @@ import org.apache.solr.common.util.Named
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.ConfigSetProperties;
 import org.apache.zookeeper.KeeperException;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+
 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;
@@ -68,8 +68,7 @@ public class TestConfigSetsAPI extends S
   @Before
   public void setUp() throws Exception {
     super.setUp();
-    final File solrXml = getFile("solr").toPath().resolve("solr.xml").toFile();
-    solrCluster = new MiniSolrCloudCluster(1, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+    solrCluster = new MiniSolrCloudCluster(1, createTempDir(), buildJettyConfig("/solr"));
   }
 
   @Override

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIExclusivity.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIExclusivity.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIExclusivity.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIExclusivity.java Wed Oct 28 15:43:51 2015
@@ -56,10 +56,7 @@ public class TestConfigSetsAPIExclusivit
   @Before
   public void setUp() throws Exception {
     super.setUp();
-    final File solrXml = getFile("solr").toPath().resolve("solr.xml").toFile();
-    final File testDir = createTempDir().toFile();
-    solrCluster = new MiniSolrCloudCluster(1, testDir,
-        solrXml, buildJettyConfig("/solr"));
+    solrCluster = new MiniSolrCloudCluster(1, createTempDir(), buildJettyConfig("/solr"));
   }
 
   @Override

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPIZkFailure.java Wed Oct 28 15:43:51 2015
@@ -17,11 +17,11 @@
 
 package org.apache.solr.cloud;
 
-import com.google.common.collect.ImmutableMap;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import com.google.common.collect.ImmutableMap;
 import org.apache.commons.io.FileUtils;
 import org.apache.jute.InputArchive;
 import org.apache.jute.OutputArchive;
@@ -40,7 +41,6 @@ import org.apache.solr.client.solrj.impl
 import org.apache.solr.client.solrj.impl.HttpSolrClient.RemoteSolrException;
 import org.apache.solr.client.solrj.request.ConfigSetAdminRequest.Create;
 import org.apache.solr.client.solrj.response.ConfigSetAdminResponse;
-import org.apache.solr.cloud.ZkTestServer;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkConfigManager;
@@ -51,15 +51,14 @@ import org.apache.zookeeper.KeeperExcept
 import org.apache.zookeeper.Watcher;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
-import org.apache.zookeeper.server.quorum.Leader.Proposal;
 import org.apache.zookeeper.server.DataNode;
 import org.apache.zookeeper.server.DataTree;
 import org.apache.zookeeper.server.DataTree.ProcessTxnResult;
 import org.apache.zookeeper.server.Request;
 import org.apache.zookeeper.server.ServerCnxn;
 import org.apache.zookeeper.server.ZKDatabase;
+import org.apache.zookeeper.server.quorum.Leader.Proposal;
 import org.apache.zookeeper.txn.TxnHeader;
-
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -82,16 +81,13 @@ public class TestConfigSetsAPIZkFailure
   @Before
   public void setUp() throws Exception {
     super.setUp();
-    final File solrXml = getFile("solr").toPath().resolve("solr.xml").toFile();
-    final File testDir = createTempDir().toFile();
-    String zkDir = testDir.getAbsolutePath() + File.separator
-      + "zookeeper/server1/data";
+    final Path testDir = createTempDir();
+    String zkDir = testDir.resolve("zookeeper/server1/data").toString();
     zkTestServer = new ZkTestServer(zkDir);
     zkTestServer.run();
-    zkTestServer.setZKDatabase(
-        new FailureDuringCopyZKDatabase(zkTestServer.getZKDatabase(), zkTestServer));
+    zkTestServer.setZKDatabase(new FailureDuringCopyZKDatabase(zkTestServer.getZKDatabase(), zkTestServer));
     solrCluster = new MiniSolrCloudCluster(1, testDir,
-        solrXml, buildJettyConfig("/solr"), zkTestServer);
+        MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML, buildJettyConfig("/solr"), zkTestServer);
   }
 
   @Override

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudCluster.java Wed Oct 28 15:43:51 2015
@@ -34,13 +34,11 @@ import org.apache.lucene.util.LuceneTest
 import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks;
 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.JettyConfig.Builder;
 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;
@@ -84,33 +82,11 @@ public class TestMiniSolrCloudCluster ex
   public static TestRule solrClassRules = RuleChain.outerRule(
       new SystemPropertiesRestoreRule()).around(
       new RevertDefaultThreadHandlerRule());
-
-  @Test
-  public void testBasics() throws Exception {
-    final String collectionName = "testSolrCloudCollection";
-    testCollectionCreateSearchDelete(collectionName);
-    // sometimes run a second test e.g. to test collection create-delete-create scenario
-    if (random().nextBoolean()) testCollectionCreateSearchDelete(collectionName);
-  }
   
   private MiniSolrCloudCluster createMiniSolrCloudCluster() throws Exception {
-    return createMiniSolrCloudCluster(false);
-  }
-
-  private MiniSolrCloudCluster createMiniSolrCloudCluster(boolean multipleBaseDirs) throws Exception {
-
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
     Builder jettyConfig = JettyConfig.builder();
     jettyConfig.waitForLoadingCoresToFinish(null);
-    if (multipleBaseDirs) {
-      final File baseDirs[] = new File[NUM_SERVERS];
-      for (int ii = 0; ii < NUM_SERVERS; ++ii) {
-        baseDirs[ii] = createTempDir().toFile();
-      }
-      return new MiniSolrCloudCluster(baseDirs, solrXml, jettyConfig.build(), null);
-    } else {
-      return new MiniSolrCloudCluster(NUM_SERVERS, createTempDir().toFile(), solrXml, jettyConfig.build());
-    }
+    return new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), jettyConfig.build());
   }
     
   private void createCollection(MiniSolrCloudCluster miniCluster, String collectionName, String createNodeSet, String asyncId, boolean persistIndex) throws Exception {
@@ -129,9 +105,11 @@ public class TestMiniSolrCloudCluster ex
     
     miniCluster.createCollection(collectionName, NUM_SHARDS, REPLICATION_FACTOR, configName, createNodeSet, asyncId, collectionProperties);
   }
-  
-  protected void testCollectionCreateSearchDelete(String collectionName) throws Exception {
 
+  @Test
+  public void testCollectionCreateSearchDelete() throws Exception {
+
+    final String collectionName = "testcollection";
     MiniSolrCloudCluster miniCluster = createMiniSolrCloudCluster();
 
     final CloudSolrClient cloudSolrClient = miniCluster.getSolrClient();
@@ -145,85 +123,92 @@ public class TestMiniSolrCloudCluster ex
       }
 
       // shut down a server
+      log.info("#### Stopping a server");
       JettySolrRunner stoppedServer = miniCluster.stopJettySolrRunner(0);
       assertTrue(stoppedServer.isStopped());
       assertEquals(NUM_SERVERS - 1, miniCluster.getJettySolrRunners().size());
 
       // create a server
+      log.info("#### Starting a server");
       JettySolrRunner startedServer = miniCluster.startJettySolrRunner();
       assertTrue(startedServer.isRunning());
       assertEquals(NUM_SERVERS, miniCluster.getJettySolrRunners().size());
 
       // create collection
+      log.info("#### Creating a collection");
       final String asyncId = (random().nextBoolean() ? null : "asyncId("+collectionName+".create)="+random().nextInt());
       createCollection(miniCluster, collectionName, null, asyncId, random().nextBoolean());
       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);
+      ZkStateReader zkStateReader = miniCluster.getSolrClient().getZkStateReader();
+      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<String, JettySolrRunner> jettyMap = new HashMap<String, JettySolrRunner>();
-        for (JettySolrRunner jetty : miniCluster.getJettySolrRunners()) {
-          String key = jetty.getBaseUrl().toString().substring((jetty.getBaseUrl().getProtocol() + "://").length());
-          jettyMap.put(key, jetty);
-        }
-        Collection<Slice> 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"));
-          }
+      // modify/query collection
+      log.info("#### updating a querying 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<String, JettySolrRunner> jettyMap = new HashMap<String, JettySolrRunner>();
+      for (JettySolrRunner jetty : miniCluster.getJettySolrRunners()) {
+        String key = jetty.getBaseUrl().toString().substring((jetty.getBaseUrl().getProtocol() + "://").length());
+        jettyMap.put(key, jetty);
+      }
+      Collection<Slice> 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());
-          }
+      }
+      assertTrue("Expected to find a node without a replica", jettyMap.size() > 0);
+      log.info("#### Stopping a server");
+      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);
-        }
+      // re-create a server (to restore original NUM_SERVERS count)
+      log.info("#### Starting a server");
+      startedServer = miniCluster.startJettySolrRunner(jettyToStop);
+      assertTrue(startedServer.isRunning());
+      assertEquals(NUM_SERVERS, miniCluster.getJettySolrRunners().size());
 
-        // delete the collection we created earlier
-        miniCluster.deleteCollection(collectionName);
-        AbstractDistribZkTestBase.waitForCollectionToDisappear(collectionName, zkStateReader, true, true, 330);
+
+      // delete the collection we created earlier
+      miniCluster.deleteCollection(collectionName);
+      AbstractDistribZkTestBase.waitForCollectionToDisappear(collectionName, zkStateReader, true, true, 330);
+
+      // create it again
+      String asyncId2 = (random().nextBoolean() ? null : "asyncId("+collectionName+".create)="+random().nextInt());
+      createCollection(miniCluster, collectionName, null, asyncId2, random().nextBoolean());
+      if (asyncId2 != null) {
+        assertEquals("did not see async createCollection completion", "completed", AbstractFullDistribZkTestBase.getRequestStateAfterCompletion(asyncId2, 330, cloudSolrClient));
       }
+      AbstractDistribZkTestBase.waitForRecoveriesToFinish(collectionName, zkStateReader, true, true, 330);
+
+      // check that there's no left-over state
+      assertEquals(0, cloudSolrClient.query(new SolrQuery("*:*")).getResults().getNumFound());
+      cloudSolrClient.add(doc);
+      cloudSolrClient.commit();
+      assertEquals(1, cloudSolrClient.query(new SolrQuery("*:*")).getResults().getNumFound());
+
     }
     finally {
       miniCluster.shutdown();
@@ -233,16 +218,15 @@ public class TestMiniSolrCloudCluster ex
   @Test
   public void testErrorsInStartup() throws Exception {
 
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
     AtomicInteger jettyIndex = new AtomicInteger();
 
     MiniSolrCloudCluster cluster = null;
     try {
-      cluster = new MiniSolrCloudCluster(3, createTempDir().toFile(), solrXml, JettyConfig.builder().build()) {
+      cluster = new MiniSolrCloudCluster(3, createTempDir(), JettyConfig.builder().build()) {
         @Override
-        public JettySolrRunner startJettySolrRunner(JettyConfig config) throws Exception {
+        public JettySolrRunner startJettySolrRunner(String name, String context, JettyConfig config) throws Exception {
           if (jettyIndex.incrementAndGet() != 2)
-            return super.startJettySolrRunner(config);
+            return super.startJettySolrRunner(name, context, config);
           throw new IOException("Fake exception on startup!");
         }
       };
@@ -262,10 +246,9 @@ public class TestMiniSolrCloudCluster ex
   @Test
   public void testErrorsInShutdown() throws Exception {
 
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
     AtomicInteger jettyIndex = new AtomicInteger();
 
-    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(3, createTempDir().toFile(), solrXml, JettyConfig.builder().build()) {
+    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(3, createTempDir(), JettyConfig.builder().build()) {
         @Override
         protected JettySolrRunner stopJettySolrRunner(JettySolrRunner jetty) throws Exception {
           JettySolrRunner j = super.stopJettySolrRunner(jetty);
@@ -288,12 +271,11 @@ public class TestMiniSolrCloudCluster ex
   }
 
   @Test
-  public void testExraFilters() throws Exception {
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
+  public void testExtraFilters() throws Exception {
     Builder jettyConfig = JettyConfig.builder();
     jettyConfig.waitForLoadingCoresToFinish(null);
     jettyConfig.withFilter(JettySolrRunner.DebugFilter.class, "*");
-    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir().toFile(), solrXml, jettyConfig.build());
+    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), jettyConfig.build());
     cluster.shutdown();
   }
 
@@ -346,7 +328,7 @@ public class TestMiniSolrCloudCluster ex
 
     final String collectionName = "testStopAllStartAllCollection";
 
-    final MiniSolrCloudCluster miniCluster = createMiniSolrCloudCluster(true);
+    final MiniSolrCloudCluster miniCluster = createMiniSolrCloudCluster();
 
     try {
       assertNotNull(miniCluster.getZkServer());

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterBase.java Wed Oct 28 15:43:51 2015
@@ -28,12 +28,10 @@ import com.carrotsearch.randomizedtestin
 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;
@@ -80,12 +78,9 @@ public class TestMiniSolrCloudClusterBas
   }
 
   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;
+    return new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), jettyConfig.build());
   }
 
   private void createCollection(MiniSolrCloudCluster miniCluster, String collectionName, String createNodeSet, String asyncId) throws Exception {
@@ -184,16 +179,6 @@ public class TestMiniSolrCloudClusterBas
         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);
       }

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterKerberos.java Wed Oct 28 15:43:51 2015
@@ -131,11 +131,8 @@ public class TestMiniSolrCloudClusterKer
   @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")
   @Test
   @Override
-  public void testBasics() throws Exception {
-    final String collectionName = "testSolrCloudCollectionKerberos";
-    testCollectionCreateSearchDelete(collectionName);
-    // sometimes run a second test e.g. to test collection create-delete-create scenario
-    if (random().nextBoolean()) testCollectionCreateSearchDelete(collectionName);
+  public void testCollectionCreateSearchDelete() throws Exception {
+    super.testCollectionCreateSearchDelete();
   }
 
   @AwaitsFix(bugUrl="https://issues.apache.org/jira/browse/HADOOP-9893")

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java Wed Oct 28 15:43:51 2015
@@ -17,7 +17,10 @@ package org.apache.solr.cloud;
  * limitations under the License.
  */
 
+import java.util.List;
+
 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.HttpSolrClient;
 import org.apache.solr.client.solrj.request.CoreAdminRequest;
@@ -26,9 +29,6 @@ import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import java.io.File;
-import java.util.List;
-
 /**
  * Tests SSL (if test framework selects it) with MiniSolrCloudCluster.
  * {@link TestMiniSolrCloudCluster} does not inherit from {@link SolrTestCaseJ4}
@@ -41,9 +41,8 @@ public class TestMiniSolrCloudClusterSSL
 
   @BeforeClass
   public static void startup() throws Exception {
-    String testHome = SolrTestCaseJ4.TEST_HOME();
-    miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, null, createTempDir().toFile(), new File(testHome, "solr-no-core.xml"),
-      null, null, sslConfig);
+    JettyConfig config = JettyConfig.builder().withSSLConfig(sslConfig).build();
+    miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir(), config);
   }
 
   @AfterClass
@@ -65,7 +64,7 @@ public class TestMiniSolrCloudClusterSSL
     assertEquals(NUM_SERVERS - 1, miniCluster.getJettySolrRunners().size());
 
     // create a new server
-    JettySolrRunner startedServer = miniCluster.startJettySolrRunner(null, null, null, sslConfig);
+    JettySolrRunner startedServer = miniCluster.startJettySolrRunner();
     assertTrue(startedServer.isRunning());
     assertEquals(NUM_SERVERS, miniCluster.getJettySolrRunners().size());
 

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java Wed Oct 28 15:43:51 2015
@@ -157,9 +157,8 @@ public class TestSolrCloudWithKerberosAl
   protected void testCollectionCreateSearchDelete() throws Exception {
     HttpClientUtil.setConfigurer(new Krb5HttpClientConfigurer());
     String collectionName = "testkerberoscollection";
-    
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
-    MiniSolrCloudCluster miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, null, createTempDir().toFile(), solrXml, null, null);
+
+    MiniSolrCloudCluster miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir());
     CloudSolrClient cloudSolrClient = miniCluster.getSolrClient();
     cloudSolrClient.setDefaultCollection(collectionName);
     

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/PingRequestHandlerTest.java Wed Oct 28 15:43:51 2015
@@ -174,9 +174,8 @@ public class PingRequestHandlerTest exte
   }
 
  public void testPingInClusterWithNoHealthCheck() throws Exception {
-   
-    File solrXml = new File(SolrTestCaseJ4.TEST_HOME(), "solr-no-core.xml");
-    MiniSolrCloudCluster miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+
+    MiniSolrCloudCluster miniCluster = new MiniSolrCloudCluster(NUM_SERVERS, createTempDir());
 
     final CloudSolrClient cloudSolrClient = miniCluster.getSolrClient();
 

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/stats/TestDistribIDF.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/stats/TestDistribIDF.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/stats/TestDistribIDF.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/stats/TestDistribIDF.java Wed Oct 28 15:43:51 2015
@@ -52,8 +52,7 @@ public class TestDistribIDF extends Solr
     }
 
     super.setUp();
-    final File solrXml = getFile("solr").toPath().resolve("solr-no-core.xml").toFile();
-    solrCluster = new MiniSolrCloudCluster(3, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+    solrCluster = new MiniSolrCloudCluster(3, createTempDir());
     // set some system properties for use by tests
     System.setProperty("solr.test.sys.prop1", "propone");
     System.setProperty("solr.test.sys.prop2", "proptwo");

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestSolrCLIRunExample.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestSolrCLIRunExample.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestSolrCLIRunExample.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestSolrCLIRunExample.java Wed Oct 28 15:43:51 2015
@@ -25,8 +25,11 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.net.ServerSocket;
+import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -95,9 +98,9 @@ public class TestSolrCLIRunExample exten
           if (!hasFlag("-cloud", args) && !hasFlag("-c", args))
             return startStandaloneSolr(args);
 
-          File baseDir = createTempDir().toFile();
-          File solrHomeDir = new File(getArg("-s", args));
+          String solrHomeDir = getArg("-s", args);
           int port = Integer.parseInt(getArg("-p", args));
+          String solrxml = new String(Files.readAllBytes(Paths.get(solrHomeDir).resolve("solr.xml")), Charset.defaultCharset());
 
           JettyConfig jettyConfig =
               JettyConfig.builder().setContext("/solr").setPort(port).build();
@@ -106,7 +109,7 @@ public class TestSolrCLIRunExample exten
               System.setProperty("host", "localhost");
               System.setProperty("jetty.port", String.valueOf(port));
               solrCloudCluster =
-                  new MiniSolrCloudCluster(1, baseDir, new File(solrHomeDir, "solr.xml"), jettyConfig);
+                  new MiniSolrCloudCluster(1, createTempDir(), solrxml, jettyConfig);
             } else {
               // another member of this cluster -- not supported yet, due to how MiniSolrCloudCluster works
               throw new IllegalArgumentException("Only launching one SolrCloud node is supported by this test!");

Modified: lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/impl/TestCloudSolrClientConnections.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/impl/TestCloudSolrClientConnections.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/impl/TestCloudSolrClientConnections.java (original)
+++ lucene/dev/trunk/solr/solrj/src/test/org/apache/solr/client/solrj/impl/TestCloudSolrClientConnections.java Wed Oct 28 15:43:51 2015
@@ -17,6 +17,9 @@ package org.apache.solr.client.solrj.imp
  * limitations under the License.
  */
 
+import java.nio.file.Path;
+import java.util.concurrent.TimeUnit;
+
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.cloud.MiniSolrCloudCluster;
@@ -24,19 +27,13 @@ import org.apache.solr.common.SolrExcept
 import org.apache.solr.common.cloud.ZkConfigManager;
 import org.junit.Test;
 
-import java.io.File;
-import java.nio.file.Path;
-import java.util.concurrent.TimeUnit;
-
 public class TestCloudSolrClientConnections extends SolrTestCaseJ4 {
 
   @Test
   public void testCloudClientCanConnectAfterClusterComesUp() throws Exception {
 
     // Start by creating a cluster with no jetties
-
-    File solrXml = getFile("solrj").toPath().resolve("solr/solr.xml").toFile();
-    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(0, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(0, createTempDir());
     try {
 
       CloudSolrClient client = cluster.getSolrClient();
@@ -66,10 +63,9 @@ public class TestCloudSolrClientConnecti
   @Test
   public void testCloudClientUploads() throws Exception {
 
-    File solrXml = getFile("solrj").toPath().resolve("solr/solr.xml").toFile();
     Path configPath = getFile("solrj").toPath().resolve("solr/configsets/configset-2/conf");
 
-    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(0, createTempDir().toFile(), solrXml, buildJettyConfig("/solr"));
+    MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(0, createTempDir());
     try {
       CloudSolrClient client = cluster.getSolrClient();
       try {

Modified: lucene/dev/trunk/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java?rev=1711041&r1=1711040&r2=1711041&view=diff
==============================================================================
--- lucene/dev/trunk/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java (original)
+++ lucene/dev/trunk/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java Wed Oct 28 15:43:51 2015
@@ -17,6 +17,26 @@ package org.apache.solr.cloud;
  * limitations under the License.
  */
 
+import javax.servlet.Filter;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
 import com.google.common.base.Charsets;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettyConfig;
@@ -36,43 +56,75 @@ import org.apache.solr.common.util.Named
 import org.apache.solr.common.util.SolrjNamedThreadFactory;
 import org.apache.zookeeper.KeeperException;
 import org.eclipse.jetty.servlet.ServletHolder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.servlet.Filter;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
 
 /**
  * "Mini" SolrCloud cluster to be used for testing
  */
 public class MiniSolrCloudCluster {
   
-  private static Logger log = LoggerFactory.getLogger(MiniSolrCloudCluster.class);
+  public static final String DEFAULT_CLOUD_SOLR_XML = "<solr>\n" +
+      "\n" +
+      "  <str name=\"shareSchema\">${shareSchema:false}</str>\n" +
+      "  <str name=\"configSetBaseDir\">${configSetBaseDir:configsets}</str>\n" +
+      "  <str name=\"coreRootDirectory\">${coreRootDirectory:.}</str>\n" +
+      "\n" +
+      "  <shardHandlerFactory name=\"shardHandlerFactory\" class=\"HttpShardHandlerFactory\">\n" +
+      "    <str name=\"urlScheme\">${urlScheme:}</str>\n" +
+      "    <int name=\"socketTimeout\">${socketTimeout:90000}</int>\n" +
+      "    <int name=\"connTimeout\">${connTimeout:15000}</int>\n" +
+      "  </shardHandlerFactory>\n" +
+      "\n" +
+      "  <solrcloud>\n" +
+      "    <str name=\"host\">127.0.0.1</str>\n" +
+      "    <int name=\"hostPort\">${hostPort:8983}</int>\n" +
+      "    <str name=\"hostContext\">${hostContext:solr}</str>\n" +
+      "    <int name=\"zkClientTimeout\">${solr.zkclienttimeout:30000}</int>\n" +
+      "    <bool name=\"genericCoreNodeNames\">${genericCoreNodeNames:true}</bool>\n" +
+      "    <int name=\"leaderVoteWait\">10000</int>\n" +
+      "    <int name=\"distribUpdateConnTimeout\">${distribUpdateConnTimeout:45000}</int>\n" +
+      "    <int name=\"distribUpdateSoTimeout\">${distribUpdateSoTimeout:340000}</int>\n" +
+      "  </solrcloud>\n" +
+      "  \n" +
+      "</solr>\n";
+
+  public static final JettyConfig DEFAULT_JETTY_CONFIG = JettyConfig.builder().setContext("/solr").build();
 
   private final ZkTestServer zkServer;
   private final boolean externalZkServer;
   private final List<JettySolrRunner> jettys = new LinkedList<>();
-  private final File testDir;
-  private final File testDirs[];
+  private final Path baseDir;
   private final CloudSolrClient solrClient;
   private final JettyConfig jettyConfig;
 
   private final ExecutorService executor = ExecutorUtil.newMDCAwareCachedThreadPool(new SolrjNamedThreadFactory("jetty-launcher"));
 
+  private final AtomicInteger nodeIds = new AtomicInteger();
+
+  /**
+   * Create a MiniSolrCloudCluster with default configuration
+   *
+   * @param numServers number of Solr servers to start
+   * @param baseDir base directory that the mini cluster should be run from
+   *
+   * @throws Exception if there was an error starting the cluster
+   */
+  public MiniSolrCloudCluster(int numServers, Path baseDir) throws Exception {
+    this(numServers, baseDir, DEFAULT_CLOUD_SOLR_XML, DEFAULT_JETTY_CONFIG, null);
+  }
+
+  /**
+   * Create a MiniSolrCloudCluster with default solr.xml
+   *
+   * @param numServers number of Solr servers to start
+   * @param baseDir base directory that the mini cluster should be run from
+   * @param jettyConfig Jetty configuration
+   *
+   * @throws Exception if there was an error starting the cluster
+   */
+  public MiniSolrCloudCluster(int numServers, Path baseDir, JettyConfig jettyConfig) throws Exception {
+    this(numServers, baseDir, DEFAULT_CLOUD_SOLR_XML, jettyConfig, null);
+  }
+
   /**
    * Create a MiniSolrCloudCluster
    *
@@ -85,7 +137,7 @@ public class MiniSolrCloudCluster {
    *
    * @throws Exception if there was an error starting the cluster
    */
-  public MiniSolrCloudCluster(int numServers, String hostContext, File baseDir, File solrXml,
+  public MiniSolrCloudCluster(int numServers, String hostContext, Path baseDir, String solrXml,
       SortedMap<ServletHolder, String> extraServlets,
       SortedMap<Class<? extends Filter>, String> extraRequestFilters) throws Exception {
     this(numServers, hostContext, baseDir, solrXml, extraServlets, extraRequestFilters, null);
@@ -104,7 +156,7 @@ public class MiniSolrCloudCluster {
    *
    * @throws Exception if there was an error starting the cluster
    */
-  public MiniSolrCloudCluster(int numServers, String hostContext, File baseDir, File solrXml,
+  public MiniSolrCloudCluster(int numServers, String hostContext, Path baseDir, String solrXml,
       SortedMap<ServletHolder, String> extraServlets,
       SortedMap<Class<? extends Filter>, String> extraRequestFilters,
       SSLConfig sslConfig) throws Exception {
@@ -126,7 +178,7 @@ public class MiniSolrCloudCluster {
    *
    * @throws Exception if there was an error starting the cluster
    */
-  public MiniSolrCloudCluster(int numServers, File baseDir, File solrXml, JettyConfig jettyConfig) throws Exception {
+  public MiniSolrCloudCluster(int numServers, Path baseDir, String solrXml, JettyConfig jettyConfig) throws Exception {
     this(numServers, baseDir, solrXml, jettyConfig, null);
   }
 
@@ -141,24 +193,16 @@ public class MiniSolrCloudCluster {
    *
    * @throws Exception if there was an error starting the cluster
    */
-  public MiniSolrCloudCluster(int numServers, File baseDir, File solrXml, JettyConfig jettyConfig, ZkTestServer zkTestServer) throws Exception {
-    this(numServers, baseDir, null, solrXml, jettyConfig, zkTestServer);
-  }
-
-  public MiniSolrCloudCluster(File[] baseDirs, File solrXml, JettyConfig jettyConfig, ZkTestServer zkTestServer) throws Exception {
-    this(baseDirs.length, null, baseDirs, solrXml, jettyConfig, zkTestServer);
-  }
-
-  private MiniSolrCloudCluster(int numServers, File baseDir, File[] baseDirs, File solrXml, JettyConfig jettyConfig, ZkTestServer zkTestServer) throws Exception {
+  public MiniSolrCloudCluster(int numServers, Path baseDir, String solrXml, JettyConfig jettyConfig, ZkTestServer zkTestServer) throws Exception {
 
-    this.testDir = baseDir;
-    this.testDirs = baseDirs;
+    this.baseDir = baseDir;
     this.jettyConfig = jettyConfig;
 
+    Files.createDirectories(baseDir);
+
     this.externalZkServer = zkTestServer != null;
     if (!externalZkServer) {
-      String zkDir = (testDir != null ? testDir : testDirs[0]).getAbsolutePath() + File.separator
-        + "zookeeper/server1/data";
+      String zkDir = baseDir.resolve("zookeeper/server1/data").toString();
       zkTestServer = new ZkTestServer(zkDir);
       zkTestServer.run();
     }
@@ -166,7 +210,7 @@ public class MiniSolrCloudCluster {
 
     try(SolrZkClient zkClient = new SolrZkClient(zkServer.getZkHost(),
         AbstractZkTestCase.TIMEOUT, 45000, null)) {
-      zkClient.makePath("/solr/solr.xml", solrXml, false, true);
+      zkClient.makePath("/solr/solr.xml", solrXml.getBytes(Charset.defaultCharset()), true);
       if (jettyConfig.sslConfig != null && jettyConfig.sslConfig.isSSLMode()) {
         zkClient.makePath("/solr" + ZkStateReader.CLUSTER_PROPS, "{'urlScheme':'https'}".getBytes(Charsets.UTF_8), true);
       }
@@ -177,14 +221,10 @@ public class MiniSolrCloudCluster {
 
     List<Callable<JettySolrRunner>> startups = new ArrayList<>(numServers);
     for (int i = 0; i < numServers; ++i) {
-      final Integer testDirsIdx = new Integer(i);
       startups.add(new Callable<JettySolrRunner>() {
         @Override
         public JettySolrRunner call() throws Exception {
-          if (testDir != null)
-            return startJettySolrRunner(jettyConfig);
-          else
-            return startJettySolrRunner(testDirsIdx, jettyConfig.context, jettyConfig);
+          return startJettySolrRunner(newNodeName(), jettyConfig.context, jettyConfig);
         }
       });
     }
@@ -227,6 +267,16 @@ public class MiniSolrCloudCluster {
     solrClient = buildSolrClient();
   }
 
+  private String newNodeName() {
+    return "node" + nodeIds.incrementAndGet();
+  }
+
+  private Path createInstancePath(String name) throws IOException {
+    Path instancePath = baseDir.resolve(name);
+    Files.createDirectory(instancePath);
+    return instancePath;
+  }
+
   /**
    * @return ZooKeeper server used by the MiniCluster
    */
@@ -251,10 +301,10 @@ public class MiniSolrCloudCluster {
    * @return new Solr instance
    *
    */
-  public JettySolrRunner startJettySolrRunner(String hostContext,
+  public JettySolrRunner startJettySolrRunner(String name, String hostContext,
       SortedMap<ServletHolder, String> extraServlets,
       SortedMap<Class<? extends Filter>, String> extraRequestFilters) throws Exception {
-    return startJettySolrRunner(hostContext, extraServlets, extraRequestFilters, null);
+    return startJettySolrRunner(name, hostContext, extraServlets, extraRequestFilters, null);
   }
 
   /**
@@ -267,10 +317,10 @@ public class MiniSolrCloudCluster {
    *
    * @return new Solr instance
    */
-  public JettySolrRunner startJettySolrRunner(String hostContext,
+  public JettySolrRunner startJettySolrRunner(String name, String hostContext,
       SortedMap<ServletHolder, String> extraServlets,
       SortedMap<Class<? extends Filter>, String> extraRequestFilters, SSLConfig sslConfig) throws Exception {
-    return startJettySolrRunner(hostContext, JettyConfig.builder()
+    return startJettySolrRunner(name, hostContext, JettyConfig.builder()
         .withServlets(extraServlets)
         .withFilters(extraRequestFilters)
         .withSSLConfig(sslConfig)
@@ -278,31 +328,19 @@ public class MiniSolrCloudCluster {
   }
 
   /**
-   * Start a new Solr instance
-   *
-   * @param config a JettyConfig for the instance's {@link org.apache.solr.client.solrj.embedded.JettySolrRunner}
-   *
-   * @return a JettySolrRunner
-   */
-  public JettySolrRunner startJettySolrRunner(JettyConfig config) throws Exception {
-    return startJettySolrRunner(config.context, config);
-  }
-
-  /**
    * Start a new Solr instance on a particular servlet context
    *
+   * @param name the instance name
    * @param hostContext the context to run on
    * @param config a JettyConfig for the instance's {@link org.apache.solr.client.solrj.embedded.JettySolrRunner}
    *
    * @return a JettySolrRunner
    */
-  public JettySolrRunner startJettySolrRunner(String hostContext, JettyConfig config) throws Exception {
-    return startJettySolrRunner(null, hostContext, config);
-  }
-  public JettySolrRunner startJettySolrRunner(Integer testDirsIdx, String hostContext, JettyConfig config) throws Exception {
+  public JettySolrRunner startJettySolrRunner(String name, String hostContext, JettyConfig config) throws Exception {
+    Path runnerPath = createInstancePath(name);
     String context = getHostContextSuitableForServletContext(hostContext);
     JettyConfig newConfig = JettyConfig.builder(config).setContext(context).build();
-    JettySolrRunner jetty = new JettySolrRunner((testDirsIdx != null ? testDirs[testDirsIdx.intValue()] : testDir).getAbsolutePath(), newConfig);
+    JettySolrRunner jetty = new JettySolrRunner(runnerPath.toString(), newConfig);
     jetty.start();
     jettys.add(jetty);
     return jetty;
@@ -314,7 +352,7 @@ public class MiniSolrCloudCluster {
    * @return a JettySolrRunner
    */
   public JettySolrRunner startJettySolrRunner() throws Exception {
-    return startJettySolrRunner(jettyConfig);
+    return startJettySolrRunner(newNodeName(), jettyConfig.context, jettyConfig);
   }
 
   /**
@@ -331,6 +369,7 @@ public class MiniSolrCloudCluster {
 
   protected JettySolrRunner startJettySolrRunner(JettySolrRunner jetty) throws Exception {
     jetty.start();
+    jettys.add(jetty);
     return jetty;
   }