public void testConcurrentCreateAndDeleteDoesNotFail() {
    final File configDir = getFile("solr").toPath().resolve("configsets/configset-2/conf").toFile();
    final AtomicReference<Exception> failure = new AtomicReference<>();
    final int timeToRunSec = 30;
    final Thread[] threads = new Thread[10];
    for (int i = 0; i < threads.length; i++) {
      final String collectionName = "collection" + i;
      uploadConfig(configDir, collectionName);
      final SolrClient solrClient =
          new HttpSolrClient(solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString());
      threads[i] =
          new CreateDeleteSearchCollectionThread(
              "create-delete-search-" + i,
              collectionName,
              collectionName,
              timeToRunSec,
              solrClient,
              failure);
    }

    startAll(threads);
    joinAll(threads);

    assertNull("concurrent create and delete collection failed: " + failure.get(), failure.get());
  }
  public void testConcurrentCreateAndDeleteOverTheSameConfig() {
    final String configName = "testconfig";
    final File configDir = getFile("solr").toPath().resolve("configsets/configset-2/conf").toFile();
    uploadConfig(configDir, configName); // upload config once, to be used by all collections
    final SolrClient solrClient =
        new HttpSolrClient(solrCluster.getJettySolrRunners().get(0).getBaseUrl().toString());
    final AtomicReference<Exception> failure = new AtomicReference<>();
    final int timeToRunSec = 30;
    final Thread[] threads = new Thread[2];
    for (int i = 0; i < threads.length; i++) {
      final String collectionName = "collection" + i;
      threads[i] =
          new CreateDeleteCollectionThread(
              "create-delete-" + i, collectionName, configName, timeToRunSec, solrClient, failure);
    }

    startAll(threads);
    joinAll(threads);

    assertNull("concurrent create and delete collection failed: " + failure.get(), failure.get());

    try {
      solrClient.close();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
 private void uploadConfig(File configDir, String configName) {
   try {
     solrCluster.uploadConfigDir(configDir, configName);
   } catch (IOException | KeeperException | InterruptedException e) {
     throw new RuntimeException(e);
   }
 }
 @Override
 @After
 public void tearDown() throws Exception {
   solrCluster.shutdown();
   super.tearDown();
 }
 /**
  * Sets the tracking queue for all nodes participating in this cluster. Once this method returns,
  * all search and core admin requests distributed to shards will be submitted to the given queue.
  *
  * <p>This is equivalent to calling: <code>
  * TrackingShardHandlerFactory.setTrackingQueue(cluster.getJettySolrRunners(), queue)</code>
  *
  * @see
  *     org.apache.solr.handler.component.TrackingShardHandlerFactory#setTrackingQueue(java.util.List,
  *     java.util.Queue)
  */
 public static void setTrackingQueue(
     MiniSolrCloudCluster cluster, Queue<ShardRequestAndParams> queue) {
   setTrackingQueue(cluster.getJettySolrRunners(), queue);
 }
  /**
   * Starts a source cluster with no CDCR configuration, indexes enough documents such that the at
   * least one old tlog is closed and thrown away so that the source cluster does not have all
   * updates available in tlogs only.
   *
   * <p>Then we start a target cluster with CDCR configuration and we change the source cluster
   * configuration to use CDCR (i.e. CdcrUpdateLog, CdcrRequestHandler and CdcrUpdateProcessor) and
   * restart it.
   *
   * <p>We test that all updates eventually make it to the target cluster and that the
   * collectioncheckpoint call returns the same version as the last update indexed on the source.
   */
  @Test
  public void testConvertClusterToCdcrAndBootstrap() throws Exception {
    // start the target first so that we know its zkhost
    MiniSolrCloudCluster target =
        new MiniSolrCloudCluster(1, createTempDir("cdcr-target"), buildJettyConfig("/solr"));
    try {
      target.waitForAllNodes(30);
      System.out.println("Target zkHost = " + target.getZkServer().getZkAddress());
      System.setProperty("cdcr.target.zkHost", target.getZkServer().getZkAddress());

      // start a cluster with no cdcr
      MiniSolrCloudCluster source =
          new MiniSolrCloudCluster(1, createTempDir("cdcr-source"), buildJettyConfig("/solr"));
      try {
        source.waitForAllNodes(30);
        source.uploadConfigSet(configset("cdcr-source-disabled"), "cdcr-source");

        // create a collection with the cdcr-source-disabled configset
        CollectionAdminRequest.createCollection("cdcr-source", "cdcr-source", 1, 1)
            // todo investigate why this is necessary??? because by default it selects a ram
            // directory which deletes the tlogs on reloads?
            .withProperty("solr.directoryFactory", "solr.StandardDirectoryFactory")
            .process(source.getSolrClient());

        // index 10000 docs with a hard commit every 1000 documents
        CloudSolrClient sourceSolrClient = source.getSolrClient();
        sourceSolrClient.setDefaultCollection("cdcr-source");
        int numDocs = 0;
        for (int k = 0; k < 100; k++) {
          UpdateRequest req = new UpdateRequest();
          for (; numDocs < (k + 1) * 100; numDocs++) {
            SolrInputDocument doc = new SolrInputDocument();
            doc.addField("id", "source_" + numDocs);
            doc.addField("xyz", numDocs);
            req.add(doc);
          }
          req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
          System.out.println("Adding 100 docs with commit=true, numDocs=" + numDocs);
          req.process(sourceSolrClient);
        }

        QueryResponse response = sourceSolrClient.query(new SolrQuery("*:*"));
        assertEquals("", numDocs, response.getResults().getNumFound());

        // lets find and keep the maximum version assigned by source cluster across all our updates
        long maxVersion = Long.MIN_VALUE;
        ModifiableSolrParams params = new ModifiableSolrParams();
        params.set(CommonParams.QT, "/get");
        params.set("getVersions", numDocs);
        response = sourceSolrClient.query(params);
        List<Long> versions = (List<Long>) response.getResponse().get("versions");
        for (Long version : versions) {
          maxVersion = Math.max(maxVersion, version);
        }

        //       upload the cdcr-enabled config and restart source cluster
        source.uploadConfigSet(configset("cdcr-source"), "cdcr-source");
        JettySolrRunner runner = source.stopJettySolrRunner(0);
        source.startJettySolrRunner(runner);
        assertTrue(runner.isRunning());
        AbstractDistribZkTestBase.waitForRecoveriesToFinish(
            "cdcr-source", source.getSolrClient().getZkStateReader(), true, true, 330);

        response = sourceSolrClient.query(new SolrQuery("*:*"));
        assertEquals(
            "Document mismatch on source after restart",
            numDocs,
            response.getResults().getNumFound());

        // setup the target cluster
        target.uploadConfigSet(configset("cdcr-target"), "cdcr-target");
        CollectionAdminRequest.createCollection("cdcr-target", "cdcr-target", 1, 1)
            .process(target.getSolrClient());
        CloudSolrClient targetSolrClient = target.getSolrClient();
        targetSolrClient.setDefaultCollection("cdcr-target");
        Thread.sleep(1000);

        cdcrStart(targetSolrClient);
        cdcrStart(sourceSolrClient);

        response = getCdcrQueue(sourceSolrClient);
        System.out.println("Cdcr queue response: " + response.getResponse());
        long foundDocs = waitForTargetToSync(numDocs, targetSolrClient);
        assertEquals("Document mismatch on target after sync", numDocs, foundDocs);

        params = new ModifiableSolrParams();
        params.set(CommonParams.ACTION, CdcrParams.CdcrAction.COLLECTIONCHECKPOINT.toString());
        params.set(CommonParams.QT, "/cdcr");
        response = targetSolrClient.query(params);
        Long checkpoint = (Long) response.getResponse().get(CdcrParams.CHECKPOINT);
        assertNotNull(checkpoint);
        assertEquals(
            "COLLECTIONCHECKPOINT from target cluster should have returned the maximum "
                + "version across all updates made to source",
            maxVersion,
            checkpoint.longValue());
      } finally {
        source.shutdown();
      }
    } finally {
      target.shutdown();
    }
  }
  public void testBootstrapWithContinousIndexingOnSourceCluster() throws Exception {
    // start the target first so that we know its zkhost
    MiniSolrCloudCluster target =
        new MiniSolrCloudCluster(1, createTempDir("cdcr-target"), buildJettyConfig("/solr"));
    target.waitForAllNodes(30);
    try {
      System.out.println("Target zkHost = " + target.getZkServer().getZkAddress());
      System.setProperty("cdcr.target.zkHost", target.getZkServer().getZkAddress());

      MiniSolrCloudCluster source =
          new MiniSolrCloudCluster(1, createTempDir("cdcr-source"), buildJettyConfig("/solr"));
      try {
        source.waitForAllNodes(30);
        source.uploadConfigSet(configset("cdcr-source"), "cdcr-source");

        CollectionAdminRequest.createCollection("cdcr-source", "cdcr-source", 1, 1)
            .withProperty("solr.directoryFactory", "solr.StandardDirectoryFactory")
            .process(source.getSolrClient());

        // index 10000 docs with a hard commit every 1000 documents
        CloudSolrClient sourceSolrClient = source.getSolrClient();
        sourceSolrClient.setDefaultCollection("cdcr-source");
        int numDocs = 0;
        for (int k = 0; k < 100; k++) {
          UpdateRequest req = new UpdateRequest();
          for (; numDocs < (k + 1) * 100; numDocs++) {
            SolrInputDocument doc = new SolrInputDocument();
            doc.addField("id", "source_" + numDocs);
            doc.addField("xyz", numDocs);
            req.add(doc);
          }
          req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
          System.out.println("Adding 100 docs with commit=true, numDocs=" + numDocs);
          req.process(sourceSolrClient);
        }

        QueryResponse response = sourceSolrClient.query(new SolrQuery("*:*"));
        assertEquals("", numDocs, response.getResults().getNumFound());

        // setup the target cluster
        target.uploadConfigSet(configset("cdcr-target"), "cdcr-target");
        CollectionAdminRequest.createCollection("cdcr-target", "cdcr-target", 1, 1)
            .process(target.getSolrClient());
        CloudSolrClient targetSolrClient = target.getSolrClient();
        targetSolrClient.setDefaultCollection("cdcr-target");
        Thread.sleep(1000);

        cdcrStart(targetSolrClient);
        cdcrStart(sourceSolrClient);

        int c = 0;
        for (int k = 0; k < 100; k++) {
          UpdateRequest req = new UpdateRequest();
          for (; c < (k + 1) * 100; c++, numDocs++) {
            SolrInputDocument doc = new SolrInputDocument();
            doc.addField("id", "source_" + numDocs);
            doc.addField("xyz", numDocs);
            req.add(doc);
          }
          req.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
          System.out.println("Adding 100 docs with commit=true, numDocs=" + numDocs);
          req.process(sourceSolrClient);
        }

        response = sourceSolrClient.query(new SolrQuery("*:*"));
        assertEquals("", numDocs, response.getResults().getNumFound());

        response = getCdcrQueue(sourceSolrClient);
        System.out.println("Cdcr queue response: " + response.getResponse());
        long foundDocs = waitForTargetToSync(numDocs, targetSolrClient);
        assertEquals("Document mismatch on target after sync", numDocs, foundDocs);

      } finally {
        source.shutdown();
      }
    } finally {
      target.shutdown();
    }
  }