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.filter;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.nio.charset.StandardCharsets;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.regex.Pattern;
029import org.apache.hadoop.hbase.CompareOperator;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.testclassification.MediumTests;
032import org.apache.hadoop.hbase.testclassification.RegionServerTests;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.junit.After;
035import org.junit.Before;
036import org.junit.ClassRule;
037import org.junit.Test;
038import org.junit.experimental.categories.Category;
039
040/**
041 * This class tests ParseFilter.java It tests the entire work flow from when a string is given by
042 * the user and how it is parsed to construct the corresponding Filter object
043 */
044@Category({ RegionServerTests.class, MediumTests.class })
045public class TestParseFilter {
046
047  @ClassRule
048  public static final HBaseClassTestRule CLASS_RULE =
049    HBaseClassTestRule.forClass(TestParseFilter.class);
050
051  ParseFilter f;
052  Filter filter;
053
054  @Before
055  public void setUp() throws Exception {
056    f = new ParseFilter();
057  }
058
059  @After
060  public void tearDown() throws Exception {
061    // Nothing to do.
062  }
063
064  @Test
065  public void testKeyOnlyFilter() throws IOException {
066    String filterString = "KeyOnlyFilter()";
067    doTestFilter(filterString, KeyOnlyFilter.class);
068
069    String filterString2 = "KeyOnlyFilter ('') ";
070    byte[] filterStringAsByteArray2 = Bytes.toBytes(filterString2);
071    try {
072      filter = f.parseFilterString(filterStringAsByteArray2);
073      assertTrue(false);
074    } catch (IllegalArgumentException e) {
075      System.out.println(e.getMessage());
076    }
077  }
078
079  @Test
080  public void testFirstKeyOnlyFilter() throws IOException {
081    String filterString = " FirstKeyOnlyFilter( ) ";
082    doTestFilter(filterString, FirstKeyOnlyFilter.class);
083
084    String filterString2 = " FirstKeyOnlyFilter ('') ";
085    byte[] filterStringAsByteArray2 = Bytes.toBytes(filterString2);
086    try {
087      filter = f.parseFilterString(filterStringAsByteArray2);
088      assertTrue(false);
089    } catch (IllegalArgumentException e) {
090      System.out.println(e.getMessage());
091    }
092  }
093
094  @Test
095  public void testPrefixFilter() throws IOException {
096    String filterString = " PrefixFilter('row' ) ";
097    PrefixFilter prefixFilter = doTestFilter(filterString, PrefixFilter.class);
098    byte[] prefix = prefixFilter.getPrefix();
099    assertEquals("row", new String(prefix, StandardCharsets.UTF_8));
100
101    filterString = " PrefixFilter(row)";
102    try {
103      doTestFilter(filterString, PrefixFilter.class);
104      assertTrue(false);
105    } catch (IllegalArgumentException e) {
106      System.out.println(e.getMessage());
107    }
108  }
109
110  @Test
111  public void testColumnPrefixFilter() throws IOException {
112    String filterString = " ColumnPrefixFilter('qualifier' ) ";
113    ColumnPrefixFilter columnPrefixFilter = doTestFilter(filterString, ColumnPrefixFilter.class);
114    byte[] columnPrefix = columnPrefixFilter.getPrefix();
115    assertEquals("qualifier", new String(columnPrefix, StandardCharsets.UTF_8));
116  }
117
118  @Test
119  public void testMultipleColumnPrefixFilter() throws IOException {
120    String filterString = " MultipleColumnPrefixFilter('qualifier1', 'qualifier2' ) ";
121    MultipleColumnPrefixFilter multipleColumnPrefixFilter =
122      doTestFilter(filterString, MultipleColumnPrefixFilter.class);
123    byte[][] prefixes = multipleColumnPrefixFilter.getPrefix();
124    assertEquals("qualifier1", new String(prefixes[0], StandardCharsets.UTF_8));
125    assertEquals("qualifier2", new String(prefixes[1], StandardCharsets.UTF_8));
126  }
127
128  @Test
129  public void testColumnCountGetFilter() throws IOException {
130    String filterString = " ColumnCountGetFilter(4)";
131    ColumnCountGetFilter columnCountGetFilter =
132      doTestFilter(filterString, ColumnCountGetFilter.class);
133    int limit = columnCountGetFilter.getLimit();
134    assertEquals(4, limit);
135
136    filterString = " ColumnCountGetFilter('abc')";
137    try {
138      doTestFilter(filterString, ColumnCountGetFilter.class);
139      assertTrue(false);
140    } catch (IllegalArgumentException e) {
141      System.out.println(e.getMessage());
142    }
143
144    filterString = " ColumnCountGetFilter(2147483648)";
145    try {
146      doTestFilter(filterString, ColumnCountGetFilter.class);
147      assertTrue(false);
148    } catch (IllegalArgumentException e) {
149      System.out.println(e.getMessage());
150    }
151  }
152
153  @Test
154  public void testPageFilter() throws IOException {
155    String filterString = " PageFilter(4)";
156    PageFilter pageFilter = doTestFilter(filterString, PageFilter.class);
157    long pageSize = pageFilter.getPageSize();
158    assertEquals(4, pageSize);
159
160    filterString = " PageFilter('123')";
161    try {
162      doTestFilter(filterString, PageFilter.class);
163      assertTrue(false);
164    } catch (IllegalArgumentException e) {
165      System.out.println("PageFilter needs an int as an argument");
166    }
167  }
168
169  @Test
170  public void testColumnPaginationFilter() throws IOException {
171    String filterString = "ColumnPaginationFilter(4, 6)";
172    ColumnPaginationFilter columnPaginationFilter =
173      doTestFilter(filterString, ColumnPaginationFilter.class);
174    int limit = columnPaginationFilter.getLimit();
175    assertEquals(4, limit);
176    int offset = columnPaginationFilter.getOffset();
177    assertEquals(6, offset);
178
179    filterString = " ColumnPaginationFilter('124')";
180    try {
181      doTestFilter(filterString, ColumnPaginationFilter.class);
182      assertTrue(false);
183    } catch (IllegalArgumentException e) {
184      System.out.println("ColumnPaginationFilter needs two arguments");
185    }
186
187    filterString = " ColumnPaginationFilter('4' , '123a')";
188    try {
189      doTestFilter(filterString, ColumnPaginationFilter.class);
190      assertTrue(false);
191    } catch (IllegalArgumentException e) {
192      System.out.println("ColumnPaginationFilter needs two ints as arguments");
193    }
194
195    filterString = " ColumnPaginationFilter('4' , '-123')";
196    try {
197      doTestFilter(filterString, ColumnPaginationFilter.class);
198      assertTrue(false);
199    } catch (IllegalArgumentException e) {
200      System.out.println("ColumnPaginationFilter arguments should not be negative");
201    }
202  }
203
204  @Test
205  public void testInclusiveStopFilter() throws IOException {
206    String filterString = "InclusiveStopFilter ('row 3')";
207    InclusiveStopFilter inclusiveStopFilter = doTestFilter(filterString, InclusiveStopFilter.class);
208    byte[] stopRowKey = inclusiveStopFilter.getStopRowKey();
209    assertEquals("row 3", new String(stopRowKey, StandardCharsets.UTF_8));
210  }
211
212  @Test
213  public void testTimestampsFilter() throws IOException {
214    String filterString = "TimestampsFilter(9223372036854775806, 6)";
215    TimestampsFilter timestampsFilter = doTestFilter(filterString, TimestampsFilter.class);
216    List<Long> timestamps = timestampsFilter.getTimestamps();
217    assertEquals(2, timestamps.size());
218    assertEquals(Long.valueOf(6), timestamps.get(0));
219
220    filterString = "TimestampsFilter()";
221    timestampsFilter = doTestFilter(filterString, TimestampsFilter.class);
222    timestamps = timestampsFilter.getTimestamps();
223    assertEquals(0, timestamps.size());
224
225    filterString = "TimestampsFilter(9223372036854775808, 6)";
226    try {
227      doTestFilter(filterString, ColumnPaginationFilter.class);
228      assertTrue(false);
229    } catch (IllegalArgumentException e) {
230      System.out.println("Long Argument was too large");
231    }
232
233    filterString = "TimestampsFilter(-45, 6)";
234    try {
235      doTestFilter(filterString, ColumnPaginationFilter.class);
236      assertTrue(false);
237    } catch (IllegalArgumentException e) {
238      System.out.println("Timestamp Arguments should not be negative");
239    }
240  }
241
242  @Test
243  public void testRowFilter() throws IOException {
244    String filterString = "RowFilter ( =,   'binary:regionse')";
245    RowFilter rowFilter = doTestFilter(filterString, RowFilter.class);
246    assertEquals(CompareOperator.EQUAL, rowFilter.getCompareOperator());
247    assertTrue(rowFilter.getComparator() instanceof BinaryComparator);
248    BinaryComparator binaryComparator = (BinaryComparator) rowFilter.getComparator();
249    assertEquals("regionse", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
250  }
251
252  @Test
253  public void testFamilyFilter() throws IOException {
254    String filterString = "FamilyFilter(>=, 'binaryprefix:pre')";
255    FamilyFilter familyFilter = doTestFilter(filterString, FamilyFilter.class);
256    assertEquals(CompareOperator.GREATER_OR_EQUAL, familyFilter.getCompareOperator());
257    assertTrue(familyFilter.getComparator() instanceof BinaryPrefixComparator);
258    BinaryPrefixComparator binaryPrefixComparator =
259      (BinaryPrefixComparator) familyFilter.getComparator();
260    assertEquals("pre", new String(binaryPrefixComparator.getValue(), StandardCharsets.UTF_8));
261  }
262
263  @Test
264  public void testQualifierFilter() throws IOException {
265    String filterString = "QualifierFilter(=, 'regexstring:pre*')";
266    QualifierFilter qualifierFilter = doTestFilter(filterString, QualifierFilter.class);
267    assertEquals(CompareOperator.EQUAL, qualifierFilter.getCompareOperator());
268    assertTrue(qualifierFilter.getComparator() instanceof RegexStringComparator);
269    RegexStringComparator regexStringComparator =
270      (RegexStringComparator) qualifierFilter.getComparator();
271    assertEquals("pre*", new String(regexStringComparator.getValue(), StandardCharsets.UTF_8));
272  }
273
274  @Test
275  public void testQualifierFilterNoCase() throws IOException {
276    String filterString = "QualifierFilter(=, 'regexstringnocase:pre*')";
277    QualifierFilter qualifierFilter = doTestFilter(filterString, QualifierFilter.class);
278    assertEquals(CompareOperator.EQUAL, qualifierFilter.getCompareOperator());
279    assertTrue(qualifierFilter.getComparator() instanceof RegexStringComparator);
280    RegexStringComparator regexStringComparator =
281      (RegexStringComparator) qualifierFilter.getComparator();
282    assertEquals("pre*", new String(regexStringComparator.getValue(), StandardCharsets.UTF_8));
283    int regexComparatorFlags = regexStringComparator.getEngine().getFlags();
284    assertEquals(Pattern.CASE_INSENSITIVE | Pattern.DOTALL, regexComparatorFlags);
285  }
286
287  @Test
288  public void testValueFilter() throws IOException {
289    String filterString = "ValueFilter(!=, 'substring:pre')";
290    ValueFilter valueFilter = doTestFilter(filterString, ValueFilter.class);
291    assertEquals(CompareOperator.NOT_EQUAL, valueFilter.getCompareOperator());
292    assertTrue(valueFilter.getComparator() instanceof SubstringComparator);
293    SubstringComparator substringComparator = (SubstringComparator) valueFilter.getComparator();
294    assertEquals("pre", new String(substringComparator.getValue(), StandardCharsets.UTF_8));
295  }
296
297  @Test
298  public void testColumnRangeFilter() throws IOException {
299    String filterString = "ColumnRangeFilter('abc', true, 'xyz', false)";
300    ColumnRangeFilter columnRangeFilter = doTestFilter(filterString, ColumnRangeFilter.class);
301    assertEquals("abc", new String(columnRangeFilter.getMinColumn(), StandardCharsets.UTF_8));
302    assertEquals("xyz", new String(columnRangeFilter.getMaxColumn(), StandardCharsets.UTF_8));
303    assertTrue(columnRangeFilter.isMinColumnInclusive());
304    assertFalse(columnRangeFilter.isMaxColumnInclusive());
305  }
306
307  @Test
308  public void testDependentColumnFilter() throws IOException {
309    String filterString = "DependentColumnFilter('family', 'qualifier', true, =, 'binary:abc')";
310    DependentColumnFilter dependentColumnFilter =
311      doTestFilter(filterString, DependentColumnFilter.class);
312    assertEquals("family", new String(dependentColumnFilter.getFamily(), StandardCharsets.UTF_8));
313    assertEquals("qualifier",
314      new String(dependentColumnFilter.getQualifier(), StandardCharsets.UTF_8));
315    assertTrue(dependentColumnFilter.getDropDependentColumn());
316    assertEquals(CompareOperator.EQUAL, dependentColumnFilter.getCompareOperator());
317    assertTrue(dependentColumnFilter.getComparator() instanceof BinaryComparator);
318    BinaryComparator binaryComparator = (BinaryComparator) dependentColumnFilter.getComparator();
319    assertEquals("abc", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
320  }
321
322  @Test
323  public void testSingleColumnValueFilter() throws IOException {
324    String filterString =
325      "SingleColumnValueFilter " + "('family', 'qualifier', >=, 'binary:a', true, false)";
326    SingleColumnValueFilter singleColumnValueFilter =
327      doTestFilter(filterString, SingleColumnValueFilter.class);
328    assertEquals("family", new String(singleColumnValueFilter.getFamily(), StandardCharsets.UTF_8));
329    assertEquals("qualifier",
330      new String(singleColumnValueFilter.getQualifier(), StandardCharsets.UTF_8));
331    assertEquals(CompareOperator.GREATER_OR_EQUAL, singleColumnValueFilter.getCompareOperator());
332    assertTrue(singleColumnValueFilter.getComparator() instanceof BinaryComparator);
333    BinaryComparator binaryComparator = (BinaryComparator) singleColumnValueFilter.getComparator();
334    assertEquals("a", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
335    assertTrue(singleColumnValueFilter.getFilterIfMissing());
336    assertFalse(singleColumnValueFilter.getLatestVersionOnly());
337
338    filterString = "SingleColumnValueFilter ('family', 'qualifier', >, 'binaryprefix:a')";
339    singleColumnValueFilter = doTestFilter(filterString, SingleColumnValueFilter.class);
340    assertEquals("family", new String(singleColumnValueFilter.getFamily(), StandardCharsets.UTF_8));
341    assertEquals("qualifier",
342      new String(singleColumnValueFilter.getQualifier(), StandardCharsets.UTF_8));
343    assertEquals(CompareOperator.GREATER, singleColumnValueFilter.getCompareOperator());
344    assertTrue(singleColumnValueFilter.getComparator() instanceof BinaryPrefixComparator);
345    BinaryPrefixComparator binaryPrefixComparator =
346      (BinaryPrefixComparator) singleColumnValueFilter.getComparator();
347    assertEquals("a", new String(binaryPrefixComparator.getValue(), StandardCharsets.UTF_8));
348    assertFalse(singleColumnValueFilter.getFilterIfMissing());
349    assertTrue(singleColumnValueFilter.getLatestVersionOnly());
350  }
351
352  @Test
353  public void testSingleColumnValueExcludeFilter() throws IOException {
354    String filterString =
355      "SingleColumnValueExcludeFilter ('family', 'qualifier', <, 'binaryprefix:a')";
356    SingleColumnValueExcludeFilter singleColumnValueExcludeFilter =
357      doTestFilter(filterString, SingleColumnValueExcludeFilter.class);
358    assertEquals(CompareOperator.LESS, singleColumnValueExcludeFilter.getCompareOperator());
359    assertEquals("family",
360      new String(singleColumnValueExcludeFilter.getFamily(), StandardCharsets.UTF_8));
361    assertEquals("qualifier",
362      new String(singleColumnValueExcludeFilter.getQualifier(), StandardCharsets.UTF_8));
363    assertEquals("a", new String(singleColumnValueExcludeFilter.getComparator().getValue(),
364      StandardCharsets.UTF_8));
365    assertFalse(singleColumnValueExcludeFilter.getFilterIfMissing());
366    assertTrue(singleColumnValueExcludeFilter.getLatestVersionOnly());
367
368    filterString = "SingleColumnValueExcludeFilter "
369      + "('family', 'qualifier', <=, 'binaryprefix:a', true, false)";
370    singleColumnValueExcludeFilter =
371      doTestFilter(filterString, SingleColumnValueExcludeFilter.class);
372    assertEquals("family",
373      new String(singleColumnValueExcludeFilter.getFamily(), StandardCharsets.UTF_8));
374    assertEquals("qualifier",
375      new String(singleColumnValueExcludeFilter.getQualifier(), StandardCharsets.UTF_8));
376    assertEquals(CompareOperator.LESS_OR_EQUAL,
377      singleColumnValueExcludeFilter.getCompareOperator());
378    assertTrue(singleColumnValueExcludeFilter.getComparator() instanceof BinaryPrefixComparator);
379    BinaryPrefixComparator binaryPrefixComparator =
380      (BinaryPrefixComparator) singleColumnValueExcludeFilter.getComparator();
381    assertEquals("a", new String(binaryPrefixComparator.getValue(), StandardCharsets.UTF_8));
382    assertTrue(singleColumnValueExcludeFilter.getFilterIfMissing());
383    assertFalse(singleColumnValueExcludeFilter.getLatestVersionOnly());
384  }
385
386  @Test
387  public void testSkipFilter() throws IOException {
388    String filterString = "SKIP ValueFilter( =,  'binary:0')";
389    SkipFilter skipFilter = doTestFilter(filterString, SkipFilter.class);
390    assertTrue(skipFilter.getFilter() instanceof ValueFilter);
391    ValueFilter valueFilter = (ValueFilter) skipFilter.getFilter();
392
393    assertEquals(CompareOperator.EQUAL, valueFilter.getCompareOperator());
394    assertTrue(valueFilter.getComparator() instanceof BinaryComparator);
395    BinaryComparator binaryComparator = (BinaryComparator) valueFilter.getComparator();
396    assertEquals("0", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
397  }
398
399  @Test
400  public void testWhileFilter() throws IOException {
401    String filterString = " WHILE   RowFilter ( !=, 'binary:row1')";
402    WhileMatchFilter whileMatchFilter = doTestFilter(filterString, WhileMatchFilter.class);
403    assertTrue(whileMatchFilter.getFilter() instanceof RowFilter);
404    RowFilter rowFilter = (RowFilter) whileMatchFilter.getFilter();
405
406    assertEquals(CompareOperator.NOT_EQUAL, rowFilter.getCompareOperator());
407    assertTrue(rowFilter.getComparator() instanceof BinaryComparator);
408    BinaryComparator binaryComparator = (BinaryComparator) rowFilter.getComparator();
409    assertEquals("row1", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
410  }
411
412  @Test
413  public void testCompoundFilter1() throws IOException {
414    String filterString = " (PrefixFilter ('realtime')AND  FirstKeyOnlyFilter())";
415    FilterList filterList = doTestFilter(filterString, FilterList.class);
416    ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters();
417
418    assertTrue(filters.get(0) instanceof PrefixFilter);
419    assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter);
420    PrefixFilter PrefixFilter = (PrefixFilter) filters.get(0);
421    byte[] prefix = PrefixFilter.getPrefix();
422    assertEquals("realtime", new String(prefix, StandardCharsets.UTF_8));
423    FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1);
424  }
425
426  @Test
427  public void testCompoundFilter2() throws IOException {
428    String filterString = "(PrefixFilter('realtime') AND QualifierFilter (>=, 'binary:e'))"
429      + "OR FamilyFilter (=, 'binary:qualifier') ";
430    FilterList filterList = doTestFilter(filterString, FilterList.class);
431    ArrayList<Filter> filterListFilters = (ArrayList<Filter>) filterList.getFilters();
432    assertTrue(filterListFilters.get(0) instanceof FilterList);
433    assertTrue(filterListFilters.get(1) instanceof FamilyFilter);
434    assertEquals(FilterList.Operator.MUST_PASS_ONE, filterList.getOperator());
435
436    filterList = (FilterList) filterListFilters.get(0);
437    FamilyFilter familyFilter = (FamilyFilter) filterListFilters.get(1);
438
439    filterListFilters = (ArrayList<Filter>) filterList.getFilters();
440    assertTrue(filterListFilters.get(0) instanceof PrefixFilter);
441    assertTrue(filterListFilters.get(1) instanceof QualifierFilter);
442    assertEquals(FilterList.Operator.MUST_PASS_ALL, filterList.getOperator());
443
444    assertEquals(CompareOperator.EQUAL, familyFilter.getCompareOperator());
445    assertTrue(familyFilter.getComparator() instanceof BinaryComparator);
446    BinaryComparator binaryComparator = (BinaryComparator) familyFilter.getComparator();
447    assertEquals("qualifier", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
448
449    PrefixFilter prefixFilter = (PrefixFilter) filterListFilters.get(0);
450    byte[] prefix = prefixFilter.getPrefix();
451    assertEquals("realtime", new String(prefix, StandardCharsets.UTF_8));
452
453    QualifierFilter qualifierFilter = (QualifierFilter) filterListFilters.get(1);
454    assertEquals(CompareOperator.GREATER_OR_EQUAL, qualifierFilter.getCompareOperator());
455    assertTrue(qualifierFilter.getComparator() instanceof BinaryComparator);
456    binaryComparator = (BinaryComparator) qualifierFilter.getComparator();
457    assertEquals("e", new String(binaryComparator.getValue(), StandardCharsets.UTF_8));
458  }
459
460  @Test
461  public void testCompoundFilter3() throws IOException {
462    String filterString = " ColumnPrefixFilter ('realtime')AND  "
463      + "FirstKeyOnlyFilter() OR SKIP FamilyFilter(=, 'substring:hihi')";
464    FilterList filterList = doTestFilter(filterString, FilterList.class);
465    ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters();
466
467    assertTrue(filters.get(0) instanceof FilterList);
468    assertTrue(filters.get(1) instanceof SkipFilter);
469
470    filterList = (FilterList) filters.get(0);
471    SkipFilter skipFilter = (SkipFilter) filters.get(1);
472
473    filters = (ArrayList<Filter>) filterList.getFilters();
474    assertTrue(filters.get(0) instanceof ColumnPrefixFilter);
475    assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter);
476
477    ColumnPrefixFilter columnPrefixFilter = (ColumnPrefixFilter) filters.get(0);
478    byte[] columnPrefix = columnPrefixFilter.getPrefix();
479    assertEquals("realtime", new String(columnPrefix, StandardCharsets.UTF_8));
480
481    FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1);
482
483    assertTrue(skipFilter.getFilter() instanceof FamilyFilter);
484    FamilyFilter familyFilter = (FamilyFilter) skipFilter.getFilter();
485
486    assertEquals(CompareOperator.EQUAL, familyFilter.getCompareOperator());
487    assertTrue(familyFilter.getComparator() instanceof SubstringComparator);
488    SubstringComparator substringComparator = (SubstringComparator) familyFilter.getComparator();
489    assertEquals("hihi", new String(substringComparator.getValue(), StandardCharsets.UTF_8));
490  }
491
492  @Test
493  public void testCompoundFilter4() throws IOException {
494    String filterString = " ColumnPrefixFilter ('realtime') OR "
495      + "FirstKeyOnlyFilter() OR SKIP FamilyFilter(=, 'substring:hihi')";
496    FilterList filterList = doTestFilter(filterString, FilterList.class);
497    ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters();
498
499    assertTrue(filters.get(0) instanceof ColumnPrefixFilter);
500    assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter);
501    assertTrue(filters.get(2) instanceof SkipFilter);
502
503    ColumnPrefixFilter columnPrefixFilter = (ColumnPrefixFilter) filters.get(0);
504    FirstKeyOnlyFilter firstKeyOnlyFilter = (FirstKeyOnlyFilter) filters.get(1);
505    SkipFilter skipFilter = (SkipFilter) filters.get(2);
506
507    byte[] columnPrefix = columnPrefixFilter.getPrefix();
508    assertEquals("realtime", new String(columnPrefix, StandardCharsets.UTF_8));
509
510    assertTrue(skipFilter.getFilter() instanceof FamilyFilter);
511    FamilyFilter familyFilter = (FamilyFilter) skipFilter.getFilter();
512
513    assertEquals(CompareOperator.EQUAL, familyFilter.getCompareOperator());
514    assertTrue(familyFilter.getComparator() instanceof SubstringComparator);
515    SubstringComparator substringComparator = (SubstringComparator) familyFilter.getComparator();
516    assertEquals("hihi", new String(substringComparator.getValue(), StandardCharsets.UTF_8));
517  }
518
519  @Test
520  public void testCompoundFilter5() throws IOException {
521    String filterStr = "(ValueFilter(!=, 'substring:pre'))";
522    ValueFilter valueFilter = doTestFilter(filterStr, ValueFilter.class);
523    assertTrue(valueFilter.getComparator() instanceof SubstringComparator);
524
525    filterStr = "(ValueFilter(>=,'binary:x') AND (ValueFilter(<=,'binary:y')))"
526      + " OR ValueFilter(=,'binary:ab')";
527    filter = f.parseFilterString(filterStr);
528    assertTrue(filter instanceof FilterList);
529    List<Filter> list = ((FilterList) filter).getFilters();
530    assertEquals(2, list.size());
531    assertTrue(list.get(0) instanceof FilterList);
532    assertTrue(list.get(1) instanceof ValueFilter);
533  }
534
535  @Test
536  public void testIncorrectCompareOperator() throws IOException {
537    String filterString = "RowFilter ('>>' , 'binary:region')";
538    try {
539      doTestFilter(filterString, RowFilter.class);
540      assertTrue(false);
541    } catch (IllegalArgumentException e) {
542      System.out.println("Incorrect compare operator >>");
543    }
544  }
545
546  @Test
547  public void testIncorrectComparatorType() throws IOException {
548    String filterString = "RowFilter ('>=' , 'binaryoperator:region')";
549    try {
550      doTestFilter(filterString, RowFilter.class);
551      assertTrue(false);
552    } catch (IllegalArgumentException e) {
553      System.out.println("Incorrect comparator type: binaryoperator");
554    }
555
556    filterString = "RowFilter ('>=' 'regexstring:pre*')";
557    try {
558      doTestFilter(filterString, RowFilter.class);
559      assertTrue(false);
560    } catch (IllegalArgumentException e) {
561      System.out.println("RegexStringComparator can only be used with EQUAL or NOT_EQUAL");
562    }
563
564    filterString = "SingleColumnValueFilter"
565      + " ('family', 'qualifier', '>=', 'substring:a', 'true', 'false')')";
566    try {
567      doTestFilter(filterString, RowFilter.class);
568      assertTrue(false);
569    } catch (IllegalArgumentException e) {
570      System.out.println("SubtringComparator can only be used with EQUAL or NOT_EQUAL");
571    }
572  }
573
574  @Test
575  public void testPrecedence1() throws IOException {
576    String filterString =
577      " (PrefixFilter ('realtime')AND  FirstKeyOnlyFilter()" + " OR KeyOnlyFilter())";
578    FilterList filterList = doTestFilter(filterString, FilterList.class);
579
580    ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters();
581
582    assertTrue(filters.get(0) instanceof FilterList);
583    assertTrue(filters.get(1) instanceof KeyOnlyFilter);
584
585    filterList = (FilterList) filters.get(0);
586    filters = (ArrayList<Filter>) filterList.getFilters();
587
588    assertTrue(filters.get(0) instanceof PrefixFilter);
589    assertTrue(filters.get(1) instanceof FirstKeyOnlyFilter);
590
591    PrefixFilter prefixFilter = (PrefixFilter) filters.get(0);
592    byte[] prefix = prefixFilter.getPrefix();
593    assertEquals("realtime", new String(prefix, StandardCharsets.UTF_8));
594  }
595
596  @Test
597  public void testPrecedence2() throws IOException {
598    String filterString =
599      " PrefixFilter ('realtime')AND  SKIP FirstKeyOnlyFilter()" + "OR KeyOnlyFilter()";
600    FilterList filterList = doTestFilter(filterString, FilterList.class);
601    ArrayList<Filter> filters = (ArrayList<Filter>) filterList.getFilters();
602
603    assertTrue(filters.get(0) instanceof FilterList);
604    assertTrue(filters.get(1) instanceof KeyOnlyFilter);
605
606    filterList = (FilterList) filters.get(0);
607    filters = (ArrayList<Filter>) filterList.getFilters();
608
609    assertTrue(filters.get(0) instanceof PrefixFilter);
610    assertTrue(filters.get(1) instanceof SkipFilter);
611
612    PrefixFilter prefixFilter = (PrefixFilter) filters.get(0);
613    byte[] prefix = prefixFilter.getPrefix();
614    assertEquals("realtime", new String(prefix, StandardCharsets.UTF_8));
615
616    SkipFilter skipFilter = (SkipFilter) filters.get(1);
617    assertTrue(skipFilter.getFilter() instanceof FirstKeyOnlyFilter);
618  }
619
620  @Test
621  public void testUnescapedQuote1() throws IOException {
622    String filterString = "InclusiveStopFilter ('row''3')";
623    InclusiveStopFilter inclusiveStopFilter = doTestFilter(filterString, InclusiveStopFilter.class);
624    byte[] stopRowKey = inclusiveStopFilter.getStopRowKey();
625    assertEquals("row'3", new String(stopRowKey, StandardCharsets.UTF_8));
626  }
627
628  @Test
629  public void testUnescapedQuote2() throws IOException {
630    String filterString = "InclusiveStopFilter ('row''3''')";
631    InclusiveStopFilter inclusiveStopFilter = doTestFilter(filterString, InclusiveStopFilter.class);
632    byte[] stopRowKey = inclusiveStopFilter.getStopRowKey();
633    assertEquals("row'3'", new String(stopRowKey, StandardCharsets.UTF_8));
634  }
635
636  @Test
637  public void testUnescapedQuote3() throws IOException {
638    String filterString = " InclusiveStopFilter ('''')";
639    InclusiveStopFilter inclusiveStopFilter = doTestFilter(filterString, InclusiveStopFilter.class);
640    byte[] stopRowKey = inclusiveStopFilter.getStopRowKey();
641    assertEquals("'", new String(stopRowKey, StandardCharsets.UTF_8));
642  }
643
644  @Test
645  public void testIncorrectFilterString() throws IOException {
646    String filterString = "()";
647    byte[] filterStringAsByteArray = Bytes.toBytes(filterString);
648    try {
649      filter = f.parseFilterString(filterStringAsByteArray);
650      assertTrue(false);
651    } catch (IllegalArgumentException e) {
652      System.out.println(e.getMessage());
653    }
654  }
655
656  @Test
657  public void testCorrectFilterString() throws IOException {
658    String filterString = "(FirstKeyOnlyFilter())";
659    FirstKeyOnlyFilter firstKeyOnlyFilter = doTestFilter(filterString, FirstKeyOnlyFilter.class);
660  }
661
662  @Test
663  public void testRegisterFilter() {
664    ParseFilter.registerFilter("MyFilter", "some.class");
665
666    assertTrue(f.getSupportedFilters().contains("MyFilter"));
667  }
668
669  private <T extends Filter> T doTestFilter(String filterString, Class<T> clazz)
670    throws IOException {
671    byte[] filterStringAsByteArray = Bytes.toBytes(filterString);
672    filter = f.parseFilterString(filterStringAsByteArray);
673    assertEquals(clazz, filter.getClass());
674    return clazz.cast(filter);
675  }
676
677  @Test
678  public void testColumnValueFilter() throws IOException {
679    String filterString = "ColumnValueFilter ('family', 'qualifier', <, 'binaryprefix:value')";
680    ColumnValueFilter cvf = doTestFilter(filterString, ColumnValueFilter.class);
681    assertEquals("family", new String(cvf.getFamily(), StandardCharsets.UTF_8));
682    assertEquals("qualifier", new String(cvf.getQualifier(), StandardCharsets.UTF_8));
683    assertEquals(CompareOperator.LESS, cvf.getCompareOperator());
684    assertTrue(cvf.getComparator() instanceof BinaryPrefixComparator);
685    assertEquals("value", new String(cvf.getComparator().getValue(), StandardCharsets.UTF_8));
686  }
687}