@Test
  public void testEncodeDecodeCommonStats() throws IOException {
    CommonStatsFlags flags = new CommonStatsFlags();
    Flag[] values = CommonStatsFlags.Flag.values();
    assertThat(flags.anySet(), equalTo(true));

    for (Flag flag : values) {
      flags.set(flag, false);
    }
    assertThat(flags.anySet(), equalTo(false));
    for (Flag flag : values) {
      flags.set(flag, true);
    }
    assertThat(flags.anySet(), equalTo(true));
    Random random = getRandom();
    flags.set(values[random.nextInt(values.length)], false);
    assertThat(flags.anySet(), equalTo(true));

    {
      BytesStreamOutput out = new BytesStreamOutput();
      flags.writeTo(out);
      out.close();
      BytesReference bytes = out.bytes();
      CommonStatsFlags readStats =
          CommonStatsFlags.readCommonStatsFlags(new BytesStreamInput(bytes));
      for (Flag flag : values) {
        assertThat(flags.isSet(flag), equalTo(readStats.isSet(flag)));
      }
    }

    {
      for (Flag flag : values) {
        flags.set(flag, random.nextBoolean());
      }
      BytesStreamOutput out = new BytesStreamOutput();
      flags.writeTo(out);
      out.close();
      BytesReference bytes = out.bytes();
      CommonStatsFlags readStats =
          CommonStatsFlags.readCommonStatsFlags(new BytesStreamInput(bytes));
      for (Flag flag : values) {
        assertThat(flags.isSet(flag), equalTo(readStats.isSet(flag)));
      }
    }
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    String[] nodesIds = Strings.splitStringByCommaToArray(request.param("nodeId"));
    Set<String> metrics = Strings.splitStringByCommaToSet(request.param("metric", "_all"));

    NodesStatsRequest nodesStatsRequest = new NodesStatsRequest(nodesIds);
    nodesStatsRequest.listenerThreaded(false);

    if (metrics.size() == 1 && metrics.contains("_all")) {
      nodesStatsRequest.all();
      nodesStatsRequest.indices(CommonStatsFlags.ALL);
    } else {
      nodesStatsRequest.clear();
      nodesStatsRequest.os(metrics.contains("os"));
      nodesStatsRequest.jvm(metrics.contains("jvm"));
      nodesStatsRequest.threadPool(metrics.contains("thread_pool"));
      nodesStatsRequest.network(metrics.contains("network"));
      nodesStatsRequest.fs(metrics.contains("fs"));
      nodesStatsRequest.transport(metrics.contains("transport"));
      nodesStatsRequest.http(metrics.contains("http"));
      nodesStatsRequest.indices(metrics.contains("indices"));
      nodesStatsRequest.process(metrics.contains("process"));
      nodesStatsRequest.breaker(metrics.contains("breaker"));

      // check for index specific metrics
      if (metrics.contains("indices")) {
        Set<String> indexMetrics =
            Strings.splitStringByCommaToSet(request.param("indexMetric", "_all"));
        if (indexMetrics.size() == 1 && indexMetrics.contains("_all")) {
          nodesStatsRequest.indices(CommonStatsFlags.ALL);
        } else {
          CommonStatsFlags flags = new CommonStatsFlags();
          for (Flag flag : CommonStatsFlags.Flag.values()) {
            flags.set(flag, indexMetrics.contains(flag.getRestName()));
          }
          nodesStatsRequest.indices(flags);
        }
      }
    }

    if (nodesStatsRequest.indices().isSet(Flag.FieldData)
        && (request.hasParam("fields") || request.hasParam("fielddata_fields"))) {
      nodesStatsRequest
          .indices()
          .fieldDataFields(
              request.paramAsStringArray(
                  "fielddata_fields", request.paramAsStringArray("fields", null)));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Completion)
        && (request.hasParam("fields") || request.hasParam("completion_fields"))) {
      nodesStatsRequest
          .indices()
          .completionDataFields(
              request.paramAsStringArray(
                  "completion_fields", request.paramAsStringArray("fields", null)));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Search) && (request.hasParam("groups"))) {
      nodesStatsRequest.indices().groups(request.paramAsStringArray("groups", null));
    }
    if (nodesStatsRequest.indices().isSet(Flag.Indexing) && (request.hasParam("types"))) {
      nodesStatsRequest.indices().types(request.paramAsStringArray("types", null));
    }

    client
        .admin()
        .cluster()
        .nodesStats(
            nodesStatsRequest,
            new ActionListener<NodesStatsResponse>() {
              @Override
              public void onResponse(NodesStatsResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder.startObject();
                  response.toXContent(builder, request);
                  builder.endObject();
                  channel.sendResponse(new BytesRestResponse(RestStatus.OK, builder));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new BytesRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
  @Test
  public void testAllFlags() throws Exception {
    // rely on 1 replica for this tests
    createIndex("test1");
    createIndex("test2");

    ClusterHealthResponse clusterHealthResponse =
        client()
            .admin()
            .cluster()
            .prepareHealth()
            .setWaitForEvents(Priority.LANGUID)
            .setWaitForGreenStatus()
            .execute()
            .actionGet();
    assertThat(clusterHealthResponse.isTimedOut(), equalTo(false));

    client()
        .prepareIndex("test1", "type1", Integer.toString(1))
        .setSource("field", "value")
        .execute()
        .actionGet();
    client()
        .prepareIndex("test1", "type2", Integer.toString(1))
        .setSource("field", "value")
        .execute()
        .actionGet();
    client()
        .prepareIndex("test2", "type", Integer.toString(1))
        .setSource("field", "value")
        .execute()
        .actionGet();

    client().admin().indices().prepareRefresh().execute().actionGet();
    IndicesStatsRequestBuilder builder = client().admin().indices().prepareStats();
    Flag[] values = CommonStatsFlags.Flag.values();
    for (Flag flag : values) {
      set(flag, builder, false);
    }

    IndicesStatsResponse stats = builder.execute().actionGet();
    for (Flag flag : values) {
      assertThat(isSet(flag, stats.getPrimaries()), equalTo(false));
      assertThat(isSet(flag, stats.getTotal()), equalTo(false));
    }

    for (Flag flag : values) {
      set(flag, builder, true);
    }
    stats = builder.execute().actionGet();
    for (Flag flag : values) {
      assertThat(isSet(flag, stats.getPrimaries()), equalTo(true));
      assertThat(isSet(flag, stats.getTotal()), equalTo(true));
    }
    Random random = getRandom();
    EnumSet<Flag> flags = EnumSet.noneOf(Flag.class);
    for (Flag flag : values) {
      if (random.nextBoolean()) {
        flags.add(flag);
      }
    }

    for (Flag flag : values) {
      set(flag, builder, false); // clear all
    }

    for (Flag flag : flags) { // set the flags
      set(flag, builder, true);
    }
    stats = builder.execute().actionGet();
    for (Flag flag : flags) { // check the flags
      assertThat(isSet(flag, stats.getPrimaries()), equalTo(true));
      assertThat(isSet(flag, stats.getTotal()), equalTo(true));
    }

    for (Flag flag : EnumSet.complementOf(flags)) { // check the complement
      assertThat(isSet(flag, stats.getPrimaries()), equalTo(false));
      assertThat(isSet(flag, stats.getTotal()), equalTo(false));
    }
  }