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