/**
   * Tests Functional#reduce with the summation reduction; we traverse all keys (in each direction)
   * to make sure the sum and count are correct and keys and values match up.
   */
  public void testSummationReduction() throws Exception {
    final AtomicLong counter = new AtomicLong();
    final Exchange exchange = getExchange(db, true);

    Reduction<String, Integer, Integer> summation =
        new Reduction<String, Integer, Integer>() {
          @Override
          public Integer reduce(Pair<String, Integer> row, Integer accum) {
            Assert.assertEquals(row.getKey(), getKey(row.getValue()));
            counter.getAndIncrement();

            return accum + row.getValue();
          }
        };

    int ascendingSum = Functional.reduce(exchange, getFullTraversal(Direction.ASC), summation, 0);
    Assert.assertEquals(ascendingSum, 499500);
    Assert.assertEquals(counter.get(), 1000);

    counter.set(0);

    int descendingSum = Functional.reduce(exchange, getFullTraversal(Direction.DESC), summation, 0);

    Assert.assertEquals(descendingSum, 499500);
    Assert.assertEquals(counter.get(), 1000);
  }
  /**
   * Tests Functional#reduce with the summation reduction and a KeyFilter; we traverse the bounded
   * keys (in each direction) to make sure the sum and count are correct and keys and values match
   * up.
   */
  public void testSummationReductionWithKeyFilter() throws Exception {
    final AtomicLong counter = new AtomicLong();
    final Exchange exchange = getExchange(db, true);

    Reduction<String, Integer, Integer> summation =
        new Reduction<String, Integer, Integer>() {
          @Override
          public Integer reduce(Pair<String, Integer> row, Integer accum) {
            Assert.assertEquals(row.getKey(), getKey(row.getValue()));
            counter.getAndIncrement();

            return accum + row.getValue();
          }
        };

    KeyFilter filter100 =
        new KeyFilter(new Term[] {KeyFilter.rangeTerm(getKey(100), getKey(200), true, false)});

    int ascendingSum =
        Functional.reduce(
            exchange,
            new TraversalSpec<String, Integer>(Direction.ASC, filter100, null),
            summation,
            0);

    Assert.assertEquals(ascendingSum, 14950);
    Assert.assertEquals(counter.get(), 100);

    counter.set(0);

    KeyFilter filter300 =
        new KeyFilter(new Term[] {KeyFilter.rangeTerm(getKey(300), getKey(400), true, false)});

    int descendingSum =
        Functional.reduce(
            exchange,
            new TraversalSpec<String, Integer>(Direction.DESC, filter300, null),
            summation,
            0);
    Assert.assertEquals(descendingSum, 34950);
    Assert.assertEquals(counter.get(), 100);
  }