1   /**
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.client;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertNotNull;
24  
25  import org.apache.hadoop.hbase.SmallTests;
26  import org.junit.Test;
27  
28  import java.io.IOException;
29  import java.util.Arrays;
30  import java.util.HashMap;
31  import java.util.List;
32  import java.util.Map;
33  
34  import org.apache.hadoop.hbase.filter.BinaryComparator;
35  import org.apache.hadoop.hbase.filter.ColumnCountGetFilter;
36  import org.apache.hadoop.hbase.filter.ColumnPaginationFilter;
37  import org.apache.hadoop.hbase.filter.ColumnPrefixFilter;
38  import org.apache.hadoop.hbase.filter.ColumnRangeFilter;
39  import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
40  import org.apache.hadoop.hbase.filter.DependentColumnFilter;
41  import org.apache.hadoop.hbase.filter.FamilyFilter;
42  import org.apache.hadoop.hbase.filter.Filter;
43  import org.apache.hadoop.hbase.filter.FilterList;
44  import org.apache.hadoop.hbase.filter.FilterList.Operator;
45  import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
46  import org.apache.hadoop.hbase.filter.InclusiveStopFilter;
47  import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
48  import org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter;
49  import org.apache.hadoop.hbase.filter.PageFilter;
50  import org.apache.hadoop.hbase.filter.PrefixFilter;
51  import org.apache.hadoop.hbase.filter.QualifierFilter;
52  import org.apache.hadoop.hbase.filter.RowFilter;
53  import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
54  import org.apache.hadoop.hbase.filter.SingleColumnValueExcludeFilter;
55  import org.apache.hadoop.hbase.filter.SkipFilter;
56  import org.apache.hadoop.hbase.filter.TimestampsFilter;
57  import org.apache.hadoop.hbase.filter.ValueFilter;
58  import org.apache.hadoop.hbase.filter.WhileMatchFilter;
59  import org.apache.hadoop.hbase.util.Bytes;
60  
61  import org.codehaus.jackson.map.ObjectMapper;
62  import org.junit.experimental.categories.Category;
63  
64  /**
65   * Run tests that use the functionality of the Operation superclass for
66   * Puts, Gets, Deletes, Scans, and MultiPuts.
67   */
68  @Category(SmallTests.class)
69  public class TestOperation {
70    private static byte [] ROW = Bytes.toBytes("testRow");
71    private static byte [] FAMILY = Bytes.toBytes("testFamily");
72    private static byte [] QUALIFIER = Bytes.toBytes("testQualifier");
73    private static byte [] VALUE = Bytes.toBytes("testValue");
74  
75    private static ObjectMapper mapper = new ObjectMapper();
76  
77    private static List<Long> TS_LIST = Arrays.asList(2L, 3L, 5L);
78    private static TimestampsFilter TS_FILTER = new TimestampsFilter(TS_LIST);
79    private static String STR_TS_FILTER =
80        TS_FILTER.getClass().getSimpleName() + " (3/3): [2, 3, 5]";
81  
82    private static List<Long> L_TS_LIST =
83        Arrays.asList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L);
84    private static TimestampsFilter L_TS_FILTER =
85        new TimestampsFilter(L_TS_LIST);
86    private static String STR_L_TS_FILTER =
87        L_TS_FILTER.getClass().getSimpleName() + " (5/11): [0, 1, 2, 3, 4]";
88  
89    private static String COL_NAME_1 = "col1";
90    private static ColumnPrefixFilter COL_PRE_FILTER =
91        new ColumnPrefixFilter(COL_NAME_1.getBytes());
92    private static String STR_COL_PRE_FILTER =
93        COL_PRE_FILTER.getClass().getSimpleName() + " " + COL_NAME_1;
94  
95    private static String COL_NAME_2 = "col2";
96    private static ColumnRangeFilter CR_FILTER = new ColumnRangeFilter(
97        COL_NAME_1.getBytes(), true, COL_NAME_2.getBytes(), false);
98    private static String STR_CR_FILTER = CR_FILTER.getClass().getSimpleName()
99        + " [" + COL_NAME_1 + ", " + COL_NAME_2 + ")";
100 
101   private static int COL_COUNT = 9;
102   private static ColumnCountGetFilter CCG_FILTER =
103       new ColumnCountGetFilter(COL_COUNT);
104   private static String STR_CCG_FILTER =
105       CCG_FILTER.getClass().getSimpleName() + " " + COL_COUNT;
106 
107   private static int LIMIT = 3;
108   private static int OFFSET = 4;
109   private static ColumnPaginationFilter CP_FILTER =
110       new ColumnPaginationFilter(LIMIT, OFFSET);
111   private static String STR_CP_FILTER = CP_FILTER.getClass().getSimpleName()
112       + " (" + LIMIT + ", " + OFFSET + ")";
113 
114   private static String STOP_ROW_KEY = "stop";
115   private static InclusiveStopFilter IS_FILTER =
116       new InclusiveStopFilter(STOP_ROW_KEY.getBytes());
117   private static String STR_IS_FILTER =
118       IS_FILTER.getClass().getSimpleName() + " " + STOP_ROW_KEY;
119 
120   private static String PREFIX = "prefix";
121   private static PrefixFilter PREFIX_FILTER =
122       new PrefixFilter(PREFIX.getBytes());
123   private static String STR_PREFIX_FILTER = "PrefixFilter " + PREFIX;
124 
125   private static byte[][] PREFIXES = {
126       "0".getBytes(), "1".getBytes(), "2".getBytes()};
127   private static MultipleColumnPrefixFilter MCP_FILTER =
128       new MultipleColumnPrefixFilter(PREFIXES);
129   private static String STR_MCP_FILTER =
130       MCP_FILTER.getClass().getSimpleName() + " (3/3): [0, 1, 2]";
131 
132   private static byte[][] L_PREFIXES = {
133     "0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(),
134     "4".getBytes(), "5".getBytes(), "6".getBytes(), "7".getBytes()};
135   private static MultipleColumnPrefixFilter L_MCP_FILTER =
136       new MultipleColumnPrefixFilter(L_PREFIXES);
137   private static String STR_L_MCP_FILTER =
138       L_MCP_FILTER.getClass().getSimpleName() + " (5/8): [0, 1, 2, 3, 4]";
139 
140   private static int PAGE_SIZE = 9;
141   private static PageFilter PAGE_FILTER = new PageFilter(PAGE_SIZE);
142   private static String STR_PAGE_FILTER =
143       PAGE_FILTER.getClass().getSimpleName() + " " + PAGE_SIZE;
144 
145   private static SkipFilter SKIP_FILTER = new SkipFilter(L_TS_FILTER);
146   private static String STR_SKIP_FILTER =
147       SKIP_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER;
148 
149   private static WhileMatchFilter WHILE_FILTER =
150       new WhileMatchFilter(L_TS_FILTER);
151   private static String STR_WHILE_FILTER =
152       WHILE_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER;
153 
154   private static KeyOnlyFilter KEY_ONLY_FILTER = new KeyOnlyFilter();
155   private static String STR_KEY_ONLY_FILTER =
156       KEY_ONLY_FILTER.getClass().getSimpleName();
157 
158   private static FirstKeyOnlyFilter FIRST_KEY_ONLY_FILTER =
159       new FirstKeyOnlyFilter();
160   private static String STR_FIRST_KEY_ONLY_FILTER =
161       FIRST_KEY_ONLY_FILTER.getClass().getSimpleName();
162 
163   private static CompareOp CMP_OP = CompareOp.EQUAL;
164   private static byte[] CMP_VALUE = "value".getBytes();
165   private static BinaryComparator BC = new BinaryComparator(CMP_VALUE);
166   private static DependentColumnFilter DC_FILTER =
167       new DependentColumnFilter(FAMILY, QUALIFIER, true, CMP_OP, BC);
168   private static String STR_DC_FILTER = String.format(
169       "%s (%s, %s, %s, %s, %s)", DC_FILTER.getClass().getSimpleName(),
170       Bytes.toStringBinary(FAMILY), Bytes.toStringBinary(QUALIFIER), true,
171       CMP_OP.name(), Bytes.toStringBinary(BC.getValue()));
172 
173   private static FamilyFilter FAMILY_FILTER = new FamilyFilter(CMP_OP, BC);
174   private static String STR_FAMILY_FILTER =
175       FAMILY_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
176 
177   private static QualifierFilter QUALIFIER_FILTER =
178       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 =
184       ROW_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
185 
186   private static ValueFilter VALUE_FILTER = new ValueFilter(CMP_OP, BC);
187   private static String STR_VALUE_FILTER =
188       VALUE_FILTER.getClass().getSimpleName() + " (EQUAL, value)";
189 
190   private static SingleColumnValueFilter SCV_FILTER =
191       new SingleColumnValueFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE);
192   private static String STR_SCV_FILTER = String.format("%s (%s, %s, %s, %s)",
193       SCV_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY),
194       Bytes.toStringBinary(QUALIFIER), CMP_OP.name(),
195       Bytes.toStringBinary(CMP_VALUE));
196 
197   private static SingleColumnValueExcludeFilter SCVE_FILTER =
198       new SingleColumnValueExcludeFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE);
199   private static String STR_SCVE_FILTER = String.format("%s (%s, %s, %s, %s)",
200       SCVE_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY),
201       Bytes.toStringBinary(QUALIFIER), CMP_OP.name(),
202       Bytes.toStringBinary(CMP_VALUE));
203 
204   private static FilterList AND_FILTER_LIST = new FilterList(
205       Operator.MUST_PASS_ALL, Arrays.asList((Filter) TS_FILTER, L_TS_FILTER,
206           CR_FILTER));
207   private static String STR_AND_FILTER_LIST = String.format(
208       "%s AND (3/3): [%s, %s, %s]", AND_FILTER_LIST.getClass().getSimpleName(),
209       STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER);
210 
211   private static FilterList OR_FILTER_LIST = new FilterList(
212       Operator.MUST_PASS_ONE, Arrays.asList((Filter) TS_FILTER, L_TS_FILTER,
213           CR_FILTER));
214   private static String STR_OR_FILTER_LIST = String.format(
215       "%s OR (3/3): [%s, %s, %s]", AND_FILTER_LIST.getClass().getSimpleName(),
216       STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER);
217 
218   private static FilterList L_FILTER_LIST = new FilterList(
219       Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, CR_FILTER, COL_PRE_FILTER,
220           CCG_FILTER, CP_FILTER, PREFIX_FILTER, PAGE_FILTER));
221   private static String STR_L_FILTER_LIST = String.format(
222       "%s AND (5/8): [%s, %s, %s, %s, %s]",
223       L_FILTER_LIST.getClass().getSimpleName(), STR_TS_FILTER, STR_L_TS_FILTER,
224       STR_CR_FILTER, STR_COL_PRE_FILTER, STR_CCG_FILTER, STR_CP_FILTER);
225 
226   private static Filter[] FILTERS = {
227     TS_FILTER,             // TimestampsFilter
228     L_TS_FILTER,           // TimestampsFilter
229     COL_PRE_FILTER,        // ColumnPrefixFilter
230     CP_FILTER,             // ColumnPaginationFilter
231     CR_FILTER,             // ColumnRangeFilter
232     CCG_FILTER,            // ColumnCountGetFilter
233     IS_FILTER,             // InclusiveStopFilter
234     PREFIX_FILTER,         // PrefixFilter
235     PAGE_FILTER,           // PageFilter
236     SKIP_FILTER,           // SkipFilter
237     WHILE_FILTER,          // WhileMatchFilter
238     KEY_ONLY_FILTER,       // KeyOnlyFilter
239     FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter
240     MCP_FILTER,            // MultipleColumnPrefixFilter
241     L_MCP_FILTER,          // MultipleColumnPrefixFilter
242     DC_FILTER,             // DependentColumnFilter
243     FAMILY_FILTER,         // FamilyFilter
244     QUALIFIER_FILTER,      // QualifierFilter
245     ROW_FILTER,            // RowFilter
246     VALUE_FILTER,          // ValueFilter
247     SCV_FILTER,            // SingleColumnValueFilter
248     SCVE_FILTER,           // SingleColumnValueExcludeFilter
249     AND_FILTER_LIST,       // FilterList
250     OR_FILTER_LIST,        // FilterList
251     L_FILTER_LIST,         // FilterList
252   };
253 
254   private static String[] FILTERS_INFO = {
255     STR_TS_FILTER,             // TimestampsFilter
256     STR_L_TS_FILTER,           // TimestampsFilter
257     STR_COL_PRE_FILTER,        // ColumnPrefixFilter
258     STR_CP_FILTER,             // ColumnPaginationFilter
259     STR_CR_FILTER,             // ColumnRangeFilter
260     STR_CCG_FILTER,            // ColumnCountGetFilter
261     STR_IS_FILTER,             // InclusiveStopFilter
262     STR_PREFIX_FILTER,         // PrefixFilter
263     STR_PAGE_FILTER,           // PageFilter
264     STR_SKIP_FILTER,           // SkipFilter
265     STR_WHILE_FILTER,          // WhileMatchFilter
266     STR_KEY_ONLY_FILTER,       // KeyOnlyFilter
267     STR_FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter
268     STR_MCP_FILTER,            // MultipleColumnPrefixFilter
269     STR_L_MCP_FILTER,          // MultipleColumnPrefixFilter
270     STR_DC_FILTER,             // DependentColumnFilter
271     STR_FAMILY_FILTER,         // FamilyFilter
272     STR_QUALIFIER_FILTER,      // QualifierFilter
273     STR_ROW_FILTER,            // RowFilter
274     STR_VALUE_FILTER,          // ValueFilter
275     STR_SCV_FILTER,            // SingleColumnValueFilter
276     STR_SCVE_FILTER,           // SingleColumnValueExcludeFilter
277     STR_AND_FILTER_LIST,       // FilterList
278     STR_OR_FILTER_LIST,        // FilterList
279     STR_L_FILTER_LIST,         // FilterList
280   };
281 
282   static {
283     assertEquals("The sizes of static arrays do not match: "
284         + "[FILTERS: %d <=> FILTERS_INFO: %d]",
285         FILTERS.length, FILTERS_INFO.length);
286   }
287 
288   /**
289    * Test the client Operations' JSON encoding to ensure that produced JSON is 
290    * parseable and that the details are present and not corrupted.
291    * @throws IOException
292    */
293   @Test
294   public void testOperationJSON()
295       throws IOException {
296     // produce a Scan Operation
297     Scan scan = new Scan(ROW);
298     scan.addColumn(FAMILY, QUALIFIER);
299     // get its JSON representation, and parse it
300     String json = scan.toJSON();
301     Map<String, Object> parsedJSON = mapper.readValue(json, HashMap.class);
302     // check for the row
303     assertEquals("startRow incorrect in Scan.toJSON()",
304         Bytes.toStringBinary(ROW), parsedJSON.get("startRow"));
305     // check for the family and the qualifier.
306     List familyInfo = (List) ((Map) parsedJSON.get("families")).get(
307         Bytes.toStringBinary(FAMILY));
308     assertNotNull("Family absent in Scan.toJSON()", familyInfo);
309     assertEquals("Qualifier absent in Scan.toJSON()", 1, familyInfo.size());
310     assertEquals("Qualifier incorrect in Scan.toJSON()",
311         Bytes.toStringBinary(QUALIFIER),
312         familyInfo.get(0));
313 
314     // produce a Get Operation
315     Get get = new Get(ROW);
316     get.addColumn(FAMILY, QUALIFIER);
317     // get its JSON representation, and parse it
318     json = get.toJSON();
319     parsedJSON = mapper.readValue(json, HashMap.class);
320     // check for the row
321     assertEquals("row incorrect in Get.toJSON()",
322         Bytes.toStringBinary(ROW), parsedJSON.get("row"));
323     // check for the family and the qualifier.
324     familyInfo = (List) ((Map) parsedJSON.get("families")).get(
325         Bytes.toStringBinary(FAMILY));
326     assertNotNull("Family absent in Get.toJSON()", familyInfo);
327     assertEquals("Qualifier absent in Get.toJSON()", 1, familyInfo.size());
328     assertEquals("Qualifier incorrect in Get.toJSON()",
329         Bytes.toStringBinary(QUALIFIER),
330         familyInfo.get(0));
331 
332     // produce a Put operation
333     Put put = new Put(ROW);
334     put.add(FAMILY, QUALIFIER, VALUE);
335     // get its JSON representation, and parse it
336     json = put.toJSON();
337     parsedJSON = mapper.readValue(json, HashMap.class);
338     // check for the row
339     assertEquals("row absent in Put.toJSON()",
340         Bytes.toStringBinary(ROW), parsedJSON.get("row"));
341     // check for the family and the qualifier.
342     familyInfo = (List) ((Map) parsedJSON.get("families")).get(
343         Bytes.toStringBinary(FAMILY));
344     assertNotNull("Family absent in Put.toJSON()", familyInfo);
345     assertEquals("KeyValue absent in Put.toJSON()", 1, familyInfo.size());
346     Map kvMap = (Map) familyInfo.get(0);
347     assertEquals("Qualifier incorrect in Put.toJSON()",
348         Bytes.toStringBinary(QUALIFIER),
349         kvMap.get("qualifier"));
350     assertEquals("Value length incorrect in Put.toJSON()", 
351         VALUE.length, kvMap.get("vlen"));
352 
353     // produce a Delete operation
354     Delete delete = new Delete(ROW);
355     delete.deleteColumn(FAMILY, QUALIFIER);
356     // get its JSON representation, and parse it
357     json = delete.toJSON();
358     parsedJSON = mapper.readValue(json, HashMap.class);
359     // check for the row
360     assertEquals("row absent in Delete.toJSON()",
361         Bytes.toStringBinary(ROW), parsedJSON.get("row"));
362     // check for the family and the qualifier.
363     familyInfo = (List) ((Map) parsedJSON.get("families")).get(
364         Bytes.toStringBinary(FAMILY));
365     assertNotNull("Family absent in Delete.toJSON()", familyInfo);
366     assertEquals("KeyValue absent in Delete.toJSON()", 1, familyInfo.size());
367     kvMap = (Map) familyInfo.get(0);
368     assertEquals("Qualifier incorrect in Delete.toJSON()", 
369         Bytes.toStringBinary(QUALIFIER), kvMap.get("qualifier"));
370   }
371 
372   @org.junit.Rule
373   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
374     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
375 }
376