/** Test method for {@link X509Authenticator#startAuthentication(Credential, Connection)} . */
  @Test
  public void testStartAuthentication() {
    final Credential credential = Credential.builder().userName("CN=foo").build();
    final Connection mockConnection = createMock(Connection.class);
    final Capture<ReplyCallback> capture = new Capture<ReplyCallback>();

    final DocumentBuilder b = BuilderFactory.start();
    b.add("authenticate", 1);
    b.add("user", "CN=foo");
    b.add("mechanism", X509Authenticator.MECHANISM);

    mockConnection.send(
        eq(new Command(X509Authenticator.EXTERNAL, Command.COMMAND_COLLECTION, b.build())),
        capture(capture));
    expectLastCall();

    replay(mockConnection);

    final X509Authenticator auth = new X509Authenticator();

    auth.startAuthentication(credential, mockConnection);

    verify(mockConnection);

    assertThat(capture.getValue(), instanceOf(X509ResponseCallback.class));
  }
  /**
   * Re-bootstraps the environment. Normally this method is only called once during the constructor
   * of the factory to initialize the delegate but users can reset the delegate by manually invoking
   * this method.
   *
   * <p>A bootstrap will issue one commands to the first working MongoDB process. The reply to the
   * {@link IsMaster} command is used to detect connecting to a mongos <tt>process</tt> and by
   * extension a Sharded configuration.
   *
   * <p>If not using a Sharded configuration then the server status is checked for a <tt>repl</tt>
   * element. If present a Replication Set configuration is assumed.
   *
   * <p>If neither a Sharded or Replication Set is being used then a plain socket connection factory
   * is used.
   */
  protected void bootstrap() {
    final SocketConnectionFactory socketFactory = createSocketFactory(myConfig);
    socketFactory.setMetrics(myMetrics);

    ProxiedConnectionFactory factory = socketFactory;

    // Authentication has to be right on top of the physical
    // connection.
    if (myConfig.isAuthenticating()) {
      factory = new AuthenticationConnectionFactory(factory, myConfig);
    }

    try {
      // Use the socket factories cluster.
      final Cluster cluster = socketFactory.getCluster();
      for (final InetSocketAddress addr : myConfig.getServerAddresses()) {
        Connection conn = null;
        final FutureReplyCallback future = new FutureReplyCallback();
        try {
          conn = factory.connect(cluster.add(addr), myConfig);

          conn.send(new IsMaster(), future);
          final Reply reply = future.get();

          // Close the connection now that we have the reply.
          IOUtils.close(conn);

          final List<Document> results = reply.getResults();
          if (!results.isEmpty()) {
            final Document doc = results.get(0);

            if (isMongos(doc)) {
              LOG.debug("Sharded bootstrap to {}.", addr);
              cluster.clear(); // not needed.
              myDelegate = bootstrapSharded(factory);
            } else if (isReplicationSet(doc)) {
              LOG.debug("Replica-set bootstrap to {}.", addr);
              cluster.clear(); // not needed.
              myDelegate = bootstrapReplicaSet(factory);
            } else {
              LOG.debug("Simple MongoDB bootstrap to {}.", addr);
              myDelegate = factory;
            }
            factory = null; // Don't close.
            return;
          }
        } catch (final IOException ioe) {
          LOG.warn(ioe, "I/O error during bootstrap to {}.", addr);
        } catch (final InterruptedException e) {
          LOG.warn(e, "Interrupted during bootstrap to {}.", addr);
        } catch (final ExecutionException e) {
          LOG.warn(e, "Error during bootstrap to {}.", addr);
        } finally {
          IOUtils.close(
              conn, Level.WARNING, "I/O error shutting down bootstrap connection to " + addr + ".");
        }
      }
    } finally {
      IOUtils.close(factory);
    }
  }