You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2015/11/11 19:14:07 UTC

[1/3] phoenix git commit: PHOENIX-2396 Set root cause exception when parsing server exception

Repository: phoenix
Updated Branches:
  refs/heads/4.x-HBase-0.98 dfdcba45a -> 14580f78c


PHOENIX-2396 Set root cause exception when parsing server exception


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/a722b0eb
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/a722b0eb
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/a722b0eb

Branch: refs/heads/4.x-HBase-0.98
Commit: a722b0eb957d599f2be164bc39ef58a5133bc19e
Parents: dfdcba4
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 16:27:12 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 09:58:37 2015 -0800

----------------------------------------------------------------------
 .../apache/phoenix/exception/SQLExceptionCode.java   |  5 ++---
 .../java/org/apache/phoenix/util/ServerUtil.java     | 15 +++++----------
 2 files changed, 7 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/a722b0eb/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 53a13be..cc0d0ed 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -418,11 +418,10 @@ public enum SQLExceptionCode {
         }
     }
     
-    public static SQLExceptionCode fromErrorCode(int errorCode) throws SQLException {
+    public static SQLExceptionCode fromErrorCode(int errorCode) {
         SQLExceptionCode code = errorCodeMap.get(errorCode);
         if (code == null) {
-            throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNKNOWN_ERROR_CODE)
-            .setMessage(Integer.toString(errorCode)).build().buildException();
+            return SQLExceptionCode.UNKNOWN_ERROR_CODE;
         }
         return code;
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a722b0eb/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
index 0998e72..a51dc84 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ServerUtil.java
@@ -116,21 +116,16 @@ public class ServerUtil {
     }
 
     private static SQLException parseRemoteException(Throwable t) {
-        	String message = t.getLocalizedMessage();
-        	if (message != null) {
+        String message = t.getLocalizedMessage();
+        if (message != null) {
             // If the message matches the standard pattern, recover the SQLException and throw it.
             Matcher matcher = PATTERN.matcher(t.getLocalizedMessage());
             if (matcher.find()) {
                 int statusCode = Integer.parseInt(matcher.group(1));
-                SQLExceptionCode code;
-                try {
-                    code = SQLExceptionCode.fromErrorCode(statusCode);
-                } catch (SQLException e) {
-                    return e;
-                }
-                return new SQLExceptionInfo.Builder(code).setMessage(matcher.group()).build().buildException();
+                SQLExceptionCode code = SQLExceptionCode.fromErrorCode(statusCode);
+                return new SQLExceptionInfo.Builder(code).setMessage(matcher.group()).setRootCause(t).build().buildException();
             }
-        	}
+        }
         return null;
     }
 


[3/3] phoenix git commit: PHOENIX-2399 Server is sometimes unable to find Phoenix driver

Posted by ja...@apache.org.
PHOENIX-2399 Server is sometimes unable to find Phoenix driver


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/14580f78
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/14580f78
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/14580f78

Branch: refs/heads/4.x-HBase-0.98
Commit: 14580f78cf58327b794477356d0bc33200a08778
Parents: b9a3c53
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 18:15:08 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 10:08:34 2015 -0800

----------------------------------------------------------------------
 .../example/EndToEndCoveredIndexingIT.java      | 1634 +++++++++---------
 .../EndtoEndIndexingWithCompressionIT.java      |   31 +-
 .../phoenix/mapreduce/CsvBulkLoadToolIT.java    |    5 +
 .../apache/phoenix/mapreduce/IndexToolIT.java   |    5 +
 .../org/apache/phoenix/query/QueryServices.java |    1 +
 .../phoenix/query/QueryServicesOptions.java     |    6 +
 .../java/org/apache/phoenix/util/QueryUtil.java |   13 +-
 .../phoenix/query/QueryServicesTestImpl.java    |    6 +-
 8 files changed, 872 insertions(+), 829 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
index 1cf6b5c..01812f3 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndToEndCoveredIndexingIT.java
@@ -18,6 +18,7 @@
 package org.apache.phoenix.hbase.index.covered.example;
 
 
+import static org.apache.phoenix.query.BaseTest.initAndRegisterDriver;
 import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster;
 
 import java.io.IOException;
@@ -47,6 +48,11 @@ import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
 import org.apache.phoenix.hbase.index.IndexTestingUtils;
 import org.apache.phoenix.hbase.index.Indexer;
 import org.apache.phoenix.hbase.index.TableName;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+import org.apache.phoenix.util.PhoenixRuntime;
+import org.apache.phoenix.util.ReadOnlyProps;
+import org.apache.phoenix.util.TestUtil;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -61,824 +67,838 @@ import org.junit.experimental.categories.Category;
  */
 @Category(NeedsOwnMiniClusterTest.class)
 public class EndToEndCoveredIndexingIT {
-  private static final Log LOG = LogFactory.getLog(EndToEndCoveredIndexingIT.class);
-  protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
-  private static final String FAM_STRING = "FAMILY";
-  private static final byte[] FAM = Bytes.toBytes(FAM_STRING);
-  private static final String FAM2_STRING = "FAMILY2";
-  private static final byte[] FAM2 = Bytes.toBytes(FAM2_STRING);
-  private static final byte[] EMPTY_BYTES = new byte[0];
-  private static final byte[] indexed_qualifer = Bytes.toBytes("indexed_qual");
-  private static final byte[] regular_qualifer = Bytes.toBytes("reg_qual");
-  private static final byte[] row1 = Bytes.toBytes("row1");
-  private static final byte[] value1 = Bytes.toBytes("val1");
-  private static final byte[] value2 = Bytes.toBytes("val2");
-  private static final byte[] value3 = Bytes.toBytes("val3");
-  // match a single family:qualifier pair
-  private static final CoveredColumn col1 = new CoveredColumn(FAM_STRING, indexed_qualifer);
-  // matches the family2:* columns
-  private static final CoveredColumn col2 = new CoveredColumn(FAM2_STRING, null);
-  private static final CoveredColumn col3 = new CoveredColumn(FAM2_STRING, indexed_qualifer);
-  
-  @Rule
-  public TableName TestTable = new TableName();
-  
-  private ColumnGroup fam1;
-  private ColumnGroup fam2;
-
-  // setup a couple of index columns
-  private void setupColumns() {
-    fam1 = new ColumnGroup(getIndexTableName());
-    fam2 = new ColumnGroup(getIndexTableName() + "2");
-    // values are [col1][col2_1]...[col2_n]
-    fam1.add(col1);
-    fam1.add(col2);
-    // value is [col2]
-    fam2.add(col3);
-  }
-
-  private String getIndexTableName() {
-    return Bytes.toString(TestTable.getTableName()) + "_index";
-  }
-
-  @BeforeClass
-  public static void setupCluster() throws Exception {
-    Configuration conf = UTIL.getConfiguration();
-    setUpConfigForMiniCluster(conf);
-    IndexTestingUtils.setupConfig(conf);
-    // disable version checking, so we can test against whatever version of HBase happens to be
-    // installed (right now, its generally going to be SNAPSHOT versions).
-    conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
-    UTIL.startMiniCluster();
-  }
-
-  @AfterClass
-  public static void teardownCluster() throws Exception {
-    UTIL.shutdownMiniCluster();
-  }
-
-  @Before
-  public void setup() throws Exception {
-    setupColumns();
-  }
-
-  /**
-   * Test that a bunch of puts with a single timestamp across all the puts builds and inserts index
-   * entries as expected
-   * @throws Exception on failure
-   */
-  @Test
-  public void testSimpleTimestampedUpdates() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts = 10;
-    p.add(FAM, indexed_qualifer, ts, value1);
-    p.add(FAM, regular_qualifer, ts, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-
-    // verify that the index matches
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Test that the multiple timestamps in a single put build the correct index updates.
-   * @throws Exception on failure
-   */
-  @Test
-  public void testMultipleTimestampsInSinglePut() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts1 = 10;
-    long ts2 = 11;
-    p.add(FAM, indexed_qualifer, ts1, value1);
-    p.add(FAM, regular_qualifer, ts1, value2);
-    // our group indexes all columns in the this family, so any qualifier here is ok
-    p.add(FAM2, regular_qualifer, ts2, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check the first entry at ts1
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
-    // check the second entry at ts2
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Test that we make updates to multiple {@link ColumnGroup}s across a single put/delete 
-   * @throws Exception on failure
-   */
-  @Test
-  public void testMultipleConcurrentGroupsUpdated() throws Exception {
-    HTable primary = createSetupTables(fam1, fam2);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts = 10;
-    p.add(FAM, indexed_qualifer, ts, value1);
-    p.add(FAM, regular_qualifer, ts, value2);
-    p.add(FAM2, indexed_qualifer, ts, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-    HTable index2 = new HTable(UTIL.getConfiguration(), fam2.getTable());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // and check the second index as well
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index2, expected, ts, value3);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1, index2);
-  }
-
-  /**
-   * HBase has a 'fun' property wherein you can completely clobber an existing row if you make a
-   * {@link Put} at the exact same dimension (row, cf, cq, ts) as an existing row. The old row
-   * disappears and the new value (since the rest of the row is the same) completely subsumes it.
-   * This test ensures that we remove the old entry and put a new entry in its place.
-   * @throws Exception on failure
-   */
-  @Test
-  public void testOverwritingPutsCorrectlyGetIndexed() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts = 10;
-    p.add(FAM, indexed_qualifer, ts, value1);
-    p.add(FAM, regular_qualifer, ts, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check the first entry at ts
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // now overwrite the put in the primary table with a new value
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check the first entry at ts
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value3);
-    // and verify that a scan at the first entry returns nothing (ignore the updated row)
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts,
-      value1, value2);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-  
-  @Test
-  public void testSimpleDeletes() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a simple Put
-    long ts = 10;
-    Put p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts, value1);
-    p.add(FAM, regular_qualifer, ts, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    Delete d = new Delete(row1);
-    primary.delete(d);
-
-    HTable index = new HTable(UTIL.getConfiguration(), fam1.getTable());
-    List<KeyValue> expected = Collections.<KeyValue> emptyList();
-    // scan over all time should cause the delete to be covered
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, 0, Long.MAX_VALUE, value1,
-      HConstants.EMPTY_END_ROW);
-
-    // scan at the older timestamp should still show the older value
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts, value1);
-
-    // cleanup
-    closeAndCleanupTables(index, primary);
-  }
-
-  /**
-   * If we don't have any updates to make to the index, we don't take a lock on the WAL. However, we
-   * need to make sure that we don't try to unlock the WAL on write time when we don't write
-   * anything, since that will cause an java.lang.IllegalMonitorStateException
-   * @throws Exception on failure
-   */
-  @Test
-  public void testDeletesWithoutPreviousState() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a delete on the primary table (no data, so no index updates...hopefully).
-    long ts = 10;
-    Delete d = new Delete(row1);
-    primary.delete(d);
-
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-    List<KeyValue> expected = Collections.<KeyValue> emptyList();
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // a delete of a specific family/column should also not show any index updates
-    d = new Delete(row1);
-    d.deleteColumn(FAM, indexed_qualifer);
-    primary.delete(d);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // also just a family marker should have the same effect
-    d = new Delete(row1);
-    d.deleteFamily(FAM);
-    primary.delete(d);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // also just a family marker should have the same effect
-    d = new Delete(row1);
-    d.deleteColumns(FAM, indexed_qualifer);
-    primary.delete(d);
-    primary.flushCommits();
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Similar to the {@link #testMultipleTimestampsInSinglePut()}, this check the same with deletes
-   * @throws Exception on failure
-   */
-  @Test
-  public void testMultipleTimestampsInSingleDelete() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts1 = 10, ts2 = 11, ts3 = 12;
-    p.add(FAM, indexed_qualifer, ts1, value1);
-    // our group indexes all columns in the this family, so any qualifier here is ok
-    p.add(FAM2, regular_qualifer, ts2, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    // check to make sure everything we expect is there
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
-    // ts1, we just have v1
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
-    // at ts2, don't have the above anymore
-    pairs.clear();
-    expected = Collections.emptyList();
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts2 + 1, value1, value1);
-    // but we do have the new entry at ts2
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
-    // now build up a delete with a couple different timestamps
-    Delete d = new Delete(row1);
-    // these deletes have to match the exact ts since we are doing an exact match (deleteColumn).
-    d.deleteColumn(FAM, indexed_qualifer, ts1);
-    // since this doesn't match exactly, we actually shouldn't see a change in table state
-    d.deleteColumn(FAM2, regular_qualifer, ts3);
-    primary.delete(d);
-
-    // at ts1, we should have the put covered exactly by the delete and into the entire future
-    expected = Collections.emptyList();
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, Long.MAX_VALUE, value1,
-      value1);
-
-    // at ts2, we should just see value3
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
-    // the later delete is a point delete, so we shouldn't see any change at ts3
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts3, value1,
-      HConstants.EMPTY_END_ROW);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Covering deletes (via {@link Delete#deleteColumns}) cover everything back in time from the
-   * given time. If its modifying the latest state, we don't need to do anything but add deletes. If
-   * its modifying back in time state, we need to just fix up the surrounding elements as anything
-   * else ahead of it will be fixed up by later updates.
-   * <p>
-   * similar to {@link #testMultipleTimestampsInSingleDelete()}, but with covering deletes.
-   * @throws Exception on failure
-   */
-  @Test
-  public void testDeleteColumnsInThePast() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts1 = 10, ts2 = 11, ts3 = 12;
-    p.add(FAM, indexed_qualifer, ts1, value1);
-    p.add(FAM2, regular_qualifer, ts2, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    // now build up a delete with a couple different timestamps
-    Delete d = new Delete(row1);
-    // these deletes don't need to match the exact ts because they cover everything earlier
-    d.deleteColumns(FAM, indexed_qualifer, ts2);
-    d.deleteColumns(FAM2, regular_qualifer, ts3);
-    primary.delete(d);
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check the first entry at ts1
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
-
-    // delete at ts2 changes what the put would insert
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
-
-    // final delete clears out everything
-    expected = Collections.emptyList();
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value1);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-  
-  /**
-   * If the client is using custom timestamps is possible that the updates come out-of-order (i.e.
-   * update to ts 10 comes after the update to ts 12). In the case, we need to be sure that the
-   * index is correctly updated when the out of order put arrives.
-   * @throws Exception
-   */
-  @Test
-  public void testOutOfOrderUpdates() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts = 12;
-    p.add(FAM, indexed_qualifer, ts, value1);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check the first entry at ts
-    List<KeyValue> expectedTs1 = CoveredColumnIndexCodec
-        .getIndexKeyValueForTesting(row1, ts, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
-
-    // now make a put back in time
-    long ts2 = ts - 2;
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts2, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-
-    // check to make sure the back in time entry exists
-    List<KeyValue> expectedTs2 = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2,
-      pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs2, ts2, value2);
-    // then it should be gone at the newer ts (because it deletes itself)
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts2,
-      ts + 1, value2, HConstants.EMPTY_END_ROW);
-
-    // but that the original index entry is still visible at ts, just fine
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Its possible (i.e. from a fast, frequently writing client) that they put more than the
-   * 'visible' number of versions in a row before a client make a put 'back in time' on that row. If
-   * we don't scan the current table properly, we won't see an index update for that 'back in time'
-   * update since the usual lookup will only see the regular number of versions. This ability to see
-   * back in time depends on running HBase 0.94.9
-   * @throws Exception on failure
-   */
-  @Test
-  public void testExceedVersionsOutOfOrderPut() throws Exception {
-    // setup the index
-    HTable primary = createSetupTables(fam2);
-
-    // do a put to the primary table
-    Put p = new Put(row1);
-    long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5;
-    byte[] value4 = Bytes.toBytes("val4");
-    byte[] value5 = Bytes.toBytes("val5");
-    p.add(FAM2, indexed_qualifer, ts1, value1);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM2, indexed_qualifer, ts3, value3);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM2, indexed_qualifer, ts4, value4);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM2, indexed_qualifer, ts5, value5);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
-
-    // do a raw scan of everything in the table
-    if (LOG.isDebugEnabled()) {
-      // the whole table, all the keys
-      Scan s = new Scan();
-      s.setRaw(true);
-      ResultScanner scanner = index.getScanner(s);
-      for (Result r : scanner) {
-        LOG.debug("Found row:" + r);
-      }
-      scanner.close();
+    private static final Log LOG = LogFactory.getLog(EndToEndCoveredIndexingIT.class);
+    protected static final HBaseTestingUtility UTIL = new HBaseTestingUtility();
+    private static final String FAM_STRING = "FAMILY";
+    private static final byte[] FAM = Bytes.toBytes(FAM_STRING);
+    private static final String FAM2_STRING = "FAMILY2";
+    private static final byte[] FAM2 = Bytes.toBytes(FAM2_STRING);
+    private static final byte[] EMPTY_BYTES = new byte[0];
+    private static final byte[] indexed_qualifer = Bytes.toBytes("indexed_qual");
+    private static final byte[] regular_qualifer = Bytes.toBytes("reg_qual");
+    private static final byte[] row1 = Bytes.toBytes("row1");
+    private static final byte[] value1 = Bytes.toBytes("val1");
+    private static final byte[] value2 = Bytes.toBytes("val2");
+    private static final byte[] value3 = Bytes.toBytes("val3");
+    // match a single family:qualifier pair
+    private static final CoveredColumn col1 = new CoveredColumn(FAM_STRING, indexed_qualifer);
+    // matches the family2:* columns
+    private static final CoveredColumn col2 = new CoveredColumn(FAM2_STRING, null);
+    private static final CoveredColumn col3 = new CoveredColumn(FAM2_STRING, indexed_qualifer);
+
+    @Rule
+    public TableName TestTable = new TableName();
+
+    private ColumnGroup fam1;
+    private ColumnGroup fam2;
+
+    // setup a couple of index columns
+    private void setupColumns() {
+        fam1 = new ColumnGroup(getIndexTableName());
+        fam2 = new ColumnGroup(getIndexTableName() + "2");
+        // values are [col1][col2_1]...[col2_n]
+        fam1.add(col1);
+        fam1.add(col2);
+        // value is [col2]
+        fam2.add(col3);
     }
 
-    /*
-     * now we have definitely exceeded the number of versions visible to a usual client of the
-     * primary table, so we should try doing a put 'back in time' an make sure that has the correct
-     * index values and cleanup
+    private String getIndexTableName() {
+        return Bytes.toString(TestTable.getTableName()) + "_index";
+    }
+
+    protected static void setupConfig() throws Exception {
+        Configuration conf = UTIL.getConfiguration();
+        setUpConfigForMiniCluster(conf);
+        IndexTestingUtils.setupConfig(conf);
+        // disable version checking, so we can test against whatever version of HBase happens to be
+        // installed (right now, its generally going to be SNAPSHOT versions).
+        conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
+    }
+
+    protected static void initDriver() throws Exception {
+        Configuration conf = UTIL.getConfiguration();
+        String zkQuorum = TestUtil.LOCALHOST + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + UTIL.getZkCluster().getClientPort();
+        String url = PhoenixRuntime.JDBC_PROTOCOL +
+                PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + zkQuorum + 
+                PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR + 
+                conf.get(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
+        initAndRegisterDriver(url, ReadOnlyProps.EMPTY_PROPS);
+    }
+
+    @BeforeClass
+    public static void setupCluster() throws Exception {
+        setupConfig();
+        UTIL.startMiniCluster();
+        initDriver();
+    }
+
+    @AfterClass
+    public static void teardownCluster() throws Exception {
+        UTIL.shutdownMiniCluster();
+    }
+
+    @Before
+    public void setup() throws Exception {
+        setupColumns();
+    }
+
+    /**
+     * Test that a bunch of puts with a single timestamp across all the puts builds and inserts index
+     * entries as expected
+     * @throws Exception on failure
+     */
+    @Test
+    public void testSimpleTimestampedUpdates() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts = 10;
+        p.add(FAM, indexed_qualifer, ts, value1);
+        p.add(FAM, regular_qualifer, ts, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+
+        // verify that the index matches
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
+    }
+
+    /**
+     * Test that the multiple timestamps in a single put build the correct index updates.
+     * @throws Exception on failure
+     */
+    @Test
+    public void testMultipleTimestampsInSinglePut() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts1 = 10;
+        long ts2 = 11;
+        p.add(FAM, indexed_qualifer, ts1, value1);
+        p.add(FAM, regular_qualifer, ts1, value2);
+        // our group indexes all columns in the this family, so any qualifier here is ok
+        p.add(FAM2, regular_qualifer, ts2, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), getIndexTableName());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check the first entry at ts1
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+        // check the second entry at ts2
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
+    }
+
+    /**
+     * Test that we make updates to multiple {@link ColumnGroup}s across a single put/delete 
+     * @throws Exception on failure
+     */
+    @Test
+    public void testMultipleConcurrentGroupsUpdated() throws Exception {
+        HTable primary = createSetupTables(fam1, fam2);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts = 10;
+        p.add(FAM, indexed_qualifer, ts, value1);
+        p.add(FAM, regular_qualifer, ts, value2);
+        p.add(FAM2, indexed_qualifer, ts, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+        HTable index2 = new HTable(UTIL.getConfiguration(), fam2.getTable());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // and check the second index as well
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index2, expected, ts, value3);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1, index2);
+    }
+
+    /**
+     * HBase has a 'fun' property wherein you can completely clobber an existing row if you make a
+     * {@link Put} at the exact same dimension (row, cf, cq, ts) as an existing row. The old row
+     * disappears and the new value (since the rest of the row is the same) completely subsumes it.
+     * This test ensures that we remove the old entry and put a new entry in its place.
+     * @throws Exception on failure
+     */
+    @Test
+    public void testOverwritingPutsCorrectlyGetIndexed() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts = 10;
+        p.add(FAM, indexed_qualifer, ts, value1);
+        p.add(FAM, regular_qualifer, ts, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check the first entry at ts
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // now overwrite the put in the primary table with a new value
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check the first entry at ts
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value3);
+        // and verify that a scan at the first entry returns nothing (ignore the updated row)
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts,
+                value1, value2);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
+    }
+
+    @Test
+    public void testSimpleDeletes() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a simple Put
+        long ts = 10;
+        Put p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts, value1);
+        p.add(FAM, regular_qualifer, ts, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        Delete d = new Delete(row1);
+        primary.delete(d);
+
+        HTable index = new HTable(UTIL.getConfiguration(), fam1.getTable());
+        List<KeyValue> expected = Collections.<KeyValue> emptyList();
+        // scan over all time should cause the delete to be covered
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, 0, Long.MAX_VALUE, value1,
+                HConstants.EMPTY_END_ROW);
+
+        // scan at the older timestamp should still show the older value
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts, value1);
+
+        // cleanup
+        closeAndCleanupTables(index, primary);
+    }
+
+    /**
+     * If we don't have any updates to make to the index, we don't take a lock on the WAL. However, we
+     * need to make sure that we don't try to unlock the WAL on write time when we don't write
+     * anything, since that will cause an java.lang.IllegalMonitorStateException
+     * @throws Exception on failure
      */
