@Test
  public void testNetworkPartitionDuringReplicaIndexOp() throws Exception {
    final String INDEX = "testidx";

    List<String> nodes = internalCluster().startNodesAsync(2, nodeSettings).get();

    // Create index test with 1 shard, 1 replica and ensure it is green
    createIndex(INDEX);
    ensureGreen(INDEX);

    // Disable allocation so the replica cannot be reallocated when it fails
    Settings s =
        ImmutableSettings.builder().put("cluster.routing.allocation.enable", "none").build();
    client().admin().cluster().prepareUpdateSettings().setTransientSettings(s).get();

    // Determine which node holds the primary shard
    ClusterState state = getNodeClusterState(nodes.get(0));
    IndexShardRoutingTable shard = state.getRoutingTable().index(INDEX).shard(0);
    String primaryNode;
    String replicaNode;
    if (shard.getShards().get(0).primary()) {
      primaryNode = nodes.get(0);
      replicaNode = nodes.get(1);
    } else {
      primaryNode = nodes.get(1);
      replicaNode = nodes.get(0);
    }
    logger.info("--> primary shard is on {}", primaryNode);

    // Index a document to make sure everything works well
    IndexResponse resp =
        internalCluster()
            .client(primaryNode)
            .prepareIndex(INDEX, "doc")
            .setSource("foo", "bar")
            .get();
    assertThat(
        "document exists on primary node",
        internalCluster()
            .client(primaryNode)
            .prepareGet(INDEX, "doc", resp.getId())
            .setPreference("_only_local")
            .get()
            .isExists(),
        equalTo(true));
    assertThat(
        "document exists on replica node",
        internalCluster()
            .client(replicaNode)
            .prepareGet(INDEX, "doc", resp.getId())
            .setPreference("_only_local")
            .get()
            .isExists(),
        equalTo(true));

    // Disrupt the network so indexing requests fail to replicate
    logger.info("--> preventing index/replica operations");
    TransportService mockTransportService =
        internalCluster().getInstance(TransportService.class, primaryNode);
    ((MockTransportService) mockTransportService)
        .addFailToSendNoConnectRule(
            internalCluster().getInstance(Discovery.class, replicaNode).localNode(),
            ImmutableSet.of(IndexAction.NAME + "[r]"));
    mockTransportService = internalCluster().getInstance(TransportService.class, replicaNode);
    ((MockTransportService) mockTransportService)
        .addFailToSendNoConnectRule(
            internalCluster().getInstance(Discovery.class, primaryNode).localNode(),
            ImmutableSet.of(IndexAction.NAME + "[r]"));

    logger.info("--> indexing into primary");
    // the replica shard should now be marked as failed because the replication operation will fail
    resp =
        internalCluster()
            .client(primaryNode)
            .prepareIndex(INDEX, "doc")
            .setSource("foo", "baz")
            .get();
    // wait until the cluster reaches an exact yellow state, meaning replica has failed
    assertBusy(
        new Runnable() {
          @Override
          public void run() {
            assertThat(
                client().admin().cluster().prepareHealth().get().getStatus(),
                equalTo(ClusterHealthStatus.YELLOW));
          }
        });
    assertThat(
        "document should still be indexed and available",
        client().prepareGet(INDEX, "doc", resp.getId()).get().isExists(),
        equalTo(true));

    state = getNodeClusterState(randomFrom(nodes.toArray(Strings.EMPTY_ARRAY)));
    RoutingNodes rn = state.routingNodes();
    logger.info(
        "--> counts: total: {}, unassigned: {}, initializing: {}, relocating: {}, started: {}",
        rn.shards(
                new Predicate<MutableShardRouting>() {
                  @Override
                  public boolean apply(
                      org.elasticsearch.cluster.routing.MutableShardRouting input) {
                    return true;
                  }
                })
            .size(),
        rn.shardsWithState(UNASSIGNED).size(),
        rn.shardsWithState(INITIALIZING).size(),
        rn.shardsWithState(RELOCATING).size(),
        rn.shardsWithState(STARTED).size());
    logger.info(
        "--> unassigned: {}, initializing: {}, relocating: {}, started: {}",
        rn.shardsWithState(UNASSIGNED),
        rn.shardsWithState(INITIALIZING),
        rn.shardsWithState(RELOCATING),
        rn.shardsWithState(STARTED));

    assertThat(
        "only a single shard is now active (replica should be failed and not reallocated)",
        rn.shardsWithState(STARTED).size(),
        equalTo(1));
  }
  @Test
  public void testMockFailToSendNoConnectRule() {
    serviceA.registerHandler(
        "sayHello",
        new BaseTransportRequestHandler<StringMessageRequest>() {
          @Override
          public StringMessageRequest newInstance() {
            return new StringMessageRequest();
          }

          @Override
          public String executor() {
            return ThreadPool.Names.GENERIC;
          }

          @Override
          public void messageReceived(StringMessageRequest request, TransportChannel channel)
              throws Exception {
            assertThat("moshe", equalTo(request.message));
            throw new RuntimeException("bad message !!!");
          }
        });

    serviceB.addFailToSendNoConnectRule(nodeA);

    TransportFuture<StringMessageResponse> res =
        serviceB.submitRequest(
            nodeA,
            "sayHello",
            new StringMessageRequest("moshe"),
            new BaseTransportResponseHandler<StringMessageResponse>() {
              @Override
              public StringMessageResponse newInstance() {
                return new StringMessageResponse();
              }

              @Override
              public String executor() {
                return ThreadPool.Names.GENERIC;
              }

              @Override
              public void handleResponse(StringMessageResponse response) {
                assertThat("got response instead of exception", false, equalTo(true));
              }

              @Override
              public void handleException(TransportException exp) {
                assertThat(exp.getCause().getMessage(), endsWith("DISCONNECT: simulated"));
              }
            });

    try {
      res.txGet();
      assertThat("exception should be thrown", false, equalTo(true));
    } catch (Exception e) {
      assertThat(e.getCause().getMessage(), endsWith("DISCONNECT: simulated"));
    }

    try {
      serviceB.connectToNode(nodeA);
      assertThat("exception should be thrown", false, equalTo(true));
    } catch (ConnectTransportException e) {
      // all is well
    }

    try {
      serviceB.connectToNodeLight(nodeA);
      assertThat("exception should be thrown", false, equalTo(true));
    } catch (ConnectTransportException e) {
      // all is well
    }

    serviceA.removeHandler("sayHello");
  }