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.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertNull;
022import static org.junit.jupiter.api.Assertions.assertThrows;
023import static org.junit.jupiter.api.Assertions.assertTrue;
024import static org.junit.jupiter.api.Assertions.fail;
025
026import java.io.IOException;
027import java.util.Arrays;
028import java.util.Set;
029import org.apache.commons.lang3.builder.EqualsBuilder;
030import org.apache.hadoop.hbase.HConstants;
031import org.apache.hadoop.hbase.client.Scan.ReadType;
032import org.apache.hadoop.hbase.filter.FilterList;
033import org.apache.hadoop.hbase.filter.IncompatibleFilterException;
034import org.apache.hadoop.hbase.filter.PageFilter;
035import org.apache.hadoop.hbase.security.access.Permission;
036import org.apache.hadoop.hbase.security.visibility.Authorizations;
037import org.apache.hadoop.hbase.testclassification.ClientTests;
038import org.apache.hadoop.hbase.testclassification.SmallTests;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.junit.jupiter.api.Tag;
041import org.junit.jupiter.api.Test;
042
043import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
044import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
045
046// TODO: cover more test cases
047@Tag(ClientTests.TAG)
048@Tag(SmallTests.TAG)
049public class TestScan {
050
051  @Test
052  public void testAttributesSerialization() throws IOException {
053    Scan scan = new Scan();
054    scan.setAttribute("attribute1", Bytes.toBytes("value1"));
055    scan.setAttribute("attribute2", Bytes.toBytes("value2"));
056    scan.setAttribute("attribute3", Bytes.toBytes("value3"));
057
058    ClientProtos.Scan scanProto = ProtobufUtil.toScan(scan);
059
060    Scan scan2 = ProtobufUtil.toScan(scanProto);
061
062    assertNull(scan2.getAttribute("absent"));
063    assertTrue(Arrays.equals(Bytes.toBytes("value1"), scan2.getAttribute("attribute1")));
064    assertTrue(Arrays.equals(Bytes.toBytes("value2"), scan2.getAttribute("attribute2")));
065    assertTrue(Arrays.equals(Bytes.toBytes("value3"), scan2.getAttribute("attribute3")));
066    assertEquals(3, scan2.getAttributesMap().size());
067  }
068
069  @Test
070  public void testGetToScan() throws Exception {
071    Get get = new Get(Bytes.toBytes(1));
072    get.setCacheBlocks(true).setConsistency(Consistency.TIMELINE).setFilter(new FilterList())
073      .setId("get").setIsolationLevel(IsolationLevel.READ_COMMITTED)
074      .setLoadColumnFamiliesOnDemand(false).setMaxResultsPerColumnFamily(1000).readVersions(9999)
075      .setRowOffsetPerColumnFamily(5).setTimeRange(0, 13)
076      .setAttribute("att_v0", Bytes.toBytes("att_v0"))
077      .setColumnFamilyTimeRange(Bytes.toBytes("cf"), 0, 123).setReplicaId(3)
078      .setACL("test_user", new Permission(Permission.Action.READ))
079      .setAuthorizations(new Authorizations("test_label")).setQueryMetricsEnabled(true)
080      .setPriority(3);
081
082    Scan scan = new Scan(get);
083    assertEquals(get.getCacheBlocks(), scan.getCacheBlocks());
084    assertEquals(get.getConsistency(), scan.getConsistency());
085    assertEquals(get.getFilter(), scan.getFilter());
086    assertEquals(get.getId(), scan.getId());
087    assertEquals(get.getIsolationLevel(), scan.getIsolationLevel());
088    assertEquals(get.getLoadColumnFamiliesOnDemandValue(),
089      scan.getLoadColumnFamiliesOnDemandValue());
090    assertEquals(get.getMaxResultsPerColumnFamily(), scan.getMaxResultsPerColumnFamily());
091    assertEquals(get.getMaxVersions(), scan.getMaxVersions());
092    assertEquals(get.getRowOffsetPerColumnFamily(), scan.getRowOffsetPerColumnFamily());
093    assertEquals(get.getTimeRange().getMin(), scan.getTimeRange().getMin());
094    assertEquals(get.getTimeRange().getMax(), scan.getTimeRange().getMax());
095    assertTrue(Bytes.equals(get.getAttribute("att_v0"), scan.getAttribute("att_v0")));
096    assertEquals(get.getColumnFamilyTimeRange().get(Bytes.toBytes("cf")).getMin(),
097      scan.getColumnFamilyTimeRange().get(Bytes.toBytes("cf")).getMin());
098    assertEquals(get.getColumnFamilyTimeRange().get(Bytes.toBytes("cf")).getMax(),
099      scan.getColumnFamilyTimeRange().get(Bytes.toBytes("cf")).getMax());
100    assertEquals(get.getReplicaId(), scan.getReplicaId());
101    assertEquals(get.getACL(), scan.getACL());
102    assertEquals(get.getAuthorizations().getLabels(), scan.getAuthorizations().getLabels());
103    assertEquals(get.getPriority(), scan.getPriority());
104    assertEquals(get.isQueryMetricsEnabled(), scan.isQueryMetricsEnabled());
105  }
106
107  @Test
108  public void testScanAttributes() {
109    Scan scan = new Scan();
110    assertTrue(scan.getAttributesMap().isEmpty());
111    assertNull(scan.getAttribute("absent"));
112
113    scan.setAttribute("absent", null);
114    assertTrue(scan.getAttributesMap().isEmpty());
115    assertNull(scan.getAttribute("absent"));
116
117    // adding attribute
118    scan.setAttribute("attribute1", Bytes.toBytes("value1"));
119    assertTrue(Arrays.equals(Bytes.toBytes("value1"), scan.getAttribute("attribute1")));
120    assertEquals(1, scan.getAttributesMap().size());
121    assertTrue(Arrays.equals(Bytes.toBytes("value1"), scan.getAttributesMap().get("attribute1")));
122
123    // overriding attribute value
124    scan.setAttribute("attribute1", Bytes.toBytes("value12"));
125    assertTrue(Arrays.equals(Bytes.toBytes("value12"), scan.getAttribute("attribute1")));
126    assertEquals(1, scan.getAttributesMap().size());
127    assertTrue(Arrays.equals(Bytes.toBytes("value12"), scan.getAttributesMap().get("attribute1")));
128
129    // adding another attribute
130    scan.setAttribute("attribute2", Bytes.toBytes("value2"));
131    assertTrue(Arrays.equals(Bytes.toBytes("value2"), scan.getAttribute("attribute2")));
132    assertEquals(2, scan.getAttributesMap().size());
133    assertTrue(Arrays.equals(Bytes.toBytes("value2"), scan.getAttributesMap().get("attribute2")));
134
135    // removing attribute
136    scan.setAttribute("attribute2", null);
137    assertNull(scan.getAttribute("attribute2"));
138    assertEquals(1, scan.getAttributesMap().size());
139    assertNull(scan.getAttributesMap().get("attribute2"));
140
141    // removing non-existed attribute
142    scan.setAttribute("attribute2", null);
143    assertNull(scan.getAttribute("attribute2"));
144    assertEquals(1, scan.getAttributesMap().size());
145    assertNull(scan.getAttributesMap().get("attribute2"));
146
147    // removing another attribute
148    scan.setAttribute("attribute1", null);
149    assertNull(scan.getAttribute("attribute1"));
150    assertTrue(scan.getAttributesMap().isEmpty());
151    assertNull(scan.getAttributesMap().get("attribute1"));
152  }
153
154  @Test
155  public void testNullQualifier() {
156    Scan scan = new Scan();
157    byte[] family = Bytes.toBytes("family");
158    scan.addColumn(family, null);
159    Set<byte[]> qualifiers = scan.getFamilyMap().get(family);
160    assertEquals(1, qualifiers.size());
161  }
162
163  @Test
164  public void testSetAuthorizations() {
165    Scan scan = new Scan();
166    scan.setAuthorizations(new Authorizations("A", "B", "0123", "A0", "1A1", "_a"));
167    scan.setAuthorizations(new Authorizations("A|B"));
168    scan.setAuthorizations(new Authorizations("A&B"));
169    scan.setAuthorizations(new Authorizations("!B"));
170    scan.setAuthorizations(new Authorizations("A", "(A)"));
171    scan.setAuthorizations(new Authorizations("A", "{A"));
172    scan.setAuthorizations(new Authorizations(" "));
173    scan.setAuthorizations(new Authorizations(":B"));
174    scan.setAuthorizations(new Authorizations("-B"));
175    scan.setAuthorizations(new Authorizations(".B"));
176    scan.setAuthorizations(new Authorizations("/B"));
177  }
178
179  @Test
180  public void testSetStartRowAndSetStopRow() {
181    Scan scan = new Scan();
182    scan.withStartRow(null);
183    scan.withStartRow(new byte[1]);
184    scan.withStartRow(new byte[HConstants.MAX_ROW_LENGTH]);
185    try {
186      scan.withStartRow(new byte[HConstants.MAX_ROW_LENGTH + 1]);
187      fail("should've thrown exception");
188    } catch (IllegalArgumentException iae) {
189      // Expected
190    }
191
192    scan.withStopRow(null);
193    scan.withStopRow(new byte[1]);
194    scan.withStopRow(new byte[HConstants.MAX_ROW_LENGTH]);
195    try {
196      scan.withStopRow(new byte[HConstants.MAX_ROW_LENGTH + 1]);
197      fail("should've thrown exception");
198    } catch (IllegalArgumentException iae) {
199      // Expected
200    }
201  }
202
203  @Test
204  public void testScanCopyConstructor() throws Exception {
205    Scan scan = new Scan();
206
207    scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q"))
208      .setACL("test_user", new Permission(Permission.Action.READ)).setAllowPartialResults(true)
209      .setAsyncPrefetch(false).setAttribute("test_key", Bytes.toBytes("test_value"))
210      .setAuthorizations(new Authorizations("test_label")).setBatch(10).setCacheBlocks(false)
211      .setCaching(10).setConsistency(Consistency.TIMELINE).setFilter(new FilterList())
212      .setId("scan_copy_constructor").setIsolationLevel(IsolationLevel.READ_COMMITTED).setLimit(100)
213      .setLoadColumnFamiliesOnDemand(false).setMaxResultSize(100).setMaxResultsPerColumnFamily(1000)
214      .readVersions(9999).setMvccReadPoint(5).setNeedCursorResult(true).setPriority(1).setRaw(true)
215      .setReplicaId(3).setReversed(true).setRowOffsetPerColumnFamily(5)
216      .setStartStopRowForPrefixScan(Bytes.toBytes("row_")).setScanMetricsEnabled(true)
217      .setReadType(ReadType.STREAM).withStartRow(Bytes.toBytes("row_1"))
218      .withStopRow(Bytes.toBytes("row_2")).setTimeRange(0, 13).setQueryMetricsEnabled(true);
219
220    // create a copy of existing scan object
221    Scan scanCopy = new Scan(scan);
222
223    // validate fields of copied scan object match with the original scan object
224    assertEquals(scan.getACL(), scanCopy.getACL());
225    assertEquals(scan.getAllowPartialResults(), scanCopy.getAllowPartialResults());
226    assertEquals(scan.getAttribute("test_key"), scanCopy.getAttribute("test_key"));
227    assertEquals(scan.getAttributeSize(), scanCopy.getAttributeSize());
228    assertEquals(scan.getAttributesMap(), scanCopy.getAttributesMap());
229    assertEquals(scan.getAuthorizations().getLabels(), scanCopy.getAuthorizations().getLabels());
230    assertEquals(scan.getBatch(), scanCopy.getBatch());
231    assertEquals(scan.getCacheBlocks(), scanCopy.getCacheBlocks());
232    assertEquals(scan.getCaching(), scanCopy.getCaching());
233    assertEquals(scan.getConsistency(), scanCopy.getConsistency());
234    assertEquals(scan.getFamilies().length, scanCopy.getFamilies().length);
235    assertEquals(scan.getFamilies()[0], scanCopy.getFamilies()[0]);
236    assertEquals(scan.getFamilyMap(), scanCopy.getFamilyMap());
237    assertEquals(scan.getFilter(), scanCopy.getFilter());
238    assertEquals(scan.getId(), scanCopy.getId());
239    assertEquals(scan.getIsolationLevel(), scanCopy.getIsolationLevel());
240    assertEquals(scan.getLimit(), scanCopy.getLimit());
241    assertEquals(scan.getLoadColumnFamiliesOnDemandValue(),
242      scanCopy.getLoadColumnFamiliesOnDemandValue());
243    assertEquals(scan.getMaxResultSize(), scanCopy.getMaxResultSize());
244    assertEquals(scan.getMaxResultsPerColumnFamily(), scanCopy.getMaxResultsPerColumnFamily());
245    assertEquals(scan.getMaxVersions(), scanCopy.getMaxVersions());
246    assertEquals(scan.getMvccReadPoint(), scanCopy.getMvccReadPoint());
247    assertEquals(scan.getPriority(), scanCopy.getPriority());
248    assertEquals(scan.getReadType(), scanCopy.getReadType());
249    assertEquals(scan.getReplicaId(), scanCopy.getReplicaId());
250    assertEquals(scan.getRowOffsetPerColumnFamily(), scanCopy.getRowOffsetPerColumnFamily());
251    assertEquals(scan.getStartRow(), scanCopy.getStartRow());
252    assertEquals(scan.getStopRow(), scanCopy.getStopRow());
253    assertEquals(scan.getTimeRange(), scanCopy.getTimeRange());
254    assertEquals(scan.isQueryMetricsEnabled(), scanCopy.isQueryMetricsEnabled());
255
256    assertTrue(EqualsBuilder.reflectionEquals(scan, scanCopy),
257      "Make sure copy constructor adds all the fields in the copied object");
258  }
259
260  @Test
261  public void testSetFilterWithBatchThrows() {
262    Scan scan = new Scan();
263    scan.setBatch(5);
264    assertThrows(IncompatibleFilterException.class, () -> scan.setFilter(new PageFilter(10)));
265  }
266
267  @Test
268  public void testSetFilterWithoutBatchDoesNotThrow() {
269    Scan scan = new Scan();
270    scan.setFilter(new PageFilter(10));
271    // no exception expected
272  }
273
274  @Test
275  public void testSetFilterWithBatchAndNonFilterRowFilter() {
276    Scan scan = new Scan();
277    scan.setBatch(5);
278    scan.setFilter(new FilterList());
279    // FilterList.hasFilterRow() returns false, so no exception expected
280  }
281
282  @Test
283  public void testSetFilterWithBatchAndNullFilter() {
284    Scan scan = new Scan();
285    scan.setBatch(5);
286    scan.setFilter(null);
287    // null filter should not throw
288  }
289
290  @Test
291  public void testScanReadType() throws Exception {
292    Scan scan = new Scan();
293    assertEquals(ReadType.DEFAULT, scan.getReadType());
294    Scan copyScan = new Scan(scan);
295    assertEquals(ReadType.DEFAULT, copyScan.getReadType());
296  }
297}