-    p = new Put(row1);
-    p.add(FAM2, indexed_qualifer, ts2, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    // // read the index for the expected values
-    // HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
-    //
-    // do a raw scan of everything in the table
-    if (LOG.isDebugEnabled()) {
-      // the whole table, all the keys
-      Scan s = new Scan();
-      s.setRaw(true);
-      ResultScanner scanner = index.getScanner(s);
-      for (Result r : scanner) {
-        LOG.debug("Found row:" + r);
-      }
-      scanner.close();
+    @Test
+    public void testDeletesWithoutPreviousState() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a delete on the primary table (no data, so no index updates...hopefully).
+        long ts = 10;
+        Delete d = new Delete(row1);
+        primary.delete(d);
+
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+        List<KeyValue> expected = Collections.<KeyValue> emptyList();
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // a delete of a specific family/column should also not show any index updates
+        d = new Delete(row1);
+        d.deleteColumn(FAM, indexed_qualifer);
+        primary.delete(d);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // also just a family marker should have the same effect
+        d = new Delete(row1);
+        d.deleteFamily(FAM);
+        primary.delete(d);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // also just a family marker should have the same effect
+        d = new Delete(row1);
+        d.deleteColumns(FAM, indexed_qualifer);
+        primary.delete(d);
+        primary.flushCommits();
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts, value1);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
     }
 
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col3));
-
-    // check the value1 should be present at the earliest timestamp
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts1, value1, value2);
-
-    // and value1 should be removed at ts2 (even though it came later)
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts1,
-      ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
-
-    // late added column should be there just fine at its timestamp
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
-
-    // and check that the late entry also removes its self at the next timestamp up
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
-      value2, value3);
-
-    // then we should have the rest of the inserts at their appropriate timestamps. Everything else
-    // should be exactly the same, except we shouldn't see ts0 anymore at ts2
-
-    // check the third entry
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts3, value3);
-
-    // check the fourth entry
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value4, col3));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts4, value4);
-
-    // check the first entry at ts4
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
-    // verify that we remove the entry, even though its too far 'back in time'
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
-      value4);
-
-    // cleanup
-    closeAndCleanupTables(primary, index);
-  }
-
-  /**
-   * Similar to {@link #testExceedVersionsOutOfOrderPut()}, but mingles deletes and puts.
-   * @throws Exception on failure
-   */
-  @Test
-  public void testExceedVersionsOutOfOrderUpdates() throws Exception {
-    HTable primary = createSetupTables(fam1);
-
-    // setup the data to store
-    long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5, ts6 = 6;
-    byte[] value4 = Bytes.toBytes("val4"), value5 = Bytes.toBytes("val5"), value6 =
-        Bytes.toBytes("val6");
-    // values for the other column to index
-    byte[] v1_1 = ArrayUtils.addAll(value1, Bytes.toBytes("_otherCol")), v3_1 =
-        ArrayUtils.addAll(value3, Bytes.toBytes("_otherCol")), v5_1 =
-        ArrayUtils.addAll(value5, Bytes.toBytes("_otherCol")), v6_1 =
-        ArrayUtils.addAll(value6, Bytes.toBytes("_otherCol"));
-
-    // make some puts to the primary table
-    Put p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts1, value1);
-    p.add(FAM2, indexed_qualifer, ts1, v1_1);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts3, value3);
-    p.add(FAM2, indexed_qualifer, ts3, v3_1);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts5, value5);
-    p.add(FAM2, indexed_qualifer, ts5, v5_1);
-    primary.put(p);
-    primary.flushCommits();
-
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts6, value6);
-    p.add(FAM2, indexed_qualifer, ts6, v6_1);
-    primary.put(p);
-    primary.flushCommits();
-
-    /*
-     * now we have definitely exceeded the number of versions visible to a usual client of the
-     * primary table, so we should try doing a put 'back in time' an make sure that has the correct
-     * index values and cleanup
+    /**
+     * Similar to the {@link #testMultipleTimestampsInSinglePut()}, this check the same with deletes
+     * @throws Exception on failure
      */
