@Test
public void testMetricFiltersParsing() throws Exception {

  String expr = "(((key11 ne 234 AND key12 gt 23) AND " +
      "(key13 lt 34 OR key14 ge 567)) OR (key21 lt 24 OR key22 le 45))";
  TimelineFilterList expectedList = new TimelineFilterList(
      Operator.OR,
      new TimelineFilterList(
          Operator.AND,
          new TimelineFilterList(
              Operator.AND,
              new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
                  "key11", 234, false),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
                  "key12", 23, true)
          ),
          new TimelineFilterList(
              Operator.OR,
              new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
                  "key13", 34, true),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
                  "key14", 567, true)
          )
      ),
      new TimelineFilterList(
          Operator.OR,
          new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
              "key21", 24, true),
          new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
              "key22", 45, true)
      )
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ene 234";
  expectedList = new TimelineFilterList(
      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
          "abc", 234, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ne 234";
  expectedList = new TimelineFilterList(
      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
          "abc", 234, false)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ne 234 AND def gt 23";
  expectedList = new TimelineFilterList(
      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
          "abc", 234, false),
      new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
          "def", 23, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "(abc ne 234 AND def gt 23)";
  expectedList = new TimelineFilterList(
      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
          "abc", 234, false),
      new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
          "def", 23, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ne 234 AND def gt 23 OR rst lt 24";
  expectedList = new TimelineFilterList(
      Operator.OR,
      new TimelineFilterList(
          new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
              "abc", 234, false),
          new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
              "def", 23, true)
      ),
      new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
          "rst", 24, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ne 234 AND def gt 23 OR rst lt 24 OR xyz le 456";
  expectedList = new TimelineFilterList(
      Operator.OR,
      new TimelineFilterList(
          new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
              "abc", 234, false),
          new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
              "def", 23, true)
      ),
      new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
          "rst", 24, true),
      new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
          "xyz", 456, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "abc ne 234 AND def gt 23 OR rst lt 24 OR xyz le 456 AND pqr ge 2";
  expectedList = new TimelineFilterList(
      new TimelineFilterList(
          Operator.OR,
          new TimelineFilterList(
              new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
                  "abc", 234, false),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
                  "def", 23, true)
          ),
          new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
              "rst", 24, true),
          new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
              "xyz", 456, true)
      ),
      new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
          "pqr", 2, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  // Test with unnecessary spaces.
  expr = "  abc ne   234       AND       def           gt 23 OR     rst lt "+
      "           24     OR xyz     le     456    AND pqr ge 2        ";
  expectedList = new TimelineFilterList(
      new TimelineFilterList(
          Operator.OR,
          new TimelineFilterList(
              new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
                  "abc", 234, false),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_THAN,
                  "def", 23, true)
          ),
          new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
              "rst", 24, true),
          new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
              "xyz", 456, true)
      ),
      new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
          "pqr", 2, true)
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "(((key11 ne 234 AND key12 gt 23 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  expectedList = new TimelineFilterList(
      Operator.OR,
      new TimelineFilterList(
          Operator.AND,
          new TimelineFilterList(
              new TimelineFilterList(
                  Operator.OR,
                  new TimelineFilterList(
                      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
                          "key11", 234, false),
                      new TimelineCompareFilter(
                          TimelineCompareOp.GREATER_THAN, "key12", 23, true)
                  ),
                  new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
                      "key13", 24, true),
                  new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
                      "key14", 456, true)
              ),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
                  "key15", 2, true)
          ),
          new TimelineFilterList(
              Operator.OR,
              new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
                  "key16", 34, true),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
                  "key17", 567, true)
          )
      ),
      new TimelineFilterList(
          Operator.OR,
          new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
              "key21", 24, true),
          new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
              "key22", 45, true)
      )
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "   (  (     (        key11      ne     234    AND key12    gt   " +
      "23    OR    key13    lt    24 OR key14 le 456   AND   key15   ge   2" +
      "   )   AND ( key16 lt 34 OR key17 ge 567 )    )     OR " +
      "(   key21 lt 24 OR key22 le 45 )   )    ";
  expectedList = new TimelineFilterList(
      Operator.OR,
      new TimelineFilterList(
          Operator.AND,
          new TimelineFilterList(
              new TimelineFilterList(
                  Operator.OR,
                  new TimelineFilterList(
                      new TimelineCompareFilter(TimelineCompareOp.NOT_EQUAL,
                          "key11", 234, false),
                      new TimelineCompareFilter(
                          TimelineCompareOp.GREATER_THAN, "key12", 23, true)
                  ),
                  new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
                      "key13", 24, true),
                  new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
                      "key14", 456, true)
              ),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
                  "key15", 2, true)
          ),
          new TimelineFilterList(
              Operator.OR,
              new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
                  "key16", 34, true),
              new TimelineCompareFilter(TimelineCompareOp.GREATER_OR_EQUAL,
                  "key17", 567, true)
          )
      ),
      new TimelineFilterList(
          Operator.OR,
          new TimelineCompareFilter(TimelineCompareOp.LESS_THAN,
              "key21", 24, true),
          new TimelineCompareFilter(TimelineCompareOp.LESS_OR_EQUAL,
              "key22", 45, true)
      )
  );
  verifyFilterList(expr,
      TimelineReaderWebServicesUtils.parseMetricFilters(expr), expectedList);
  expr = "(((key11 ne 234 AND key12 gt 23 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45)";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Improper brackers. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((key11 ne 234 AND key12 gt v3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Non Numeric value. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((key11 ne (234 AND key12 gt 3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Unexpected opening bracket. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((k)ey11 ne 234 AND key12 gt 3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Unexpected closing bracket. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((key11 rs 234 AND key12 gt 3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Improper compare op. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((key11 ne 234 PI key12 gt 3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Improper op. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(((key11 ne 234 PI key12 gt 3 OR key13 lt 24 OR key14 le 456 " +
      "AND key15 ge 2) AND (key16 lt 34 OR key17 ge 567)) OR (key21 lt 24 " +
      "OR key22 le 45))";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Improper op. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(key11 ne 234 AND key12 gt 3)) OR (key13 lt 24 OR key14 le 456)";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Unbalanced brackets. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(key11 rne 234 AND key12 gt 3) OR (key13 lt 24 OR key14 le 456)";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Invalid compareop. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  expr = "(key11 ne 234 AND key12 gt 3) OR (key13 lt 24 OR key14 le";
  try {
    TimelineReaderWebServicesUtils.parseMetricFilters(expr);
    fail("Compareop cant be parsed. Exception should have been thrown.");
  } catch (TimelineParseException e) {}
  assertNull(TimelineReaderWebServicesUtils.parseMetricFilters(null));
  assertNull(TimelineReaderWebServicesUtils.parseMetricFilters("   "));
}