001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.client;
019
020import static org.apache.hadoop.hbase.HBaseTestingUtil.countRows;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertNull;
023import static org.junit.Assert.assertTrue;
024
025import java.io.IOException;
026import java.util.Arrays;
027import java.util.Iterator;
028import java.util.List;
029import java.util.stream.Stream;
030import org.apache.hadoop.conf.Configuration;
031import org.apache.hadoop.hbase.Cell;
032import org.apache.hadoop.hbase.CellUtil;
033import org.apache.hadoop.hbase.CompareOperator;
034import org.apache.hadoop.hbase.HBaseCommonTestingUtil;
035import org.apache.hadoop.hbase.HBaseTestingUtil;
036import org.apache.hadoop.hbase.HConstants;
037import org.apache.hadoop.hbase.HRegionLocation;
038import org.apache.hadoop.hbase.StartTestingClusterOption;
039import org.apache.hadoop.hbase.TableName;
040import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
041import org.apache.hadoop.hbase.filter.BinaryComparator;
042import org.apache.hadoop.hbase.filter.Filter;
043import org.apache.hadoop.hbase.filter.FilterList;
044import org.apache.hadoop.hbase.filter.PrefixFilter;
045import org.apache.hadoop.hbase.filter.RowFilter;
046import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
047import org.apache.hadoop.hbase.filter.WhileMatchFilter;
048import org.apache.hadoop.hbase.util.Bytes;
049import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
050import org.apache.hadoop.hbase.util.NonRepeatedEnvironmentEdge;
051import org.apache.hadoop.hbase.util.TableDescriptorChecker;
052import org.junit.jupiter.api.AfterAll;
053import org.junit.jupiter.api.AfterEach;
054import org.junit.jupiter.api.BeforeEach;
055import org.junit.jupiter.api.TestInfo;
056import org.junit.jupiter.params.provider.Arguments;
057import org.slf4j.Logger;
058import org.slf4j.LoggerFactory;
059
060public class FromClientSideTestBase {
061  private static final Logger LOG = LoggerFactory.getLogger(FromClientSideTestBase.class);
062  protected static final HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
063  static byte[] ROW = Bytes.toBytes("testRow");
064  static byte[] FAMILY = Bytes.toBytes("testFamily");
065  static final byte[] INVALID_FAMILY = Bytes.toBytes("invalidTestFamily");
066  static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
067  static byte[] VALUE = Bytes.toBytes("testValue");
068  static int SLAVES = 1;
069
070  protected Class<? extends ConnectionRegistry> registryImpl;
071  protected int numHedgedReqs;
072
073  protected TableName tableName;
074
075  protected FromClientSideTestBase(Class<? extends ConnectionRegistry> registryImpl,
076    int numHedgedReqs) {
077    this.registryImpl = registryImpl;
078    this.numHedgedReqs = numHedgedReqs;
079  }
080
081  @BeforeEach
082  public void setUp(TestInfo testInfo) {
083    tableName = TableName.valueOf(testInfo.getTestMethod().get().getName()
084      + testInfo.getDisplayName().replaceAll("[^A-Za-z0-9_]", "_"));
085  }
086
087  @AfterEach
088  public void tearDown() throws Exception {
089    for (TableDescriptor htd : TEST_UTIL.getAdmin().listTableDescriptors()) {
090      LOG.info("Tear down, remove table=" + htd.getTableName());
091      TEST_UTIL.deleteTable(htd.getTableName());
092    }
093  }
094
095  @SuppressWarnings("deprecation")
096  public static Stream<Arguments> parameters() {
097    return Stream.of(Arguments.of(RpcConnectionRegistry.class, 1),
098      Arguments.of(RpcConnectionRegistry.class, 2), Arguments.of(MasterRegistry.class, 1),
099      Arguments.of(MasterRegistry.class, 2), Arguments.of(ZKConnectionRegistry.class, 1));
100  }
101
102  protected static final void initialize(Class<?>... cps) throws Exception {
103    // Uncomment the following lines if more verbosity is needed for
104    // debugging (see HBASE-12285 for details).
105    // ((Log4JLogger)RpcServer.LOG).getLogger().setLevel(Level.ALL);
106    // ((Log4JLogger)RpcClient.LOG).getLogger().setLevel(Level.ALL);
107    // ((Log4JLogger)ScannerCallable.LOG).getLogger().setLevel(Level.ALL);
108    // make sure that we do not get the same ts twice, see HBASE-19731 for more details.
109    EnvironmentEdgeManager.injectEdge(new NonRepeatedEnvironmentEdge());
110    Configuration conf = TEST_UTIL.getConfiguration();
111    conf.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY,
112      Arrays.stream(cps).map(Class::getName).toArray(String[]::new));
113    conf.setBoolean(TableDescriptorChecker.TABLE_SANITY_CHECKS, true); // enable for below tests
114    // Use multiple masters for support hedged reads in registry
115    TEST_UTIL.startMiniCluster(
116      StartTestingClusterOption.builder().numMasters(3).numRegionServers(SLAVES).build());
117  }
118
119  @AfterAll
120  public static void tearDownAfterClass() throws Exception {
121    TEST_UTIL.shutdownMiniCluster();
122  }
123
124  @SuppressWarnings("deprecation")
125  protected final Configuration getClientConf() {
126    Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
127    conf.setClass(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY, registryImpl,
128      ConnectionRegistry.class);
129    conf.setInt(RpcConnectionRegistry.HEDGED_REQS_FANOUT_KEY, numHedgedReqs);
130    conf.setInt(MasterRegistry.MASTER_REGISTRY_HEDGED_REQS_FANOUT_KEY, numHedgedReqs);
131    return conf;
132  }
133
134  protected final Connection getConnection() throws IOException {
135    return ConnectionFactory.createConnection(getClientConf());
136  }
137
138  protected void deleteColumns(Table ht, String value, String keyPrefix) throws IOException {
139    ResultScanner scanner = buildScanner(keyPrefix, value, ht);
140    Iterator<Result> it = scanner.iterator();
141    int count = 0;
142    while (it.hasNext()) {
143      Result result = it.next();
144      Delete delete = new Delete(result.getRow());
145      delete.addColumn(Bytes.toBytes("trans-tags"), Bytes.toBytes("qual2"));
146      ht.delete(delete);
147      count++;
148    }
149    assertEquals("Did not perform correct number of deletes", 3, count);
150  }
151
152  protected int getNumberOfRows(String keyPrefix, String value, Table ht) throws Exception {
153    ResultScanner resultScanner = buildScanner(keyPrefix, value, ht);
154    Iterator<Result> scanner = resultScanner.iterator();
155    int numberOfResults = 0;
156    while (scanner.hasNext()) {
157      Result result = scanner.next();
158      System.out.println("Got back key: " + Bytes.toString(result.getRow()));
159      for (Cell kv : result.rawCells()) {
160        System.out.println("kv=" + kv.toString() + ", " + Bytes.toString(CellUtil.cloneValue(kv)));
161      }
162      numberOfResults++;
163    }
164    return numberOfResults;
165  }
166
167  protected ResultScanner buildScanner(String keyPrefix, String value, Table ht)
168    throws IOException {
169    // OurFilterList allFilters = new OurFilterList();
170    FilterList allFilters = new FilterList(/* FilterList.Operator.MUST_PASS_ALL */);
171    allFilters.addFilter(new PrefixFilter(Bytes.toBytes(keyPrefix)));
172    SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("trans-tags"),
173      Bytes.toBytes("qual2"), CompareOperator.EQUAL, Bytes.toBytes(value));
174    filter.setFilterIfMissing(true);
175    allFilters.addFilter(filter);
176
177    // allFilters.addFilter(new
178    // RowExcludingSingleColumnValueFilter(Bytes.toBytes("trans-tags"),
179    // Bytes.toBytes("qual2"), CompareOp.EQUAL, Bytes.toBytes(value)));
180
181    Scan scan = new Scan();
182    scan.addFamily(Bytes.toBytes("trans-blob"));
183    scan.addFamily(Bytes.toBytes("trans-type"));
184    scan.addFamily(Bytes.toBytes("trans-date"));
185    scan.addFamily(Bytes.toBytes("trans-tags"));
186    scan.addFamily(Bytes.toBytes("trans-group"));
187    scan.setFilter(allFilters);
188
189    return ht.getScanner(scan);
190  }
191
192  protected void putRows(Table ht, int numRows, String value, String key) throws IOException {
193    for (int i = 0; i < numRows; i++) {
194      String row = key + "_" + HBaseCommonTestingUtil.getRandomUUID().toString();
195      System.out.println(String.format("Saving row: %s, with value %s", row, value));
196      Put put = new Put(Bytes.toBytes(row));
197      put.setDurability(Durability.SKIP_WAL);
198      put.addColumn(Bytes.toBytes("trans-blob"), null, Bytes.toBytes("value for blob"));
199      put.addColumn(Bytes.toBytes("trans-type"), null, Bytes.toBytes("statement"));
200      put.addColumn(Bytes.toBytes("trans-date"), null, Bytes.toBytes("20090921010101999"));
201      put.addColumn(Bytes.toBytes("trans-tags"), Bytes.toBytes("qual2"), Bytes.toBytes(value));
202      put.addColumn(Bytes.toBytes("trans-group"), null, Bytes.toBytes("adhocTransactionGroupId"));
203      ht.put(put);
204    }
205  }
206
207  protected void assertRowCount(final Table t, final int expected) throws IOException {
208    assertEquals(expected, countRows(t, new Scan()));
209  }
210
211  /*
212   * @return Scan with RowFilter that does LESS than passed key.
213   */
214  protected Scan createScanWithRowFilter(final byte[] key) {
215    return createScanWithRowFilter(key, null, CompareOperator.LESS);
216  }
217
218  /*
219   * @return Scan with RowFilter that does CompareOp op on passed key.
220   */
221  protected Scan createScanWithRowFilter(final byte[] key, final byte[] startRow,
222    CompareOperator op) {
223    // Make sure key is of some substance... non-null and > than first key.
224    assertTrue(key != null && key.length > 0
225      && Bytes.BYTES_COMPARATOR.compare(key, new byte[] { 'a', 'a', 'a' }) >= 0);
226    LOG.info("Key=" + Bytes.toString(key));
227    Scan s = startRow == null ? new Scan() : new Scan().withStartRow(startRow);
228    Filter f = new RowFilter(op, new BinaryComparator(key));
229    f = new WhileMatchFilter(f);
230    s.setFilter(f);
231    return s;
232  }
233
234  /**
235   * Split table into multiple regions.
236   * @param t Table to split.
237   * @return Map of regions to servers.
238   */
239  protected List<HRegionLocation> splitTable(final Table t) throws IOException {
240    // Split this table in two.
241    Admin admin = TEST_UTIL.getAdmin();
242    admin.split(t.getName());
243    // Is it right closing this admin?
244    admin.close();
245    List<HRegionLocation> regions = waitOnSplit(t);
246    assertTrue(regions.size() > 1);
247    return regions;
248  }
249
250  /*
251   * Wait on table split. May return because we waited long enough on the split and it didn't
252   * happen. Caller should check.
253   * @return Map of table regions; caller needs to check table actually split.
254   */
255  private List<HRegionLocation> waitOnSplit(final Table t) throws IOException {
256    try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(t.getName())) {
257      List<HRegionLocation> regions = locator.getAllRegionLocations();
258      int originalCount = regions.size();
259      for (int i = 0; i < TEST_UTIL.getConfiguration().getInt("hbase.test.retries", 30); i++) {
260        try {
261          Thread.sleep(1000);
262        } catch (InterruptedException e) {
263          e.printStackTrace();
264        }
265        regions = locator.getAllRegionLocations();
266        if (regions.size() > originalCount) {
267          break;
268        }
269      }
270      return regions;
271    }
272  }
273
274  protected Result getSingleScanResult(Table ht, Scan scan) throws IOException {
275    try (ResultScanner scanner = ht.getScanner(scan)) {
276      return scanner.next();
277    }
278  }
279
280  byte[][] makeNAscii(byte[] base, int n) {
281    if (n > 256) {
282      return makeNBig(base, n);
283    }
284    byte[][] ret = new byte[n][];
285    for (int i = 0; i < n; i++) {
286      byte[] tail = Bytes.toBytes(Integer.toString(i));
287      ret[i] = Bytes.add(base, tail);
288    }
289    return ret;
290  }
291
292  protected byte[][] makeN(byte[] base, int n) {
293    if (n > 256) {
294      return makeNBig(base, n);
295    }
296    byte[][] ret = new byte[n][];
297    for (int i = 0; i < n; i++) {
298      ret[i] = Bytes.add(base, new byte[] { (byte) i });
299    }
300    return ret;
301  }
302
303  protected byte[][] makeNBig(byte[] base, int n) {
304    byte[][] ret = new byte[n][];
305    for (int i = 0; i < n; i++) {
306      int byteA = (i % 256);
307      int byteB = (i >> 8);
308      ret[i] = Bytes.add(base, new byte[] { (byte) byteB, (byte) byteA });
309    }
310    return ret;
311  }
312
313  protected long[] makeStamps(int n) {
314    long[] stamps = new long[n];
315    for (int i = 0; i < n; i++) {
316      stamps[i] = i + 1L;
317    }
318    return stamps;
319  }
320
321  protected static boolean equals(byte[] left, byte[] right) {
322    if (left == null && right == null) {
323      return true;
324    }
325    if (left == null && right.length == 0) {
326      return true;
327    }
328    if (right == null && left.length == 0) {
329      return true;
330    }
331    return Bytes.equals(left, right);
332  }
333
334  protected void assertKey(Cell key, byte[] row, byte[] family, byte[] qualifier, byte[] value) {
335    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
336      + Bytes.toString(CellUtil.cloneRow(key)) + "]", equals(row, CellUtil.cloneRow(key)));
337    assertTrue(
338      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
339        + Bytes.toString(CellUtil.cloneFamily(key)) + "]",
340      equals(family, CellUtil.cloneFamily(key)));
341    assertTrue(
342      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
343        + Bytes.toString(CellUtil.cloneQualifier(key)) + "]",
344      equals(qualifier, CellUtil.cloneQualifier(key)));
345    assertTrue("Expected value [" + Bytes.toString(value) + "] " + "Got value ["
346      + Bytes.toString(CellUtil.cloneValue(key)) + "]", equals(value, CellUtil.cloneValue(key)));
347  }
348
349  static void assertIncrementKey(Cell key, byte[] row, byte[] family, byte[] qualifier,
350    long value) {
351    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
352      + Bytes.toString(CellUtil.cloneRow(key)) + "]", equals(row, CellUtil.cloneRow(key)));
353    assertTrue(
354      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
355        + Bytes.toString(CellUtil.cloneFamily(key)) + "]",
356      equals(family, CellUtil.cloneFamily(key)));
357    assertTrue(
358      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
359        + Bytes.toString(CellUtil.cloneQualifier(key)) + "]",
360      equals(qualifier, CellUtil.cloneQualifier(key)));
361    assertEquals("Expected value [" + value + "] " + "Got value ["
362      + Bytes.toLong(CellUtil.cloneValue(key)) + "]", Bytes.toLong(CellUtil.cloneValue(key)),
363      value);
364  }
365
366  protected void assertNumKeys(Result result, int n) throws Exception {
367    assertEquals("Expected " + n + " keys but got " + result.size(), result.size(), n);
368  }
369
370  protected void assertNResult(Result result, byte[] row, byte[][] families, byte[][] qualifiers,
371    byte[][] values, int[][] idxs) {
372    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
373      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
374    assertEquals("Expected " + idxs.length + " keys but result contains " + result.size(),
375      result.size(), idxs.length);
376
377    Cell[] keys = result.rawCells();
378
379    for (int i = 0; i < keys.length; i++) {
380      byte[] family = families[idxs[i][0]];
381      byte[] qualifier = qualifiers[idxs[i][1]];
382      byte[] value = values[idxs[i][2]];
383      Cell key = keys[i];
384
385      byte[] famb = CellUtil.cloneFamily(key);
386      byte[] qualb = CellUtil.cloneQualifier(key);
387      byte[] valb = CellUtil.cloneValue(key);
388      assertTrue("(" + i + ") Expected family [" + Bytes.toString(family) + "] " + "Got family ["
389        + Bytes.toString(famb) + "]", equals(family, famb));
390      assertTrue("(" + i + ") Expected qualifier [" + Bytes.toString(qualifier) + "] "
391        + "Got qualifier [" + Bytes.toString(qualb) + "]", equals(qualifier, qualb));
392      assertTrue("(" + i + ") Expected value [" + Bytes.toString(value) + "] " + "Got value ["
393        + Bytes.toString(valb) + "]", equals(value, valb));
394    }
395  }
396
397  protected void assertNResult(Result result, byte[] row, byte[] family, byte[] qualifier,
398    long[] stamps, byte[][] values, int start, int end) {
399    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
400      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
401    int expectedResults = end - start + 1;
402    assertEquals(expectedResults, result.size());
403
404    Cell[] keys = result.rawCells();
405
406    for (int i = 0; i < keys.length; i++) {
407      byte[] value = values[end - i];
408      long ts = stamps[end - i];
409      Cell key = keys[i];
410
411      assertTrue("(" + i + ") Expected family [" + Bytes.toString(family) + "] " + "Got family ["
412        + Bytes.toString(CellUtil.cloneFamily(key)) + "]", CellUtil.matchingFamily(key, family));
413      assertTrue(
414        "(" + i + ") Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
415          + Bytes.toString(CellUtil.cloneQualifier(key)) + "]",
416        CellUtil.matchingQualifier(key, qualifier));
417      assertEquals("Expected ts [" + ts + "] " + "Got ts [" + key.getTimestamp() + "]", ts,
418        key.getTimestamp());
419      assertTrue("(" + i + ") Expected value [" + Bytes.toString(value) + "] " + "Got value ["
420        + Bytes.toString(CellUtil.cloneValue(key)) + "]", CellUtil.matchingValue(key, value));
421    }
422  }
423
424  /**
425   * Validate that result contains two specified keys, exactly. It is assumed key A sorts before key
426   * B.
427   */
428  protected void assertDoubleResult(Result result, byte[] row, byte[] familyA, byte[] qualifierA,
429    byte[] valueA, byte[] familyB, byte[] qualifierB, byte[] valueB) {
430    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
431      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
432    assertEquals("Expected two keys but result contains " + result.size(), 2, result.size());
433    Cell[] kv = result.rawCells();
434    Cell kvA = kv[0];
435    assertTrue(
436      "(A) Expected family [" + Bytes.toString(familyA) + "] " + "Got family ["
437        + Bytes.toString(CellUtil.cloneFamily(kvA)) + "]",
438      equals(familyA, CellUtil.cloneFamily(kvA)));
439    assertTrue(
440      "(A) Expected qualifier [" + Bytes.toString(qualifierA) + "] " + "Got qualifier ["
441        + Bytes.toString(CellUtil.cloneQualifier(kvA)) + "]",
442      equals(qualifierA, CellUtil.cloneQualifier(kvA)));
443    assertTrue("(A) Expected value [" + Bytes.toString(valueA) + "] " + "Got value ["
444      + Bytes.toString(CellUtil.cloneValue(kvA)) + "]", equals(valueA, CellUtil.cloneValue(kvA)));
445    Cell kvB = kv[1];
446    assertTrue(
447      "(B) Expected family [" + Bytes.toString(familyB) + "] " + "Got family ["
448        + Bytes.toString(CellUtil.cloneFamily(kvB)) + "]",
449      equals(familyB, CellUtil.cloneFamily(kvB)));
450    assertTrue(
451      "(B) Expected qualifier [" + Bytes.toString(qualifierB) + "] " + "Got qualifier ["
452        + Bytes.toString(CellUtil.cloneQualifier(kvB)) + "]",
453      equals(qualifierB, CellUtil.cloneQualifier(kvB)));
454    assertTrue("(B) Expected value [" + Bytes.toString(valueB) + "] " + "Got value ["
455      + Bytes.toString(CellUtil.cloneValue(kvB)) + "]", equals(valueB, CellUtil.cloneValue(kvB)));
456  }
457
458  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
459    byte[] value) {
460    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
461      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
462    assertEquals("Expected a single key but result contains " + result.size(), 1, result.size());
463    Cell kv = result.rawCells()[0];
464    assertTrue("Expected family [" + Bytes.toString(family) + "] " + "Got family ["
465      + Bytes.toString(CellUtil.cloneFamily(kv)) + "]", equals(family, CellUtil.cloneFamily(kv)));
466    assertTrue(
467      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
468        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]",
469      equals(qualifier, CellUtil.cloneQualifier(kv)));
470    assertTrue("Expected value [" + Bytes.toString(value) + "] " + "Got value ["
471      + Bytes.toString(CellUtil.cloneValue(kv)) + "]", equals(value, CellUtil.cloneValue(kv)));
472  }
473
474  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
475    long value) {
476    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
477      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
478    assertEquals("Expected a single key but result contains " + result.size(), 1, result.size());
479    Cell kv = result.rawCells()[0];
480    assertTrue("Expected family [" + Bytes.toString(family) + "] " + "Got family ["
481      + Bytes.toString(CellUtil.cloneFamily(kv)) + "]", equals(family, CellUtil.cloneFamily(kv)));
482    assertTrue(
483      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
484        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]",
485      equals(qualifier, CellUtil.cloneQualifier(kv)));
486    assertEquals("Expected value [" + value + "] " + "Got value ["
487      + Bytes.toLong(CellUtil.cloneValue(kv)) + "]", value, Bytes.toLong(CellUtil.cloneValue(kv)));
488  }
489
490  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
491    long ts, byte[] value) {
492    assertTrue("Expected row [" + Bytes.toString(row) + "] " + "Got row ["
493      + Bytes.toString(result.getRow()) + "]", equals(row, result.getRow()));
494    assertEquals("Expected a single key but result contains " + result.size(), 1, result.size());
495    Cell kv = result.rawCells()[0];
496    assertTrue("Expected family [" + Bytes.toString(family) + "] " + "Got family ["
497      + Bytes.toString(CellUtil.cloneFamily(kv)) + "]", equals(family, CellUtil.cloneFamily(kv)));
498    assertTrue(
499      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
500        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]",
501      equals(qualifier, CellUtil.cloneQualifier(kv)));
502    assertEquals("Expected ts [" + ts + "] " + "Got ts [" + kv.getTimestamp() + "]", ts,
503      kv.getTimestamp());
504    assertTrue("Expected value [" + Bytes.toString(value) + "] " + "Got value ["
505      + Bytes.toString(CellUtil.cloneValue(kv)) + "]", equals(value, CellUtil.cloneValue(kv)));
506  }
507
508  protected void assertEmptyResult(Result result) throws Exception {
509    assertTrue("expected an empty result but result contains " + result.size() + " keys",
510      result.isEmpty());
511  }
512
513  protected void assertNullResult(Result result) throws Exception {
514    assertNull("expected null result but received a non-null result", result);
515  }
516
517  protected void getVersionRangeAndVerifyGreaterThan(Table ht, byte[] row, byte[] family,
518    byte[] qualifier, long[] stamps, byte[][] values, int start, int end) throws IOException {
519    Get get = new Get(row);
520    get.addColumn(family, qualifier);
521    get.readVersions(Integer.MAX_VALUE);
522    get.setTimeRange(stamps[start + 1], Long.MAX_VALUE);
523    Result result = ht.get(get);
524    assertNResult(result, row, family, qualifier, stamps, values, start + 1, end);
525  }
526
527  protected void getVersionRangeAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
528    long[] stamps, byte[][] values, int start, int end) throws IOException {
529    Get get = new Get(row);
530    get.addColumn(family, qualifier);
531    get.readVersions(Integer.MAX_VALUE);
532    get.setTimeRange(stamps[start], stamps[end] + 1);
533    Result result = ht.get(get);
534    assertNResult(result, row, family, qualifier, stamps, values, start, end);
535  }
536
537  protected void getAllVersionsAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
538    long[] stamps, byte[][] values, int start, int end) throws IOException {
539    Get get = new Get(row);
540    get.addColumn(family, qualifier);
541    get.readVersions(Integer.MAX_VALUE);
542    Result result = ht.get(get);
543    assertNResult(result, row, family, qualifier, stamps, values, start, end);
544  }
545
546  protected void scanVersionRangeAndVerifyGreaterThan(Table ht, byte[] row, byte[] family,
547    byte[] qualifier, long[] stamps, byte[][] values, int start, int end) throws IOException {
548    Scan scan = new Scan().withStartRow(row);
549    scan.addColumn(family, qualifier);
550    scan.readVersions(Integer.MAX_VALUE);
551    scan.setTimeRange(stamps[start + 1], Long.MAX_VALUE);
552    Result result = getSingleScanResult(ht, scan);
553    assertNResult(result, row, family, qualifier, stamps, values, start + 1, end);
554  }
555
556  protected void scanVersionRangeAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
557    long[] stamps, byte[][] values, int start, int end) throws IOException {
558    Scan scan = new Scan().withStartRow(row);
559    scan.addColumn(family, qualifier);
560    scan.readVersions(Integer.MAX_VALUE);
561    scan.setTimeRange(stamps[start], stamps[end] + 1);
562    Result result = getSingleScanResult(ht, scan);
563    assertNResult(result, row, family, qualifier, stamps, values, start, end);
564  }
565
566  protected void scanAllVersionsAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
567    long[] stamps, byte[][] values, int start, int end) throws IOException {
568    Scan scan = new Scan().withStartRow(row);
569    scan.addColumn(family, qualifier);
570    scan.readVersions(Integer.MAX_VALUE);
571    Result result = getSingleScanResult(ht, scan);
572    assertNResult(result, row, family, qualifier, stamps, values, start, end);
573  }
574
575  protected void getVersionAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
576    long stamp, byte[] value) throws Exception {
577    Get get = new Get(row);
578    get.addColumn(family, qualifier);
579    get.setTimestamp(stamp);
580    get.readVersions(Integer.MAX_VALUE);
581    Result result = ht.get(get);
582    assertSingleResult(result, row, family, qualifier, stamp, value);
583  }
584
585  protected void getVersionAndVerifyMissing(Table ht, byte[] row, byte[] family, byte[] qualifier,
586    long stamp) throws Exception {
587    Get get = new Get(row);
588    get.addColumn(family, qualifier);
589    get.setTimestamp(stamp);
590    get.readVersions(Integer.MAX_VALUE);
591    Result result = ht.get(get);
592    assertEmptyResult(result);
593  }
594
595  protected void scanVersionAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
596    long stamp, byte[] value) throws Exception {
597    Scan scan = new Scan().withStartRow(row);
598    scan.addColumn(family, qualifier);
599    scan.setTimestamp(stamp);
600    scan.readVersions(Integer.MAX_VALUE);
601    Result result = getSingleScanResult(ht, scan);
602    assertSingleResult(result, row, family, qualifier, stamp, value);
603  }
604
605  protected void scanVersionAndVerifyMissing(Table ht, byte[] row, byte[] family, byte[] qualifier,
606    long stamp) throws Exception {
607    Scan scan = new Scan().withStartRow(row);
608    scan.addColumn(family, qualifier);
609    scan.setTimestamp(stamp);
610    scan.readVersions(Integer.MAX_VALUE);
611    Result result = getSingleScanResult(ht, scan);
612    assertNullResult(result);
613  }
614
615  protected void getTestNull(Table ht, byte[] row, byte[] family, byte[] value) throws Exception {
616    Get get = new Get(row);
617    get.addColumn(family, null);
618    Result result = ht.get(get);
619    assertSingleResult(result, row, family, null, value);
620
621    get = new Get(row);
622    get.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
623    result = ht.get(get);
624    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
625
626    get = new Get(row);
627    get.addFamily(family);
628    result = ht.get(get);
629    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
630
631    get = new Get(row);
632    result = ht.get(get);
633    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
634
635  }
636
637  protected void getTestNull(Table ht, byte[] row, byte[] family, long value) throws Exception {
638    Get get = new Get(row);
639    get.addColumn(family, null);
640    Result result = ht.get(get);
641    assertSingleResult(result, row, family, null, value);
642
643    get = new Get(row);
644    get.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
645    result = ht.get(get);
646    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
647
648    get = new Get(row);
649    get.addFamily(family);
650    result = ht.get(get);
651    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
652
653    get = new Get(row);
654    result = ht.get(get);
655    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
656  }
657
658  protected void scanTestNull(Table ht, byte[] row, byte[] family, byte[] value) throws Exception {
659    scanTestNull(ht, row, family, value, false);
660  }
661
662  protected void scanTestNull(Table ht, byte[] row, byte[] family, byte[] value,
663    boolean isReversedScan) throws Exception {
664
665    Scan scan = new Scan();
666    scan.setReversed(isReversedScan);
667    scan.addColumn(family, null);
668    Result result = getSingleScanResult(ht, scan);
669    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
670
671    scan = new Scan();
672    scan.setReversed(isReversedScan);
673    scan.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
674    result = getSingleScanResult(ht, scan);
675    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
676
677    scan = new Scan();
678    scan.setReversed(isReversedScan);
679    scan.addFamily(family);
680    result = getSingleScanResult(ht, scan);
681    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
682
683    scan = new Scan();
684    scan.setReversed(isReversedScan);
685    result = getSingleScanResult(ht, scan);
686    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
687
688  }
689
690  protected void singleRowGetTest(Table ht, byte[][] ROWS, byte[][] FAMILIES, byte[][] QUALIFIERS,
691    byte[][] VALUES) throws Exception {
692    // Single column from memstore
693    Get get = new Get(ROWS[0]);
694    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
695    Result result = ht.get(get);
696    assertSingleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0]);
697
698    // Single column from storefile
699    get = new Get(ROWS[0]);
700    get.addColumn(FAMILIES[2], QUALIFIERS[2]);
701    result = ht.get(get);
702    assertSingleResult(result, ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
703
704    // Single column from storefile, family match
705    get = new Get(ROWS[0]);
706    get.addFamily(FAMILIES[7]);
707    result = ht.get(get);
708    assertSingleResult(result, ROWS[0], FAMILIES[7], QUALIFIERS[7], VALUES[7]);
709
710    // Two columns, one from memstore one from storefile, same family,
711    // wildcard match
712    get = new Get(ROWS[0]);
713    get.addFamily(FAMILIES[4]);
714    result = ht.get(get);
715    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
716      QUALIFIERS[4], VALUES[4]);
717
718    // Two columns, one from memstore one from storefile, same family,
719    // explicit match
720    get = new Get(ROWS[0]);
721    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
722    get.addColumn(FAMILIES[4], QUALIFIERS[4]);
723    result = ht.get(get);
724    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
725      QUALIFIERS[4], VALUES[4]);
726
727    // Three column, one from memstore two from storefile, different families,
728    // wildcard match
729    get = new Get(ROWS[0]);
730    get.addFamily(FAMILIES[4]);
731    get.addFamily(FAMILIES[7]);
732    result = ht.get(get);
733    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES,
734      new int[][] { { 4, 0, 0 }, { 4, 4, 4 }, { 7, 7, 7 } });
735
736    // Multiple columns from everywhere storefile, many family, wildcard
737    get = new Get(ROWS[0]);
738    get.addFamily(FAMILIES[2]);
739    get.addFamily(FAMILIES[4]);
740    get.addFamily(FAMILIES[6]);
741    get.addFamily(FAMILIES[7]);
742    result = ht.get(get);
743    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
744      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
745
746    // Multiple columns from everywhere storefile, many family, wildcard
747    get = new Get(ROWS[0]);
748    get.addColumn(FAMILIES[2], QUALIFIERS[2]);
749    get.addColumn(FAMILIES[2], QUALIFIERS[4]);
750    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
751    get.addColumn(FAMILIES[4], QUALIFIERS[4]);
752    get.addColumn(FAMILIES[6], QUALIFIERS[6]);
753    get.addColumn(FAMILIES[6], QUALIFIERS[7]);
754    get.addColumn(FAMILIES[7], QUALIFIERS[7]);
755    get.addColumn(FAMILIES[7], QUALIFIERS[8]);
756    result = ht.get(get);
757    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
758      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
759
760    // Everything
761    get = new Get(ROWS[0]);
762    result = ht.get(get);
763    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
764      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 }, { 9, 0, 0 } });
765
766    // Get around inserted columns
767
768    get = new Get(ROWS[1]);
769    result = ht.get(get);
770    assertEmptyResult(result);
771
772    get = new Get(ROWS[0]);
773    get.addColumn(FAMILIES[4], QUALIFIERS[3]);
774    get.addColumn(FAMILIES[2], QUALIFIERS[3]);
775    result = ht.get(get);
776    assertEmptyResult(result);
777
778  }
779
780  protected void singleRowScanTest(Table ht, byte[][] ROWS, byte[][] FAMILIES, byte[][] QUALIFIERS,
781    byte[][] VALUES) throws Exception {
782    // Single column from memstore
783    Scan scan = new Scan();
784    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
785    Result result = getSingleScanResult(ht, scan);
786    assertSingleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0]);
787
788    // Single column from storefile
789    scan = new Scan();
790    scan.addColumn(FAMILIES[2], QUALIFIERS[2]);
791    result = getSingleScanResult(ht, scan);
792    assertSingleResult(result, ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
793
794    // Single column from storefile, family match
795    scan = new Scan();
796    scan.addFamily(FAMILIES[7]);
797    result = getSingleScanResult(ht, scan);
798    assertSingleResult(result, ROWS[0], FAMILIES[7], QUALIFIERS[7], VALUES[7]);
799
800    // Two columns, one from memstore one from storefile, same family,
801    // wildcard match
802    scan = new Scan();
803    scan.addFamily(FAMILIES[4]);
804    result = getSingleScanResult(ht, scan);
805    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
806      QUALIFIERS[4], VALUES[4]);
807
808    // Two columns, one from memstore one from storefile, same family,
809    // explicit match
810    scan = new Scan();
811    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
812    scan.addColumn(FAMILIES[4], QUALIFIERS[4]);
813    result = getSingleScanResult(ht, scan);
814    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
815      QUALIFIERS[4], VALUES[4]);
816
817    // Three column, one from memstore two from storefile, different families,
818    // wildcard match
819    scan = new Scan();
820    scan.addFamily(FAMILIES[4]);
821    scan.addFamily(FAMILIES[7]);
822    result = getSingleScanResult(ht, scan);
823    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES,
824      new int[][] { { 4, 0, 0 }, { 4, 4, 4 }, { 7, 7, 7 } });
825
826    // Multiple columns from everywhere storefile, many family, wildcard
827    scan = new Scan();
828    scan.addFamily(FAMILIES[2]);
829    scan.addFamily(FAMILIES[4]);
830    scan.addFamily(FAMILIES[6]);
831    scan.addFamily(FAMILIES[7]);
832    result = getSingleScanResult(ht, scan);
833    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
834      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
835
836    // Multiple columns from everywhere storefile, many family, wildcard
837    scan = new Scan();
838    scan.addColumn(FAMILIES[2], QUALIFIERS[2]);
839    scan.addColumn(FAMILIES[2], QUALIFIERS[4]);
840    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
841    scan.addColumn(FAMILIES[4], QUALIFIERS[4]);
842    scan.addColumn(FAMILIES[6], QUALIFIERS[6]);
843    scan.addColumn(FAMILIES[6], QUALIFIERS[7]);
844    scan.addColumn(FAMILIES[7], QUALIFIERS[7]);
845    scan.addColumn(FAMILIES[7], QUALIFIERS[8]);
846    result = getSingleScanResult(ht, scan);
847    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
848      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
849
850    // Everything
851    scan = new Scan();
852    result = getSingleScanResult(ht, scan);
853    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
854      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 }, { 9, 0, 0 } });
855
856    // Scan around inserted columns
857
858    scan = new Scan().withStartRow(ROWS[1]);
859    result = getSingleScanResult(ht, scan);
860    assertNullResult(result);
861
862    scan = new Scan();
863    scan.addColumn(FAMILIES[4], QUALIFIERS[3]);
864    scan.addColumn(FAMILIES[2], QUALIFIERS[3]);
865    result = getSingleScanResult(ht, scan);
866    assertNullResult(result);
867  }
868
869  /**
870   * Verify a single column using gets. Expects family and qualifier arrays to be valid for at least
871   * the range: idx-2 < idx < idx+2
872   */
873  protected void getVerifySingleColumn(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
874    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX, byte[][] VALUES, int VALUEIDX)
875    throws Exception {
876    Get get = new Get(ROWS[ROWIDX]);
877    Result result = ht.get(get);
878    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
879      VALUES[VALUEIDX]);
880
881    get = new Get(ROWS[ROWIDX]);
882    get.addFamily(FAMILIES[FAMILYIDX]);
883    result = ht.get(get);
884    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
885      VALUES[VALUEIDX]);
886
887    get = new Get(ROWS[ROWIDX]);
888    get.addFamily(FAMILIES[FAMILYIDX - 2]);
889    get.addFamily(FAMILIES[FAMILYIDX]);
890    get.addFamily(FAMILIES[FAMILYIDX + 2]);
891    result = ht.get(get);
892    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
893      VALUES[VALUEIDX]);
894
895    get = new Get(ROWS[ROWIDX]);
896    get.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[0]);
897    result = ht.get(get);
898    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
899      VALUES[VALUEIDX]);
900
901    get = new Get(ROWS[ROWIDX]);
902    get.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[1]);
903    get.addFamily(FAMILIES[FAMILYIDX]);
904    result = ht.get(get);
905    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
906      VALUES[VALUEIDX]);
907
908    get = new Get(ROWS[ROWIDX]);
909    get.addFamily(FAMILIES[FAMILYIDX]);
910    get.addColumn(FAMILIES[FAMILYIDX + 1], QUALIFIERS[1]);
911    get.addColumn(FAMILIES[FAMILYIDX - 2], QUALIFIERS[1]);
912    get.addFamily(FAMILIES[FAMILYIDX - 1]);
913    get.addFamily(FAMILIES[FAMILYIDX + 2]);
914    result = ht.get(get);
915    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
916      VALUES[VALUEIDX]);
917
918  }
919
920  /**
921   * Verify a single column using scanners. Expects family and qualifier arrays to be valid for at
922   * least the range: idx-2 to idx+2 Expects row array to be valid for at least idx to idx+2
923   */
924  protected void scanVerifySingleColumn(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
925    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX, byte[][] VALUES, int VALUEIDX)
926    throws Exception {
927    Scan scan = new Scan();
928    Result result = getSingleScanResult(ht, scan);
929    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
930      VALUES[VALUEIDX]);
931
932    scan = new Scan().withStartRow(ROWS[ROWIDX]);
933    result = getSingleScanResult(ht, scan);
934    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
935      VALUES[VALUEIDX]);
936
937    scan = new Scan().withStartRow(ROWS[ROWIDX]).withStopRow(ROWS[ROWIDX + 1], true);
938    result = getSingleScanResult(ht, scan);
939    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
940      VALUES[VALUEIDX]);
941
942    scan = new Scan().withStartRow(HConstants.EMPTY_START_ROW).withStopRow(ROWS[ROWIDX + 1], true);
943    result = getSingleScanResult(ht, scan);
944    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
945      VALUES[VALUEIDX]);
946
947    scan = new Scan();
948    scan.addFamily(FAMILIES[FAMILYIDX]);
949    result = getSingleScanResult(ht, scan);
950    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
951      VALUES[VALUEIDX]);
952
953    scan = new Scan();
954    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX]);
955    result = getSingleScanResult(ht, scan);
956    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
957      VALUES[VALUEIDX]);
958
959    scan = new Scan();
960    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX + 1]);
961    scan.addFamily(FAMILIES[FAMILYIDX]);
962    result = getSingleScanResult(ht, scan);
963    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
964      VALUES[VALUEIDX]);
965
966    scan = new Scan();
967    scan.addColumn(FAMILIES[FAMILYIDX - 1], QUALIFIERS[QUALIFIERIDX + 1]);
968    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX]);
969    scan.addFamily(FAMILIES[FAMILYIDX + 1]);
970    result = getSingleScanResult(ht, scan);
971    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
972      VALUES[VALUEIDX]);
973
974  }
975
976  /**
977   * Verify we do not read any values by accident around a single column Same requirements as
978   * getVerifySingleColumn
979   */
980  protected void getVerifySingleEmpty(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
981    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX) throws Exception {
982    Get get = new Get(ROWS[ROWIDX]);
983    get.addFamily(FAMILIES[4]);
984    get.addColumn(FAMILIES[4], QUALIFIERS[1]);
985    Result result = ht.get(get);
986    assertEmptyResult(result);
987
988    get = new Get(ROWS[ROWIDX]);
989    get.addFamily(FAMILIES[4]);
990    get.addColumn(FAMILIES[4], QUALIFIERS[2]);
991    result = ht.get(get);
992    assertEmptyResult(result);
993
994    get = new Get(ROWS[ROWIDX]);
995    get.addFamily(FAMILIES[3]);
996    get.addColumn(FAMILIES[4], QUALIFIERS[2]);
997    get.addFamily(FAMILIES[5]);
998    result = ht.get(get);
999    assertEmptyResult(result);
1000
1001    get = new Get(ROWS[ROWIDX + 1]);
1002    result = ht.get(get);
1003    assertEmptyResult(result);
1004
1005  }
1006
1007  protected void scanVerifySingleEmpty(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
1008    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX) throws Exception {
1009    Scan scan = new Scan().withStartRow(ROWS[ROWIDX + 1]);
1010    Result result = getSingleScanResult(ht, scan);
1011    assertNullResult(result);
1012
1013    scan = new Scan().withStartRow(ROWS[ROWIDX + 1]).withStopRow(ROWS[ROWIDX + 2], true);
1014    result = getSingleScanResult(ht, scan);
1015    assertNullResult(result);
1016
1017    scan = new Scan().withStartRow(HConstants.EMPTY_START_ROW).withStopRow(ROWS[ROWIDX]);
1018    result = getSingleScanResult(ht, scan);
1019    assertNullResult(result);
1020
1021    scan = new Scan();
1022    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX + 1]);
1023    scan.addFamily(FAMILIES[FAMILYIDX - 1]);
1024    result = getSingleScanResult(ht, scan);
1025    assertNullResult(result);
1026
1027  }
1028}