-    p = new Put(row1);
-    p.add(FAM, indexed_qualifer, ts2, value2);
-    primary.put(p);
-    primary.flushCommits();
-
-    // read the index for the expected values
-    HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
-
-    // do a raw scan of everything in the table
-    if (LOG.isDebugEnabled()) {
-      Scan s = new Scan();
-      s.setRaw(true);
-      ResultScanner scanner = index1.getScanner(s);
-      for (Result r : scanner) {
-        LOG.debug("Found row:" + r);
-      }
-      scanner.close();
+    @Test
+    public void testMultipleTimestampsInSingleDelete() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts1 = 10, ts2 = 11, ts3 = 12;
+        p.add(FAM, indexed_qualifer, ts1, value1);
+        // our group indexes all columns in the this family, so any qualifier here is ok
+        p.add(FAM2, regular_qualifer, ts2, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        // check to make sure everything we expect is there
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+        // ts1, we just have v1
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+        // at ts2, don't have the above anymore
+        pairs.clear();
+        expected = Collections.emptyList();
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts2 + 1, value1, value1);
+        // but we do have the new entry at ts2
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+        // now build up a delete with a couple different timestamps
+        Delete d = new Delete(row1);
+        // these deletes have to match the exact ts since we are doing an exact match (deleteColumn).
+        d.deleteColumn(FAM, indexed_qualifer, ts1);
+        // since this doesn't match exactly, we actually shouldn't see a change in table state
+        d.deleteColumn(FAM2, regular_qualifer, ts3);
+        primary.delete(d);
+
+        // at ts1, we should have the put covered exactly by the delete and into the entire future
+        expected = Collections.emptyList();
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, Long.MAX_VALUE, value1,
+                value1);
+
+        // at ts2, we should just see value3
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+        // the later delete is a point delete, so we shouldn't see any change at ts3
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, ts3, value1,
+                HConstants.EMPTY_END_ROW);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
     }
 
