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.jupiter.api.Assertions.assertEquals;
022import static org.junit.jupiter.api.Assertions.assertNull;
023import static org.junit.jupiter.api.Assertions.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(3, count, "Did not perform correct number of deletes");
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      LOG.info("Got back key: " + Bytes.toString(result.getRow()));
159      for (Cell kv : result.rawCells()) {
160        LOG.info("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      LOG.info(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(equals(row, CellUtil.cloneRow(key)), "Expected row [" + Bytes.toString(row) + "] "
336      + "Got row [" + Bytes.toString(CellUtil.cloneRow(key)) + "]");
337    assertTrue(equals(family, CellUtil.cloneFamily(key)),
338      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
339        + Bytes.toString(CellUtil.cloneFamily(key)) + "]");
340    assertTrue(equals(qualifier, CellUtil.cloneQualifier(key)),
341      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
342        + Bytes.toString(CellUtil.cloneQualifier(key)) + "]");
343    assertTrue(equals(value, CellUtil.cloneValue(key)), "Expected value [" + Bytes.toString(value)
344      + "] " + "Got value [" + Bytes.toString(CellUtil.cloneValue(key)) + "]");
345  }
346
347  static void assertIncrementKey(Cell key, byte[] row, byte[] family, byte[] qualifier,
348    long value) {
349    assertTrue(equals(row, CellUtil.cloneRow(key)), "Expected row [" + Bytes.toString(row) + "] "
350      + "Got row [" + Bytes.toString(CellUtil.cloneRow(key)) + "]");
351    assertTrue(equals(family, CellUtil.cloneFamily(key)),
352      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
353        + Bytes.toString(CellUtil.cloneFamily(key)) + "]");
354    assertTrue(equals(qualifier, CellUtil.cloneQualifier(key)),
355      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
356        + Bytes.toString(CellUtil.cloneQualifier(key)) + "]");
357    assertEquals(Bytes.toLong(CellUtil.cloneValue(key)), value, "Expected value [" + value + "] "
358      + "Got value [" + Bytes.toLong(CellUtil.cloneValue(key)) + "]");
359  }
360
361  protected void assertNumKeys(Result result, int n) throws Exception {
362    assertEquals(result.size(), n, "Expected " + n + " keys but got " + result.size());
363  }
364
365  protected void assertNResult(Result result, byte[] row, byte[][] families, byte[][] qualifiers,
366    byte[][] values, int[][] idxs) {
367    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
368      + "Got row [" + Bytes.toString(result.getRow()) + "]");
369    assertEquals(result.size(), idxs.length,
370      "Expected " + idxs.length + " keys but result contains " + result.size());
371
372    Cell[] keys = result.rawCells();
373
374    for (int i = 0; i < keys.length; i++) {
375      byte[] family = families[idxs[i][0]];
376      byte[] qualifier = qualifiers[idxs[i][1]];
377      byte[] value = values[idxs[i][2]];
378      Cell key = keys[i];
379
380      byte[] famb = CellUtil.cloneFamily(key);
381      byte[] qualb = CellUtil.cloneQualifier(key);
382      byte[] valb = CellUtil.cloneValue(key);
383      assertTrue(equals(family, famb), "(" + i + ") Expected family [" + Bytes.toString(family)
384        + "] " + "Got family [" + Bytes.toString(famb) + "]");
385      assertTrue(equals(qualifier, qualb), "(" + i + ") Expected qualifier ["
386        + Bytes.toString(qualifier) + "] " + "Got qualifier [" + Bytes.toString(qualb) + "]");
387      assertTrue(equals(value, valb), "(" + i + ") Expected value [" + Bytes.toString(value) + "] "
388        + "Got value [" + Bytes.toString(valb) + "]");
389    }
390  }
391
392  protected void assertNResult(Result result, byte[] row, byte[] family, byte[] qualifier,
393    long[] stamps, byte[][] values, int start, int end) {
394    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
395      + "Got row [" + Bytes.toString(result.getRow()) + "]");
396    int expectedResults = end - start + 1;
397    assertEquals(expectedResults, result.size());
398
399    Cell[] keys = result.rawCells();
400
401    for (int i = 0; i < keys.length; i++) {
402      byte[] value = values[end - i];
403      long ts = stamps[end - i];
404      Cell key = keys[i];
405
406      assertTrue(CellUtil.matchingFamily(key, family),
407        "(" + i + ") Expected family [" + Bytes.toString(family) + "] " + "Got family ["
408          + Bytes.toString(CellUtil.cloneFamily(key)) + "]");
409      assertTrue(CellUtil.matchingQualifier(key, qualifier),
410        "(" + i + ") Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
411          + Bytes.toString(CellUtil.cloneQualifier(key)) + "]");
412      assertEquals(ts, key.getTimestamp(),
413        "Expected ts [" + ts + "] " + "Got ts [" + key.getTimestamp() + "]");
414      assertTrue(CellUtil.matchingValue(key, value),
415        "(" + i + ") Expected value [" + Bytes.toString(value) + "] " + "Got value ["
416          + Bytes.toString(CellUtil.cloneValue(key)) + "]");
417    }
418  }
419
420  /**
421   * Validate that result contains two specified keys, exactly. It is assumed key A sorts before key
422   * B.
423   */
424  protected void assertDoubleResult(Result result, byte[] row, byte[] familyA, byte[] qualifierA,
425    byte[] valueA, byte[] familyB, byte[] qualifierB, byte[] valueB) {
426    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
427      + "Got row [" + Bytes.toString(result.getRow()) + "]");
428    assertEquals(2, result.size(), "Expected two keys but result contains " + result.size());
429    Cell[] kv = result.rawCells();
430    Cell kvA = kv[0];
431    assertTrue(equals(familyA, CellUtil.cloneFamily(kvA)),
432      "(A) Expected family [" + Bytes.toString(familyA) + "] " + "Got family ["
433        + Bytes.toString(CellUtil.cloneFamily(kvA)) + "]");
434    assertTrue(equals(qualifierA, CellUtil.cloneQualifier(kvA)),
435      "(A) Expected qualifier [" + Bytes.toString(qualifierA) + "] " + "Got qualifier ["
436        + Bytes.toString(CellUtil.cloneQualifier(kvA)) + "]");
437    assertTrue(equals(valueA, CellUtil.cloneValue(kvA)),
438      "(A) Expected value [" + Bytes.toString(valueA) + "] " + "Got value ["
439        + Bytes.toString(CellUtil.cloneValue(kvA)) + "]");
440    Cell kvB = kv[1];
441    assertTrue(equals(familyB, CellUtil.cloneFamily(kvB)),
442      "(B) Expected family [" + Bytes.toString(familyB) + "] " + "Got family ["
443        + Bytes.toString(CellUtil.cloneFamily(kvB)) + "]");
444    assertTrue(equals(qualifierB, CellUtil.cloneQualifier(kvB)),
445      "(B) Expected qualifier [" + Bytes.toString(qualifierB) + "] " + "Got qualifier ["
446        + Bytes.toString(CellUtil.cloneQualifier(kvB)) + "]");
447    assertTrue(equals(valueB, CellUtil.cloneValue(kvB)),
448      "(B) Expected value [" + Bytes.toString(valueB) + "] " + "Got value ["
449        + Bytes.toString(CellUtil.cloneValue(kvB)) + "]");
450  }
451
452  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
453    byte[] value) {
454    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
455      + "Got row [" + Bytes.toString(result.getRow()) + "]");
456    assertEquals(1, result.size(), "Expected a single key but result contains " + result.size());
457    Cell kv = result.rawCells()[0];
458    assertTrue(equals(family, CellUtil.cloneFamily(kv)),
459      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
460        + Bytes.toString(CellUtil.cloneFamily(kv)) + "]");
461    assertTrue(equals(qualifier, CellUtil.cloneQualifier(kv)),
462      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
463        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]");
464    assertTrue(equals(value, CellUtil.cloneValue(kv)), "Expected value [" + Bytes.toString(value)
465      + "] " + "Got value [" + Bytes.toString(CellUtil.cloneValue(kv)) + "]");
466  }
467
468  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
469    long value) {
470    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
471      + "Got row [" + Bytes.toString(result.getRow()) + "]");
472    assertEquals(1, result.size(), "Expected a single key but result contains " + result.size());
473    Cell kv = result.rawCells()[0];
474    assertTrue(equals(family, CellUtil.cloneFamily(kv)),
475      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
476        + Bytes.toString(CellUtil.cloneFamily(kv)) + "]");
477    assertTrue(equals(qualifier, CellUtil.cloneQualifier(kv)),
478      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
479        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]");
480    assertEquals(value, Bytes.toLong(CellUtil.cloneValue(kv)), "Expected value [" + value + "] "
481      + "Got value [" + Bytes.toLong(CellUtil.cloneValue(kv)) + "]");
482  }
483
484  protected void assertSingleResult(Result result, byte[] row, byte[] family, byte[] qualifier,
485    long ts, byte[] value) {
486    assertTrue(equals(row, result.getRow()), "Expected row [" + Bytes.toString(row) + "] "
487      + "Got row [" + Bytes.toString(result.getRow()) + "]");
488    assertEquals(1, result.size(), "Expected a single key but result contains " + result.size());
489    Cell kv = result.rawCells()[0];
490    assertTrue(equals(family, CellUtil.cloneFamily(kv)),
491      "Expected family [" + Bytes.toString(family) + "] " + "Got family ["
492        + Bytes.toString(CellUtil.cloneFamily(kv)) + "]");
493    assertTrue(equals(qualifier, CellUtil.cloneQualifier(kv)),
494      "Expected qualifier [" + Bytes.toString(qualifier) + "] " + "Got qualifier ["
495        + Bytes.toString(CellUtil.cloneQualifier(kv)) + "]");
496    assertEquals(ts, kv.getTimestamp(),
497      "Expected ts [" + ts + "] " + "Got ts [" + kv.getTimestamp() + "]");
498    assertTrue(equals(value, CellUtil.cloneValue(kv)), "Expected value [" + Bytes.toString(value)
499      + "] " + "Got value [" + Bytes.toString(CellUtil.cloneValue(kv)) + "]");
500  }
501
502  protected void assertEmptyResult(Result result) throws Exception {
503    assertTrue(result.isEmpty(),
504      "expected an empty result but result contains " + result.size() + " keys");
505  }
506
507  protected void assertNullResult(Result result) throws Exception {
508    assertNull(result, "expected null result but received a non-null result");
509  }
510
511  protected void getVersionRangeAndVerifyGreaterThan(Table ht, byte[] row, byte[] family,
512    byte[] qualifier, long[] stamps, byte[][] values, int start, int end) throws IOException {
513    Get get = new Get(row);
514    get.addColumn(family, qualifier);
515    get.readVersions(Integer.MAX_VALUE);
516    get.setTimeRange(stamps[start + 1], Long.MAX_VALUE);
517    Result result = ht.get(get);
518    assertNResult(result, row, family, qualifier, stamps, values, start + 1, end);
519  }
520
521  protected void getVersionRangeAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
522    long[] stamps, byte[][] values, int start, int end) throws IOException {
523    Get get = new Get(row);
524    get.addColumn(family, qualifier);
525    get.readVersions(Integer.MAX_VALUE);
526    get.setTimeRange(stamps[start], stamps[end] + 1);
527    Result result = ht.get(get);
528    assertNResult(result, row, family, qualifier, stamps, values, start, end);
529  }
530
531  protected void getAllVersionsAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
532    long[] stamps, byte[][] values, int start, int end) throws IOException {
533    Get get = new Get(row);
534    get.addColumn(family, qualifier);
535    get.readVersions(Integer.MAX_VALUE);
536    Result result = ht.get(get);
537    assertNResult(result, row, family, qualifier, stamps, values, start, end);
538  }
539
540  protected void scanVersionRangeAndVerifyGreaterThan(Table ht, byte[] row, byte[] family,
541    byte[] qualifier, long[] stamps, byte[][] values, int start, int end) throws IOException {
542    Scan scan = new Scan().withStartRow(row);
543    scan.addColumn(family, qualifier);
544    scan.readVersions(Integer.MAX_VALUE);
545    scan.setTimeRange(stamps[start + 1], Long.MAX_VALUE);
546    Result result = getSingleScanResult(ht, scan);
547    assertNResult(result, row, family, qualifier, stamps, values, start + 1, end);
548  }
549
550  protected void scanVersionRangeAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
551    long[] stamps, byte[][] values, int start, int end) throws IOException {
552    Scan scan = new Scan().withStartRow(row);
553    scan.addColumn(family, qualifier);
554    scan.readVersions(Integer.MAX_VALUE);
555    scan.setTimeRange(stamps[start], stamps[end] + 1);
556    Result result = getSingleScanResult(ht, scan);
557    assertNResult(result, row, family, qualifier, stamps, values, start, end);
558  }
559
560  protected void scanAllVersionsAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
561    long[] stamps, byte[][] values, int start, int end) throws IOException {
562    Scan scan = new Scan().withStartRow(row);
563    scan.addColumn(family, qualifier);
564    scan.readVersions(Integer.MAX_VALUE);
565    Result result = getSingleScanResult(ht, scan);
566    assertNResult(result, row, family, qualifier, stamps, values, start, end);
567  }
568
569  protected void getVersionAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
570    long stamp, byte[] value) throws Exception {
571    Get get = new Get(row);
572    get.addColumn(family, qualifier);
573    get.setTimestamp(stamp);
574    get.readVersions(Integer.MAX_VALUE);
575    Result result = ht.get(get);
576    assertSingleResult(result, row, family, qualifier, stamp, value);
577  }
578
579  protected void getVersionAndVerifyMissing(Table ht, byte[] row, byte[] family, byte[] qualifier,
580    long stamp) throws Exception {
581    Get get = new Get(row);
582    get.addColumn(family, qualifier);
583    get.setTimestamp(stamp);
584    get.readVersions(Integer.MAX_VALUE);
585    Result result = ht.get(get);
586    assertEmptyResult(result);
587  }
588
589  protected void scanVersionAndVerify(Table ht, byte[] row, byte[] family, byte[] qualifier,
590    long stamp, byte[] value) throws Exception {
591    Scan scan = new Scan().withStartRow(row);
592    scan.addColumn(family, qualifier);
593    scan.setTimestamp(stamp);
594    scan.readVersions(Integer.MAX_VALUE);
595    Result result = getSingleScanResult(ht, scan);
596    assertSingleResult(result, row, family, qualifier, stamp, value);
597  }
598
599  protected void scanVersionAndVerifyMissing(Table ht, byte[] row, byte[] family, byte[] qualifier,
600    long stamp) throws Exception {
601    Scan scan = new Scan().withStartRow(row);
602    scan.addColumn(family, qualifier);
603    scan.setTimestamp(stamp);
604    scan.readVersions(Integer.MAX_VALUE);
605    Result result = getSingleScanResult(ht, scan);
606    assertNullResult(result);
607  }
608
609  protected void getTestNull(Table ht, byte[] row, byte[] family, byte[] value) throws Exception {
610    Get get = new Get(row);
611    get.addColumn(family, null);
612    Result result = ht.get(get);
613    assertSingleResult(result, row, family, null, value);
614
615    get = new Get(row);
616    get.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
617    result = ht.get(get);
618    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
619
620    get = new Get(row);
621    get.addFamily(family);
622    result = ht.get(get);
623    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
624
625    get = new Get(row);
626    result = ht.get(get);
627    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
628
629  }
630
631  protected void getTestNull(Table ht, byte[] row, byte[] family, long value) throws Exception {
632    Get get = new Get(row);
633    get.addColumn(family, null);
634    Result result = ht.get(get);
635    assertSingleResult(result, row, family, null, value);
636
637    get = new Get(row);
638    get.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
639    result = ht.get(get);
640    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
641
642    get = new Get(row);
643    get.addFamily(family);
644    result = ht.get(get);
645    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
646
647    get = new Get(row);
648    result = ht.get(get);
649    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
650  }
651
652  protected void scanTestNull(Table ht, byte[] row, byte[] family, byte[] value) throws Exception {
653    scanTestNull(ht, row, family, value, false);
654  }
655
656  protected void scanTestNull(Table ht, byte[] row, byte[] family, byte[] value,
657    boolean isReversedScan) throws Exception {
658
659    Scan scan = new Scan();
660    scan.setReversed(isReversedScan);
661    scan.addColumn(family, null);
662    Result result = getSingleScanResult(ht, scan);
663    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
664
665    scan = new Scan();
666    scan.setReversed(isReversedScan);
667    scan.addColumn(family, HConstants.EMPTY_BYTE_ARRAY);
668    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.addFamily(family);
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    result = getSingleScanResult(ht, scan);
680    assertSingleResult(result, row, family, HConstants.EMPTY_BYTE_ARRAY, value);
681
682  }
683
684  protected void singleRowGetTest(Table ht, byte[][] ROWS, byte[][] FAMILIES, byte[][] QUALIFIERS,
685    byte[][] VALUES) throws Exception {
686    // Single column from memstore
687    Get get = new Get(ROWS[0]);
688    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
689    Result result = ht.get(get);
690    assertSingleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0]);
691
692    // Single column from storefile
693    get = new Get(ROWS[0]);
694    get.addColumn(FAMILIES[2], QUALIFIERS[2]);
695    result = ht.get(get);
696    assertSingleResult(result, ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
697
698    // Single column from storefile, family match
699    get = new Get(ROWS[0]);
700    get.addFamily(FAMILIES[7]);
701    result = ht.get(get);
702    assertSingleResult(result, ROWS[0], FAMILIES[7], QUALIFIERS[7], VALUES[7]);
703
704    // Two columns, one from memstore one from storefile, same family,
705    // wildcard match
706    get = new Get(ROWS[0]);
707    get.addFamily(FAMILIES[4]);
708    result = ht.get(get);
709    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
710      QUALIFIERS[4], VALUES[4]);
711
712    // Two columns, one from memstore one from storefile, same family,
713    // explicit match
714    get = new Get(ROWS[0]);
715    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
716    get.addColumn(FAMILIES[4], QUALIFIERS[4]);
717    result = ht.get(get);
718    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
719      QUALIFIERS[4], VALUES[4]);
720
721    // Three column, one from memstore two from storefile, different families,
722    // wildcard match
723    get = new Get(ROWS[0]);
724    get.addFamily(FAMILIES[4]);
725    get.addFamily(FAMILIES[7]);
726    result = ht.get(get);
727    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES,
728      new int[][] { { 4, 0, 0 }, { 4, 4, 4 }, { 7, 7, 7 } });
729
730    // Multiple columns from everywhere storefile, many family, wildcard
731    get = new Get(ROWS[0]);
732    get.addFamily(FAMILIES[2]);
733    get.addFamily(FAMILIES[4]);
734    get.addFamily(FAMILIES[6]);
735    get.addFamily(FAMILIES[7]);
736    result = ht.get(get);
737    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
738      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
739
740    // Multiple columns from everywhere storefile, many family, wildcard
741    get = new Get(ROWS[0]);
742    get.addColumn(FAMILIES[2], QUALIFIERS[2]);
743    get.addColumn(FAMILIES[2], QUALIFIERS[4]);
744    get.addColumn(FAMILIES[4], QUALIFIERS[0]);
745    get.addColumn(FAMILIES[4], QUALIFIERS[4]);
746    get.addColumn(FAMILIES[6], QUALIFIERS[6]);
747    get.addColumn(FAMILIES[6], QUALIFIERS[7]);
748    get.addColumn(FAMILIES[7], QUALIFIERS[7]);
749    get.addColumn(FAMILIES[7], QUALIFIERS[8]);
750    result = ht.get(get);
751    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
752      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
753
754    // Everything
755    get = new Get(ROWS[0]);
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 }, { 9, 0, 0 } });
759
760    // Get around inserted columns
761
762    get = new Get(ROWS[1]);
763    result = ht.get(get);
764    assertEmptyResult(result);
765
766    get = new Get(ROWS[0]);
767    get.addColumn(FAMILIES[4], QUALIFIERS[3]);
768    get.addColumn(FAMILIES[2], QUALIFIERS[3]);
769    result = ht.get(get);
770    assertEmptyResult(result);
771
772  }
773
774  protected void singleRowScanTest(Table ht, byte[][] ROWS, byte[][] FAMILIES, byte[][] QUALIFIERS,
775    byte[][] VALUES) throws Exception {
776    // Single column from memstore
777    Scan scan = new Scan();
778    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
779    Result result = getSingleScanResult(ht, scan);
780    assertSingleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0]);
781
782    // Single column from storefile
783    scan = new Scan();
784    scan.addColumn(FAMILIES[2], QUALIFIERS[2]);
785    result = getSingleScanResult(ht, scan);
786    assertSingleResult(result, ROWS[0], FAMILIES[2], QUALIFIERS[2], VALUES[2]);
787
788    // Single column from storefile, family match
789    scan = new Scan();
790    scan.addFamily(FAMILIES[7]);
791    result = getSingleScanResult(ht, scan);
792    assertSingleResult(result, ROWS[0], FAMILIES[7], QUALIFIERS[7], VALUES[7]);
793
794    // Two columns, one from memstore one from storefile, same family,
795    // wildcard match
796    scan = new Scan();
797    scan.addFamily(FAMILIES[4]);
798    result = getSingleScanResult(ht, scan);
799    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
800      QUALIFIERS[4], VALUES[4]);
801
802    // Two columns, one from memstore one from storefile, same family,
803    // explicit match
804    scan = new Scan();
805    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
806    scan.addColumn(FAMILIES[4], QUALIFIERS[4]);
807    result = getSingleScanResult(ht, scan);
808    assertDoubleResult(result, ROWS[0], FAMILIES[4], QUALIFIERS[0], VALUES[0], FAMILIES[4],
809      QUALIFIERS[4], VALUES[4]);
810
811    // Three column, one from memstore two from storefile, different families,
812    // wildcard match
813    scan = new Scan();
814    scan.addFamily(FAMILIES[4]);
815    scan.addFamily(FAMILIES[7]);
816    result = getSingleScanResult(ht, scan);
817    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES,
818      new int[][] { { 4, 0, 0 }, { 4, 4, 4 }, { 7, 7, 7 } });
819
820    // Multiple columns from everywhere storefile, many family, wildcard
821    scan = new Scan();
822    scan.addFamily(FAMILIES[2]);
823    scan.addFamily(FAMILIES[4]);
824    scan.addFamily(FAMILIES[6]);
825    scan.addFamily(FAMILIES[7]);
826    result = getSingleScanResult(ht, scan);
827    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
828      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
829
830    // Multiple columns from everywhere storefile, many family, wildcard
831    scan = new Scan();
832    scan.addColumn(FAMILIES[2], QUALIFIERS[2]);
833    scan.addColumn(FAMILIES[2], QUALIFIERS[4]);
834    scan.addColumn(FAMILIES[4], QUALIFIERS[0]);
835    scan.addColumn(FAMILIES[4], QUALIFIERS[4]);
836    scan.addColumn(FAMILIES[6], QUALIFIERS[6]);
837    scan.addColumn(FAMILIES[6], QUALIFIERS[7]);
838    scan.addColumn(FAMILIES[7], QUALIFIERS[7]);
839    scan.addColumn(FAMILIES[7], QUALIFIERS[8]);
840    result = getSingleScanResult(ht, scan);
841    assertNResult(result, ROWS[0], FAMILIES, QUALIFIERS, VALUES, new int[][] { { 2, 2, 2 },
842      { 2, 4, 4 }, { 4, 0, 0 }, { 4, 4, 4 }, { 6, 6, 6 }, { 6, 7, 7 }, { 7, 7, 7 } });
843
844    // Everything
845    scan = new Scan();
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 }, { 9, 0, 0 } });
849
850    // Scan around inserted columns
851
852    scan = new Scan().withStartRow(ROWS[1]);
853    result = getSingleScanResult(ht, scan);
854    assertNullResult(result);
855
856    scan = new Scan();
857    scan.addColumn(FAMILIES[4], QUALIFIERS[3]);
858    scan.addColumn(FAMILIES[2], QUALIFIERS[3]);
859    result = getSingleScanResult(ht, scan);
860    assertNullResult(result);
861  }
862
863  /**
864   * Verify a single column using gets. Expects family and qualifier arrays to be valid for at least
865   * the range: idx-2 < idx < idx+2
866   */
867  protected void getVerifySingleColumn(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
868    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX, byte[][] VALUES, int VALUEIDX)
869    throws Exception {
870    Get get = new Get(ROWS[ROWIDX]);
871    Result result = ht.get(get);
872    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
873      VALUES[VALUEIDX]);
874
875    get = new Get(ROWS[ROWIDX]);
876    get.addFamily(FAMILIES[FAMILYIDX]);
877    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 - 2]);
883    get.addFamily(FAMILIES[FAMILYIDX]);
884    get.addFamily(FAMILIES[FAMILYIDX + 2]);
885    result = ht.get(get);
886    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
887      VALUES[VALUEIDX]);
888
889    get = new Get(ROWS[ROWIDX]);
890    get.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[0]);
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[1]);
897    get.addFamily(FAMILIES[FAMILYIDX]);
898    result = ht.get(get);
899    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
900      VALUES[VALUEIDX]);
901
902    get = new Get(ROWS[ROWIDX]);
903    get.addFamily(FAMILIES[FAMILYIDX]);
904    get.addColumn(FAMILIES[FAMILYIDX + 1], QUALIFIERS[1]);
905    get.addColumn(FAMILIES[FAMILYIDX - 2], QUALIFIERS[1]);
906    get.addFamily(FAMILIES[FAMILYIDX - 1]);
907    get.addFamily(FAMILIES[FAMILYIDX + 2]);
908    result = ht.get(get);
909    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
910      VALUES[VALUEIDX]);
911
912  }
913
914  /**
915   * Verify a single column using scanners. Expects family and qualifier arrays to be valid for at
916   * least the range: idx-2 to idx+2 Expects row array to be valid for at least idx to idx+2
917   */
918  protected void scanVerifySingleColumn(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
919    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX, byte[][] VALUES, int VALUEIDX)
920    throws Exception {
921    Scan scan = new Scan();
922    Result result = getSingleScanResult(ht, scan);
923    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
924      VALUES[VALUEIDX]);
925
926    scan = new Scan().withStartRow(ROWS[ROWIDX]);
927    result = getSingleScanResult(ht, scan);
928    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
929      VALUES[VALUEIDX]);
930
931    scan = new Scan().withStartRow(ROWS[ROWIDX]).withStopRow(ROWS[ROWIDX + 1], true);
932    result = getSingleScanResult(ht, scan);
933    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
934      VALUES[VALUEIDX]);
935
936    scan = new Scan().withStartRow(HConstants.EMPTY_START_ROW).withStopRow(ROWS[ROWIDX + 1], true);
937    result = getSingleScanResult(ht, scan);
938    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
939      VALUES[VALUEIDX]);
940
941    scan = new Scan();
942    scan.addFamily(FAMILIES[FAMILYIDX]);
943    result = getSingleScanResult(ht, scan);
944    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
945      VALUES[VALUEIDX]);
946
947    scan = new Scan();
948    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX]);
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 + 1]);
955    scan.addFamily(FAMILIES[FAMILYIDX]);
956    result = getSingleScanResult(ht, scan);
957    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
958      VALUES[VALUEIDX]);
959
960    scan = new Scan();
961    scan.addColumn(FAMILIES[FAMILYIDX - 1], QUALIFIERS[QUALIFIERIDX + 1]);
962    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX]);
963    scan.addFamily(FAMILIES[FAMILYIDX + 1]);
964    result = getSingleScanResult(ht, scan);
965    assertSingleResult(result, ROWS[ROWIDX], FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX],
966      VALUES[VALUEIDX]);
967
968  }
969
970  /**
971   * Verify we do not read any values by accident around a single column Same requirements as
972   * getVerifySingleColumn
973   */
974  protected void getVerifySingleEmpty(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
975    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX) throws Exception {
976    Get get = new Get(ROWS[ROWIDX]);
977    get.addFamily(FAMILIES[4]);
978    get.addColumn(FAMILIES[4], QUALIFIERS[1]);
979    Result result = ht.get(get);
980    assertEmptyResult(result);
981
982    get = new Get(ROWS[ROWIDX]);
983    get.addFamily(FAMILIES[4]);
984    get.addColumn(FAMILIES[4], QUALIFIERS[2]);
985    result = ht.get(get);
986    assertEmptyResult(result);
987
988    get = new Get(ROWS[ROWIDX]);
989    get.addFamily(FAMILIES[3]);
990    get.addColumn(FAMILIES[4], QUALIFIERS[2]);
991    get.addFamily(FAMILIES[5]);
992    result = ht.get(get);
993    assertEmptyResult(result);
994
995    get = new Get(ROWS[ROWIDX + 1]);
996    result = ht.get(get);
997    assertEmptyResult(result);
998
999  }
1000
1001  protected void scanVerifySingleEmpty(Table ht, byte[][] ROWS, int ROWIDX, byte[][] FAMILIES,
1002    int FAMILYIDX, byte[][] QUALIFIERS, int QUALIFIERIDX) throws Exception {
1003    Scan scan = new Scan().withStartRow(ROWS[ROWIDX + 1]);
1004    Result result = getSingleScanResult(ht, scan);
1005    assertNullResult(result);
1006
1007    scan = new Scan().withStartRow(ROWS[ROWIDX + 1]).withStopRow(ROWS[ROWIDX + 2], true);
1008    result = getSingleScanResult(ht, scan);
1009    assertNullResult(result);
1010
1011    scan = new Scan().withStartRow(HConstants.EMPTY_START_ROW).withStopRow(ROWS[ROWIDX]);
1012    result = getSingleScanResult(ht, scan);
1013    assertNullResult(result);
1014
1015    scan = new Scan();
1016    scan.addColumn(FAMILIES[FAMILYIDX], QUALIFIERS[QUALIFIERIDX + 1]);
1017    scan.addFamily(FAMILIES[FAMILYIDX - 1]);
1018    result = getSingleScanResult(ht, scan);
1019    assertNullResult(result);
1020
1021  }
1022}