text: // Test copyDatabase command with various combinations of authed/unauthed and single node/replica
  // set source and dest.
  
  TestData.authMechanism = "MONGODB-CR"; // SERVER-11428
  DB.prototype._defaultAuthenticationMechanism = "MONGODB-CR"; // SERVER-11428
  
  var baseName = "jstests_clone_copyauth";
  
  /*
   * Helper to spawn a replica set, sharded cluster, or a single mongod and hide it all behind the
   * same interface.
   *
   * Arguments:
   *
   * clusterType - type of cluster to start.  Options are "sharded", "repl", or "single".
   * startWithAuth - whether to start the cluster with authentication.
   *
   * Member variables:
   *
   * conn - a connection to the node used to access this cluster, whether it's the mongod, a primary
   * mongod in a replica set, or a mongos.
   * connString - the full connection string used to connect to this cluster.  For a replica set this
   * is the full connection string including the replica set name.
   *
   * Member functions:
   *
   * stop() - stop and cleanup whatever nodes the helper spawned when it was created.
   */
  function ClusterSpawnHelper(clusterType, startWithAuth) {
  
      if (clusterType === "sharded") {
          var shardingTestConfig = {
              name : baseName + "_source",
              mongos : 1,
              shards : 1,
              config : 1
          }
          if (startWithAuth) {
              shardingTestConfig.auth = "";
              shardingTestConfig.keyFile = "jstests/libs/key1";
          }
          var shardingTest = new ShardingTest(shardingTestConfig);
          this.conn = shardingTest.s;
          this.connString = this.conn.host;
      }
      else if (clusterType === "repl") {
          var replSetTestConfig = { name: baseName + "_source", nodes: 3, nodeOptions: {} };
          if (startWithAuth) {
              replSetTestConfig.nodeOptions.auth = "";
              replSetTestConfig.nodeOptions.keyFile = "jstests/libs/key1";
          }
          var replSetTest = new ReplSetTest(replSetTestConfig);
          replSetTest.startSet();
          replSetTest.initiate();
          replSetTest.awaitReplication();
          this.conn = replSetTest.getMaster();
          this.connString = replSetTest.getURL();
      }
      else {
          var singleNodeConfig = {};
          if (startWithAuth) {
              singleNodeConfig.auth = "";
          }
          this.conn = MongoRunner.runMongod(singleNodeConfig);
          this.connString = this.conn.host;
      }
  
      this.stop = function () {
          if (clusterType === "sharded") {
              shardingTest.stop();
          }
          else if (clusterType === "repl") {
              replSetTest.stopSet();
          }
          else {
              MongoRunner.stopMongod(this.conn.port);
          }
      }
  }
  
  /*
   * Helper to test the running the "copydb" command between various kinds of clusters and various
   * combinations of authentication on the source and target.
   *
   * @param {Object} configObj
   *
   *   {
   *     sourceClusterType {string}: Type of cluster to use as the source of the copy.  Options are
   *         "single", "repl", "sharded".
   *     isSourceUsingAuth {bool}: Whether to use auth in the source cluster for the copy.
   *     targetClusterType {string}: Type of cluster to use as the target of the copy.  Options are
   *         "single", "repl", "sharded".
   *     isTargetUsingAuth {bool}: Whether to use auth in the target cluster for the copy.
   *   }
   */
  function copydbBetweenClustersTest(configObj) {
  
  
  
      // First sanity check the arguments in our configObj
      var requiredKeys = [
          'sourceClusterType',
          'isSourceUsingAuth',
          'targetClusterType',
          'isTargetUsingAuth'
      ]
  
      var i;
      for (i = 0; i < requiredKeys.length; i++) {
          assert(configObj.hasOwnProperty(requiredKeys[i]),
                 "Missing required key: " + requiredKeys[i] + " in config object");
      }
  
  
  
      // 1. Get a connection to the source database, insert data and setup auth if applicable
      source = new ClusterSpawnHelper(configObj.sourceClusterType, configObj.isSourceUsingAuth);
  
      source.conn.getDB(baseName)[baseName].save({i:1});
      assert.eq(1, source.conn.getDB(baseName)[baseName].count());
      assert.eq(1, source.conn.getDB(baseName)[baseName].findOne().i);
  
      if (configObj.isSourceUsingAuth) {
          // Create a super user so we can create a regular user and not be locked out afterwards
          source.conn.getDB("admin").createUser({ user: "sourceSuperUser", pwd: "sourceSuperUser",
                                                  roles: [ "root" ] });
          source.conn.getDB("admin").auth("sourceSuperUser", "sourceSuperUser");
  
          // Insert a document and create a regular user that we will use for the target
          // authenticating with the source
          source.conn.getDB(baseName).createUser({ user: "foo", pwd: "bar",
                                                   roles: [ "dbOwner" ] });
  
          source.conn.getDB("admin").logout();
          assert.throws(function() { source.conn.getDB(baseName)[baseName].findOne(); });
      }
  
  
  
      // 2. Get a connection to the target database, and set up auth if necessary
      target = new ClusterSpawnHelper(configObj.targetClusterType, configObj.isTargetUsingAuth);
  
      if (configObj.isTargetUsingAuth) {
          target.conn.getDB("admin").createUser({ user: "targetSuperUser", pwd: "targetSuperUser",
                                                  roles: [ "root" ] });
          assert.throws(function() { target.conn.getDB(baseName)[baseName].findOne(); });
          target.conn.getDB("admin").auth("targetSuperUser", "targetSuperUser");
      }
  
  
  
      // 3. Run the copydb command
      target.conn.getDB(baseName).dropDatabase();
      assert.eq(0, target.conn.getDB(baseName)[baseName].count());
      if (configObj.isSourceUsingAuth) {
          // We only need to pass username and password if the target has to send authentication
          // information to the source cluster
          assert.commandWorked(target.conn.getDB(baseName).copyDatabase(baseName, baseName,
                                                                        source.connString,
                                                                        "foo", "bar"));
      }
      else {
          // We are copying from a cluster with no auth
          assert.commandWorked(target.conn.getDB(baseName).copyDatabase(baseName, baseName,
                                                                        source.connString));
      }
      assert.eq(1, target.conn.getDB(baseName)[baseName].count());
      assert.eq(1, target.conn.getDB(baseName)[baseName].findOne().i);
  
  
  
      // 4. Do any necessary cleanup
      source.stop();
      target.stop();
  }
  
  var sourceClusterTypeValues = [ "single", "repl", "sharded" ]
  var isSourceUsingAuthValues = [ true, false ]
  var targetClusterTypeValues = [ "single", "repl", "sharded" ]
  var isTargetUsingAuthValues = [ true, false ]
  for (var i = 0; i < sourceClusterTypeValues.length; i++) {
      for (var j = 0; j < isSourceUsingAuthValues.length; j++) {
          for (var k = 0; k < targetClusterTypeValues.length; k++) {
              for (var l = 0; l < isTargetUsingAuthValues.length; l++) {
                  if (sourceClusterTypeValues[i] === "sharded" &&
                      targetClusterTypeValues[k] === "sharded") {
                      // SERVER-13112
                      continue;
                  }
                  if (sourceClusterTypeValues[i] === "repl" &&
                      targetClusterTypeValues[k] === "repl") {
                      // SERVER-13077
                      continue;
                  }
                  if (isSourceUsingAuthValues[j] === true &&
                      targetClusterTypeValues[k] === "sharded") {
                      // SERVER-6427
                      continue;
                  }
                  var testCase = {
                      'sourceClusterType' : sourceClusterTypeValues[i],
                      'isSourceUsingAuth' : isSourceUsingAuthValues[j],
                      'targetClusterType' : targetClusterTypeValues[k],
                      'isTargetUsingAuth' : isTargetUsingAuthValues[l]
                  }
                  print("Running copydb with auth test:");
                  printjson(testCase);
                  copydbBetweenClustersTest(testCase);
              }
          }
      }
  }
  
  print(baseName + " success!");
  