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.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNotNull;
022
023import java.io.IOException;
024import java.lang.reflect.Type;
025import java.nio.ByteBuffer;
026import java.util.Arrays;
027import java.util.List;
028import java.util.Map;
029import org.apache.hadoop.hbase.Cell;
030import org.apache.hadoop.hbase.CellComparatorImpl;
031import org.apache.hadoop.hbase.CellUtil;
032import org.apache.hadoop.hbase.HBaseClassTestRule;
033import org.apache.hadoop.hbase.HConstants;
034import org.apache.hadoop.hbase.KeyValue;
035import org.apache.hadoop.hbase.filter.BinaryComparator;
036import org.apache.hadoop.hbase.filter.ColumnCountGetFilter;
037import org.apache.hadoop.hbase.filter.ColumnPaginationFilter;
038import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
039import org.apache.hadoop.hbase.filter.ColumnRangeFilter;
040import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
041import org.apache.hadoop.hbase.filter.DependentColumnFilter;
042import org.apache.hadoop.hbase.filter.FamilyFilter;
043import org.apache.hadoop.hbase.filter.Filter;
044import org.apache.hadoop.hbase.filter.FilterList;
045import org.apache.hadoop.hbase.filter.FilterList.Operator;
046import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
047import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
048import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
049import org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter;
050import org.apache.hadoop.hbase.filter.PageFilter;
051import org.apache.hadoop.hbase.filter.PrefixFilter;
052import org.apache.hadoop.hbase.filter.QualifierFilter;
053import org.apache.hadoop.hbase.filter.RowFilter;
054import org.apache.hadoop.hbase.filter.SingleColumnValueExcludeFilter;
055import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
056import org.apache.hadoop.hbase.filter.SkipFilter;
057import org.apache.hadoop.hbase.filter.TimestampsFilter;
058import org.apache.hadoop.hbase.filter.ValueFilter;
059import org.apache.hadoop.hbase.filter.WhileMatchFilter;
060import org.apache.hadoop.hbase.testclassification.ClientTests;
061import org.apache.hadoop.hbase.testclassification.SmallTests;
062import org.apache.hadoop.hbase.util.BuilderStyleTest;
063import org.apache.hadoop.hbase.util.Bytes;
064import org.apache.hadoop.hbase.util.GsonUtil;
065import org.junit.Assert;
066import org.junit.ClassRule;
067import org.junit.Test;
068import org.junit.experimental.categories.Category;
069
070import org.apache.hbase.thirdparty.com.google.common.reflect.TypeToken;
071import org.apache.hbase.thirdparty.com.google.gson.Gson;
072import org.apache.hbase.thirdparty.com.google.gson.GsonBuilder;
073import org.apache.hbase.thirdparty.com.google.gson.LongSerializationPolicy;
074import org.apache.hbase.thirdparty.com.google.gson.ToNumberPolicy;
075
076/**
077 * Run tests that use the functionality of the Operation superclass for Puts, Gets, Deletes, Scans,
078 * and MultiPuts.
079 */
080@Category({ ClientTests.class, SmallTests.class })
081public class TestOperation {
082  @ClassRule
083  public static final HBaseClassTestRule CLASS_RULE =
084    HBaseClassTestRule.forClass(TestOperation.class);
085
086  private static byte[] ROW = Bytes.toBytes("testRow");
087  private static byte[] FAMILY = Bytes.toBytes("testFamily");
088  private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
089  private static byte[] VALUE = Bytes.toBytes("testValue");
090
091  private static Gson GSON = GsonUtil.createGson().create();
092
093  private static List<Long> TS_LIST = Arrays.asList(2L, 3L, 5L);
094  private static TimestampsFilter TS_FILTER = new TimestampsFilter(TS_LIST);
095  private static String STR_TS_FILTER = TS_FILTER.getClass().getSimpleName() + " (3/3): [2, 3, 5]";
096
097  private static List<Long> L_TS_LIST = Arrays.asList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L);
098  private static TimestampsFilter L_TS_FILTER = new TimestampsFilter(L_TS_LIST);
099  private static String STR_L_TS_FILTER =
100    L_TS_FILTER.getClass().getSimpleName() + " (5/11): [0, 1, 2, 3, 4]";
101
102  private static String COL_NAME_1 = "col1";
103  private static ColumnPrefixFilter COL_PRE_FILTER =
104    new ColumnPrefixFilter(Bytes.toBytes(COL_NAME_1));
105  private static String STR_COL_PRE_FILTER =
106    COL_PRE_FILTER.getClass().getSimpleName() + " " + COL_NAME_1;
107
108  private static String COL_NAME_2 = "col2";
109  private static ColumnRangeFilter CR_FILTER =
110    new ColumnRangeFilter(Bytes.toBytes(COL_NAME_1), true, Bytes.toBytes(COL_NAME_2), false);
111  private static String STR_CR_FILTER =
112    CR_FILTER.getClass().getSimpleName() + " [" + COL_NAME_1 + ", " + COL_NAME_2 + ")";
113
114  private static int COL_COUNT = 9;
115  private static ColumnCountGetFilter CCG_FILTER = new ColumnCountGetFilter(COL_COUNT);
116  private static String STR_CCG_FILTER = CCG_FILTER.getClass().getSimpleName() + " " + COL_COUNT;
117
118  private static int LIMIT = 3;
119  private static int OFFSET = 4;
120  private static ColumnPaginationFilter CP_FILTER = new ColumnPaginationFilter(LIMIT, OFFSET);
121  private static String STR_CP_FILTER =
122    CP_FILTER.getClass().getSimpleName() + " (" + LIMIT + ", " + OFFSET + ")";
123
124  private static String STOP_ROW_KEY = "stop";
125  private static InclusiveStopFilter IS_FILTER =
126    new InclusiveStopFilter(Bytes.toBytes(STOP_ROW_KEY));
127  private static String STR_IS_FILTER = IS_FILTER.getClass().getSimpleName() + " " + STOP_ROW_KEY;
128
129  private static String PREFIX = "prefix";
130  private static PrefixFilter PREFIX_FILTER = new PrefixFilter(Bytes.toBytes(PREFIX));
131  private static String STR_PREFIX_FILTER = "PrefixFilter " + PREFIX;
132
133  private static byte[][] PREFIXES = { Bytes.toBytes("0"), Bytes.toBytes("1"), Bytes.toBytes("2") };
134  private static MultipleColumnPrefixFilter MCP_FILTER = new MultipleColumnPrefixFilter(PREFIXES);
135  private static String STR_MCP_FILTER =
136    MCP_FILTER.getClass().getSimpleName() + " (3/3): [0, 1, 2]";
137
138  private static byte[][] L_PREFIXES =
139    { Bytes.toBytes("0"), Bytes.toBytes("1"), Bytes.toBytes("2"), Bytes.toBytes("3"),
140      Bytes.toBytes("4"), Bytes.toBytes("5"), Bytes.toBytes("6"), Bytes.toBytes("7") };
141  private static MultipleColumnPrefixFilter L_MCP_FILTER =
142    new MultipleColumnPrefixFilter(L_PREFIXES);
143  private static String STR_L_MCP_FILTER =
144    L_MCP_FILTER.getClass().getSimpleName() + " (5/8): [0, 1, 2, 3, 4]";
145
146  private static int PAGE_SIZE = 9;
147  private static PageFilter PAGE_FILTER = new PageFilter(PAGE_SIZE);
148  private static String STR_PAGE_FILTER = PAGE_FILTER.getClass().getSimpleName() + " " + PAGE_SIZE;
149
150  private static SkipFilter SKIP_FILTER = new SkipFilter(L_TS_FILTER);
151  private static String STR_SKIP_FILTER =
152    SKIP_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER;
153
154  private static WhileMatchFilter WHILE_FILTER = new WhileMatchFilter(L_TS_FILTER);
155  private static String STR_WHILE_FILTER =
156    WHILE_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER;
157
158  private static KeyOnlyFilter KEY_ONLY_FILTER = new KeyOnlyFilter();
159  private static String STR_KEY_ONLY_FILTER = KEY_ONLY_FILTER.getClass().getSimpleName();
160
161  private static FirstKeyOnlyFilter FIRST_KEY_ONLY_FILTER = new FirstKeyOnlyFilter();
162  private static String STR_FIRST_KEY_ONLY_FILTER =
163    FIRST_KEY_ONLY_FILTER.getClass().getSimpleName();
164
165  private static CompareOp CMP_OP = CompareOp.EQUAL;
166  private static byte[] CMP_VALUE = Bytes.toBytes("value");
167  private static BinaryComparator BC = new BinaryComparator(CMP_VALUE);
168  private static DependentColumnFilter DC_FILTER =
169    new DependentColumnFilter(FAMILY, QUALIFIER, true, CMP_OP, BC);
170  private static String STR_DC_FILTER = String.format("%s (%s, %s, %s, %s, %s)",
171    DC_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY),
172    Bytes.toStringBinary(QUALIFIER), true, CMP_OP.name(), Bytes.toStringBinary(BC.getValue()));
173
174  private static FamilyFilter FAMILY_FILTER = new FamilyFilter(CMP_OP, BC);
175  private static String STR_FAMILY_FILTER =
176    FAMILY_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
177
178  private static QualifierFilter QUALIFIER_FILTER = new QualifierFilter(CMP_OP, BC);
179  private static String STR_QUALIFIER_FILTER =
180    QUALIFIER_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
181
182  private static RowFilter ROW_FILTER = new RowFilter(CMP_OP, BC);
183  private static String STR_ROW_FILTER = ROW_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
184
185  private static ValueFilter VALUE_FILTER = new ValueFilter(CMP_OP, BC);
186  private static String STR_VALUE_FILTER =
187    VALUE_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
188
189  private static SingleColumnValueFilter SCV_FILTER =
190    new SingleColumnValueFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE);
191  private static String STR_SCV_FILTER = String.format("%s (%s, %s, %s, %s)",
192    SCV_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY),
193    Bytes.toStringBinary(QUALIFIER), CMP_OP.name(), Bytes.toStringBinary(CMP_VALUE));
194
195  private static SingleColumnValueExcludeFilter SCVE_FILTER =
196    new SingleColumnValueExcludeFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE);
197  private static String STR_SCVE_FILTER = String.format("%s (%s, %s, %s, %s)",
198    SCVE_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY),
199    Bytes.toStringBinary(QUALIFIER), CMP_OP.name(), Bytes.toStringBinary(CMP_VALUE));
200
201  private static FilterList AND_FILTER_LIST = new FilterList(Operator.MUST_PASS_ALL,
202    Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, CR_FILTER));
203  private static String STR_AND_FILTER_LIST = String.format("%s AND (3/3): [%s, %s, %s]",
204    AND_FILTER_LIST.getClass().getSimpleName(), STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER);
205
206  private static FilterList OR_FILTER_LIST = new FilterList(Operator.MUST_PASS_ONE,
207    Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, CR_FILTER));
208  private static String STR_OR_FILTER_LIST = String.format("%s OR (3/3): [%s, %s, %s]",
209    AND_FILTER_LIST.getClass().getSimpleName(), STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER);
210
211  private static FilterList L_FILTER_LIST = new FilterList(Arrays.asList((Filter) TS_FILTER,
212    L_TS_FILTER, CR_FILTER, COL_PRE_FILTER, CCG_FILTER, CP_FILTER, PREFIX_FILTER, PAGE_FILTER));
213  private static String STR_L_FILTER_LIST = String.format("%s AND (5/8): [%s, %s, %s, %s, %s, %s]",
214    L_FILTER_LIST.getClass().getSimpleName(), STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER,
215    STR_COL_PRE_FILTER, STR_CCG_FILTER, STR_CP_FILTER);
216
217  private static Filter[] FILTERS = { TS_FILTER, // TimestampsFilter
218    L_TS_FILTER, // TimestampsFilter
219    COL_PRE_FILTER, // ColumnPrefixFilter
220    CP_FILTER, // ColumnPaginationFilter
221    CR_FILTER, // ColumnRangeFilter
222    CCG_FILTER, // ColumnCountGetFilter
223    IS_FILTER, // InclusiveStopFilter
224    PREFIX_FILTER, // PrefixFilter
225    PAGE_FILTER, // PageFilter
226    SKIP_FILTER, // SkipFilter
227    WHILE_FILTER, // WhileMatchFilter
228    KEY_ONLY_FILTER, // KeyOnlyFilter
229    FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter
230    MCP_FILTER, // MultipleColumnPrefixFilter
231    L_MCP_FILTER, // MultipleColumnPrefixFilter
232    DC_FILTER, // DependentColumnFilter
233    FAMILY_FILTER, // FamilyFilter
234    QUALIFIER_FILTER, // QualifierFilter
235    ROW_FILTER, // RowFilter
236    VALUE_FILTER, // ValueFilter
237    SCV_FILTER, // SingleColumnValueFilter
238    SCVE_FILTER, // SingleColumnValueExcludeFilter
239    AND_FILTER_LIST, // FilterList
240    OR_FILTER_LIST, // FilterList
241    L_FILTER_LIST, // FilterList
242  };
243
244  private static String[] FILTERS_INFO = { STR_TS_FILTER, // TimestampsFilter
245    STR_L_TS_FILTER, // TimestampsFilter
246    STR_COL_PRE_FILTER, // ColumnPrefixFilter
247    STR_CP_FILTER, // ColumnPaginationFilter
248    STR_CR_FILTER, // ColumnRangeFilter
249    STR_CCG_FILTER, // ColumnCountGetFilter
250    STR_IS_FILTER, // InclusiveStopFilter
251    STR_PREFIX_FILTER, // PrefixFilter
252    STR_PAGE_FILTER, // PageFilter
253    STR_SKIP_FILTER, // SkipFilter
254    STR_WHILE_FILTER, // WhileMatchFilter
255    STR_KEY_ONLY_FILTER, // KeyOnlyFilter
256    STR_FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter
257    STR_MCP_FILTER, // MultipleColumnPrefixFilter
258    STR_L_MCP_FILTER, // MultipleColumnPrefixFilter
259    STR_DC_FILTER, // DependentColumnFilter
260    STR_FAMILY_FILTER, // FamilyFilter
261    STR_QUALIFIER_FILTER, // QualifierFilter
262    STR_ROW_FILTER, // RowFilter
263    STR_VALUE_FILTER, // ValueFilter
264    STR_SCV_FILTER, // SingleColumnValueFilter
265    STR_SCVE_FILTER, // SingleColumnValueExcludeFilter
266    STR_AND_FILTER_LIST, // FilterList
267    STR_OR_FILTER_LIST, // FilterList
268    STR_L_FILTER_LIST, // FilterList
269  };
270
271  static {
272    assertEquals("The sizes of static arrays do not match: " + "[FILTERS: %d <=> FILTERS_INFO: %d]",
273      FILTERS.length, FILTERS_INFO.length);
274  }
275
276  /**
277   * Test the client Operations' JSON encoding to ensure that produced JSON is parseable and that
278   * the details are present and not corrupted.
279   * @throws IOException if the JSON conversion fails
280   */
281  @Test
282  public void testOperationJSON() throws IOException {
283    // produce a Scan Operation
284    Scan scan = new Scan(ROW);
285    scan.addColumn(FAMILY, QUALIFIER);
286    // get its JSON representation, and parse it
287    String json = scan.toJSON();
288    Type typeOfHashMap = new TypeToken<Map<String, Object>>() {
289    }.getType();
290    Map<String, Object> parsedJSON = GSON.fromJson(json, typeOfHashMap);
291    // check for the row
292    assertEquals("startRow incorrect in Scan.toJSON()", Bytes.toStringBinary(ROW),
293      parsedJSON.get("startRow"));
294    // check for the family and the qualifier.
295    List familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
296    assertNotNull("Family absent in Scan.toJSON()", familyInfo);
297    assertEquals("Qualifier absent in Scan.toJSON()", 1, familyInfo.size());
298    assertEquals("Qualifier incorrect in Scan.toJSON()", Bytes.toStringBinary(QUALIFIER),
299      familyInfo.get(0));
300
301    // produce a Get Operation
302    Get get = new Get(ROW);
303    get.addColumn(FAMILY, QUALIFIER);
304    // get its JSON representation, and parse it
305    json = get.toJSON();
306    parsedJSON = GSON.fromJson(json, typeOfHashMap);
307    // check for the row
308    assertEquals("row incorrect in Get.toJSON()", Bytes.toStringBinary(ROW), parsedJSON.get("row"));
309    // check for the family and the qualifier.
310    familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
311    assertNotNull("Family absent in Get.toJSON()", familyInfo);
312    assertEquals("Qualifier absent in Get.toJSON()", 1, familyInfo.size());
313    assertEquals("Qualifier incorrect in Get.toJSON()", Bytes.toStringBinary(QUALIFIER),
314      familyInfo.get(0));
315
316    // produce a Put operation
317    Put put = new Put(ROW);
318    put.addColumn(FAMILY, QUALIFIER, VALUE);
319    // get its JSON representation, and parse it
320    json = put.toJSON();
321    parsedJSON = GSON.fromJson(json, typeOfHashMap);
322    // check for the row
323    assertEquals("row absent in Put.toJSON()", Bytes.toStringBinary(ROW), parsedJSON.get("row"));
324    // check for the family and the qualifier.
325    familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
326    assertNotNull("Family absent in Put.toJSON()", familyInfo);
327    assertEquals("KeyValue absent in Put.toJSON()", 1, familyInfo.size());
328    Map kvMap = (Map) familyInfo.get(0);
329    assertEquals("Qualifier incorrect in Put.toJSON()", Bytes.toStringBinary(QUALIFIER),
330      kvMap.get("qualifier"));
331    assertEquals("Value length incorrect in Put.toJSON()", VALUE.length,
332      ((Number) kvMap.get("vlen")).intValue());
333
334    // produce a Delete operation
335    Delete delete = new Delete(ROW);
336    delete.addColumn(FAMILY, QUALIFIER);
337    // get its JSON representation, and parse it
338    json = delete.toJSON();
339    parsedJSON = GSON.fromJson(json, typeOfHashMap);
340    // check for the row
341    assertEquals("row absent in Delete.toJSON()", Bytes.toStringBinary(ROW), parsedJSON.get("row"));
342    // check for the family and the qualifier.
343    familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
344    assertNotNull("Family absent in Delete.toJSON()", familyInfo);
345    assertEquals("KeyValue absent in Delete.toJSON()", 1, familyInfo.size());
346    kvMap = (Map) familyInfo.get(0);
347    assertEquals("Qualifier incorrect in Delete.toJSON()", Bytes.toStringBinary(QUALIFIER),
348      kvMap.get("qualifier"));
349  }
350
351  /**
352   * Test the client Scan Operations' JSON encoding to ensure that produced JSON is parseable and
353   * that the details are present and not corrupted.
354   * @throws IOException if the JSON conversion fails
355   */
356  @Test
357  public void testScanOperationToJSON() throws IOException {
358    // produce a Scan Operation
359    Scan scan = new Scan().withStartRow(ROW, true);
360    scan.addColumn(FAMILY, QUALIFIER);
361    scan.withStopRow(ROW, true);
362    scan.readVersions(5);
363    scan.setBatch(10);
364    scan.setAllowPartialResults(true);
365    scan.setMaxResultsPerColumnFamily(3);
366    scan.setRowOffsetPerColumnFamily(8);
367    scan.setCaching(20);
368    scan.setMaxResultSize(50);
369    scan.setCacheBlocks(true);
370    scan.setReversed(true);
371    scan.setTimeRange(1000, 2000);
372    scan.setAsyncPrefetch(true);
373    scan.setMvccReadPoint(123);
374    scan.setLimit(5);
375    scan.setReadType(Scan.ReadType.PREAD);
376    scan.setNeedCursorResult(true);
377    scan.setFilter(SCV_FILTER);
378    scan.setReplicaId(1);
379    scan.setConsistency(Consistency.STRONG);
380    scan.setLoadColumnFamiliesOnDemand(true);
381    scan.setColumnFamilyTimeRange(FAMILY, 2000, 3000);
382    scan.setPriority(10);
383
384    // get its JSON representation, and parse it
385    String json = scan.toJSON();
386    Type typeOfHashMap = new TypeToken<Map<String, Object>>() {
387    }.getType();
388    Gson gson = new GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.STRING)
389      .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create();
390    Map<String, Object> parsedJSON = gson.fromJson(json, typeOfHashMap);
391    // check for the row
392    assertEquals("startRow incorrect in Scan.toJSON()", Bytes.toStringBinary(ROW),
393      parsedJSON.get("startRow"));
394    // check for the family and the qualifier.
395    List familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
396    assertNotNull("Family absent in Scan.toJSON()", familyInfo);
397    assertEquals("Qualifier absent in Scan.toJSON()", 1, familyInfo.size());
398    assertEquals("Qualifier incorrect in Scan.toJSON()", Bytes.toStringBinary(QUALIFIER),
399      familyInfo.get(0));
400    assertEquals("stopRow incorrect in Scan.toJSON()", Bytes.toStringBinary(ROW),
401      parsedJSON.get("stopRow"));
402    assertEquals("includeStartRow incorrect in Scan.toJSON()", true,
403      parsedJSON.get("includeStartRow"));
404    assertEquals("includeStopRow incorrect in Scan.toJSON()", true,
405      parsedJSON.get("includeStopRow"));
406    assertEquals("maxVersions incorrect in Scan.toJSON()", 5L, parsedJSON.get("maxVersions"));
407    assertEquals("batch incorrect in Scan.toJSON()", 10L, parsedJSON.get("batch"));
408    assertEquals("allowPartialResults incorrect in Scan.toJSON()", true,
409      parsedJSON.get("allowPartialResults"));
410    assertEquals("storeLimit incorrect in Scan.toJSON()", 3L, parsedJSON.get("storeLimit"));
411    assertEquals("storeOffset incorrect in Scan.toJSON()", 8L, parsedJSON.get("storeOffset"));
412    assertEquals("caching incorrect in Scan.toJSON()", 20L, parsedJSON.get("caching"));
413    assertEquals("maxResultSize incorrect in Scan.toJSON()", "50", parsedJSON.get("maxResultSize"));
414    assertEquals("cacheBlocks incorrect in Scan.toJSON()", true, parsedJSON.get("cacheBlocks"));
415    assertEquals("reversed incorrect in Scan.toJSON()", true, parsedJSON.get("reversed"));
416    List trList = (List) parsedJSON.get("timeRange");
417    assertEquals("timeRange incorrect in Scan.toJSON()", 2, trList.size());
418    assertEquals("timeRange incorrect in Scan.toJSON()", "1000", trList.get(0));
419    assertEquals("timeRange incorrect in Scan.toJSON()", "2000", trList.get(1));
420
421    assertEquals("asyncPrefetch incorrect in Scan.toJSON()", true, parsedJSON.get("asyncPrefetch"));
422    assertEquals("mvccReadPoint incorrect in Scan.toJSON()", "123",
423      parsedJSON.get("mvccReadPoint"));
424    assertEquals("limit incorrect in Scan.toJSON()", 5L, parsedJSON.get("limit"));
425    assertEquals("readType incorrect in Scan.toJSON()", "PREAD", parsedJSON.get("readType"));
426    assertEquals("needCursorResult incorrect in Scan.toJSON()", true,
427      parsedJSON.get("needCursorResult"));
428
429    Map colFamTimeRange = (Map) parsedJSON.get("colFamTimeRangeMap");
430    assertEquals("colFamTimeRangeMap incorrect in Scan.toJSON()", 1L, colFamTimeRange.size());
431    List testFamily = (List) colFamTimeRange.get("testFamily");
432    assertEquals("colFamTimeRangeMap incorrect in Scan.toJSON()", 2L, testFamily.size());
433    assertEquals("colFamTimeRangeMap incorrect in Scan.toJSON()", "2000", testFamily.get(0));
434    assertEquals("colFamTimeRangeMap incorrect in Scan.toJSON()", "3000", testFamily.get(1));
435
436    assertEquals("targetReplicaId incorrect in Scan.toJSON()", 1L,
437      parsedJSON.get("targetReplicaId"));
438    assertEquals("consistency incorrect in Scan.toJSON()", "STRONG", parsedJSON.get("consistency"));
439    assertEquals("loadColumnFamiliesOnDemand incorrect in Scan.toJSON()", true,
440      parsedJSON.get("loadColumnFamiliesOnDemand"));
441
442    assertEquals("priority incorrect in Scan.toJSON()", 10L, parsedJSON.get("priority"));
443
444  }
445
446  @Test
447  public void testPutCreationWithByteBuffer() {
448    Put p = new Put(ROW);
449    List<Cell> c = p.get(FAMILY, QUALIFIER);
450    Assert.assertEquals(0, c.size());
451    Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimestamp());
452
453    p.addColumn(FAMILY, ByteBuffer.wrap(QUALIFIER), 1984L, ByteBuffer.wrap(VALUE));
454    c = p.get(FAMILY, QUALIFIER);
455    Assert.assertEquals(1, c.size());
456    Assert.assertEquals(1984L, c.get(0).getTimestamp());
457    Assert.assertArrayEquals(VALUE, CellUtil.cloneValue(c.get(0)));
458    Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimestamp());
459    Assert.assertEquals(0, CellComparatorImpl.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
460
461    p = new Put(ROW);
462    p.addColumn(FAMILY, ByteBuffer.wrap(QUALIFIER), 2013L, null);
463    c = p.get(FAMILY, QUALIFIER);
464    Assert.assertEquals(1, c.size());
465    Assert.assertEquals(2013L, c.get(0).getTimestamp());
466    Assert.assertArrayEquals(new byte[] {}, CellUtil.cloneValue(c.get(0)));
467    Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimestamp());
468    Assert.assertEquals(0, CellComparatorImpl.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
469
470    p = new Put(ByteBuffer.wrap(ROW));
471    p.addColumn(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null);
472    c = p.get(FAMILY, QUALIFIER);
473    Assert.assertEquals(1, c.size());
474    Assert.assertEquals(2001L, c.get(0).getTimestamp());
475    Assert.assertArrayEquals(new byte[] {}, CellUtil.cloneValue(c.get(0)));
476    Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0)));
477    Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimestamp());
478    Assert.assertEquals(0, CellComparatorImpl.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
479
480    p = new Put(ByteBuffer.wrap(ROW), 1970L);
481    p.addColumn(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null);
482    c = p.get(FAMILY, QUALIFIER);
483    Assert.assertEquals(1, c.size());
484    Assert.assertEquals(2001L, c.get(0).getTimestamp());
485    Assert.assertArrayEquals(new byte[] {}, CellUtil.cloneValue(c.get(0)));
486    Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0)));
487    Assert.assertEquals(1970L, p.getTimestamp());
488    Assert.assertEquals(0, CellComparatorImpl.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0))));
489  }
490
491  @Test
492  @SuppressWarnings("rawtypes")
493  public void testOperationSubClassMethodsAreBuilderStyle() {
494    /*
495     * All Operation subclasses should have a builder style setup where setXXX/addXXX methods can be
496     * chainable together: . For example: Scan scan = new Scan() .setFoo(foo) .setBar(bar)
497     * .setBuz(buz) This test ensures that all methods starting with "set" returns the declaring
498     * object
499     */
500
501    // TODO: We should ensure all subclasses of Operation is checked.
502    Class[] classes = new Class[] { Operation.class, OperationWithAttributes.class, Mutation.class,
503      Query.class, Delete.class, Increment.class, Append.class, Put.class, Get.class, Scan.class };
504
505    BuilderStyleTest.assertClassesAreBuilderStyle(classes);
506  }
507
508  /**
509   * Test the client Get Operations' JSON encoding to ensure that produced JSON is parseable and
510   * that the details are present and not corrupted.
511   * @throws IOException if the JSON conversion fails
512   */
513  @Test
514  public void testGetOperationToJSON() throws IOException {
515    // produce a Scan Operation
516    Get get = new Get(ROW);
517    get.addColumn(FAMILY, QUALIFIER);
518    get.readVersions(5);
519    get.setMaxResultsPerColumnFamily(3);
520    get.setRowOffsetPerColumnFamily(8);
521    get.setCacheBlocks(true);
522    get.setMaxResultsPerColumnFamily(5);
523    get.setRowOffsetPerColumnFamily(9);
524    get.setCheckExistenceOnly(true);
525    get.setTimeRange(1000, 2000);
526    get.setFilter(SCV_FILTER);
527    get.setReplicaId(1);
528    get.setConsistency(Consistency.STRONG);
529    get.setLoadColumnFamiliesOnDemand(true);
530    get.setColumnFamilyTimeRange(FAMILY, 2000, 3000);
531    get.setPriority(10);
532
533    // get its JSON representation, and parse it
534    String json = get.toJSON();
535    Type typeOfHashMap = new TypeToken<Map<String, Object>>() {
536    }.getType();
537    Gson gson = new GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.STRING)
538      .setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create();
539    Map<String, Object> parsedJSON = gson.fromJson(json, typeOfHashMap);
540    // check for the row
541    assertEquals("row incorrect in Get.toJSON()", Bytes.toStringBinary(ROW), parsedJSON.get("row"));
542    // check for the family and the qualifier.
543    List familyInfo = (List) ((Map) parsedJSON.get("families")).get(Bytes.toStringBinary(FAMILY));
544    assertNotNull("Family absent in Get.toJSON()", familyInfo);
545    assertEquals("Qualifier absent in Get.toJSON()", 1, familyInfo.size());
546    assertEquals("Qualifier incorrect in Get.toJSON()", Bytes.toStringBinary(QUALIFIER),
547      familyInfo.get(0));
548
549    assertEquals("maxVersions incorrect in Get.toJSON()", 5L, parsedJSON.get("maxVersions"));
550
551    assertEquals("storeLimit incorrect in Get.toJSON()", 5L, parsedJSON.get("storeLimit"));
552    assertEquals("storeOffset incorrect in Get.toJSON()", 9L, parsedJSON.get("storeOffset"));
553
554    assertEquals("cacheBlocks incorrect in Get.toJSON()", true, parsedJSON.get("cacheBlocks"));
555
556    List trList = (List) parsedJSON.get("timeRange");
557    assertEquals("timeRange incorrect in Get.toJSON()", 2, trList.size());
558    assertEquals("timeRange incorrect in Get.toJSON()", "1000", trList.get(0));
559    assertEquals("timeRange incorrect in Get.toJSON()", "2000", trList.get(1));
560
561    Map colFamTimeRange = (Map) parsedJSON.get("colFamTimeRangeMap");
562    assertEquals("colFamTimeRangeMap incorrect in Get.toJSON()", 1L, colFamTimeRange.size());
563    List testFamily = (List) colFamTimeRange.get("testFamily");
564    assertEquals("colFamTimeRangeMap incorrect in Get.toJSON()", 2L, testFamily.size());
565    assertEquals("colFamTimeRangeMap incorrect in Get.toJSON()", "2000", testFamily.get(0));
566    assertEquals("colFamTimeRangeMap incorrect in Get.toJSON()", "3000", testFamily.get(1));
567
568    assertEquals("targetReplicaId incorrect in Get.toJSON()", 1L,
569      parsedJSON.get("targetReplicaId"));
570    assertEquals("consistency incorrect in Get.toJSON()", "STRONG", parsedJSON.get("consistency"));
571    assertEquals("loadColumnFamiliesOnDemand incorrect in Get.toJSON()", true,
572      parsedJSON.get("loadColumnFamiliesOnDemand"));
573
574    assertEquals("priority incorrect in Get.toJSON()", 10L, parsedJSON.get("priority"));
575    assertEquals("checkExistenceOnly incorrect in Get.toJSON()", true,
576      parsedJSON.get("checkExistenceOnly"));
577
578  }
579}