-    // build the expected kvs
-    List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
-    pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
-
-    // check the value1 should be present at the earliest timestamp
-    List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1, value2);
-
-    // and value1 should be removed at ts2 (even though it came later)
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts1,
-      ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
-
-    // late added column should be there just fine at its timestamp
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value2);
-
-    // and check that the late entry also removes its self at the next timestamp up
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts3,
-      value2, value3);
-
-    // -----------------------------------------------
-    // Check Delete intermingled
-    // -----------------------------------------------
-
-    // verify that the old row is there
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v3_1, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
-    // scan from the start key forward (should only include [value3][v3_3])
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, expected.get(0).getKey(),
-      value4);
-
-    // then do a delete of just one of the indexed columns. This should insert a delete for all just
-    // the single value, then a put & a later corresponding in the past for the new value
-    Delete d = new Delete(row1);
-    d.deleteColumn(FAM2, indexed_qualifer, ts3);
-    primary.delete(d);
-
-    // we shouldn't find that entry, but we should find [value3][v1_1] since that is next entry back
-    // in time from the current
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
-    // it should be re-written at 3
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
-
-    // but we shouldn't find it at ts5 since it should be covered again
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts5,
-      value3, value4);
-
-    // now remove all the older columns in FAM2 at 4
-    d = new Delete(row1);
-    d.deleteColumns(FAM2, indexed_qualifer, ts4);
-    primary.delete(d);
-
-    // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
-    // all the entries for that column
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts4, value3, value4);
-
-    // same as above, but now do it at 3 (on earlier)
-    d = new Delete(row1);
-    d.deleteColumns(FAM2, indexed_qualifer, ts3);
-    primary.delete(d);
-
-    // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
-    // all the entries for that column
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
-
-    // -----------------------------------------------
-    // then we should have the rest of the inserts at their appropriate timestamps. Everything else
-    // should be exactly the same, except we shouldn't see ts0 anymore at ts2
-    // -----------------------------------------------
-
-    // check the entry at 5
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value5, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v5_1, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts5, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts5, value5);
-
-    // check the entry at 6
-    pairs.clear();
-    pairs.add(new Pair<byte[], CoveredColumn>(value6, col1));
-    pairs.add(new Pair<byte[], CoveredColumn>(v6_1, col2));
-    expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts6, pairs);
-    IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts6, value5);
-
-    // cleanup
-    closeAndCleanupTables(primary, index1);
-  }
-
-  /**
-   * Create the primary table (to which you should write), setup properly for indexing the given
-   * {@link ColumnGroup}s. Also creates the necessary index tables to match the passes groups.
-   * @param groups {@link ColumnGroup}s to index, creating one index table per column group.
-   * @return reference to the primary table
-   * @throws IOException if there is an issue communicating with HBase
-   */
-  @SuppressWarnings("deprecation")
-private HTable createSetupTables(ColumnGroup... groups) throws IOException {
-    HBaseAdmin admin = UTIL.getHBaseAdmin();
-    // setup the index
-    CoveredColumnIndexSpecifierBuilder builder = new CoveredColumnIndexSpecifierBuilder();
-    for (ColumnGroup group : groups) {
-      builder.addIndexGroup(group);
-      // create the index tables
-      CoveredColumnIndexer.createIndexTable(admin, group.getTable());
+    /**
+     * Covering deletes (via {@link Delete#deleteColumns}) cover everything back in time from the
+     * given time. If its modifying the latest state, we don't need to do anything but add deletes. If
+     * its modifying back in time state, we need to just fix up the surrounding elements as anything
+     * else ahead of it will be fixed up by later updates.
+     * <p>
+     * similar to {@link #testMultipleTimestampsInSingleDelete()}, but with covering deletes.
+     * @throws Exception on failure
+     */
+    @Test
+    public void testDeleteColumnsInThePast() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts1 = 10, ts2 = 11, ts3 = 12;
+        p.add(FAM, indexed_qualifer, ts1, value1);
+        p.add(FAM2, regular_qualifer, ts2, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        // now build up a delete with a couple different timestamps
+        Delete d = new Delete(row1);
+        // these deletes don't need to match the exact ts because they cover everything earlier
+        d.deleteColumns(FAM, indexed_qualifer, ts2);
+        d.deleteColumns(FAM2, regular_qualifer, ts3);
+        primary.delete(d);
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check the first entry at ts1
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1);
+
+        // delete at ts2 changes what the put would insert
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value1);
+
+        // final delete clears out everything
+        expected = Collections.emptyList();
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value1);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
     }
 
