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}