/**
   * Test result formatter.
   *
   * @param conf the conf
   * @param status the status
   * @param isDir the is dir
   * @param reDirectUrl the re direct url
   * @throws InterruptedException the interrupted exception
   * @throws IOException Signals that an I/O exception has occurred.
   */
  private void testResultFormatter(LensConf conf, Status status, boolean isDir, String reDirectUrl)
      throws InterruptedException, IOException {
    // test post execute op
    final WebTarget target = target().path("queryapi/queries");

    final FormDataMultiPart mp = new FormDataMultiPart();
    conf.addProperty(LensConfConstants.QUERY_PERSISTENT_RESULT_SET, "true");
    mp.bodyPart(
        new FormDataBodyPart(
            FormDataContentDisposition.name("sessionid").build(),
            lensSessionId,
            MediaType.APPLICATION_XML_TYPE));
    mp.bodyPart(
        new FormDataBodyPart(
            FormDataContentDisposition.name("query").build(),
            "select ID, IDSTR, IDARR, IDSTRARR from " + testTable));
    mp.bodyPart(
        new FormDataBodyPart(FormDataContentDisposition.name("operation").build(), "execute"));
    mp.bodyPart(
        new FormDataBodyPart(
            FormDataContentDisposition.name("conf").fileName("conf").build(),
            conf,
            MediaType.APPLICATION_XML_TYPE));
    QueryHandle handle =
        target
            .request()
            .post(
                Entity.entity(mp, MediaType.MULTIPART_FORM_DATA_TYPE),
                new GenericType<LensAPIResult<QueryHandle>>() {})
            .getData();

    Assert.assertNotNull(handle);

    // Get query
    LensQuery ctx =
        target
            .path(handle.toString())
            .queryParam("sessionid", lensSessionId)
            .request()
            .get(LensQuery.class);
    // wait till the query finishes
    QueryStatus stat = ctx.getStatus();
    while (!stat.finished()) {
      ctx =
          target
              .path(handle.toString())
              .queryParam("sessionid", lensSessionId)
              .request()
              .get(LensQuery.class);
      stat = ctx.getStatus();
      Thread.sleep(1000);
    }

    Assert.assertEquals(ctx.getStatus().getStatus(), status);

    if (status.equals(QueryStatus.Status.SUCCESSFUL)) {
      QueryContext qctx = queryService.getQueryContext(handle);
      if (qctx == null) {
        // This shouldn't occur. It is appearing when query gets purged. So adding extra logs
        // for debugging in the future.
        log.info("successful query's QueryContext is null");
        log.info("query handle: {}", handle);
        log.info("allQueries: {}", queryService.allQueries);
        // not doing formatter validation if qctx is null
      } else if (!isDir) {
        // isDir is true if the formatter is skipped due to result being the max size allowed
        if (qctx.isDriverPersistent()) {
          Assert.assertTrue(qctx.getQueryOutputFormatter() instanceof PersistedOutputFormatter);
        } else {
          Assert.assertTrue(qctx.getQueryOutputFormatter() instanceof InMemoryOutputFormatter);
        }
      } else {
        Assert.assertNull(qctx.getQueryOutputFormatter());
      }
      // fetch results
      TestQueryService.validatePersistedResult(
          handle,
          target(),
          lensSessionId,
          new String[][] {
            {"ID", "INT"}, {"IDSTR", "STRING"}, {"IDARR", "ARRAY"}, {"IDSTRARR", "ARRAY"},
          },
          isDir);
      if (!isDir) {
        TestQueryService.validateHttpEndPoint(target(), lensSessionId, handle, reDirectUrl);
      }
    } else {
      assertTrue(ctx.getSubmissionTime() > 0);
      assertTrue(ctx.getLaunchTime() > 0);
      assertTrue(ctx.getDriverStartTime() > 0);
      assertTrue(ctx.getDriverFinishTime() > 0);
      assertTrue(ctx.getFinishTime() > 0);
      Assert.assertEquals(ctx.getStatus().getStatus(), QueryStatus.Status.FAILED);
    }
  }
 @Override
 public int compare(final QueryContext o1, final QueryContext o2) {
   // swap order for reverse sorting
   return Integer.compare(o2.getFailedAttempts().size(), o1.getFailedAttempts().size());
 }