You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2013/05/30 09:53:46 UTC

svn commit: r1487777 [45/50] - in /lucene/dev/branches/security: ./ dev-tools/ dev-tools/eclipse/dot.settings/ dev-tools/idea/.idea/ dev-tools/idea/.idea/libraries/ dev-tools/idea/lucene/replicator/ dev-tools/maven/ dev-tools/maven/lucene/ dev-tools/ma...

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/OpenCloseCoreStressTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/OpenCloseCoreStressTest.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/OpenCloseCoreStressTest.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/OpenCloseCoreStressTest.java Thu May 30 07:53:18 2013
@@ -45,9 +45,6 @@ import java.util.concurrent.atomic.Atomi
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
-import static org.apache.solr.core.SolrCore.verbose;
-import static org.junit.Assert.fail;
-
 /**
  * Incorporate the open/close stress tests into unit tests.
  */
@@ -58,7 +55,6 @@ public class OpenCloseCoreStressTest ext
   private int numCores = 20;
   private Map<String, Long> coreCounts;
   private List<String> coreNames;
-  Random random = new Random(System.currentTimeMillis());
 
   static final int COMMIT_WITHIN = 5000;
 
@@ -182,19 +178,19 @@ public class OpenCloseCoreStressTest ext
 
     try {
 
-      verbose("Starting indexing and querying");
+      log.info("Starting indexing and querying");
 
       int secondsRun = 0;
       int secondsRemaining = secondsToRun;
       do {
 
         int cycleSeconds = Math.min(resetInterval, secondsRemaining);
-        verbose(String.format(Locale.ROOT, "\n\n\n\n\nStarting a %,d second cycle, seconds left: %,d. Seconds run so far: %,d.",
+        log.info(String.format(Locale.ROOT, "\n\n\n\n\nStarting a %,d second cycle, seconds left: %,d. Seconds run so far: %,d.",
             cycleSeconds, secondsRemaining, secondsRun));
 
-        Indexer idxer = new Indexer(this, url, indexingServers, indexingThreads, cycleSeconds);
+        Indexer idxer = new Indexer(this, url, indexingServers, indexingThreads, cycleSeconds, random());
 
-        Queries queries = new Queries(this, url, queryServers, queryThreads);
+        Queries queries = new Queries(this, url, queryServers, queryThreads, random());
 
         idxer.waitOnThreads();
 
@@ -219,11 +215,12 @@ public class OpenCloseCoreStressTest ext
 
   private void makeCores(File home, boolean oldStyle) throws Exception {
     File testSrcRoot = new File(SolrTestCaseJ4.TEST_HOME());
+    String srcSolrXml = "solr-stress-new.xml";
+
     if (oldStyle) {
-      FileUtils.copyFile(new File(testSrcRoot, "solr-stress.xml"), new File(home, "solr.xml"));
-    } else {
-      FileUtils.copyFile(new File(testSrcRoot, "solr-stress.properties"), new File(home, "solr.properties"));
+      srcSolrXml = "solr-stress-old.xml";
     }
+    FileUtils.copyFile(new File(testSrcRoot, srcSolrXml), new File(home, "solr.xml"));
 
     // create directories in groups of 100 until you have enough.
     for (int idx = 0; idx < numCores; ++idx) {
@@ -237,7 +234,7 @@ public class OpenCloseCoreStressTest ext
   private void makeCore(File coreDir, File testSrcRoot, boolean oldStyle) throws IOException {
     File conf = new File(coreDir, "conf");
 
-    if (!conf.mkdirs()) log.info("mkdirs returned false in makeCore... ignoring");
+    if (!conf.mkdirs()) log.warn("mkdirs returned false in makeCore... ignoring");
 
     File testConf = new File(testSrcRoot, "collection1/conf");
 
@@ -253,7 +250,7 @@ public class OpenCloseCoreStressTest ext
 
 
   void deleteAllDocuments(HttpSolrServer server, Queries queries) {
-    verbose("Deleting data from last cycle, this may take a few minutes.");
+    log.info("Deleting data from last cycle, this may take a few minutes.");
 
     for (String core : coreNames) {
       try {
@@ -266,7 +263,7 @@ public class OpenCloseCoreStressTest ext
     }
 
     // We're testing, after all. Let's be really sure things are as we expect.
-    verbose("Insuring all cores empty");
+    log.info("Insuring all cores empty");
     long foundDocs = 0;
     for (String core : coreNames) {
       try {
@@ -279,7 +276,7 @@ public class OpenCloseCoreStressTest ext
     }
 
     if (foundDocs > 0) {
-      verbose("Found docs after purging done, this is bad.");
+      log.warn("Found docs after purging done, this is bad.");
     }
     // Reset counters for another go-round
     coreCounts.clear();
@@ -289,27 +286,31 @@ public class OpenCloseCoreStressTest ext
   }
 
   private void checkResults(HttpSolrServer server, Queries queries, Indexer idxer) throws InterruptedException {
-    verbose("Checking if indexes have all the documents they should...");
+    log.info("Checking if indexes have all the documents they should...");
     long totalDocsFound = 0;
     for (Map.Entry<String, Long> ent : coreCounts.entrySet()) {
       server.setBaseURL(url + ent.getKey());
-      try {
-        server.commit(true, true);
-      } catch (Exception e) {
-        fail("Exception when committing core " + ent.getKey() + " " + e.getMessage());
+      for (int idx = 0; idx < 3; ++idx) {
+        try {
+          server.commit(true, true);
+          break; // retry loop
+        } catch (Exception e) {
+          log.warn("Exception when committing core " + ent.getKey() + " " + e.getMessage());
+          Thread.sleep(100L);
+        }
       }
       long numFound = queries.getCount(server, ent.getKey());
       totalDocsFound += numFound;
       assertEquals(String.format(Locale.ROOT, "Core %s bad!", ent.getKey()), (long) ent.getValue(), numFound);
     }
 
-    verbose(String.format(Locale.ROOT, "\n\nDocs indexed (cumulative, all cycles): %,d, total docs: %,d: Cycle stats: updates: %,d: qtimes: %,d",
+    log.info(String.format(Locale.ROOT, "\n\nDocs indexed (cumulative, all cycles): %,d, total docs: %,d: Cycle stats: updates: %,d: qtimes: %,d",
         Indexer.idUnique.get(), totalDocsFound, idxer.getAccumUpdates(), idxer.getAccumQtimes()));
 
     cumulativeDocs += totalDocsFound;
   }
 
-  String getRandomCore() {
+  String getRandomCore(Random random) {
     return coreNames.get(Math.abs(random.nextInt()) % coreNames.size());
   }
 
@@ -338,14 +339,14 @@ class Indexer {
 
   ArrayList<OneIndexer> _threads = new ArrayList<OneIndexer>();
 
-  public Indexer(OpenCloseCoreStressTest OCCST, String url, List<HttpSolrServer> servers, int numThreads, int secondsToRun) {
+  public Indexer(OpenCloseCoreStressTest OCCST, String url, List<HttpSolrServer> servers, int numThreads, int secondsToRun, Random random) {
     stopTime = System.currentTimeMillis() + (secondsToRun * 1000);
     nextTime = System.currentTimeMillis() + 60000;
     docsThisCycle.set(0);
     qTimesAccum.set(0);
     updateCounts.set(0);
     for (int idx = 0; idx < numThreads; ++idx) {
-      OneIndexer one = new OneIndexer(OCCST, url, servers.get(idx));
+      OneIndexer one = new OneIndexer(OCCST, url, servers.get(idx), random.nextLong());
       _threads.add(one);
       one.start();
     }
@@ -371,7 +372,7 @@ class Indexer {
 
   synchronized static void progress(int myId, String core) {
     if (nextTime - System.currentTimeMillis() <= 0) {
-      verbose(String.format(Locale.ROOT, " s indexed: [run %,8d] [cycle %,8d] [last minute %,8d] Last core updated: %s. Seconds left in cycle %,4d",
+      SolrTestCaseJ4.log.info(String.format(Locale.ROOT, " s indexed: [run %,8d] [cycle %,8d] [last minute %,8d] Last core updated: %s. Seconds left in cycle %,4d",
           myId, docsThisCycle.get(), myId - lastCount, core, stopTime - (System.currentTimeMillis() / 1000)));
       lastCount = myId;
       nextTime += (System.currentTimeMillis() / 1000) * 60;
@@ -384,21 +385,23 @@ class OneIndexer extends Thread {
   private final OpenCloseCoreStressTest OCCST;
   private final HttpSolrServer server;
   private final String baseUrl;
+  private final Random random;
 
-  OneIndexer(OpenCloseCoreStressTest OCCST, String url, HttpSolrServer server) {
+  OneIndexer(OpenCloseCoreStressTest OCCST, String url, HttpSolrServer server, long seed) {
     this.OCCST = OCCST;
     this.server = server;
     this.baseUrl = url;
+    this.random = new Random(seed);
   }
 
   @Override
   public void run() {
-    verbose(String.format(Locale.ROOT, "Starting indexing thread: " + getId()));
+    SolrTestCaseJ4.log.info(String.format(Locale.ROOT, "Starting indexing thread: " + getId()));
 
     while (Indexer.stopTime > System.currentTimeMillis()) {
       int myId = Indexer.idUnique.incrementAndGet();
       Indexer.docsThisCycle.incrementAndGet();
-      String core = OCCST.getRandomCore();
+      String core = OCCST.getRandomCore(random);
       OCCST.incrementCoreCount(core);
       Indexer.progress(myId, core);
       for (int idx = 0; idx < 3; ++idx) {
@@ -412,20 +415,20 @@ class OneIndexer extends Thread {
           server.setBaseURL(baseUrl + core);
           UpdateResponse response = server.add(doc, OpenCloseCoreStressTest.COMMIT_WITHIN);
           if (response.getStatus() != 0) {
-            verbose("Failed to index a document with status " + response.getStatus());
+            SolrTestCaseJ4.log.warn("Failed to index a document to core " + core + " with status " + response.getStatus());
           } else {
             Indexer.qTimesAccum.addAndGet(response.getQTime());
             Indexer.updateCounts.incrementAndGet();
+            break; // retry loop.
           }
           Thread.sleep(100L); // Let's not go crazy here.
-          break; // try loop.
         } catch (Exception e) {
           if (e instanceof InterruptedException) return;
           Indexer.errors.incrementAndGet();
           if (idx == 2) {
-            fail("Could not reach server while indexing for three tries, quitting " + e.getMessage());
+            SolrTestCaseJ4.log.warn("Could not reach server while indexing for three tries, quitting " + e.getMessage());
           } else {
-            verbose("Indexing thread " + Thread.currentThread().getId() + " swallowed one exception " + e.getMessage());
+            SolrTestCaseJ4.log.info("Indexing thread " + Thread.currentThread().getId() + " swallowed one exception " + e.getMessage());
             try {
               Thread.sleep(500);
             } catch (InterruptedException tex) {
@@ -435,7 +438,7 @@ class OneIndexer extends Thread {
         }
       }
     }
-    verbose("Leaving indexing thread " + getId());
+    SolrTestCaseJ4.log.info("Leaving indexing thread " + getId());
   }
 }
 
@@ -446,10 +449,10 @@ class Queries {
   static AtomicInteger _errors = new AtomicInteger(0);
   String baseUrl;
 
-  public Queries(OpenCloseCoreStressTest OCCST, String url, List<HttpSolrServer> servers, int numThreads) {
+  public Queries(OpenCloseCoreStressTest OCCST, String url, List<HttpSolrServer> servers, int numThreads, Random random) {
     baseUrl = url;
     for (int idx = 0; idx < numThreads; ++idx) {
-      Thread one = new OneQuery(OCCST, url, servers.get(idx));
+      Thread one = new OneQuery(OCCST, url, servers.get(idx), random.nextLong());
       _threads.add(one);
       one.start();
     }
@@ -487,18 +490,20 @@ class OneQuery extends Thread {
   OpenCloseCoreStressTest OCCST;
   private final HttpSolrServer server;
   private final String baseUrl;
+  private final Random random;
 
-  OneQuery(OpenCloseCoreStressTest OCCST, String url, HttpSolrServer server) {
+  OneQuery(OpenCloseCoreStressTest OCCST, String url, HttpSolrServer server, long seed) {
     this.OCCST = OCCST;
     this.server = server;
     this.baseUrl = url;
+    this.random = new Random(seed);
   }
 
   @Override
   public void run() {
-    verbose(String.format(Locale.ROOT, "Starting query thread: " + getId()));
+    SolrTestCaseJ4.log.info(String.format(Locale.ROOT, "Starting query thread: " + getId()));
     while (Queries._keepon.get()) {
-      String core = OCCST.getRandomCore();
+      String core = OCCST.getRandomCore(random);
       for (int idx = 0; idx < 3; ++idx) {
         ModifiableSolrParams params = new ModifiableSolrParams();
         params.set("qt", "/select");
@@ -511,7 +516,7 @@ class OneQuery extends Thread {
           QueryResponse response = server.query(params);
 
           if (response.getStatus() != 0) {
-            verbose("Failed to index a document with status " + response.getStatus());
+            SolrTestCaseJ4.log.warn("Failed to query core " + core + " with status " + response.getStatus());
           }
             // Perhaps collect some stats here in future.
           break; // retry loop
@@ -519,9 +524,9 @@ class OneQuery extends Thread {
           if (e instanceof InterruptedException) return;
           Queries._errors.incrementAndGet();
           if (idx == 2) {
-            fail("Could not reach server while indexing for three tries, quitting " + e.getMessage());
+            SolrTestCaseJ4.log.warn("Could not reach server while indexing for three tries, quitting " + e.getMessage());
           } else {
-            verbose("Querying thread: " + Thread.currentThread().getId() + " swallowed exception: " + e.getMessage());
+            SolrTestCaseJ4.log.info("Querying thread: " + Thread.currentThread().getId() + " swallowed exception: " + e.getMessage());
             try {
               Thread.sleep(500L);
             } catch (InterruptedException tex) {
@@ -531,7 +536,7 @@ class OneQuery extends Thread {
         }
       }
     }
-    verbose(String.format(Locale.ROOT, "Leaving query thread: " + getId()));
+    SolrTestCaseJ4.log.info(String.format(Locale.ROOT, "Leaving query thread: " + getId()));
   }
 
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/ResourceLoaderTest.java Thu May 30 07:53:18 2013
@@ -22,6 +22,7 @@ import junit.framework.Assert;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.analysis.core.KeywordTokenizerFactory;
 import org.apache.lucene.analysis.ngram.NGramFilterFactory;
+import org.apache.lucene.util._TestUtil;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.handler.admin.LukeRequestHandler;
 import org.apache.solr.handler.component.FacetComponent;
@@ -30,10 +31,15 @@ import org.apache.lucene.analysis.util.R
 import org.apache.solr.util.plugin.SolrCoreAware;
 
 import java.io.File;
+import java.io.FileFilter;
+import java.io.FileOutputStream;
 import java.io.InputStream;
 import java.nio.charset.CharacterCodingException;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
 
 public class ResourceLoaderTest extends LuceneTestCase 
 {
@@ -53,8 +59,8 @@ public class ResourceLoaderTest extends 
     
     Class clazz = ResourceLoaderAware.class;
     // Check ResourceLoaderAware valid objects
-    loader.assertAwareCompatibility( clazz, new NGramFilterFactory() );
-    loader.assertAwareCompatibility( clazz, new KeywordTokenizerFactory() );
+    loader.assertAwareCompatibility( clazz, new NGramFilterFactory(new HashMap<String,String>()) );
+    loader.assertAwareCompatibility( clazz, new KeywordTokenizerFactory(new HashMap<String,String>()) );
     
     // Make sure it throws an error for invalid objects
     Object[] invalid = new Object[] {
@@ -80,9 +86,9 @@ public class ResourceLoaderTest extends 
     
     // Make sure it throws an error for invalid objects
     invalid = new Object[] {
-        new NGramFilterFactory(),
+        new NGramFilterFactory(new HashMap<String,String>()),
         "hello",  new Float( 12.3f ),
-        new KeywordTokenizerFactory()
+        new KeywordTokenizerFactory(new HashMap<String,String>())
     };
     for( Object obj : invalid ) {
       try {
@@ -130,4 +136,51 @@ public class ResourceLoaderTest extends 
       assertTrue(expected.getCause() instanceof CharacterCodingException);
     }
   }
+
+  public void testClassLoaderLibs() throws Exception {
+    File tmpRoot = _TestUtil.getTempDir("testClassLoaderLibs");
+
+    File lib = new File(tmpRoot, "lib");
+    lib.mkdirs();
+
+    JarOutputStream jar1 = new JarOutputStream(new FileOutputStream(new File(lib, "jar1.jar")));
+    jar1.putNextEntry(new JarEntry("aLibFile"));
+    jar1.closeEntry();
+    jar1.close();
+
+    File otherLib = new File(tmpRoot, "otherLib");
+    otherLib.mkdirs();
+
+    JarOutputStream jar2 = new JarOutputStream(new FileOutputStream(new File(otherLib, "jar2.jar")));
+    jar2.putNextEntry(new JarEntry("explicitFile"));
+    jar2.closeEntry();
+    jar2.close();
+    JarOutputStream jar3 = new JarOutputStream(new FileOutputStream(new File(otherLib, "jar3.jar")));
+    jar3.putNextEntry(new JarEntry("otherFile"));
+    jar3.closeEntry();
+    jar3.close();
+
+    SolrResourceLoader loader = new SolrResourceLoader(tmpRoot.getAbsolutePath());
+
+    // ./lib is accessible by default
+    assertNotNull(loader.getClassLoader().getResource("aLibFile"));
+
+    // file filter works (and doesn't add other files in the same dir)
+    final File explicitFileJar = new File(otherLib, "jar2.jar").getAbsoluteFile();
+    loader.addToClassLoader("otherLib",
+        new FileFilter() {
+          @Override
+          public boolean accept(File pathname) {
+            return pathname.equals(explicitFileJar);
+          }
+        }, false);
+    assertNotNull(loader.getClassLoader().getResource("explicitFile"));
+    assertNull(loader.getClassLoader().getResource("otherFile"));
+
+
+    // null file filter means accept all (making otherFile accessible)
+    loader.addToClassLoader("otherLib", null, false);
+    assertNotNull(loader.getClassLoader().getResource("otherFile"));
+    loader.close();
+  }
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java Thu May 30 07:53:18 2013
@@ -30,8 +30,15 @@ import org.apache.solr.util.plugin.SolrC
 import org.junit.Test;
 
 import java.io.File;
-import java.util.concurrent.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
 public class SolrCoreTest extends SolrTestCaseJ4 {
   private static final String COLLECTION1 = "collection1";
   
@@ -52,7 +59,7 @@ public class SolrCoreTest extends SolrTe
     final CoreContainer cores = h.getCoreContainer();
     SolrCore core = cores.getCore("");
 
-    IndexSchema schema = h.getCore().getSchema();
+    IndexSchema schema = h.getCore().getLatestSchema();
     assertEquals(COLLECTION1, cores.getDefaultCoreName());
     
     cores.remove("");

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestBadConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestBadConfig.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestBadConfig.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestBadConfig.java Thu May 30 07:53:18 2013
@@ -64,4 +64,18 @@ public class TestBadConfig extends Abstr
                   "DummyMergePolicy");
   }
 
+  public void testSchemaMutableButNotManaged() throws Exception {
+    assertConfigs("bad-solrconfig-schema-mutable-but-not-managed.xml",
+                  "schema-minimal.xml", "Unexpected arg(s): {mutable=false,managedSchemaResourceName=schema.xml}");
+  }
+
+  public void testManagedSchemaCannotBeNamedSchemaDotXml() throws Exception {
+    assertConfigs("bad-solrconfig-managed-schema-named-schema.xml.xml",
+                  "schema-minimal.xml", "managedSchemaResourceName can't be 'schema.xml'");
+  }
+  
+  public void testUnknownSchemaAttribute() throws Exception {
+    assertConfigs("bad-solrconfig-unexpected-schema-attribute.xml", "schema-minimal.xml",
+                  "Unexpected arg(s): {bogusParam=bogusValue}");
+  }
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCodecSupport.java Thu May 30 07:53:18 2013
@@ -35,7 +35,7 @@ public class TestCodecSupport extends So
 
   public void testPostingsFormats() {
     Codec codec = h.getCore().getCodec();
-    Map<String, SchemaField> fields = h.getCore().getSchema().getFields();
+    Map<String, SchemaField> fields = h.getCore().getLatestSchema().getFields();
     SchemaField schemaField = fields.get("string_pulsing_f");
     PerFieldPostingsFormat format = (PerFieldPostingsFormat) codec.postingsFormat();
     assertEquals("Pulsing41", format.getPostingsFormatForField(schemaField.getName()).getName());
@@ -50,7 +50,7 @@ public class TestCodecSupport extends So
 
   public void testDocValuesFormats() {
     Codec codec = h.getCore().getCodec();
-    Map<String, SchemaField> fields = h.getCore().getSchema().getFields();
+    Map<String, SchemaField> fields = h.getCore().getLatestSchema().getFields();
     SchemaField schemaField = fields.get("string_disk_f");
     PerFieldDocValuesFormat format = (PerFieldDocValuesFormat) codec.docValuesFormat();
     assertEquals("Disk", format.getDocValuesFormatForField(schemaField.getName()).getName());

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java Thu May 30 07:53:18 2013
@@ -24,42 +24,62 @@ import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
 
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.xpath.XPathExpressionException;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.lucene.util.IOUtils;
+import org.apache.lucene.util._TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.xml.sax.SAXException;
 
 public class TestCoreContainer extends SolrTestCaseJ4 {
-  
+
+  private static String oldSolrHome;
+  private static final String SOLR_HOME_PROP = "solr.solr.home";
+
   @BeforeClass
   public static void beforeClass() throws Exception {
+    oldSolrHome = System.getProperty(SOLR_HOME_PROP);
     initCore("solrconfig.xml", "schema.xml");
   }
 
+  @AfterClass
+  public static void afterClass() {
+    if (oldSolrHome != null) {
+      System.setProperty(SOLR_HOME_PROP, oldSolrHome);
+    } else {
+      System.clearProperty(SOLR_HOME_PROP);
+    }
+  }
+
+  private File solrHomeDirectory;
 
-  public void testShareSchema() throws IOException, ParserConfigurationException, SAXException {
-    
-    final File solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName()
-        + "_shareSchema");
+  private CoreContainer init(String dirName) throws Exception {
+
+    solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName() + dirName);
 
     if (solrHomeDirectory.exists()) {
       FileUtils.deleteDirectory(solrHomeDirectory);
     }
     assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
-    
+
     FileUtils.copyDirectory(new File(SolrTestCaseJ4.TEST_HOME()), solrHomeDirectory);
-    
-    File fconf = new File(solrHomeDirectory, "solr.xml");
 
-    final CoreContainer cores = new CoreContainer(solrHomeDirectory.getAbsolutePath());
+    CoreContainer ret = new CoreContainer(solrHomeDirectory.getAbsolutePath());
+    ret.load(solrHomeDirectory.getAbsolutePath(), new File(solrHomeDirectory, "solr.xml"));
+    return ret;
+  }
+
+  @Test
+  public void testShareSchema() throws Exception {
     System.setProperty("shareSchema", "true");
-    cores.load(solrHomeDirectory.getAbsolutePath(), fconf);
+    final CoreContainer cores = init("_shareSchema");
     try {
       cores.setPersistent(false);
       assertTrue(cores.isShareSchema());
@@ -70,7 +90,7 @@ public class TestCoreContainer extends S
       CoreDescriptor descriptor2 = new CoreDescriptor(cores, "core2", "./collection1");
       SolrCore core2 = cores.create(descriptor2);
       
-      assertSame(core1.getSchema(), core2.getSchema());
+      assertSame(core1.getLatestSchema(), core2.getLatestSchema());
       
       core1.close();
       core2.close();
@@ -79,32 +99,48 @@ public class TestCoreContainer extends S
       System.clearProperty("shareSchema");
     }
   }
-  
+
   @Test
-  public void testReload() throws Exception {
-    final CoreContainer cc = h.getCoreContainer();
-    
-    class TestThread extends Thread {
-      @Override
-      public void run() {
-        cc.reload("collection1");
-      }
-    }
-    
-    List<Thread> threads = new ArrayList<Thread>();
-    int numThreads = 4;
-    for (int i = 0; i < numThreads; i++) {
-      threads.add(new TestThread());
-    }
-    
-    for (Thread thread : threads) {
-      thread.start();
+  public void testReloadSequential() throws Exception {
+    final CoreContainer cc = init("_reloadSequential");
+    try {
+      cc.reload("collection1");
+      cc.reload("collection1");
+      cc.reload("collection1");
+      cc.reload("collection1");
+
+    } finally {
+      cc.shutdown();
     }
-    
-    for (Thread thread : threads) {
-      thread.join();
+  }
+
+  @Test
+  public void testReloadThreaded() throws Exception {
+    final CoreContainer cc = init("_reloadThreaded");
+
+      class TestThread extends Thread {
+        @Override
+        public void run() {
+          cc.reload("collection1");
+        }
+      }
+
+      List<Thread> threads = new ArrayList<Thread>();
+      int numThreads = 4;
+      for (int i = 0; i < numThreads; i++) {
+        threads.add(new TestThread());
+      }
+
+      for (Thread thread : threads) {
+        thread.start();
+      }
+
+      for (Thread thread : threads) {
+        thread.join();
     }
 
+    cc.shutdown();
+
   }
 
   @Test
@@ -117,6 +153,7 @@ public class TestCoreContainer extends S
     assertTrue("Failed to mkdirs workDir", workDir.mkdirs());
     
     final CoreContainer cores = h.getCoreContainer();
+
     cores.setPersistent(true); // is this needed since we make explicit calls?
 
     String instDir = null;
@@ -171,18 +208,20 @@ public class TestCoreContainer extends S
       assertEquals("cores not added?", 3, cores.getCoreNames().size());
       
       final File twoXml = new File(workDir, "2.solr.xml");
-      cores.transientCacheSize = 32;
 
       cores.persistFile(twoXml);
 
       assertXmlFile(twoXml, "/solr[@persistent='true']",
-          "/solr/cores[@defaultCoreName='collection1' and @transientCacheSize='32']",
+          "/solr/cores[@defaultCoreName='collection1']",
           "/solr/cores/core[@name='collection1' and @instanceDir='" + instDir
               + "']", "/solr/cores/core[@name='X' and @instanceDir='" + instDir
               + "' and @dataDir='" + dataX + "']",
           "/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
           "3=count(/solr/cores/core)");
 
+      // Test for saving implicit properties, we should not do this.
+      assertXmlFile(twoXml, "/solr/cores/core[@name='X' and not(@solr.core.instanceDir) and not (@solr.core.configName)]");
+
       // delete a core, check persistence again
       assertNotNull("removing X returned null", cores.remove("X"));
       
@@ -191,9 +230,9 @@ public class TestCoreContainer extends S
       
       assertXmlFile(threeXml, "/solr[@persistent='true']",
           "/solr/cores[@defaultCoreName='collection1']",
-          "/solr/cores/core[@name='collection1' and @instanceDir='" + instDir
-              + "']", "/solr/cores/core[@name='Y' and @instanceDir='" + instY
-              + "']", "2=count(/solr/cores/core)");
+          "/solr/cores/core[@name='collection1' and @instanceDir='" + instDir + "']",
+          "/solr/cores/core[@name='Y' and @instanceDir='" + instY + "']",
+          "2=count(/solr/cores/core)");
       
       // sanity check that persisting w/o changes has no changes
       
@@ -216,42 +255,13 @@ public class TestCoreContainer extends S
     }
   }
   
-  public void assertXmlFile(final File file, String... xpath)
-      throws IOException, SAXException {
-    
-    try {
-      String xml = FileUtils.readFileToString(file, "UTF-8");
-      String results = h.validateXPath(xml, xpath);
-      if (null != results) {
-        String msg = "File XPath failure: file=" + file.getPath() + " xpath="
-            + results + "\n\nxml was: " + xml;
-        fail(msg);
-      }
-    } catch (XPathExpressionException e2) {
-      throw new RuntimeException("XPath is invalid", e2);
-    }
-  }
 
+  @Test
   public void testNoCores() throws IOException, ParserConfigurationException, SAXException {
     //create solrHome
     File solrHomeDirectory = new File(TEMP_DIR, this.getClass().getName()
         + "_noCores");
-    if (solrHomeDirectory.exists()) {
-      FileUtils.deleteDirectory(solrHomeDirectory);
-    }
-    assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
-    try {
-      File solrXmlFile = new File(solrHomeDirectory, "solr.xml");
-      BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(solrXmlFile), IOUtils.CHARSET_UTF_8));
-      out.write(EMPTY_SOLR_XML);
-      out.close();
-    } catch (IOException e) {
-      FileUtils.deleteDirectory(solrHomeDirectory);
-      throw e;
-    }
-    
-    //init
-    System.setProperty("solr.solr.home", solrHomeDirectory.getAbsolutePath());
+    SetUpHome(solrHomeDirectory, EMPTY_SOLR_XML);
     CoreContainer.Initializer init = new CoreContainer.Initializer();
     CoreContainer cores = null;
     try {
@@ -261,7 +271,7 @@ public class TestCoreContainer extends S
       fail("CoreContainer not created" + e.getMessage());
     }
     try {
-      //assert cero cores
+      //assert zero cores
       assertEquals("There should not be cores", 0, cores.getCores().size());
       
       FileUtils.copyDirectory(new File(SolrTestCaseJ4.TEST_HOME(), "collection1"), solrHomeDirectory);
@@ -271,8 +281,13 @@ public class TestCoreContainer extends S
       cores.register(newCore, false);
       
       //assert one registered core
+
       assertEquals("There core registered", 1, cores.getCores().size());
-      
+
+
+      assertXmlFile(new File(solrHomeDirectory, "solr.xml"),
+          "/solr/cores[@transientCacheSize='32']");
+
       newCore.close();
       cores.remove("core1");
       //assert cero cores
@@ -283,11 +298,116 @@ public class TestCoreContainer extends S
     }
 
   }
+
+  private void SetUpHome(File solrHomeDirectory, String xmlFile) throws IOException {
+    if (solrHomeDirectory.exists()) {
+      FileUtils.deleteDirectory(solrHomeDirectory);
+    }
+    assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
+    try {
+      File solrXmlFile = new File(solrHomeDirectory, "solr.xml");
+      BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(solrXmlFile), IOUtils.CHARSET_UTF_8));
+      out.write(xmlFile);
+      out.close();
+    } catch (IOException e) {
+      FileUtils.deleteDirectory(solrHomeDirectory);
+      throw e;
+    }
+
+    //init
+    System.setProperty(SOLR_HOME_PROP, solrHomeDirectory.getAbsolutePath());
+  }
+
+  @Test
+  public void testClassLoaderHierarchy() throws Exception {
+    final CoreContainer cc = init("_classLoaderHierarchy");
+    try {
+      cc.setPersistent(false);
+      ClassLoader sharedLoader = cc.loader.getClassLoader();
+      ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
+      assertSame(contextLoader, sharedLoader.getParent());
+
+      CoreDescriptor descriptor1 = new CoreDescriptor(cc, "core1", "./collection1");
+      SolrCore core1 = cc.create(descriptor1);
+      ClassLoader coreLoader = core1.getResourceLoader().getClassLoader();
+      assertSame(sharedLoader, coreLoader.getParent());
+
+      core1.close();
+    } finally {
+      cc.shutdown();
+    }
+  }
+
+  @Test
+  public void testSharedLib() throws Exception {
+    File tmpRoot = _TestUtil.getTempDir("testSharedLib");
+
+    File lib = new File(tmpRoot, "lib");
+    lib.mkdirs();
+
+    JarOutputStream jar1 = new JarOutputStream(new FileOutputStream(new File(lib, "jar1.jar")));
+    jar1.putNextEntry(new JarEntry("defaultSharedLibFile"));
+    jar1.closeEntry();
+    jar1.close();
+
+    File customLib = new File(tmpRoot, "customLib");
+    customLib.mkdirs();
+
+    JarOutputStream jar2 = new JarOutputStream(new FileOutputStream(new File(customLib, "jar2.jar")));
+    jar2.putNextEntry(new JarEntry("customSharedLibFile"));
+    jar2.closeEntry();
+    jar2.close();
+
+    FileUtils.writeStringToFile(new File(tmpRoot, "default-lib-solr.xml"), "<solr><cores/></solr>", "UTF-8");
+    FileUtils.writeStringToFile(new File(tmpRoot, "explicit-lib-solr.xml"), "<solr sharedLib=\"lib\"><cores/></solr>", "UTF-8");
+    FileUtils.writeStringToFile(new File(tmpRoot, "custom-lib-solr.xml"), "<solr sharedLib=\"customLib\"><cores/></solr>", "UTF-8");
+
+    final CoreContainer cc1 = new CoreContainer(tmpRoot.getAbsolutePath());
+    cc1.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "default-lib-solr.xml"));
+    try {
+      cc1.loader.openResource("defaultSharedLibFile").close();
+    } finally {
+      cc1.shutdown();
+    }
+
+    final CoreContainer cc2 = new CoreContainer(tmpRoot.getAbsolutePath());
+    cc2.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "explicit-lib-solr.xml"));
+    try {
+      cc2.loader.openResource("defaultSharedLibFile").close();
+    } finally {
+      cc2.shutdown();
+    }
+
+    final CoreContainer cc3 = new CoreContainer(tmpRoot.getAbsolutePath());
+    cc3.load(tmpRoot.getAbsolutePath(), new File(tmpRoot, "custom-lib-solr.xml"));
+    try {
+      cc3.loader.openResource("customSharedLibFile").close();
+    } finally {
+      cc3.shutdown();
+    }
+  }
   
   private static final String EMPTY_SOLR_XML ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
       "<solr persistent=\"false\">\n" +
-      "  <cores adminPath=\"/admin/cores\">\n" +
+      "  <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
       "  </cores>\n" +
       "</solr>";
-  
+
+  private static final String SOLR_XML_SAME_NAME ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
+      "<solr persistent=\"false\">\n" +
+      "  <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
+      "    <core name=\"core1\" instanceDir=\"core1\" dataDir=\"core1\"/> \n" +
+      "    <core name=\"core1\" instanceDir=\"core2\" dataDir=\"core2\"/> \n " +
+      "  </cores>\n" +
+      "</solr>";
+
+  private static final String SOLR_XML_SAME_DATADIR ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
+      "<solr persistent=\"false\">\n" +
+      "  <cores adminPath=\"/admin/cores\" transientCacheSize=\"32\" >\n" +
+      "    <core name=\"core2\" instanceDir=\"core2\" dataDir=\"../samedatadir\" schema=\"schema-tiny.xml\" config=\"solrconfig-minimal.xml\" /> \n" +
+      "    <core name=\"core1\" instanceDir=\"core2\" dataDir=\"../samedatadir\" schema=\"schema-tiny.xml\" config=\"solrconfig-minimal.xml\"  /> \n " +
+      "  </cores>\n" +
+      "</solr>";
+
+
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestJmxIntegration.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestJmxIntegration.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestJmxIntegration.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestJmxIntegration.java Thu May 30 07:53:18 2013
@@ -69,15 +69,29 @@ public class TestJmxIntegration extends 
     assertTrue("No MBeans found in server", mbeanServer.getMBeanCount() > 0);
 
     Set<ObjectInstance> objects = mbeanServer.queryMBeans(null, null);
-    assertFalse("No SolrInfoMBean objects found in mbean server", objects
+    assertFalse("No objects found in mbean server", objects
             .isEmpty());
+    int numDynamicMbeans = 0;
     for (ObjectInstance o : objects) {
+      assertNotNull("Null name on: " + o.toString(), o.getObjectName());
       MBeanInfo mbeanInfo = mbeanServer.getMBeanInfo(o.getObjectName());
       if (mbeanInfo.getClassName().endsWith(SolrDynamicMBean.class.getName())) {
-        assertTrue("No Attributes found for mbean: " + mbeanInfo, mbeanInfo
-                .getAttributes().length > 0);
+        numDynamicMbeans++;
+        MBeanAttributeInfo[] attrs = mbeanInfo.getAttributes();
+        assertTrue("No Attributes found for mbean: " + mbeanInfo, 
+                   0 < attrs.length);
+        for (MBeanAttributeInfo attr : attrs) {
+          // ensure every advertised attribute is gettable
+          try {
+            Object trash = mbeanServer.getAttribute(o.getObjectName(), attr.getName());
+          } catch (javax.management.AttributeNotFoundException e) {
+            throw new RuntimeException("Unable to featch attribute for " + o.getObjectName()
+                                       + ": " + attr.getName(), e);
+          }
+        }
       }
     }
+    assertTrue("No SolrDynamicMBeans found", 0 < numDynamicMbeans);
   }
 
   @Test

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestLazyCores.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestLazyCores.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestLazyCores.java Thu May 30 07:53:18 2013
@@ -20,9 +20,13 @@ package org.apache.solr.core;
 import org.apache.commons.io.FileUtils;
 import org.apache.lucene.util.IOUtils;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.util.NamedList;
+import org.apache.solr.handler.admin.CoreAdminHandler;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.update.AddUpdateCommand;
 import org.apache.solr.update.CommitUpdateCommand;
@@ -48,14 +52,6 @@ public class TestLazyCores extends SolrT
 
   private final File solrHomeDirectory = new File(TEMP_DIR, "org.apache.solr.core.TestLazyCores_testlazy");
 
-  private void copyConfFiles(File home, String subdir) throws IOException {
-
-    File subHome = new File(new File(home, subdir), "conf");
-    assertTrue("Failed to make subdirectory ", subHome.mkdirs());
-    String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
-    FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(subHome, "schema-tiny.xml"));
-    FileUtils.copyFile(new File(top, "solrconfig-minimal.xml"), new File(subHome, "solrconfig-minimal.xml"));
-  }
 
   private CoreContainer init() throws Exception {
 
@@ -64,7 +60,7 @@ public class TestLazyCores extends SolrT
     }
     assertTrue("Failed to mkdirs workDir", solrHomeDirectory.mkdirs());
     for (int idx = 1; idx < 10; ++idx) {
-      copyConfFiles(solrHomeDirectory, "collection" + idx);
+      copyMinConf(new File(solrHomeDirectory, "collection" + idx));
     }
 
     File solrXml = new File(solrHomeDirectory, "solr.xml");
@@ -83,7 +79,6 @@ public class TestLazyCores extends SolrT
       FileUtils.deleteDirectory(solrHomeDirectory);
     }
   }
-
   @Test
   public void testLazyLoad() throws Exception {
     CoreContainer cc = init();
@@ -127,6 +122,7 @@ public class TestLazyCores extends SolrT
 
   // This is a little weak. I'm not sure how to test that lazy core2 is loaded automagically. The getCore
   // will, of course, load it.
+
   @Test
   public void testLazySearch() throws Exception {
     CoreContainer cc = init();
@@ -246,6 +242,7 @@ public class TestLazyCores extends SolrT
   }
 
   // Test case for SOLR-4300
+
   @Test
   public void testRace() throws Exception {
     final List<SolrCore> theCores = new ArrayList<SolrCore>();
@@ -280,6 +277,146 @@ public class TestLazyCores extends SolrT
     }
   }
 
+  private void tryCreateFail(CoreAdminHandler admin, String name, String dataDir, String... errs) throws Exception {
+    try {
+      SolrQueryResponse resp = new SolrQueryResponse();
+
+      SolrQueryRequest request = req(CoreAdminParams.ACTION,
+          CoreAdminParams.CoreAdminAction.CREATE.toString(),
+          CoreAdminParams.DATA_DIR, dataDir,
+          CoreAdminParams.NAME, name,
+          "schema", "schema-tiny.xml",
+          "config", "solrconfig-minimal.xml");
+
+      admin.handleRequestBody(request, resp);
+      fail("Should have thrown an error");
+    } catch (SolrException se) {
+      SolrException cause = (SolrException)se.getCause();
+      assertEquals("Exception code should be 500", 500, cause.code());
+      for (String err : errs) {
+       assertTrue("Should have seen an exception containing the an error",
+            cause.getMessage().contains(err));
+      }
+    }
+  }
+  @Test
+  public void testCreateSame() throws Exception {
+    final CoreContainer cc = init();
+    try {
+      // First, try all 4 combinations of load on startup and transient
+      final CoreAdminHandler admin = new CoreAdminHandler(cc);
+      SolrCore lc2 = cc.getCore("collectionLazy2");
+      SolrCore lc4 = cc.getCore("collectionLazy4");
+      SolrCore lc5 = cc.getCore("collectionLazy5");
+      SolrCore lc6 = cc.getCore("collectionLazy6");
+
+      copyMinConf(new File(solrHomeDirectory, "t2"));
+      copyMinConf(new File(solrHomeDirectory, "t4"));
+      copyMinConf(new File(solrHomeDirectory, "t5"));
+      copyMinConf(new File(solrHomeDirectory, "t6"));
+
+
+      // Should also fail with the same name
+      tryCreateFail(admin, "collectionLazy2", "t12", "Core with name", "collectionLazy2", "already exists");
+      tryCreateFail(admin, "collectionLazy4", "t14", "Core with name", "collectionLazy4", "already exists");
+      tryCreateFail(admin, "collectionLazy5", "t15", "Core with name", "collectionLazy5", "already exists");
+      tryCreateFail(admin, "collectionLazy6", "t16", "Core with name", "collectionLazy6", "already exists");
+
+      lc2.close();
+      lc4.close();
+      lc5.close();
+      lc6.close();
+
+    } finally {
+      cc.shutdown();
+    }
+  }
+
+  //Make sure persisting not-loaded lazy cores is done. See SOLR-4347
+
+  @Test
+  public void testPersistence() throws Exception {
+    final CoreContainer cc = init();
+    try {
+      copyMinConf(new File(solrHomeDirectory, "core1"));
+      copyMinConf(new File(solrHomeDirectory, "core2"));
+      copyMinConf(new File(solrHomeDirectory, "core3"));
+      copyMinConf(new File(solrHomeDirectory, "core4"));
+
+      cc.setPersistent(true);
+      CoreDescriptor d1 = new CoreDescriptor(cc, "core1", "./core1");
+      d1.setTransient(true);
+      d1.setLoadOnStartup(true);
+      d1.setSchemaName("schema-tiny.xml");
+      d1.setConfigName("solrconfig-minimal.xml");
+      SolrCore core1 = cc.create(d1);
+
+      CoreDescriptor d2 = new CoreDescriptor(cc, "core2", "./core2");
+      d2.setTransient(true);
+      d2.setLoadOnStartup(false);
+      d2.setSchemaName("schema-tiny.xml");
+      d2.setConfigName("solrconfig-minimal.xml");
+      SolrCore core2 = cc.create(d2);
+
+      CoreDescriptor d3 = new CoreDescriptor(cc, "core3", "./core3");
+      d3.setTransient(false);
+      d3.setLoadOnStartup(true);
+      d3.setSchemaName("schema-tiny.xml");
+      d3.setConfigName("solrconfig-minimal.xml");
+      SolrCore core3 = cc.create(d3);
+
+      CoreDescriptor d4 = new CoreDescriptor(cc, "core4", "./core4");
+      d4.setTransient(false);
+      d4.setLoadOnStartup(false);
+      d4.setSchemaName("schema-tiny.xml");
+      d4.setConfigName("solrconfig-minimal.xml");
+      SolrCore core4 = cc.create(d4);
+
+      final File oneXml = new File(solrHomeDirectory, "lazy1.solr.xml");
+      cc.persistFile(oneXml);
+
+      assertXmlFile(oneXml,
+          "/solr/cores/core[@name='collection1']",
+          "/solr/cores/core[@name='collectionLazy2']",
+          "/solr/cores/core[@name='collectionLazy3']",
+          "/solr/cores/core[@name='collectionLazy4']",
+          "/solr/cores/core[@name='collectionLazy5']",
+          "/solr/cores/core[@name='collectionLazy6']",
+          "/solr/cores/core[@name='collectionLazy7']",
+          "/solr/cores/core[@name='collectionLazy8']",
+          "/solr/cores/core[@name='collectionLazy9']",
+          "/solr/cores/core[@name='core1']",
+          "/solr/cores/core[@name='core2']",
+          "/solr/cores/core[@name='core3']",
+          "/solr/cores/core[@name='core4']");
+      assertXmlFile(oneXml, "13=count(/solr/cores/core)");
+
+      removeOne(cc, "collectionLazy2");
+      removeOne(cc, "collectionLazy3");
+      removeOne(cc, "collectionLazy4");
+      removeOne(cc, "collectionLazy5");
+      removeOne(cc, "collectionLazy6");
+      removeOne(cc, "collectionLazy7");
+      removeOne(cc, "core1");
+      removeOne(cc, "core2");
+      removeOne(cc, "core3");
+      removeOne(cc, "core4");
+
+      // now test that unloading a core means the core is not persisted
+
+      final File twoXml = new File(solrHomeDirectory, "lazy2.solr.xml");
+      cc.persistFile(twoXml);
+
+      assertXmlFile(twoXml, "3=count(/solr/cores/core)");
+    } finally {
+      cc.shutdown();
+    }
+  }
+
+  private void removeOne(CoreContainer cc, String coreName) {
+    SolrCore tmp = cc.remove(coreName);
+    if (tmp != null) tmp.close();
+  }
   public static void checkNotInCores(CoreContainer cc, String... nameCheck) {
     Collection<String> names = cc.getCoreNames();
     for (String name : nameCheck) {

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestMergePolicyConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestMergePolicyConfig.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestMergePolicyConfig.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestMergePolicyConfig.java Thu May 30 07:53:18 2013
@@ -31,7 +31,7 @@ public class TestMergePolicyConfig exten
   }
   
   public void testTieredMergePolicyConfig() throws Exception {
-    IndexWriterConfig iwc = solrConfig.indexConfig.toIndexWriterConfig(h.getCore().getSchema());
+    IndexWriterConfig iwc = solrConfig.indexConfig.toIndexWriterConfig(h.getCore().getLatestSchema());
     MergePolicy mp = iwc.getMergePolicy();
     assertTrue(mp instanceof TieredMergePolicy);
     TieredMergePolicy tieredMP = (TieredMergePolicy) mp;

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderListener.java Thu May 30 07:53:18 2013
@@ -75,7 +75,7 @@ public class TestQuerySenderListener ext
     assertNotNull("Event is null", evt);
     assertTrue(evt + " is not equal to " + EventParams.FIRST_SEARCHER, evt.equals(EventParams.FIRST_SEARCHER) == true);
 
-    SolrIndexSearcher newSearcher = new SolrIndexSearcher(core, core.getNewIndexDir(), core.getSchema(), core.getSolrConfig().indexConfig, "testQuerySenderListener", false, core.getDirectoryFactory());
+    SolrIndexSearcher newSearcher = new SolrIndexSearcher(core, core.getNewIndexDir(), core.getLatestSchema(), core.getSolrConfig().indexConfig, "testQuerySenderListener", false, core.getDirectoryFactory());
 
     qsl.newSearcher(newSearcher, currentSearcher);
     evt = mock.req.getParams().get(EventParams.EVENT);

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestQuerySenderNoQuery.java Thu May 30 07:53:18 2013
@@ -75,7 +75,7 @@ public class TestQuerySenderNoQuery exte
     assertNotNull("Mock is null", mock);
     assertNull("Req (firstsearcher) is not null", mock.req);
 
-    SolrIndexSearcher newSearcher = new SolrIndexSearcher(core, core.getNewIndexDir(), core.getSchema(), core.getSolrConfig().indexConfig, "testQuerySenderNoQuery", false, core.getDirectoryFactory());
+    SolrIndexSearcher newSearcher = new SolrIndexSearcher(core, core.getNewIndexDir(), core.getLatestSchema(), core.getSolrConfig().indexConfig, "testQuerySenderNoQuery", false, core.getDirectoryFactory());
 
     qsl.newSearcher(newSearcher, currentSearcher); // get newSearcher.
     assertNull("Req (newsearcher) is not null", mock.req);

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestSolrIndexConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestSolrIndexConfig.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestSolrIndexConfig.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestSolrIndexConfig.java Thu May 30 07:53:18 2013
@@ -29,7 +29,7 @@ public class TestSolrIndexConfig extends
   }
   
   public void testIndexConfig() throws Exception {
-    IndexWriterConfig iwc = solrConfig.indexConfig.toIndexWriterConfig(h.getCore().getSchema());
+    IndexWriterConfig iwc = solrConfig.indexConfig.toIndexWriterConfig(h.getCore().getLatestSchema());
 
     assertEquals(123, iwc.getMaxThreadStates());
   }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestXIncludeConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestXIncludeConfig.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestXIncludeConfig.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/core/TestXIncludeConfig.java Thu May 30 07:53:18 2013
@@ -19,6 +19,7 @@ package org.apache.solr.core;
 
 import javax.xml.parsers.DocumentBuilderFactory;
 
+import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.update.processor.RegexReplaceProcessorFactory;
 import org.apache.solr.update.processor.UpdateRequestProcessorChain;
 import org.apache.solr.util.AbstractSolrTestCase;
@@ -60,9 +61,8 @@ public class TestXIncludeConfig extends 
                  RegexReplaceProcessorFactory.class,
                  chain.getFactories()[0].getClass());
 
-    assertNotNull("ft-included is null",
-                  core.getSchema().getFieldTypeByName("ft-included"));
-    assertNotNull("field-included is null",
-                  core.getSchema().getFieldOrNull("field-included"));
+    IndexSchema schema = core.getLatestSchema();
+    assertNotNull("ft-included is null", schema.getFieldTypeByName("ft-included"));
+    assertNotNull("field-included is null", schema.getFieldOrNull("field-included"));
   }
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/DocumentAnalysisRequestHandlerTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/DocumentAnalysisRequestHandlerTest.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/DocumentAnalysisRequestHandlerTest.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/DocumentAnalysisRequestHandlerTest.java Thu May 30 07:53:18 2013
@@ -216,7 +216,7 @@ public class DocumentAnalysisRequestHand
             .setShowMatch(true)
             .addDocument(document);
 
-    NamedList<Object> result = handler.handleAnalysisRequest(request, h.getCore().getSchema());
+    NamedList<Object> result = handler.handleAnalysisRequest(request, h.getCore().getLatestSchema());
     assertNotNull("result is null and it shouldn't be", result);
     NamedList<NamedList<NamedList<Object>>> documentResult = (NamedList<NamedList<NamedList<Object>>>) result.get("1");
     assertNotNull("An analysis for document with key '1' should be returned", documentResult);
@@ -323,16 +323,16 @@ public class DocumentAnalysisRequestHand
     tokenList = valueResult.get("org.apache.lucene.analysis.core.StopFilter");
     assertNotNull("Expecting the 'StopFilter' to be applied on the index for the 'text' field", tokenList);
     assertEquals("Expecting 4 tokens after stop word removal", 4, tokenList.size());
-    assertToken(tokenList.get(0), new TokenInfo("fox", null, "<ALPHANUM>", 4, 7, 1, new int[]{2,2,2,1}, null, false));
-    assertToken(tokenList.get(1), new TokenInfo("jumped", null, "<ALPHANUM>", 8, 14, 2, new int[]{3,3,3,2}, null, false));
-    assertToken(tokenList.get(2), new TokenInfo("over", null, "<ALPHANUM>", 15, 19, 3, new int[]{4,4,4,3}, null, false));
-    assertToken(tokenList.get(3), new TokenInfo("dogs", null, "<ALPHANUM>", 24, 28, 4, new int[]{6,6,6,4}, null, false));
+    assertToken(tokenList.get(0), new TokenInfo("fox", null, "<ALPHANUM>", 4, 7, 2, new int[]{2,2,2,2}, null, false));
+    assertToken(tokenList.get(1), new TokenInfo("jumped", null, "<ALPHANUM>", 8, 14, 3, new int[]{3,3,3,3}, null, false));
+    assertToken(tokenList.get(2), new TokenInfo("over", null, "<ALPHANUM>", 15, 19, 4, new int[]{4,4,4,4}, null, false));
+    assertToken(tokenList.get(3), new TokenInfo("dogs", null, "<ALPHANUM>", 24, 28, 6, new int[]{6,6,6,6}, null, false));
     tokenList = valueResult.get("org.apache.lucene.analysis.en.PorterStemFilter");
     assertNotNull("Expecting the 'PorterStemFilter' to be applied on the index for the 'text' field", tokenList);
     assertEquals("Expecting 4 tokens", 4, tokenList.size());
-    assertToken(tokenList.get(0), new TokenInfo("fox", null, "<ALPHANUM>", 4, 7, 1, new int[]{2,2,2,1,1}, null, false));
-    assertToken(tokenList.get(1), new TokenInfo("jump", null, "<ALPHANUM>", 8, 14, 2, new int[]{3,3,3,2,2}, null, true));
-    assertToken(tokenList.get(2), new TokenInfo("over", null, "<ALPHANUM>", 15, 19, 3, new int[]{4,4,4,3,3}, null, false));
-    assertToken(tokenList.get(3), new TokenInfo("dog", null, "<ALPHANUM>", 24, 28, 4, new int[]{6,6,6,4,4}, null, false));
+    assertToken(tokenList.get(0), new TokenInfo("fox", null, "<ALPHANUM>", 4, 7, 2, new int[]{2,2,2,2,2}, null, false));
+    assertToken(tokenList.get(1), new TokenInfo("jump", null, "<ALPHANUM>", 8, 14, 3, new int[]{3,3,3,3,3}, null, true));
+    assertToken(tokenList.get(2), new TokenInfo("over", null, "<ALPHANUM>", 15, 19, 4, new int[]{4,4,4,4,4}, null, false));
+    assertToken(tokenList.get(3), new TokenInfo("dog", null, "<ALPHANUM>", 24, 28, 6, new int[]{6,6,6,6,6}, null, false));
   }
 }

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/FieldAnalysisRequestHandlerTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/FieldAnalysisRequestHandlerTest.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/FieldAnalysisRequestHandlerTest.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/FieldAnalysisRequestHandlerTest.java Thu May 30 07:53:18 2013
@@ -18,7 +18,6 @@
 package org.apache.solr.handler;
 
 import org.apache.lucene.analysis.MockTokenizer;
-import org.apache.lucene.analysis.core.KeywordTokenizer;
 import org.apache.lucene.analysis.core.WhitespaceTokenizer;
 import org.apache.solr.common.params.AnalysisParams;
 import org.apache.solr.common.params.CommonParams;
@@ -126,7 +125,7 @@ public class FieldAnalysisRequestHandler
     request.setQuery("fox brown");
     request.setShowMatch(true);
 
-    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getSchema());
+    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getLatestSchema());
     assertTrue("result is null and it shouldn't be", result != null);
 
     NamedList<NamedList> fieldTypes = result.get("field_types");
@@ -179,25 +178,25 @@ public class FieldAnalysisRequestHandler
     tokenList = indexPart.get("org.apache.lucene.analysis.core.StopFilter");
     assertNotNull("Expcting StopFilter analysis breakdown", tokenList);
     assertEquals(tokenList.size(), 8);
-    assertToken(tokenList.get(0), new TokenInfo("quick", null, "<ALPHANUM>", 4, 9, 1, new int[]{2,2,2,1}, null, false));
-    assertToken(tokenList.get(1), new TokenInfo("red", null, "<ALPHANUM>", 10, 13, 2, new int[]{3,3,3,2}, null, false));
-    assertToken(tokenList.get(2), new TokenInfo("fox", null, "<ALPHANUM>", 14, 17, 3, new int[]{4,4,4,3}, null, true));
-    assertToken(tokenList.get(3), new TokenInfo("jumped", null, "<ALPHANUM>", 18, 24, 4, new int[]{5,5,5,4}, null, false));
-    assertToken(tokenList.get(4), new TokenInfo("over", null, "<ALPHANUM>", 25, 29, 5, new int[]{6,6,6,5}, null, false));
-    assertToken(tokenList.get(5), new TokenInfo("lazy", null, "<ALPHANUM>", 34, 38, 6, new int[]{8,8,8,6}, null, false));
-    assertToken(tokenList.get(6), new TokenInfo("brown", null, "<ALPHANUM>", 39, 44, 7, new int[]{9,9,9,7}, null, true));
-    assertToken(tokenList.get(7), new TokenInfo("dogs", null, "<ALPHANUM>", 45, 49, 8, new int[]{10,10,10,8}, null, false));
+    assertToken(tokenList.get(0), new TokenInfo("quick", null, "<ALPHANUM>", 4, 9, 2, new int[]{2,2,2,2}, null, false));
+    assertToken(tokenList.get(1), new TokenInfo("red", null, "<ALPHANUM>", 10, 13, 3, new int[]{3,3,3,3}, null, false));
+    assertToken(tokenList.get(2), new TokenInfo("fox", null, "<ALPHANUM>", 14, 17, 4, new int[]{4,4,4,4}, null, true));
+    assertToken(tokenList.get(3), new TokenInfo("jumped", null, "<ALPHANUM>", 18, 24, 5, new int[]{5,5,5,5}, null, false));
+    assertToken(tokenList.get(4), new TokenInfo("over", null, "<ALPHANUM>", 25, 29, 6, new int[]{6,6,6,6}, null, false));
+    assertToken(tokenList.get(5), new TokenInfo("lazy", null, "<ALPHANUM>", 34, 38, 8, new int[]{8,8,8,8}, null, false));
+    assertToken(tokenList.get(6), new TokenInfo("brown", null, "<ALPHANUM>", 39, 44, 9, new int[]{9,9,9,9}, null, true));
+    assertToken(tokenList.get(7), new TokenInfo("dogs", null, "<ALPHANUM>", 45, 49, 10, new int[]{10,10,10,10}, null, false));
     tokenList = indexPart.get("org.apache.lucene.analysis.en.PorterStemFilter");
     assertNotNull("Expcting PorterStemFilter analysis breakdown", tokenList);
     assertEquals(tokenList.size(), 8);
-    assertToken(tokenList.get(0), new TokenInfo("quick", null, "<ALPHANUM>", 4, 9, 1, new int[]{2,2,2,1,1}, null, false));
-    assertToken(tokenList.get(1), new TokenInfo("red", null, "<ALPHANUM>", 10, 13, 2, new int[]{3,3,3,2,2}, null, false));
-    assertToken(tokenList.get(2), new TokenInfo("fox", null, "<ALPHANUM>", 14, 17, 3, new int[]{4,4,4,3,3}, null, true));
-    assertToken(tokenList.get(3), new TokenInfo("jump", null, "<ALPHANUM>", 18, 24, 4, new int[]{5,5,5,4,4}, null, false));
-    assertToken(tokenList.get(4), new TokenInfo("over", null, "<ALPHANUM>", 25, 29, 5, new int[]{6,6,6,5,5}, null, false));
-    assertToken(tokenList.get(5), new TokenInfo("lazi", null, "<ALPHANUM>", 34, 38, 6, new int[]{8,8,8,6,6}, null, false));
-    assertToken(tokenList.get(6), new TokenInfo("brown", null, "<ALPHANUM>", 39, 44, 7, new int[]{9,9,9,7,7}, null, true));
-    assertToken(tokenList.get(7), new TokenInfo("dog", null, "<ALPHANUM>", 45, 49, 8, new int[]{10,10,10,8,8}, null, false));
+    assertToken(tokenList.get(0), new TokenInfo("quick", null, "<ALPHANUM>", 4, 9, 2, new int[]{2,2,2,2,2}, null, false));
+    assertToken(tokenList.get(1), new TokenInfo("red", null, "<ALPHANUM>", 10, 13, 3, new int[]{3,3,3,3,3}, null, false));
+    assertToken(tokenList.get(2), new TokenInfo("fox", null, "<ALPHANUM>", 14, 17, 4, new int[]{4,4,4,4,4}, null, true));
+    assertToken(tokenList.get(3), new TokenInfo("jump", null, "<ALPHANUM>", 18, 24, 5, new int[]{5,5,5,5,5}, null, false));
+    assertToken(tokenList.get(4), new TokenInfo("over", null, "<ALPHANUM>", 25, 29, 6, new int[]{6,6,6,6,6}, null, false));
+    assertToken(tokenList.get(5), new TokenInfo("lazi", null, "<ALPHANUM>", 34, 38, 8, new int[]{8,8,8,8,8}, null, false));
+    assertToken(tokenList.get(6), new TokenInfo("brown", null, "<ALPHANUM>", 39, 44, 9, new int[]{9,9,9,9,9}, null, true));
+    assertToken(tokenList.get(7), new TokenInfo("dog", null, "<ALPHANUM>", 45, 49, 10, new int[]{10,10,10,10,10}, null, false));
 
     NamedList<List<NamedList>> queryPart = textType.get("query");
     assertNotNull("expecting a query token analysis for field type 'text'", queryPart);
@@ -315,7 +314,7 @@ public class FieldAnalysisRequestHandler
     request.setFieldValue("<html><body>whátëvêr</body></html>");
     request.setShowMatch(false);
 
-    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getSchema());
+    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getLatestSchema());
     assertTrue("result is null and it shouldn't be", result != null);
 
     NamedList<NamedList> fieldTypes = result.get("field_types");
@@ -343,7 +342,7 @@ public class FieldAnalysisRequestHandler
     request.setFieldValue("hi, 3456-12 a Test");
     request.setShowMatch(false);
 
-    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getSchema());
+    NamedList<NamedList> result = handler.handleAnalysisRequest(request, h.getCore().getLatestSchema());
     assertTrue("result is null and it shouldn't be", result != null);
 
     NamedList<NamedList> fieldTypes = result.get("field_types");

Modified: lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java (original)
+++ lucene/dev/branches/security/solr/core/src/test/org/apache/solr/handler/TestReplicationHandler.java Thu May 30 07:53:18 2013
@@ -28,7 +28,11 @@ import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.Set;
+import java.util.Date;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -47,14 +51,23 @@ import org.apache.solr.client.solrj.Solr
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.impl.HttpSolrServer;
+import org.apache.solr.client.solrj.request.UpdateRequest;
 import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.UpdateResponse;
+import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrDocument;
 import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.core.CachingDirectoryFactory;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.core.StandardDirectoryFactory;
+import org.apache.solr.servlet.SolrDispatchFilter;
 import org.apache.solr.util.AbstractSolrTestCase;
 import org.junit.After;
 import org.junit.Before;
@@ -66,12 +79,11 @@ import org.junit.Test;
  *
  * @since 1.4
  */
-// TODO: can this test be sped up? it used to not be so slow...
 @Slow
 public class TestReplicationHandler extends SolrTestCaseJ4 {
 
 
-  private static final String CONF_DIR = "." + File.separator + "solr"
+  private static final String CONF_DIR = "solr"
       + File.separator + "collection1" + File.separator + "conf"
       + File.separator;
 
@@ -104,14 +116,11 @@ public class TestReplicationHandler exte
   }
 
   public void clearIndexWithReplication() throws Exception {
-    NamedList res = query("*:*", masterClient);
-    SolrDocumentList docs = (SolrDocumentList)res.get("response");
-    if (docs.getNumFound() != 0) {
+    if (numFound(query("*:*", masterClient)) != 0) {
       masterClient.deleteByQuery("*:*");
       masterClient.commit();
-      // wait for replication to sync
-      res = rQuery(0, "*:*", slaveClient);
-      assertEquals(0, ((SolrDocumentList) res.get("response")).getNumFound());
+      // wait for replication to sync & verify
+      assertEquals(0, numFound(rQuery(0, "*:*", slaveClient)));
     }
   }
 
@@ -166,6 +175,7 @@ public class TestReplicationHandler exte
     ModifiableSolrParams params = new ModifiableSolrParams();
 
     params.add("q", query);
+    params.add("sort","id desc");
 
     QueryResponse qres = s.query(params);
 
@@ -177,22 +187,27 @@ public class TestReplicationHandler exte
   /** will sleep up to 30 seconds, looking for expectedDocCount */
   private NamedList rQuery(int expectedDocCount, String query, SolrServer server) throws Exception {
     int timeSlept = 0;
-    NamedList res = null;
-    SolrDocumentList docList = null;
-    do {
-      res = query(query, server);
-      docList = (SolrDocumentList) res.get("response");
+    NamedList res = query(query, server);
+    while (expectedDocCount != numFound(res)
+           && timeSlept < 30000) {
+      log.info("Waiting for " + expectedDocCount + " docs");
       timeSlept += 100;
       Thread.sleep(100);
-    } while(docList.getNumFound() != expectedDocCount && timeSlept < 45000);
+      res = query(query, server);
+    }
     return res;
   }
   
+  private long numFound(NamedList res) {
+    return ((SolrDocumentList) res.get("response")).getNumFound();
+  }
+
   private NamedList<Object> getDetails(SolrServer s) throws Exception {
     
 
     ModifiableSolrParams params = new ModifiableSolrParams();
     params.set("command","details");
+    params.set("_trace","getDetails");
     params.set("qt","/replication");
     QueryRequest req = new QueryRequest(params);
 
@@ -213,6 +228,7 @@ public class TestReplicationHandler exte
 
     ModifiableSolrParams params = new ModifiableSolrParams();
     params.set("command","commits");
+    params.set("_trace","getCommits");
     params.set("qt","/replication");
     QueryRequest req = new QueryRequest(params);
 
@@ -228,6 +244,7 @@ public class TestReplicationHandler exte
     
     ModifiableSolrParams params = new ModifiableSolrParams();
     params.set("command","indexversion");
+    params.set("_trace","getIndexVersion");
     params.set("qt","/replication");
     QueryRequest req = new QueryRequest(params);
 
@@ -322,6 +339,56 @@ public class TestReplicationHandler exte
     }
   }
 
+  /**
+   * Verify that empty commits and/or commits with openSearcher=false 
+   * on the master do not cause subsequent replication problems on the slave 
+   */
+  public void testEmptyCommits() throws Exception {
+    clearIndexWithReplication();
+    
+    // add a doc to master and commit
+    index(masterClient, "id", "1", "name", "empty1");
+    emptyUpdate(masterClient, "commit", "true");
+    // force replication
+    pullFromMasterToSlave();
+    // verify doc is on slave
+    rQuery(1, "name:empty1", slaveClient);
+    assertVersions(masterClient, slaveClient);
+
+    // do a completely empty commit on master and force replication
+    emptyUpdate(masterClient, "commit", "true");
+    pullFromMasterToSlave();
+
+    // add another doc and verify slave gets it
+    index(masterClient, "id", "2", "name", "empty2");
+    emptyUpdate(masterClient, "commit", "true");
+    // force replication
+    pullFromMasterToSlave();
+
+    rQuery(1, "name:empty2", slaveClient);
+    assertVersions(masterClient, slaveClient);
+
+    // add a third doc but don't open a new searcher on master
+    index(masterClient, "id", "3", "name", "empty3");
+    emptyUpdate(masterClient, "commit", "true", "openSearcher", "false");
+    pullFromMasterToSlave();
+    
+    // verify slave can search the doc, but master doesn't
+    rQuery(0, "name:empty3", masterClient);
+    rQuery(1, "name:empty3", slaveClient);
+
+    // final doc with hard commit, slave and master both showing all docs
+    index(masterClient, "id", "4", "name", "empty4");
+    emptyUpdate(masterClient, "commit", "true");
+    pullFromMasterToSlave();
+
+    String q = "name:(empty1 empty2 empty3 empty4)";
+    rQuery(4, q, masterClient);
+    rQuery(4, q, slaveClient);
+    assertVersions(masterClient, slaveClient);
+
+  }
+
   @Test
   public void doTestReplicateAfterWrite2Slave() throws Exception {
     clearIndexWithReplication();
@@ -335,9 +402,7 @@ public class TestReplicationHandler exte
     
     masterClient.commit();
 
-    NamedList masterQueryRsp = rQuery(nDocs, "*:*", masterClient);
-    SolrDocumentList masterQueryResult = (SolrDocumentList) masterQueryRsp.get("response");
-    assertEquals(nDocs, masterQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(rQuery(nDocs, "*:*", masterClient)));
 
     // Make sure that both the index version and index generation on the slave is
     // higher than that of the master, just to make the test harder.
@@ -353,14 +418,8 @@ public class TestReplicationHandler exte
     index(slaveClient, "id", 555, "name", "name = " + 555);
     slaveClient.commit(true, true);
 
-
-    
     //this doc is added to slave so it should show an item w/ that result
-    SolrDocumentList slaveQueryResult = null;
-    NamedList slaveQueryRsp;
-    slaveQueryRsp = rQuery(1, "id:555", slaveClient);
-    slaveQueryResult = (SolrDocumentList) slaveQueryRsp.get("response");
-    assertEquals(1, slaveQueryResult.getNumFound());
+    assertEquals(1, numFound(rQuery(1, "id:555", slaveClient)));
 
     //Let's fetch the index rather than rely on the polling.
     invokeReplicationCommand(masterJetty.getLocalPort(), "enablereplication");
@@ -406,16 +465,18 @@ public class TestReplicationHandler exte
 
     NamedList masterQueryRsp = rQuery(nDocs, "*:*", masterClient);
     SolrDocumentList masterQueryResult = (SolrDocumentList) masterQueryRsp.get("response");
-    assertEquals(nDocs, masterQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(masterQueryRsp));
 
     //get docs from slave and check if number is equal to master
     NamedList slaveQueryRsp = rQuery(nDocs, "*:*", slaveClient);
     SolrDocumentList slaveQueryResult = (SolrDocumentList) slaveQueryRsp.get("response");
-    assertEquals(nDocs, slaveQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(slaveQueryRsp));
 
     //compare results
     String cmp = BaseDistributedSearchTestCase.compare(masterQueryResult, slaveQueryResult, 0, null);
     assertEquals(null, cmp);
+    
+    assertVersions(masterClient, slaveClient);
 
     //start config files replication test
     masterClient.deleteByQuery("*:*");
@@ -451,9 +512,9 @@ public class TestReplicationHandler exte
     index(masterClient, "id", "2000", "name", "name = " + 2000, "newname", "newname = " + 2000);
     masterClient.commit();
 
-    NamedList masterQueryRsp2 = rQuery(1, "*:*", masterClient);
-    SolrDocumentList masterQueryResult2 = (SolrDocumentList) masterQueryRsp2.get("response");
-    assertEquals(1, masterQueryResult2.getNumFound());
+    assertEquals(1, numFound( rQuery(1, "*:*", masterClient)));
+    
+    assertVersions(masterClient, slaveClient);
 
     slaveQueryRsp = rQuery(1, "*:*", slaveClient);
     SolrDocument d = ((SolrDocumentList) slaveQueryRsp.get("response")).get(0);
@@ -462,6 +523,9 @@ public class TestReplicationHandler exte
     assertTrue(slaveXsltDir.isDirectory());
     assertTrue(slaveXsl.exists());
     
+    checkForSingleIndex(masterJetty);
+    checkForSingleIndex(slaveJetty);
+    
   }
 
   @Test
@@ -479,12 +543,12 @@ public class TestReplicationHandler exte
 
     NamedList masterQueryRsp = rQuery(nDocs, "*:*", masterClient);
     SolrDocumentList masterQueryResult = (SolrDocumentList) masterQueryRsp.get("response");
-    assertEquals(nDocs, masterQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(masterQueryRsp));
 
     //get docs from slave and check if number is equal to master
     NamedList slaveQueryRsp = rQuery(nDocs, "*:*", slaveClient);
     SolrDocumentList slaveQueryResult = (SolrDocumentList) slaveQueryRsp.get("response");
-    assertEquals(nDocs, slaveQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(slaveQueryRsp));
 
     //compare results
     String cmp = BaseDistributedSearchTestCase.compare(masterQueryResult, slaveQueryResult, 0, null);
@@ -497,25 +561,19 @@ public class TestReplicationHandler exte
     masterClient.commit();
 
     //get docs from master and check if number is equal to master
-    masterQueryRsp = rQuery(nDocs+1, "*:*", masterClient);
-    masterQueryResult = (SolrDocumentList) masterQueryRsp.get("response");
-    assertEquals(nDocs+1, masterQueryResult.getNumFound());
+    assertEquals(nDocs+1, numFound(rQuery(nDocs+1, "*:*", masterClient)));
     
     // NOTE: this test is wierd, we want to verify it DOESNT replicate...
     // for now, add a sleep for this.., but the logic is wierd.
     Thread.sleep(3000);
     
     //get docs from slave and check if number is not equal to master; polling is disabled
-    slaveQueryRsp = rQuery(nDocs, "*:*", slaveClient);
-    slaveQueryResult = (SolrDocumentList) slaveQueryRsp.get("response");
-    assertEquals(nDocs, slaveQueryResult.getNumFound());
+    assertEquals(nDocs, numFound(rQuery(nDocs, "*:*", slaveClient)));
 
     // re-enable replication
     invokeReplicationCommand(slaveJetty.getLocalPort(), "enablepoll");
 
-    slaveQueryRsp = rQuery(nDocs+1, "*:*", slaveClient);
-    slaveQueryResult = (SolrDocumentList) slaveQueryRsp.get("response");
-    assertEquals(nDocs+1, slaveQueryResult.getNumFound());   
+    assertEquals(nDocs+1, numFound(rQuery(nDocs+1, "*:*", slaveClient)));
   }
 
   @Test
@@ -645,13 +703,145 @@ public class TestReplicationHandler exte
     NamedList<Object> details = getDetails(masterClient);
    
     details = getDetails(slaveClient);
+    
+    checkForSingleIndex(masterJetty);
+    checkForSingleIndex(slaveJetty);
+  }
+  
+  
+  @Test
+  public void doTestStressReplication() throws Exception {
+    // change solrconfig on slave
+    // this has no entry for pollinginterval
+    
+    // get us a straight standard fs dir rather than mock*dir
+    boolean useStraightStandardDirectory = random().nextBoolean();
+    
+    if (useStraightStandardDirectory) {
+      useFactory(null);
+    }
+    final String SLAVE_SCHEMA_1 = "schema-replication1.xml";
+    final String SLAVE_SCHEMA_2 = "schema-replication2.xml";
+    String slaveSchema = SLAVE_SCHEMA_1;
 
-    // NOTE: at this point, the slave is not polling any more
-    // restore it.
-    slave.copyConfigFile(CONF_DIR + "solrconfig-slave.xml", "solrconfig.xml");
-    slaveJetty.stop();
-    slaveJetty = createJetty(slave);
-    slaveClient = createNewSolrServer(slaveJetty.getLocalPort());
+    try {
+      
+      slave.copyConfigFile(CONF_DIR +"solrconfig-slave1.xml", "solrconfig.xml");
+      slave.copyConfigFile(CONF_DIR +slaveSchema, "schema.xml");
+      slaveJetty.stop();
+      slaveJetty = createJetty(slave);
+      slaveClient = createNewSolrServer(slaveJetty.getLocalPort());
+
+      master.copyConfigFile(CONF_DIR + "solrconfig-master3.xml",
+          "solrconfig.xml");
+      masterJetty.stop();
+      masterJetty = createJetty(master);
+      masterClient = createNewSolrServer(masterJetty.getLocalPort());
+      
+      masterClient.deleteByQuery("*:*");
+      slaveClient.deleteByQuery("*:*");
+      slaveClient.commit();
+      
+      int maxDocs = TEST_NIGHTLY ? 1000 : 200;
+      int rounds = TEST_NIGHTLY ? 80 : 8;
+      int totalDocs = 0;
+      int id = 0;
+      for (int x = 0; x < rounds; x++) {
+        
+        final boolean confCoreReload = random().nextBoolean();
+        if (confCoreReload) {
+          // toggle the schema file used
+
+          slaveSchema = slaveSchema.equals(SLAVE_SCHEMA_1) ? 
+            SLAVE_SCHEMA_2 : SLAVE_SCHEMA_1;
+          master.copyConfigFile(CONF_DIR + slaveSchema, "schema.xml");
+        }
+        
+        int docs = random().nextInt(maxDocs);
+        for (int i = 0; i < docs; i++) {
+          index(masterClient, "id", id++, "name", "name = " + i);
+        }
+        
+        totalDocs += docs;
+        masterClient.commit();
+        
+        NamedList masterQueryRsp = rQuery(totalDocs, "*:*", masterClient);
+        SolrDocumentList masterQueryResult = (SolrDocumentList) masterQueryRsp
+            .get("response");
+        assertEquals(totalDocs, masterQueryResult.getNumFound());
+        
+        // snappull
+        Date slaveCoreStart = watchCoreStartAt(slaveClient, 30*1000, null);
+        pullFromMasterToSlave();
+        if (confCoreReload) {
+          watchCoreStartAt(slaveClient, 30*1000, slaveCoreStart);
+        }
+
+        // get docs from slave and check if number is equal to master
+        NamedList slaveQueryRsp = rQuery(totalDocs, "*:*", slaveClient);
+        SolrDocumentList slaveQueryResult = (SolrDocumentList) slaveQueryRsp
+            .get("response");
+        assertEquals(totalDocs, slaveQueryResult.getNumFound());
+        // compare results
+        String cmp = BaseDistributedSearchTestCase.compare(masterQueryResult,
+            slaveQueryResult, 0, null);
+        assertEquals(null, cmp);
+        
+        assertVersions(masterClient, slaveClient);
+        
+        checkForSingleIndex(masterJetty);
+        checkForSingleIndex(slaveJetty);
+        
+        if (random().nextBoolean()) {
+          // move the slave ahead
+          for (int i = 0; i < 3; i++) {
+            index(slaveClient, "id", id++, "name", "name = " + i);
+          }
+          slaveClient.commit();
+        }
+        
+      }
+      
+    } finally {
+      if (useStraightStandardDirectory) {
+        resetFactory();
+      }
+    }
+  }
+
+  private void checkForSingleIndex(JettySolrRunner jetty) {
+    CoreContainer cores = ((SolrDispatchFilter) jetty.getDispatchFilter().getFilter()).getCores();
+    Collection<SolrCore> theCores = cores.getCores();
+    for (SolrCore core : theCores) {
+      String ddir = core.getDataDir();
+      CachingDirectoryFactory dirFactory = (CachingDirectoryFactory) core.getDirectoryFactory();
+      synchronized (dirFactory) {
+        Set<String> livePaths = dirFactory.getLivePaths();
+        // one for data, one for hte index under data
+        assertEquals(livePaths.toString(), 2, livePaths.size());
+        // :TODO: assert that one of the paths is a subpath of hte other
+      }
+      if (dirFactory instanceof StandardDirectoryFactory) {
+        System.out.println(Arrays.asList(new File(ddir).list()));
+        assertEquals(Arrays.asList(new File(ddir).list()).toString(), 1, indexDirCount(ddir));
+      }
+    }
+  }
+
+  private int indexDirCount(String ddir) {
+    String[] list = new File(ddir).list();
+    int cnt = 0;
+    for (String file : list) {
+      if (!file.endsWith(".properties")) {
+        cnt++;
+      }
+    }
+    return cnt;
+  }
+
+  private void pullFromMasterToSlave() throws MalformedURLException,
+      IOException {
+    pullFromTo(masterJetty, slaveJetty);
   }
   
   @Test
@@ -727,11 +917,14 @@ public class TestReplicationHandler exte
     Long maxVersionClient1 = getVersion(client1);
     Long maxVersionClient2 = getVersion(client2);
 
-    assertEquals(maxVersionClient1, maxVersionClient2);
+    if (maxVersionClient1 > 0 && maxVersionClient2 > 0) {
+      assertEquals(maxVersionClient1, maxVersionClient2);
+    }
     
-    // check vs /replication?command=indexverion call
+    // check vs /replication?command=indexversion call
     ModifiableSolrParams params = new ModifiableSolrParams();
     params.set("qt", "/replication");
+    params.set("_trace", "assertVersions");
     params.set("command", "indexversion");
     QueryRequest req = new QueryRequest(params);
     NamedList<Object> resp = client1.request(req);
@@ -742,7 +935,6 @@ public class TestReplicationHandler exte
     // check vs /replication?command=indexversion call
     resp = client2.request(req);
     version = (Long) resp.get("indexversion");
-    
     assertEquals(maxVersionClient2, version);
   }
 
@@ -769,7 +961,7 @@ public class TestReplicationHandler exte
     URL url;
     InputStream stream;
     masterUrl = "http://127.0.0.1:" + to.getLocalPort()
-        + "/solr/replication?command=fetchindex&masterUrl=";
+        + "/solr/replication?wait=true&command=fetchindex&masterUrl=";
     masterUrl += "http://127.0.0.1:" + from.getLocalPort()
         + "/solr/replication";
     url = new URL(masterUrl);
@@ -961,7 +1153,6 @@ public class TestReplicationHandler exte
   }
 
   @Test
-  //@Ignore("ignore while i track down the intermittent problem with this test")
   public void doTestIndexAndConfigAliasReplication() throws Exception {
     clearIndexWithReplication();
 
@@ -989,6 +1180,7 @@ public class TestReplicationHandler exte
     //clear master index
     masterClient.deleteByQuery("*:*");
     masterClient.commit();
+    rQuery(0, "*:*", masterClient); // sanity check w/retry
 
     //change solrconfig on master
     master.copyConfigFile(CONF_DIR + "solrconfig-master1.xml", 
@@ -1016,29 +1208,36 @@ public class TestReplicationHandler exte
 
     slaveClient.deleteByQuery("*:*");
     slaveClient.commit();
+    rQuery(0, "*:*", slaveClient); // sanity check w/retry
     
+    // record collection1's start time on slave
+    final Date slaveStartTime = watchCoreStartAt(slaveClient, 30*1000, null);
+
     //add a doc with new field and commit on master to trigger snappull from slave.
-    index(masterClient, "id", "2000", "name", "name = " + 2000, "newname", "newname = " + 2000);
+    index(masterClient, "id", "2000", "name", "name = " + 2000, "newname", "n2000");
     masterClient.commit();
+    rQuery(1, "newname:n2000", masterClient);  // sanity check
+
+    // wait for slave to reload core by watching updated startTime
+    watchCoreStartAt(slaveClient, 30*1000, slaveStartTime);
 
-    NamedList masterQueryRsp2 = rQuery(1, "*:*", masterClient);
+    NamedList masterQueryRsp2 = rQuery(1, "id:2000", masterClient);
     SolrDocumentList masterQueryResult2 = (SolrDocumentList) masterQueryRsp2.get("response");
     assertEquals(1, masterQueryResult2.getNumFound());
 
-    NamedList slaveQueryRsp2 = rQuery(1, "*:*", slaveClient);
+    NamedList slaveQueryRsp2 = rQuery(1, "id:2000", slaveClient);
     SolrDocumentList slaveQueryResult2 = (SolrDocumentList) slaveQueryRsp2.get("response");
     assertEquals(1, slaveQueryResult2.getNumFound());
     
-    // we need to wait until the core is reloaded
-    rQuery(1, "*:*", slaveClient);
-
-    index(slaveClient, "id", "2000", "name", "name = " + 2001, "newname", "newname = " + 2001);
+    index(slaveClient, "id", "2001", "name", "name = " + 2001, "newname", "n2001");
     slaveClient.commit();
 
-    slaveQueryRsp = rQuery(1, "*:*", slaveClient);
+    slaveQueryRsp = rQuery(1, "id:2001", slaveClient);
     SolrDocument d = ((SolrDocumentList) slaveQueryRsp.get("response")).get(0);
-    assertEquals("newname = 2001", (String) d.getFieldValue("newname"));
+    assertEquals("n2001", (String) d.getFieldValue("newname"));
     
+    checkForSingleIndex(masterJetty);
+    checkForSingleIndex(slaveJetty);
   }
 
 
@@ -1222,6 +1421,59 @@ public class TestReplicationHandler exte
     out.close();
   }
 
+  private UpdateResponse emptyUpdate(SolrServer client, String... params) 
+    throws SolrServerException, IOException {
+
+    UpdateRequest req = new UpdateRequest();
+    req.setParams(params(params));
+    return req.process(client);
+  }
+
+  /**
+   * Polls the SolrCore stats using the specified client until the "startTime" 
+   * time for collection is after the specified "min".  Will loop for 
+   * at most "timeout" milliseconds before throwing an assertion failure.
+   * 
+   * @param client The SolrServer to poll
+   * @param timeout the max milliseconds to continue polling for
+   * @param min the startTime value must exceed this value before the method will return, if null this method will return the first startTime value encountered.
+   * @return the startTime value of collection
+   */
+  private Date watchCoreStartAt(SolrServer client, final long timeout, 
+                                final Date min) throws InterruptedException, IOException, SolrServerException {
+    final long sleepInterval = 200;
+    long timeSlept = 0;
+
+    SolrParams p = params("action","status", "core", "collection1");
+    while (timeSlept < timeout) {
+      QueryRequest req = new QueryRequest(p);
+      req.setPath("/admin/cores");
+      try {
+        NamedList data = client.request(req);
+        for (String k : new String[] {"status","collection1"}) {
+          Object o = data.get(k);
+          assertNotNull("core status rsp missing key: " + k, o);
+          data = (NamedList) o;
+        }
+        Date startTime = (Date) data.get("startTime");
+        assertNotNull("core has null startTime", startTime);
+        if (null == min || startTime.after(min)) {
+          return startTime;
+        }
+      } catch (SolrException e) {
+        // workarround for SOLR-4668
+        if (500 != e.code()) {
+          throw e;
+        } // else server possibly from the core reload in progress...
+      }
+
+      timeSlept += sleepInterval;
+      Thread.sleep(sleepInterval);
+    }
+    fail("timed out waiting for collection1 startAt time to exceed: " + min);
+    return min; // compilation neccessity
+  }
+
   private static class SolrInstance {
 
     private String name;