-    // setup the primary table
-    String indexedTableName = Bytes.toString(TestTable.getTableName());
-    @SuppressWarnings("deprecation")
-    HTableDescriptor pTable = new HTableDescriptor(indexedTableName);
-    pTable.addFamily(new HColumnDescriptor(FAM));
-    pTable.addFamily(new HColumnDescriptor(FAM2));
-    builder.build(pTable);
-
-    // create the primary table
-    admin.createTable(pTable);
-    HTable primary = new HTable(UTIL.getConfiguration(), indexedTableName);
-    primary.setAutoFlush(false);
-    return primary;
-  }
-
-  private void closeAndCleanupTables(HTable... tables) throws IOException {
-    if (tables == null) {
-      return;
+    /**
+     * If the client is using custom timestamps is possible that the updates come out-of-order (i.e.
+     * update to ts 10 comes after the update to ts 12). In the case, we need to be sure that the
+     * index is correctly updated when the out of order put arrives.
+     * @throws Exception
+     */
+    @Test
+    public void testOutOfOrderUpdates() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts = 12;
+        p.add(FAM, indexed_qualifer, ts, value1);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check the first entry at ts
+        List<KeyValue> expectedTs1 = CoveredColumnIndexCodec
+                .getIndexKeyValueForTesting(row1, ts, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
+
+        // now make a put back in time
+        long ts2 = ts - 2;
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts2, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+
+        // check to make sure the back in time entry exists
+        List<KeyValue> expectedTs2 = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2,
+                pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs2, ts2, value2);
+        // then it should be gone at the newer ts (because it deletes itself)
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts2,
+                ts + 1, value2, HConstants.EMPTY_END_ROW);
+
+        // but that the original index entry is still visible at ts, just fine
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expectedTs1, ts, value1);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
     }
 
