@Test
  public void testRebalanceOnlyAfterAllShardsAreActive() {
    ShardsAllocation strategy =
        new ShardsAllocation(
            settingsBuilder().put("cluster.routing.allocation.concurrent_recoveries", 10).build());

    logger.info("Building initial routing table");

    MetaData metaData =
        newMetaDataBuilder()
            .put(newIndexMetaDataBuilder("test").numberOfShards(5).numberOfReplicas(1))
            .build();

    RoutingTable routingTable =
        routingTable()
            .add(indexRoutingTable("test").initializeEmpty(metaData.index("test")))
            .build();

    ClusterState clusterState =
        newClusterStateBuilder().metaData(metaData).routingTable(routingTable).build();

    assertThat(routingTable.index("test").shards().size(), equalTo(5));
    for (int i = 0; i < routingTable.index("test").shards().size(); i++) {
      assertThat(routingTable.index("test").shard(i).shards().size(), equalTo(2));
      assertThat(routingTable.index("test").shard(i).shards().get(0).state(), equalTo(UNASSIGNED));
      assertThat(routingTable.index("test").shard(i).shards().get(1).state(), equalTo(UNASSIGNED));
      assertThat(routingTable.index("test").shard(i).shards().get(0).currentNodeId(), nullValue());
      assertThat(routingTable.index("test").shard(i).shards().get(1).currentNodeId(), nullValue());
    }

    logger.info("start two nodes and fully start the shards");
    clusterState =
        newClusterStateBuilder()
            .state(clusterState)
            .nodes(newNodesBuilder().put(newNode("node1")).put(newNode("node2")))
            .build();
    RoutingTable prevRoutingTable = routingTable;
    routingTable = strategy.reroute(clusterState).routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();

    for (int i = 0; i < routingTable.index("test").shards().size(); i++) {
      assertThat(routingTable.index("test").shard(i).shards().size(), equalTo(2));
      assertThat(routingTable.index("test").shard(i).primaryShard().state(), equalTo(INITIALIZING));
      assertThat(
          routingTable.index("test").shard(i).replicaShards().get(0).state(), equalTo(UNASSIGNED));
    }

    logger.info("start all the primary shards, replicas will start initializing");
    RoutingNodes routingNodes = clusterState.routingNodes();
    prevRoutingTable = routingTable;
    routingTable =
        strategy
            .applyStartedShards(clusterState, routingNodes.shardsWithState(INITIALIZING))
            .routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();
    routingNodes = clusterState.routingNodes();

    for (int i = 0; i < routingTable.index("test").shards().size(); i++) {
      assertThat(routingTable.index("test").shard(i).shards().size(), equalTo(2));
      assertThat(routingTable.index("test").shard(i).primaryShard().state(), equalTo(STARTED));
      assertThat(
          routingTable.index("test").shard(i).replicaShards().get(0).state(),
          equalTo(INITIALIZING));
    }

    logger.info("now, start 8 more nodes, and check that no rebalancing/relocation have happened");
    clusterState =
        newClusterStateBuilder()
            .state(clusterState)
            .nodes(
                newNodesBuilder()
                    .putAll(clusterState.nodes())
                    .put(newNode("node3"))
                    .put(newNode("node4"))
                    .put(newNode("node5"))
                    .put(newNode("node6"))
                    .put(newNode("node7"))
                    .put(newNode("node8"))
                    .put(newNode("node9"))
                    .put(newNode("node10")))
            .build();
    prevRoutingTable = routingTable;
    routingTable = strategy.reroute(clusterState).routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();
    routingNodes = clusterState.routingNodes();

    for (int i = 0; i < routingTable.index("test").shards().size(); i++) {
      assertThat(routingTable.index("test").shard(i).shards().size(), equalTo(2));
      assertThat(routingTable.index("test").shard(i).primaryShard().state(), equalTo(STARTED));
      assertThat(
          routingTable.index("test").shard(i).replicaShards().get(0).state(),
          equalTo(INITIALIZING));
    }

    logger.info("start the replica shards, rebalancing should start");
    routingNodes = clusterState.routingNodes();
    prevRoutingTable = routingTable;
    routingTable =
        strategy
            .applyStartedShards(clusterState, routingNodes.shardsWithState(INITIALIZING))
            .routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();
    routingNodes = clusterState.routingNodes();

    // we only allow one relocation at a time
    assertThat(routingTable.shardsWithState(STARTED).size(), equalTo(5));
    assertThat(routingTable.shardsWithState(RELOCATING).size(), equalTo(5));

    logger.info("complete relocation, other half of relocation should happen");
    routingNodes = clusterState.routingNodes();
    prevRoutingTable = routingTable;
    routingTable =
        strategy
            .applyStartedShards(clusterState, routingNodes.shardsWithState(INITIALIZING))
            .routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();
    routingNodes = clusterState.routingNodes();

    // we now only relocate 3, since 2 remain where they are!
    assertThat(routingTable.shardsWithState(STARTED).size(), equalTo(7));
    assertThat(routingTable.shardsWithState(RELOCATING).size(), equalTo(3));

    logger.info("complete relocation, thats it!");
    routingNodes = clusterState.routingNodes();
    prevRoutingTable = routingTable;
    routingTable =
        strategy
            .applyStartedShards(clusterState, routingNodes.shardsWithState(INITIALIZING))
            .routingTable();
    clusterState = newClusterStateBuilder().state(clusterState).routingTable(routingTable).build();
    routingNodes = clusterState.routingNodes();

    assertThat(routingTable.shardsWithState(STARTED).size(), equalTo(10));
    // make sure we have an even relocation
    for (RoutingNode routingNode : routingNodes) {
      assertThat(routingNode.shards().size(), equalTo(1));
    }
  }
  @Test
  public void testSimpleJsonFromAndTo() throws IOException {
    MetaData metaData =
        newMetaDataBuilder()
            .maxNumberOfShardsPerNode(2)
            .put(newIndexMetaDataBuilder("test1").numberOfShards(1).numberOfReplicas(2))
            .put(
                newIndexMetaDataBuilder("test2")
                    .settings(settingsBuilder().put("setting1", "value1").put("setting2", "value2"))
                    .numberOfShards(2)
                    .numberOfReplicas(3))
            .put(
                newIndexMetaDataBuilder("test3")
                    .numberOfShards(1)
                    .numberOfReplicas(2)
                    .putMapping("mapping1", MAPPING_SOURCE1))
            .put(
                newIndexMetaDataBuilder("test4")
                    .settings(settingsBuilder().put("setting1", "value1").put("setting2", "value2"))
                    .numberOfShards(1)
                    .numberOfReplicas(2)
                    .putMapping("mapping1", MAPPING_SOURCE1)
                    .putMapping("mapping2", MAPPING_SOURCE2))
            .build();

    String metaDataSource = MetaData.Builder.toJson(metaData);
    System.out.println("ToJson: " + metaDataSource);

    MetaData parsedMetaData =
        MetaData.Builder.fromJson(
            Jackson.defaultJsonFactory().createJsonParser(metaDataSource), null);
    assertThat(parsedMetaData.maxNumberOfShardsPerNode(), equalTo(2));

    IndexMetaData indexMetaData = metaData.index("test1");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(2));
    assertThat(indexMetaData.mappings().size(), equalTo(0));

    indexMetaData = metaData.index("test2");
    assertThat(indexMetaData.numberOfShards(), equalTo(2));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(3));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(4));
    assertThat(indexMetaData.settings().get("setting1"), equalTo("value1"));
    assertThat(indexMetaData.settings().get("setting2"), equalTo("value2"));
    assertThat(indexMetaData.mappings().size(), equalTo(0));

    indexMetaData = metaData.index("test3");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(2));
    assertThat(indexMetaData.mappings().size(), equalTo(1));
    assertThat(indexMetaData.mappings().get("mapping1"), equalTo(MAPPING_SOURCE1));

    indexMetaData = metaData.index("test4");
    assertThat(indexMetaData.numberOfShards(), equalTo(1));
    assertThat(indexMetaData.numberOfReplicas(), equalTo(2));
    assertThat(indexMetaData.settings().getAsMap().size(), equalTo(4));
    assertThat(indexMetaData.settings().get("setting1"), equalTo("value1"));
    assertThat(indexMetaData.settings().get("setting2"), equalTo("value2"));
    assertThat(indexMetaData.mappings().size(), equalTo(2));
    assertThat(indexMetaData.mappings().get("mapping1"), equalTo(MAPPING_SOURCE1));
    assertThat(indexMetaData.mappings().get("mapping2"), equalTo(MAPPING_SOURCE2));
  }