001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.apache.hadoop.hbase.client; 021 022import java.io.IOException; 023import java.lang.reflect.InvocationTargetException; 024import java.lang.reflect.Method; 025import java.util.Collections; 026import java.util.Map; 027import org.apache.commons.lang3.builder.EqualsBuilder; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.filter.Filter; 030import org.apache.hadoop.hbase.filter.FilterList; 031import org.apache.hadoop.hbase.security.access.Permission; 032import org.apache.hadoop.hbase.security.visibility.Authorizations; 033import org.apache.hadoop.hbase.testclassification.ClientTests; 034import org.apache.hadoop.hbase.testclassification.SmallTests; 035import org.apache.hadoop.hbase.util.Bytes; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039import org.mockito.Mockito; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042import static org.junit.Assert.assertArrayEquals; 043import static org.junit.Assert.assertEquals; 044 045/** 046 * Small tests for ImmutableScan 047 */ 048@Category({ ClientTests.class, SmallTests.class }) 049public class TestImmutableScan { 050 051 @ClassRule 052 public static final HBaseClassTestRule CLASS_RULE = 053 HBaseClassTestRule.forClass(TestImmutableScan.class); 054 055 private static final Logger LOG = LoggerFactory.getLogger(TestImmutableScan.class); 056 057 @Test 058 public void testScanCopyConstructor() throws Exception { 059 Scan scan = new Scan(); 060 061 scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("q")) 062 .setACL("test_user2", new Permission(Permission.Action.READ)) 063 .setAllowPartialResults(true) 064 .setAsyncPrefetch(false) 065 .setAttribute("test_key", Bytes.toBytes("test_value")) 066 .setAuthorizations(new Authorizations("test_label")) 067 .setBatch(10) 068 .setCacheBlocks(false) 069 .setCaching(10) 070 .setConsistency(Consistency.TIMELINE) 071 .setFilter(new FilterList()) 072 .setId("scan_copy_constructor") 073 .setIsolationLevel(IsolationLevel.READ_COMMITTED) 074 .setLimit(100) 075 .setLoadColumnFamiliesOnDemand(false) 076 .setMaxResultSize(100) 077 .setMaxResultsPerColumnFamily(1000) 078 .readVersions(9999) 079 .setMvccReadPoint(5) 080 .setNeedCursorResult(true) 081 .setPriority(1) 082 .setRaw(true) 083 .setReplicaId(3) 084 .setReversed(true) 085 .setRowOffsetPerColumnFamily(5) 086 .setRowPrefixFilter(Bytes.toBytes("row_")) 087 .setScanMetricsEnabled(true) 088 .setSmall(true) 089 .setReadType(Scan.ReadType.STREAM) 090 .withStartRow(Bytes.toBytes("row_1")) 091 .withStopRow(Bytes.toBytes("row_2")) 092 .setTimeRange(0, 13); 093 094 // create a copy of existing scan object 095 Scan scanCopy = new ImmutableScan(scan); 096 097 // validate fields of copied scan object match with the original scan object 098 assertArrayEquals(scan.getACL(), scanCopy.getACL()); 099 assertEquals(scan.getAllowPartialResults(), scanCopy.getAllowPartialResults()); 100 assertArrayEquals(scan.getAttribute("test_key"), scanCopy.getAttribute("test_key")); 101 assertEquals(scan.getAttributeSize(), scanCopy.getAttributeSize()); 102 assertEquals(scan.getAttributesMap(), scanCopy.getAttributesMap()); 103 assertEquals(scan.getAuthorizations().getLabels(), scanCopy.getAuthorizations().getLabels()); 104 assertEquals(scan.getBatch(), scanCopy.getBatch()); 105 assertEquals(scan.getCacheBlocks(), scanCopy.getCacheBlocks()); 106 assertEquals(scan.getCaching(), scanCopy.getCaching()); 107 assertEquals(scan.getConsistency(), scanCopy.getConsistency()); 108 assertEquals(scan.getFamilies().length, scanCopy.getFamilies().length); 109 assertArrayEquals(scan.getFamilies()[0], scanCopy.getFamilies()[0]); 110 assertEquals(scan.getFamilyMap(), scanCopy.getFamilyMap()); 111 assertEquals(scan.getFilter(), scanCopy.getFilter()); 112 assertEquals(scan.getId(), scanCopy.getId()); 113 assertEquals(scan.getIsolationLevel(), scanCopy.getIsolationLevel()); 114 assertEquals(scan.getLimit(), scanCopy.getLimit()); 115 assertEquals(scan.getLoadColumnFamiliesOnDemandValue(), 116 scanCopy.getLoadColumnFamiliesOnDemandValue()); 117 assertEquals(scan.getMaxResultSize(), scanCopy.getMaxResultSize()); 118 assertEquals(scan.getMaxResultsPerColumnFamily(), scanCopy.getMaxResultsPerColumnFamily()); 119 assertEquals(scan.getMaxVersions(), scanCopy.getMaxVersions()); 120 assertEquals(scan.getMvccReadPoint(), scanCopy.getMvccReadPoint()); 121 assertEquals(scan.getPriority(), scanCopy.getPriority()); 122 assertEquals(scan.getReadType(), scanCopy.getReadType()); 123 assertEquals(scan.getReplicaId(), scanCopy.getReplicaId()); 124 assertEquals(scan.getRowOffsetPerColumnFamily(), scanCopy.getRowOffsetPerColumnFamily()); 125 assertArrayEquals(scan.getStartRow(), scanCopy.getStartRow()); 126 assertArrayEquals(scan.getStopRow(), scanCopy.getStopRow()); 127 assertEquals(scan.getTimeRange(), scanCopy.getTimeRange()); 128 assertEquals(scan.getFingerprint(), scanCopy.getFingerprint()); 129 assertEquals(scan.toMap(1), scanCopy.toMap(1)); 130 assertEquals(scan.toString(2), scanCopy.toString(2)); 131 assertEquals(scan.toJSON(2), scanCopy.toJSON(2)); 132 133 LOG.debug("Compare all getters of scan and scanCopy."); 134 compareGetters(scan, scanCopy); 135 136 testUnmodifiableSetters(scanCopy); 137 } 138 139 private void testUnmodifiableSetters(Scan scanCopy) throws IOException { 140 try { 141 scanCopy.setFilter(Mockito.mock(Filter.class)); 142 throw new RuntimeException("Should not reach here"); 143 } catch (UnsupportedOperationException e) { 144 assertEquals("ImmutableScan does not allow access to setFilter", e.getMessage()); 145 } 146 try { 147 scanCopy.addFamily(new byte[] { 0, 1 }); 148 throw new RuntimeException("Should not reach here"); 149 } catch (UnsupportedOperationException e) { 150 assertEquals("ImmutableScan does not allow access to addFamily", e.getMessage()); 151 } 152 try { 153 scanCopy.addColumn(new byte[] { 0, 1 }, new byte[] { 2, 3 }); 154 throw new RuntimeException("Should not reach here"); 155 } catch (UnsupportedOperationException e) { 156 assertEquals("ImmutableScan does not allow access to addColumn", e.getMessage()); 157 } 158 try { 159 scanCopy.setTimeRange(1L, 2L); 160 throw new RuntimeException("Should not reach here"); 161 } catch (UnsupportedOperationException e) { 162 assertEquals("ImmutableScan does not allow access to setTimeRange", e.getMessage()); 163 } 164 try { 165 scanCopy.setTimestamp(1L); 166 throw new RuntimeException("Should not reach here"); 167 } catch (UnsupportedOperationException e) { 168 assertEquals("ImmutableScan does not allow access to setTimestamp", e.getMessage()); 169 } 170 try { 171 scanCopy.setColumnFamilyTimeRange(new byte[] { 0 }, 1L, 2L); 172 throw new RuntimeException("Should not reach here"); 173 } catch (UnsupportedOperationException e) { 174 assertEquals("ImmutableScan does not allow access to setColumnFamilyTimeRange", 175 e.getMessage()); 176 } 177 try { 178 scanCopy.withStopRow(new byte[] { 1, 2 }); 179 throw new RuntimeException("Should not reach here"); 180 } catch (UnsupportedOperationException e) { 181 assertEquals("ImmutableScan does not allow access to withStopRow", e.getMessage()); 182 } 183 try { 184 scanCopy.setRowPrefixFilter(new byte[] { 1, 2 }); 185 throw new RuntimeException("Should not reach here"); 186 } catch (UnsupportedOperationException e) { 187 assertEquals("ImmutableScan does not allow access to setRowPrefixFilter", e.getMessage()); 188 } 189 try { 190 scanCopy.readAllVersions(); 191 throw new RuntimeException("Should not reach here"); 192 } catch (UnsupportedOperationException e) { 193 assertEquals("ImmutableScan does not allow access to readAllVersions", e.getMessage()); 194 } 195 try { 196 scanCopy.setBatch(1); 197 throw new RuntimeException("Should not reach here"); 198 } catch (UnsupportedOperationException e) { 199 assertEquals("ImmutableScan does not allow access to setBatch", e.getMessage()); 200 } 201 try { 202 scanCopy.setRowOffsetPerColumnFamily(1); 203 throw new RuntimeException("Should not reach here"); 204 } catch (UnsupportedOperationException e) { 205 assertEquals("ImmutableScan does not allow access to setRowOffsetPerColumnFamily", 206 e.getMessage()); 207 } 208 try { 209 scanCopy.setCaching(1); 210 throw new RuntimeException("Should not reach here"); 211 } catch (UnsupportedOperationException e) { 212 assertEquals("ImmutableScan does not allow access to setCaching", 213 e.getMessage()); 214 } 215 try { 216 scanCopy.setLoadColumnFamiliesOnDemand(true); 217 throw new RuntimeException("Should not reach here"); 218 } catch (UnsupportedOperationException e) { 219 assertEquals("ImmutableScan does not allow access to setLoadColumnFamiliesOnDemand", 220 e.getMessage()); 221 } 222 try { 223 scanCopy.setRaw(true); 224 throw new RuntimeException("Should not reach here"); 225 } catch (UnsupportedOperationException e) { 226 assertEquals("ImmutableScan does not allow access to setRaw", e.getMessage()); 227 } 228 try { 229 scanCopy.setAuthorizations(new Authorizations("test")); 230 throw new RuntimeException("Should not reach here"); 231 } catch (UnsupportedOperationException e) { 232 assertEquals("ImmutableScan does not allow access to setAuthorizations", e.getMessage()); 233 } 234 try { 235 scanCopy.setACL("user1", new Permission(Permission.Action.READ)); 236 throw new RuntimeException("Should not reach here"); 237 } catch (UnsupportedOperationException e) { 238 assertEquals("ImmutableScan does not allow access to setACL", e.getMessage()); 239 } 240 try { 241 scanCopy.setReplicaId(12); 242 throw new RuntimeException("Should not reach here"); 243 } catch (UnsupportedOperationException e) { 244 assertEquals("ImmutableScan does not allow access to setReplicaId", e.getMessage()); 245 } 246 try { 247 scanCopy.setReadType(Scan.ReadType.STREAM); 248 throw new RuntimeException("Should not reach here"); 249 } catch (UnsupportedOperationException e) { 250 assertEquals("ImmutableScan does not allow access to setReadType", e.getMessage()); 251 } 252 try { 253 scanCopy.setOneRowLimit(); 254 throw new RuntimeException("Should not reach here"); 255 } catch (UnsupportedOperationException e) { 256 assertEquals("ImmutableScan does not allow access to setOneRowLimit", e.getMessage()); 257 } 258 try { 259 scanCopy.setNeedCursorResult(false); 260 throw new RuntimeException("Should not reach here"); 261 } catch (UnsupportedOperationException e) { 262 assertEquals("ImmutableScan does not allow access to setNeedCursorResult", e.getMessage()); 263 } 264 try { 265 scanCopy.resetMvccReadPoint(); 266 throw new RuntimeException("Should not reach here"); 267 } catch (UnsupportedOperationException e) { 268 assertEquals("ImmutableScan does not allow access to resetMvccReadPoint", e.getMessage()); 269 } 270 try { 271 scanCopy.setMvccReadPoint(1L); 272 throw new RuntimeException("Should not reach here"); 273 } catch (UnsupportedOperationException e) { 274 assertEquals("ImmutableScan does not allow access to setMvccReadPoint", e.getMessage()); 275 } 276 try { 277 scanCopy.setIsolationLevel(IsolationLevel.READ_UNCOMMITTED); 278 throw new RuntimeException("Should not reach here"); 279 } catch (UnsupportedOperationException e) { 280 assertEquals("ImmutableScan does not allow access to setIsolationLevel", e.getMessage()); 281 } 282 try { 283 scanCopy.setPriority(10); 284 throw new RuntimeException("Should not reach here"); 285 } catch (UnsupportedOperationException e) { 286 assertEquals("ImmutableScan does not allow access to setPriority", e.getMessage()); 287 } 288 try { 289 scanCopy.setConsistency(Consistency.TIMELINE); 290 throw new RuntimeException("Should not reach here"); 291 } catch (UnsupportedOperationException e) { 292 assertEquals("ImmutableScan does not allow access to setConsistency", e.getMessage()); 293 } 294 try { 295 scanCopy.setCacheBlocks(true); 296 throw new RuntimeException("Should not reach here"); 297 } catch (UnsupportedOperationException e) { 298 assertEquals("ImmutableScan does not allow access to setCacheBlocks", e.getMessage()); 299 } 300 try { 301 scanCopy.setAllowPartialResults(true); 302 throw new RuntimeException("Should not reach here"); 303 } catch (UnsupportedOperationException e) { 304 assertEquals("ImmutableScan does not allow access to setAllowPartialResults", 305 e.getMessage()); 306 } 307 try { 308 scanCopy.setId("id"); 309 throw new RuntimeException("Should not reach here"); 310 } catch (UnsupportedOperationException e) { 311 assertEquals("ImmutableScan does not allow access to setId", e.getMessage()); 312 } 313 try { 314 scanCopy.setMaxResultSize(100); 315 throw new RuntimeException("Should not reach here"); 316 } catch (UnsupportedOperationException e) { 317 assertEquals("ImmutableScan does not allow access to setMaxResultSize", e.getMessage()); 318 } 319 try { 320 scanCopy.setMaxResultsPerColumnFamily(100); 321 throw new RuntimeException("Should not reach here"); 322 } catch (UnsupportedOperationException e) { 323 assertEquals("ImmutableScan does not allow access to setMaxResultsPerColumnFamily", 324 e.getMessage()); 325 } 326 } 327 328 private void compareGetters(Scan scan, Scan scanCopy) { 329 Method[] methods = Scan.class.getMethods(); 330 for (Method method : methods) { 331 if (isGetter(method)) { 332 LOG.debug("Comparing return values of method: {}", method); 333 try { 334 Object obj1; 335 Object obj2; 336 switch (method.getName()) { 337 case "toMap": { 338 if (method.getParameterCount() == 1) { 339 obj1 = method.invoke(scan, 2); 340 obj2 = method.invoke(scanCopy, 2); 341 break; 342 } 343 } 344 case "getAttribute": { 345 if (method.getParameterCount() == 1) { 346 obj1 = method.invoke(scan, "acl"); 347 obj2 = method.invoke(scanCopy, "acl"); 348 break; 349 } 350 } 351 case "toString": { 352 if (method.getParameterCount() == 1) { 353 obj1 = method.invoke(scan, 25); 354 obj2 = method.invoke(scanCopy, 25); 355 break; 356 } 357 } 358 case "toJSON": { 359 if (method.getParameterCount() == 1) { 360 obj1 = method.invoke(scan, 25); 361 obj2 = method.invoke(scanCopy, 25); 362 break; 363 } 364 } 365 default: { 366 obj1 = method.invoke(scan); 367 obj2 = method.invoke(scanCopy); 368 } 369 } 370 if (obj1 instanceof Map && obj2 instanceof Map) { 371 obj1 = Collections.unmodifiableMap((Map<?, ?>) obj1); 372 } 373 if (!EqualsBuilder.reflectionEquals(obj1, obj2)) { 374 throw new AssertionError("Method " + method + " does not return equal values"); 375 } 376 } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) { 377 throw new AssertionError("Error invoking method " + method, e); 378 } 379 } 380 } 381 } 382 383 private static boolean isGetter(Method method) { 384 if ("hashCode".equals(method.getName()) || "equals".equals(method.getName()) 385 || method.getName().startsWith("set")) { 386 return false; 387 } 388 return !void.class.equals(method.getReturnType()) 389 && !Scan.class.equals(method.getReturnType()); 390 } 391 392}