-    for (HTable table : tables) {
-      table.close();
-      UTIL.deleteTable(table.getTableName());
+    /**
+     * Its possible (i.e. from a fast, frequently writing client) that they put more than the
+     * 'visible' number of versions in a row before a client make a put 'back in time' on that row. If
+     * we don't scan the current table properly, we won't see an index update for that 'back in time'
+     * update since the usual lookup will only see the regular number of versions. This ability to see
+     * back in time depends on running HBase 0.94.9
+     * @throws Exception on failure
+     */
+    @Test
+    public void testExceedVersionsOutOfOrderPut() throws Exception {
+        // setup the index
+        HTable primary = createSetupTables(fam2);
+
+        // do a put to the primary table
+        Put p = new Put(row1);
+        long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5;
+        byte[] value4 = Bytes.toBytes("val4");
+        byte[] value5 = Bytes.toBytes("val5");
+        p.add(FAM2, indexed_qualifer, ts1, value1);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM2, indexed_qualifer, ts3, value3);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM2, indexed_qualifer, ts4, value4);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM2, indexed_qualifer, ts5, value5);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
+
+        // do a raw scan of everything in the table
+        if (LOG.isDebugEnabled()) {
+            // the whole table, all the keys
+            Scan s = new Scan();
+            s.setRaw(true);
+            ResultScanner scanner = index.getScanner(s);
+            for (Result r : scanner) {
+                LOG.debug("Found row:" + r);
+            }
+            scanner.close();
+        }
+
+        /*
+         * now we have definitely exceeded the number of versions visible to a usual client of the
+         * primary table, so we should try doing a put 'back in time' an make sure that has the correct
+         * index values and cleanup
+         */
+        p = new Put(row1);
+        p.add(FAM2, indexed_qualifer, ts2, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        // // read the index for the expected values
+        // HTable index = new HTable(UTIL.getConfiguration(), fam2.getTable());
+        //
+        // do a raw scan of everything in the table
+        if (LOG.isDebugEnabled()) {
+            // the whole table, all the keys
+            Scan s = new Scan();
+            s.setRaw(true);
+            ResultScanner scanner = index.getScanner(s);
+            for (Result r : scanner) {
+                LOG.debug("Found row:" + r);
+            }
+            scanner.close();
+        }
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col3));
+
+        // check the value1 should be present at the earliest timestamp
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts1, value1, value2);
+
+        // and value1 should be removed at ts2 (even though it came later)
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts1,
+                ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
+
+        // late added column should be there just fine at its timestamp
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
+
+        // and check that the late entry also removes its self at the next timestamp up
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
+                value2, value3);
+
+        // then we should have the rest of the inserts at their appropriate timestamps. Everything else
+        // should be exactly the same, except we shouldn't see ts0 anymore at ts2
+
+        // check the third entry
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col3));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts3, value3);
+
+        // check the fourth entry
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value4, col3));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts4, value4);
+
+        // check the first entry at ts4
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value2, col3));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, expected, ts2, value2);
+        // verify that we remove the entry, even though its too far 'back in time'
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index, Collections.<KeyValue> emptyList(), ts3,
+                value4);
+
+        // cleanup
+        closeAndCleanupTables(primary, index);
+    }
+
+    /**
+     * Similar to {@link #testExceedVersionsOutOfOrderPut()}, but mingles deletes and puts.
+     * @throws Exception on failure
+     */
+    @Test
+    public void testExceedVersionsOutOfOrderUpdates() throws Exception {
+        HTable primary = createSetupTables(fam1);
+
+        // setup the data to store
+        long ts1 = 1, ts2 = 2, ts3 = 3, ts4 = 4, ts5 = 5, ts6 = 6;
+        byte[] value4 = Bytes.toBytes("val4"), value5 = Bytes.toBytes("val5"), value6 =
+                Bytes.toBytes("val6");
+        // values for the other column to index
+        byte[] v1_1 = ArrayUtils.addAll(value1, Bytes.toBytes("_otherCol")), v3_1 =
+                ArrayUtils.addAll(value3, Bytes.toBytes("_otherCol")), v5_1 =
+                ArrayUtils.addAll(value5, Bytes.toBytes("_otherCol")), v6_1 =
+                ArrayUtils.addAll(value6, Bytes.toBytes("_otherCol"));
+
+        // make some puts to the primary table
+        Put p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts1, value1);
+        p.add(FAM2, indexed_qualifer, ts1, v1_1);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts3, value3);
+        p.add(FAM2, indexed_qualifer, ts3, v3_1);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts5, value5);
+        p.add(FAM2, indexed_qualifer, ts5, v5_1);
+        primary.put(p);
+        primary.flushCommits();
+
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts6, value6);
+        p.add(FAM2, indexed_qualifer, ts6, v6_1);
+        primary.put(p);
+        primary.flushCommits();
+
+        /*
+         * now we have definitely exceeded the number of versions visible to a usual client of the
+         * primary table, so we should try doing a put 'back in time' an make sure that has the correct
+         * index values and cleanup
+         */
+        p = new Put(row1);
+        p.add(FAM, indexed_qualifer, ts2, value2);
+        primary.put(p);
+        primary.flushCommits();
+
+        // read the index for the expected values
+        HTable index1 = new HTable(UTIL.getConfiguration(), fam1.getTable());
+
+        // do a raw scan of everything in the table
+        if (LOG.isDebugEnabled()) {
+            Scan s = new Scan();
+            s.setRaw(true);
+            ResultScanner scanner = index1.getScanner(s);
+            for (Result r : scanner) {
+                LOG.debug("Found row:" + r);
+            }
+            scanner.close();
+        }
+
+        // build the expected kvs
+        List<Pair<byte[], CoveredColumn>> pairs = new ArrayList<Pair<byte[], CoveredColumn>>();
+        pairs.add(new Pair<byte[], CoveredColumn>(value1, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+
+        // check the value1 should be present at the earliest timestamp
+        List<KeyValue> expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts1, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts1, value1, value2);
+
+        // and value1 should be removed at ts2 (even though it came later)
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts1,
+                ts2 + 1, value1, value2); // timestamp + 1 since its exclusive end timestamp
+
+        // late added column should be there just fine at its timestamp
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value2, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts2, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts2, value2);
+
+        // and check that the late entry also removes its self at the next timestamp up
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts3,
+                value2, value3);
+
+        // -----------------------------------------------
+        // Check Delete intermingled
+        // -----------------------------------------------
+
+        // verify that the old row is there
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v3_1, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+        // scan from the start key forward (should only include [value3][v3_3])
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, expected.get(0).getKey(),
+                value4);
+
+        // then do a delete of just one of the indexed columns. This should insert a delete for all just
+        // the single value, then a put & a later corresponding in the past for the new value
+        Delete d = new Delete(row1);
+        d.deleteColumn(FAM2, indexed_qualifer, ts3);
+        primary.delete(d);
+
+        // we shouldn't find that entry, but we should find [value3][v1_1] since that is next entry back
+        // in time from the current
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v1_1, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+        // it should be re-written at 3
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
+
+        // but we shouldn't find it at ts5 since it should be covered again
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, Collections.<KeyValue> emptyList(), ts5,
+                value3, value4);
+
+        // now remove all the older columns in FAM2 at 4
+        d = new Delete(row1);
+        d.deleteColumns(FAM2, indexed_qualifer, ts4);
+        primary.delete(d);
+
+        // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
+        // all the entries for that column
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts4, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts4, value3, value4);
+
+        // same as above, but now do it at 3 (on earlier)
+        d = new Delete(row1);
+        d.deleteColumns(FAM2, indexed_qualifer, ts3);
+        primary.delete(d);
+
+        // we shouldn't find that entry, but we should find [value3][null] since deleteColumns removes
+        // all the entries for that column
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value3, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(EMPTY_BYTES, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts3, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts3, value3, value4);
+
+        // -----------------------------------------------
+        // then we should have the rest of the inserts at their appropriate timestamps. Everything else
+        // should be exactly the same, except we shouldn't see ts0 anymore at ts2
+        // -----------------------------------------------
+
+        // check the entry at 5
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value5, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v5_1, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts5, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts5, value5);
+
+        // check the entry at 6
+        pairs.clear();
+        pairs.add(new Pair<byte[], CoveredColumn>(value6, col1));
+        pairs.add(new Pair<byte[], CoveredColumn>(v6_1, col2));
+        expected = CoveredColumnIndexCodec.getIndexKeyValueForTesting(row1, ts6, pairs);
+        IndexTestingUtils.verifyIndexTableAtTimestamp(index1, expected, ts6, value5);
+
+        // cleanup
+        closeAndCleanupTables(primary, index1);
+    }
+
+    /**
+     * Create the primary table (to which you should write), setup properly for indexing the given
+     * {@link ColumnGroup}s. Also creates the necessary index tables to match the passes groups.
+     * @param groups {@link ColumnGroup}s to index, creating one index table per column group.
+     * @return reference to the primary table
+     * @throws IOException if there is an issue communicating with HBase
+     */
+    private HTable createSetupTables(ColumnGroup... groups) throws IOException {
+        HBaseAdmin admin = UTIL.getHBaseAdmin();
+        // setup the index
+        CoveredColumnIndexSpecifierBuilder builder = new CoveredColumnIndexSpecifierBuilder();
+        for (ColumnGroup group : groups) {
+            builder.addIndexGroup(group);
+            // create the index tables
+            CoveredColumnIndexer.createIndexTable(admin, group.getTable());
+        }
+
+        // setup the primary table
+        String indexedTableName = Bytes.toString(TestTable.getTableName());
+        @SuppressWarnings("deprecation")
+        HTableDescriptor pTable = new HTableDescriptor(indexedTableName);
+        pTable.addFamily(new HColumnDescriptor(FAM));
+        pTable.addFamily(new HColumnDescriptor(FAM2));
+        builder.build(pTable);
+
+        // create the primary table
+        admin.createTable(pTable);
+        HTable primary = new HTable(UTIL.getConfiguration(), indexedTableName);
+        primary.setAutoFlush(false);
+        return primary;
+    }
+
+    private void closeAndCleanupTables(HTable... tables) throws IOException {
+        if (tables == null) {
+            return;
+        }
+
+        for (HTable table : tables) {
+            table.close();
+            UTIL.deleteTable(table.getTableName());
+        }
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
index 016c59e..b0aeea3 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/hbase/index/covered/example/EndtoEndIndexingWithCompressionIT.java
@@ -17,14 +17,10 @@
  */
 package org.apache.phoenix.hbase.index.covered.example;
 
-import static org.apache.phoenix.query.BaseTest.setUpConfigForMiniCluster;
-
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec;
 import org.apache.hadoop.hbase.regionserver.wal.WALCellCodec;
-import org.apache.phoenix.hbase.index.IndexTestingUtils;
-import org.apache.phoenix.hbase.index.Indexer;
 import org.junit.BeforeClass;
 
 /**
@@ -34,19 +30,16 @@ import org.junit.BeforeClass;
 
 public class EndtoEndIndexingWithCompressionIT extends EndToEndCoveredIndexingIT {
 
-  @BeforeClass
-  public static void setupCluster() throws Exception {
-    //add our codec and enable WAL compression
-    Configuration conf = UTIL.getConfiguration();
-    setUpConfigForMiniCluster(conf);
-    IndexTestingUtils.setupConfig(conf);
-    // disable version checking, so we can test against whatever version of HBase happens to be
-    // installed (right now, its generally going to be SNAPSHOT versions).
-    conf.setBoolean(Indexer.CHECK_VERSION_CONF_KEY, false);
-    conf.set(WALCellCodec.WAL_CELL_CODEC_CLASS_KEY,
-    IndexedWALEditCodec.class.getName());
-    conf.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
-    //start the mini-cluster
-    UTIL.startMiniCluster();
-  }
+    @BeforeClass
+    public static void setupCluster() throws Exception {
+        setupConfig();
+        //add our codec and enable WAL compression
+        Configuration conf = UTIL.getConfiguration();
+        conf.set(WALCellCodec.WAL_CELL_CODEC_CLASS_KEY,
+                IndexedWALEditCodec.class.getName());
+        conf.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
+        //start the mini-cluster
+        UTIL.startMiniCluster();
+        initDriver();
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
index e2ebad4..0e74d7b 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/CsvBulkLoadToolIT.java
@@ -38,6 +38,8 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
 import org.apache.phoenix.jdbc.PhoenixDriver;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
 import org.apache.phoenix.util.DateUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.junit.AfterClass;
@@ -58,6 +60,9 @@ public class CsvBulkLoadToolIT {
         hbaseTestUtil = new HBaseTestingUtility();
         Configuration conf = hbaseTestUtil.getConfiguration();
         setUpConfigForMiniCluster(conf);
+        // Since we're using the real PhoenixDriver in this test, remove the
+        // extra JDBC argument that causes the test driver to be used.
+        conf.set(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
         hbaseTestUtil.startMiniCluster();
         hbaseTestUtil.startMiniMapReduceCluster();
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
index 30cae36..c88a5f4 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/mapreduce/IndexToolIT.java
@@ -37,6 +37,8 @@ import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.phoenix.end2end.NeedsOwnMiniClusterTest;
 import org.apache.phoenix.jdbc.PhoenixDriver;
 import org.apache.phoenix.mapreduce.index.IndexTool;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
 import org.apache.phoenix.util.MetaDataUtil;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.PropertiesUtil;
@@ -63,6 +65,9 @@ public class IndexToolIT {
         hbaseTestUtil = new HBaseTestingUtility();
         Configuration conf = hbaseTestUtil.getConfiguration();
         conf.setBoolean("hbase.defaults.for.version.skip", true);
+        // Since we're using the real PhoenixDriver in this test, remove the
+        // extra JDBC argument that causes the test driver to be used.
+        conf.set(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
         setUpConfigForMiniCluster(conf);
         hbaseTestUtil.startMiniCluster();
         hbaseTestUtil.startMiniMapReduceCluster();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index 835f639..70d8f5e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -168,6 +168,7 @@ public interface QueryServices extends SQLCloseable {
     public static final String COLLECT_REQUEST_LEVEL_METRICS = "phoenix.query.request.metrics.enabled";
     public static final String ALLOW_VIEWS_ADD_NEW_CF_BASE_TABLE = "phoenix.schema.view.newcf";
     public static final String RETURN_SEQUENCE_VALUES_ATTRIB = "phoenix.sequence.returnValues";
+    public static final String EXTRA_JDBC_ARGUMENTS_ATTRIB = "phoenix.jdbc.extra.arguments";
     
 
     /**

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
index 9f69c05..3a4a51f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
@@ -27,6 +27,7 @@ import static org.apache.phoenix.query.QueryServices.DATE_FORMAT_TIMEZONE_ATTRIB
 import static org.apache.phoenix.query.QueryServices.DELAY_FOR_SCHEMA_UPDATE_CHECK;
 import static org.apache.phoenix.query.QueryServices.DROP_METADATA_ATTRIB;
 import static org.apache.phoenix.query.QueryServices.EXPLAIN_CHUNK_COUNT_ATTRIB;
+import static org.apache.phoenix.query.QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB;
 import static org.apache.phoenix.query.QueryServices.FORCE_ROW_KEY_ORDER_ATTRIB;
 import static org.apache.phoenix.query.QueryServices.GLOBAL_METRICS_ENABLED;
 import static org.apache.phoenix.query.QueryServices.GROUPBY_MAX_CACHE_SIZE_ATTRIB;
@@ -198,6 +199,7 @@ public class QueryServicesOptions {
     public static final boolean DEFAULT_ALLOW_VIEWS_ADD_NEW_CF_BASE_TABLE = true;
     
     public static final boolean DEFAULT_RETURN_SEQUENCE_VALUES = false;
+    public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = "";
 
     private final Configuration config;
 
@@ -543,4 +545,8 @@ public class QueryServicesOptions {
         return this;
     }
     
+    public QueryServicesOptions setExtraJDBCArguments(String extraArgs) {
+        config.set(EXTRA_JDBC_ARGUMENTS_ATTRIB, extraArgs);
+        return this;
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
index 6506184..364bef5 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
@@ -45,6 +45,7 @@ import org.apache.phoenix.parse.HintNode;
 import org.apache.phoenix.parse.HintNode.Hint;
 import org.apache.phoenix.parse.WildcardParseNode;
 import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
@@ -305,6 +306,9 @@ public final class QueryUtil {
             throws ClassNotFoundException, SQLException {
         // TODO: props is ignored!
         // make sure we load the phoenix driver
+        // TODO: remove this - it doesn't belong here
+        // The driver should be loaded outside of this call as we might
+        // be using the test driver.
         Class.forName(PhoenixDriver.class.getName());
 
         // read the hbase properties from the configuration
@@ -341,8 +345,13 @@ public final class QueryUtil {
         server = Joiner.on(',').join(servers);
         String znodeParent = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT,
                 HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT);
-
-        return getUrl(server, port, znodeParent);
+        String url = getUrl(server, port, znodeParent);
+        // Mainly for testing to tack on the test=true part to ensure driver is found on server
+        String extraArgs = conf.get(QueryServices.EXTRA_JDBC_ARGUMENTS_ATTRIB, QueryServicesOptions.DEFAULT_EXTRA_JDBC_ARGUMENTS);
+        if (extraArgs.length() > 0) {
+            url += extraArgs + PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR;
+        }
+        return url;
     }
     
     public static String getViewStatement(String schemaName, String tableName, String where) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/14580f78/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
index 9fee78f..5289ab9 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java
@@ -21,6 +21,7 @@ import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_SPOOL_DIRECT
 import static org.apache.phoenix.query.QueryServicesOptions.withDefaults;
 
 import org.apache.hadoop.hbase.regionserver.wal.IndexedWALEditCodec;
+import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.ReadOnlyProps;
 
 
@@ -53,6 +54,8 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl {
     public static final long DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE =  1024L*1024L*2L; // 2 Mb
     public static final int DEFAULT_MIN_STATS_UPDATE_FREQ_MS = 0;
     public static final boolean DEFAULT_EXPLAIN_CHUNK_COUNT = false; // TODO: update explain plans in test and set to true
+    public static final String DEFAULT_EXTRA_JDBC_ARGUMENTS = PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM;
+
     
     /**
      * Set number of salt buckets lower for sequence table during testing, as a high
@@ -89,7 +92,8 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl {
                 .setDropMetaData(DEFAULT_DROP_METADATA)
                 .setMaxClientMetaDataCacheSize(DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE)
                 .setMaxServerMetaDataCacheSize(DEFAULT_MAX_SERVER_METADATA_CACHE_SIZE)
-                .setForceRowKeyOrder(DEFAULT_FORCE_ROWKEY_ORDER);
+                .setForceRowKeyOrder(DEFAULT_FORCE_ROWKEY_ORDER)
+                .setExtraJDBCArguments(DEFAULT_EXTRA_JDBC_ARGUMENTS);
     }
     
     public QueryServicesTestImpl(ReadOnlyProps defaultProps, ReadOnlyProps overrideProps) {


[2/3] phoenix git commit: PHOENIX-2397 Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18:test failed. NullPointerException

Posted by ja...@apache.org.
PHOENIX-2397 Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.18:test failed. NullPointerException


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/b9a3c532
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/b9a3c532
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/b9a3c532

Branch: refs/heads/4.x-HBase-0.98
Commit: b9a3c53204d6ca34758bea362025dfcc94e2931c
Parents: a722b0e
Author: James Taylor <ja...@apache.org>
Authored: Tue Nov 10 16:55:01 2015 -0800
Committer: James Taylor <jt...@salesforce.com>
Committed: Wed Nov 11 09:58:59 2015 -0800

----------------------------------------------------------------------
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/b9a3c532/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index e492bee..da16d4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -120,8 +120,8 @@
     <!-- Plugin versions -->
     <maven-eclipse-plugin.version>2.9</maven-eclipse-plugin.version>
     <maven-build-helper-plugin.version>1.9.1</maven-build-helper-plugin.version>
-    <maven-surefire-plugin.version>2.18</maven-surefire-plugin.version>
-    <maven-failsafe-plugin.version>2.18</maven-failsafe-plugin.version>
+    <maven-surefire-plugin.version>2.19</maven-surefire-plugin.version>
+    <maven-failsafe-plugin.version>2.19</maven-failsafe-plugin.version>
     
     <maven-dependency-plugin.version>2.1</maven-dependency-plugin.version>
     <maven.assembly.version>2.5.2</maven.assembly.version>