1 /** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 */ 19 package org.apache.hadoop.hbase.client; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.junit.Assert.assertNotNull; 23 import org.apache.hadoop.hbase.Cell; 24 import org.apache.hadoop.hbase.CellUtil; 25 import org.apache.hadoop.hbase.HConstants; 26 import org.apache.hadoop.hbase.KeyValue; 27 import org.apache.hadoop.hbase.testclassification.SmallTests; 28 import org.junit.Assert; 29 import org.junit.Test; 30 31 import java.io.IOException; 32 import java.nio.ByteBuffer; 33 import java.util.Arrays; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 38 import org.apache.hadoop.hbase.filter.BinaryComparator; 39 import org.apache.hadoop.hbase.filter.ColumnCountGetFilter; 40 import org.apache.hadoop.hbase.filter.ColumnPaginationFilter; 41 import org.apache.hadoop.hbase.filter.ColumnPrefixFilter; 42 import org.apache.hadoop.hbase.filter.ColumnRangeFilter; 43 import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp; 44 import org.apache.hadoop.hbase.filter.DependentColumnFilter; 45 import org.apache.hadoop.hbase.filter.FamilyFilter; 46 import org.apache.hadoop.hbase.filter.Filter; 47 import org.apache.hadoop.hbase.filter.FilterList; 48 import org.apache.hadoop.hbase.filter.FilterList.Operator; 49 import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter; 50 import org.apache.hadoop.hbase.filter.InclusiveStopFilter; 51 import org.apache.hadoop.hbase.filter.KeyOnlyFilter; 52 import org.apache.hadoop.hbase.filter.MultipleColumnPrefixFilter; 53 import org.apache.hadoop.hbase.filter.PageFilter; 54 import org.apache.hadoop.hbase.filter.PrefixFilter; 55 import org.apache.hadoop.hbase.filter.QualifierFilter; 56 import org.apache.hadoop.hbase.filter.RowFilter; 57 import org.apache.hadoop.hbase.filter.SingleColumnValueFilter; 58 import org.apache.hadoop.hbase.filter.SingleColumnValueExcludeFilter; 59 import org.apache.hadoop.hbase.filter.SkipFilter; 60 import org.apache.hadoop.hbase.filter.TimestampsFilter; 61 import org.apache.hadoop.hbase.filter.ValueFilter; 62 import org.apache.hadoop.hbase.filter.WhileMatchFilter; 63 import org.apache.hadoop.hbase.util.BuilderStyleTest; 64 import org.apache.hadoop.hbase.util.Bytes; 65 import org.codehaus.jackson.map.ObjectMapper; 66 import org.junit.experimental.categories.Category; 67 68 /** 69 * Run tests that use the functionality of the Operation superclass for 70 * Puts, Gets, Deletes, Scans, and MultiPuts. 71 */ 72 @Category(SmallTests.class) 73 public class TestOperation { 74 private static byte [] ROW = Bytes.toBytes("testRow"); 75 private static byte [] FAMILY = Bytes.toBytes("testFamily"); 76 private static byte [] QUALIFIER = Bytes.toBytes("testQualifier"); 77 private static byte [] VALUE = Bytes.toBytes("testValue"); 78 79 private static ObjectMapper mapper = new ObjectMapper(); 80 81 private static List<Long> TS_LIST = Arrays.asList(2L, 3L, 5L); 82 private static TimestampsFilter TS_FILTER = new TimestampsFilter(TS_LIST); 83 private static String STR_TS_FILTER = 84 TS_FILTER.getClass().getSimpleName() + " (3/3): [2, 3, 5]"; 85 86 private static List<Long> L_TS_LIST = 87 Arrays.asList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L); 88 private static TimestampsFilter L_TS_FILTER = 89 new TimestampsFilter(L_TS_LIST); 90 private static String STR_L_TS_FILTER = 91 L_TS_FILTER.getClass().getSimpleName() + " (5/11): [0, 1, 2, 3, 4]"; 92 93 private static String COL_NAME_1 = "col1"; 94 private static ColumnPrefixFilter COL_PRE_FILTER = 95 new ColumnPrefixFilter(COL_NAME_1.getBytes()); 96 private static String STR_COL_PRE_FILTER = 97 COL_PRE_FILTER.getClass().getSimpleName() + " " + COL_NAME_1; 98 99 private static String COL_NAME_2 = "col2"; 100 private static ColumnRangeFilter CR_FILTER = new ColumnRangeFilter( 101 COL_NAME_1.getBytes(), true, COL_NAME_2.getBytes(), false); 102 private static String STR_CR_FILTER = CR_FILTER.getClass().getSimpleName() 103 + " [" + COL_NAME_1 + ", " + COL_NAME_2 + ")"; 104 105 private static int COL_COUNT = 9; 106 private static ColumnCountGetFilter CCG_FILTER = 107 new ColumnCountGetFilter(COL_COUNT); 108 private static String STR_CCG_FILTER = 109 CCG_FILTER.getClass().getSimpleName() + " " + COL_COUNT; 110 111 private static int LIMIT = 3; 112 private static int OFFSET = 4; 113 private static ColumnPaginationFilter CP_FILTER = 114 new ColumnPaginationFilter(LIMIT, OFFSET); 115 private static String STR_CP_FILTER = CP_FILTER.getClass().getSimpleName() 116 + " (" + LIMIT + ", " + OFFSET + ")"; 117 118 private static String STOP_ROW_KEY = "stop"; 119 private static InclusiveStopFilter IS_FILTER = 120 new InclusiveStopFilter(STOP_ROW_KEY.getBytes()); 121 private static String STR_IS_FILTER = 122 IS_FILTER.getClass().getSimpleName() + " " + STOP_ROW_KEY; 123 124 private static String PREFIX = "prefix"; 125 private static PrefixFilter PREFIX_FILTER = 126 new PrefixFilter(PREFIX.getBytes()); 127 private static String STR_PREFIX_FILTER = "PrefixFilter " + PREFIX; 128 129 private static byte[][] PREFIXES = { 130 "0".getBytes(), "1".getBytes(), "2".getBytes()}; 131 private static MultipleColumnPrefixFilter MCP_FILTER = 132 new MultipleColumnPrefixFilter(PREFIXES); 133 private static String STR_MCP_FILTER = 134 MCP_FILTER.getClass().getSimpleName() + " (3/3): [0, 1, 2]"; 135 136 private static byte[][] L_PREFIXES = { 137 "0".getBytes(), "1".getBytes(), "2".getBytes(), "3".getBytes(), 138 "4".getBytes(), "5".getBytes(), "6".getBytes(), "7".getBytes()}; 139 private static MultipleColumnPrefixFilter L_MCP_FILTER = 140 new MultipleColumnPrefixFilter(L_PREFIXES); 141 private static String STR_L_MCP_FILTER = 142 L_MCP_FILTER.getClass().getSimpleName() + " (5/8): [0, 1, 2, 3, 4]"; 143 144 private static int PAGE_SIZE = 9; 145 private static PageFilter PAGE_FILTER = new PageFilter(PAGE_SIZE); 146 private static String STR_PAGE_FILTER = 147 PAGE_FILTER.getClass().getSimpleName() + " " + PAGE_SIZE; 148 149 private static SkipFilter SKIP_FILTER = new SkipFilter(L_TS_FILTER); 150 private static String STR_SKIP_FILTER = 151 SKIP_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER; 152 153 private static WhileMatchFilter WHILE_FILTER = 154 new WhileMatchFilter(L_TS_FILTER); 155 private static String STR_WHILE_FILTER = 156 WHILE_FILTER.getClass().getSimpleName() + " " + STR_L_TS_FILTER; 157 158 private static KeyOnlyFilter KEY_ONLY_FILTER = new KeyOnlyFilter(); 159 private static String STR_KEY_ONLY_FILTER = 160 KEY_ONLY_FILTER.getClass().getSimpleName(); 161 162 private static FirstKeyOnlyFilter FIRST_KEY_ONLY_FILTER = 163 new FirstKeyOnlyFilter(); 164 private static String STR_FIRST_KEY_ONLY_FILTER = 165 FIRST_KEY_ONLY_FILTER.getClass().getSimpleName(); 166 167 private static CompareOp CMP_OP = CompareOp.EQUAL; 168 private static byte[] CMP_VALUE = "value".getBytes(); 169 private static BinaryComparator BC = new BinaryComparator(CMP_VALUE); 170 private static DependentColumnFilter DC_FILTER = 171 new DependentColumnFilter(FAMILY, QUALIFIER, true, CMP_OP, BC); 172 private static String STR_DC_FILTER = String.format( 173 "%s (%s, %s, %s, %s, %s)", DC_FILTER.getClass().getSimpleName(), 174 Bytes.toStringBinary(FAMILY), Bytes.toStringBinary(QUALIFIER), true, 175 CMP_OP.name(), Bytes.toStringBinary(BC.getValue())); 176 177 private static FamilyFilter FAMILY_FILTER = new FamilyFilter(CMP_OP, BC); 178 private static String STR_FAMILY_FILTER = 179 FAMILY_FILTER.getClass().getSimpleName() + " (EQUAL, value)"; 180 181 private static QualifierFilter QUALIFIER_FILTER = 182 new QualifierFilter(CMP_OP, BC); 183 private static String STR_QUALIFIER_FILTER = 184 QUALIFIER_FILTER.getClass().getSimpleName() + " (EQUAL, value)"; 185 186 private static RowFilter ROW_FILTER = new RowFilter(CMP_OP, BC); 187 private static String STR_ROW_FILTER = 188 ROW_FILTER.getClass().getSimpleName() + " (EQUAL, value)"; 189 190 private static ValueFilter VALUE_FILTER = new ValueFilter(CMP_OP, BC); 191 private static String STR_VALUE_FILTER = 192 VALUE_FILTER.getClass().getSimpleName() + " (EQUAL, value)"; 193 194 private static SingleColumnValueFilter SCV_FILTER = 195 new SingleColumnValueFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE); 196 private static String STR_SCV_FILTER = String.format("%s (%s, %s, %s, %s)", 197 SCV_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY), 198 Bytes.toStringBinary(QUALIFIER), CMP_OP.name(), 199 Bytes.toStringBinary(CMP_VALUE)); 200 201 private static SingleColumnValueExcludeFilter SCVE_FILTER = 202 new SingleColumnValueExcludeFilter(FAMILY, QUALIFIER, CMP_OP, CMP_VALUE); 203 private static String STR_SCVE_FILTER = String.format("%s (%s, %s, %s, %s)", 204 SCVE_FILTER.getClass().getSimpleName(), Bytes.toStringBinary(FAMILY), 205 Bytes.toStringBinary(QUALIFIER), CMP_OP.name(), 206 Bytes.toStringBinary(CMP_VALUE)); 207 208 private static FilterList AND_FILTER_LIST = new FilterList( 209 Operator.MUST_PASS_ALL, Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, 210 CR_FILTER)); 211 private static String STR_AND_FILTER_LIST = String.format( 212 "%s AND (3/3): [%s, %s, %s]", AND_FILTER_LIST.getClass().getSimpleName(), 213 STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER); 214 215 private static FilterList OR_FILTER_LIST = new FilterList( 216 Operator.MUST_PASS_ONE, Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, 217 CR_FILTER)); 218 private static String STR_OR_FILTER_LIST = String.format( 219 "%s OR (3/3): [%s, %s, %s]", AND_FILTER_LIST.getClass().getSimpleName(), 220 STR_TS_FILTER, STR_L_TS_FILTER, STR_CR_FILTER); 221 222 private static FilterList L_FILTER_LIST = new FilterList( 223 Arrays.asList((Filter) TS_FILTER, L_TS_FILTER, CR_FILTER, COL_PRE_FILTER, 224 CCG_FILTER, CP_FILTER, PREFIX_FILTER, PAGE_FILTER)); 225 private static String STR_L_FILTER_LIST = String.format( 226 "%s AND (5/8): [%s, %s, %s, %s, %s, %s]", 227 L_FILTER_LIST.getClass().getSimpleName(), STR_TS_FILTER, STR_L_TS_FILTER, 228 STR_CR_FILTER, STR_COL_PRE_FILTER, STR_CCG_FILTER, STR_CP_FILTER); 229 230 private static Filter[] FILTERS = { 231 TS_FILTER, // TimestampsFilter 232 L_TS_FILTER, // TimestampsFilter 233 COL_PRE_FILTER, // ColumnPrefixFilter 234 CP_FILTER, // ColumnPaginationFilter 235 CR_FILTER, // ColumnRangeFilter 236 CCG_FILTER, // ColumnCountGetFilter 237 IS_FILTER, // InclusiveStopFilter 238 PREFIX_FILTER, // PrefixFilter 239 PAGE_FILTER, // PageFilter 240 SKIP_FILTER, // SkipFilter 241 WHILE_FILTER, // WhileMatchFilter 242 KEY_ONLY_FILTER, // KeyOnlyFilter 243 FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter 244 MCP_FILTER, // MultipleColumnPrefixFilter 245 L_MCP_FILTER, // MultipleColumnPrefixFilter 246 DC_FILTER, // DependentColumnFilter 247 FAMILY_FILTER, // FamilyFilter 248 QUALIFIER_FILTER, // QualifierFilter 249 ROW_FILTER, // RowFilter 250 VALUE_FILTER, // ValueFilter 251 SCV_FILTER, // SingleColumnValueFilter 252 SCVE_FILTER, // SingleColumnValueExcludeFilter 253 AND_FILTER_LIST, // FilterList 254 OR_FILTER_LIST, // FilterList 255 L_FILTER_LIST, // FilterList 256 }; 257 258 private static String[] FILTERS_INFO = { 259 STR_TS_FILTER, // TimestampsFilter 260 STR_L_TS_FILTER, // TimestampsFilter 261 STR_COL_PRE_FILTER, // ColumnPrefixFilter 262 STR_CP_FILTER, // ColumnPaginationFilter 263 STR_CR_FILTER, // ColumnRangeFilter 264 STR_CCG_FILTER, // ColumnCountGetFilter 265 STR_IS_FILTER, // InclusiveStopFilter 266 STR_PREFIX_FILTER, // PrefixFilter 267 STR_PAGE_FILTER, // PageFilter 268 STR_SKIP_FILTER, // SkipFilter 269 STR_WHILE_FILTER, // WhileMatchFilter 270 STR_KEY_ONLY_FILTER, // KeyOnlyFilter 271 STR_FIRST_KEY_ONLY_FILTER, // FirstKeyOnlyFilter 272 STR_MCP_FILTER, // MultipleColumnPrefixFilter 273 STR_L_MCP_FILTER, // MultipleColumnPrefixFilter 274 STR_DC_FILTER, // DependentColumnFilter 275 STR_FAMILY_FILTER, // FamilyFilter 276 STR_QUALIFIER_FILTER, // QualifierFilter 277 STR_ROW_FILTER, // RowFilter 278 STR_VALUE_FILTER, // ValueFilter 279 STR_SCV_FILTER, // SingleColumnValueFilter 280 STR_SCVE_FILTER, // SingleColumnValueExcludeFilter 281 STR_AND_FILTER_LIST, // FilterList 282 STR_OR_FILTER_LIST, // FilterList 283 STR_L_FILTER_LIST, // FilterList 284 }; 285 286 static { 287 assertEquals("The sizes of static arrays do not match: " 288 + "[FILTERS: %d <=> FILTERS_INFO: %d]", 289 FILTERS.length, FILTERS_INFO.length); 290 } 291 292 /** 293 * Test the client Operations' JSON encoding to ensure that produced JSON is 294 * parseable and that the details are present and not corrupted. 295 * @throws IOException 296 */ 297 @Test testOperationJSON()298 public void testOperationJSON() 299 throws IOException { 300 // produce a Scan Operation 301 Scan scan = new Scan(ROW); 302 scan.addColumn(FAMILY, QUALIFIER); 303 // get its JSON representation, and parse it 304 String json = scan.toJSON(); 305 Map<String, Object> parsedJSON = mapper.readValue(json, HashMap.class); 306 // check for the row 307 assertEquals("startRow incorrect in Scan.toJSON()", 308 Bytes.toStringBinary(ROW), parsedJSON.get("startRow")); 309 // check for the family and the qualifier. 310 List familyInfo = (List) ((Map) parsedJSON.get("families")).get( 311 Bytes.toStringBinary(FAMILY)); 312 assertNotNull("Family absent in Scan.toJSON()", familyInfo); 313 assertEquals("Qualifier absent in Scan.toJSON()", 1, familyInfo.size()); 314 assertEquals("Qualifier incorrect in Scan.toJSON()", 315 Bytes.toStringBinary(QUALIFIER), 316 familyInfo.get(0)); 317 318 // produce a Get Operation 319 Get get = new Get(ROW); 320 get.addColumn(FAMILY, QUALIFIER); 321 // get its JSON representation, and parse it 322 json = get.toJSON(); 323 parsedJSON = mapper.readValue(json, HashMap.class); 324 // check for the row 325 assertEquals("row incorrect in Get.toJSON()", 326 Bytes.toStringBinary(ROW), parsedJSON.get("row")); 327 // check for the family and the qualifier. 328 familyInfo = (List) ((Map) parsedJSON.get("families")).get( 329 Bytes.toStringBinary(FAMILY)); 330 assertNotNull("Family absent in Get.toJSON()", familyInfo); 331 assertEquals("Qualifier absent in Get.toJSON()", 1, familyInfo.size()); 332 assertEquals("Qualifier incorrect in Get.toJSON()", 333 Bytes.toStringBinary(QUALIFIER), 334 familyInfo.get(0)); 335 336 // produce a Put operation 337 Put put = new Put(ROW); 338 put.add(FAMILY, QUALIFIER, VALUE); 339 // get its JSON representation, and parse it 340 json = put.toJSON(); 341 parsedJSON = mapper.readValue(json, HashMap.class); 342 // check for the row 343 assertEquals("row absent in Put.toJSON()", 344 Bytes.toStringBinary(ROW), parsedJSON.get("row")); 345 // check for the family and the qualifier. 346 familyInfo = (List) ((Map) parsedJSON.get("families")).get( 347 Bytes.toStringBinary(FAMILY)); 348 assertNotNull("Family absent in Put.toJSON()", familyInfo); 349 assertEquals("KeyValue absent in Put.toJSON()", 1, familyInfo.size()); 350 Map kvMap = (Map) familyInfo.get(0); 351 assertEquals("Qualifier incorrect in Put.toJSON()", 352 Bytes.toStringBinary(QUALIFIER), 353 kvMap.get("qualifier")); 354 assertEquals("Value length incorrect in Put.toJSON()", 355 VALUE.length, kvMap.get("vlen")); 356 357 // produce a Delete operation 358 Delete delete = new Delete(ROW); 359 delete.deleteColumn(FAMILY, QUALIFIER); 360 // get its JSON representation, and parse it 361 json = delete.toJSON(); 362 parsedJSON = mapper.readValue(json, HashMap.class); 363 // check for the row 364 assertEquals("row absent in Delete.toJSON()", 365 Bytes.toStringBinary(ROW), parsedJSON.get("row")); 366 // check for the family and the qualifier. 367 familyInfo = (List) ((Map) parsedJSON.get("families")).get( 368 Bytes.toStringBinary(FAMILY)); 369 assertNotNull("Family absent in Delete.toJSON()", familyInfo); 370 assertEquals("KeyValue absent in Delete.toJSON()", 1, familyInfo.size()); 371 kvMap = (Map) familyInfo.get(0); 372 assertEquals("Qualifier incorrect in Delete.toJSON()", 373 Bytes.toStringBinary(QUALIFIER), kvMap.get("qualifier")); 374 } 375 376 @Test testPutCreationWithByteBuffer()377 public void testPutCreationWithByteBuffer() { 378 Put p = new Put(ROW); 379 List<Cell> c = p.get(FAMILY, QUALIFIER); 380 Assert.assertEquals(0, c.size()); 381 Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp()); 382 383 p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 1984L, ByteBuffer.wrap(VALUE)); 384 c = p.get(FAMILY, QUALIFIER); 385 Assert.assertEquals(1, c.size()); 386 Assert.assertEquals(1984L, c.get(0).getTimestamp()); 387 Assert.assertArrayEquals(VALUE, CellUtil.cloneValue(c.get(0))); 388 Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp()); 389 Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0)))); 390 391 p = new Put(ROW); 392 p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2013L, null); 393 c = p.get(FAMILY, QUALIFIER); 394 Assert.assertEquals(1, c.size()); 395 Assert.assertEquals(2013L, c.get(0).getTimestamp()); 396 Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0))); 397 Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp()); 398 Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0)))); 399 400 p = new Put(ByteBuffer.wrap(ROW)); 401 p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null); 402 c = p.get(FAMILY, QUALIFIER); 403 Assert.assertEquals(1, c.size()); 404 Assert.assertEquals(2001L, c.get(0).getTimestamp()); 405 Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0))); 406 Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0))); 407 Assert.assertEquals(HConstants.LATEST_TIMESTAMP, p.getTimeStamp()); 408 Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0)))); 409 410 p = new Put(ByteBuffer.wrap(ROW), 1970L); 411 p.add(FAMILY, ByteBuffer.wrap(QUALIFIER), 2001L, null); 412 c = p.get(FAMILY, QUALIFIER); 413 Assert.assertEquals(1, c.size()); 414 Assert.assertEquals(2001L, c.get(0).getTimestamp()); 415 Assert.assertArrayEquals(new byte[]{}, CellUtil.cloneValue(c.get(0))); 416 Assert.assertArrayEquals(ROW, CellUtil.cloneRow(c.get(0))); 417 Assert.assertEquals(1970L, p.getTimeStamp()); 418 Assert.assertEquals(0, KeyValue.COMPARATOR.compare(c.get(0), new KeyValue(c.get(0)))); 419 } 420 421 @Test 422 @SuppressWarnings("rawtypes") testOperationSubClassMethodsAreBuilderStyle()423 public void testOperationSubClassMethodsAreBuilderStyle() { 424 /* All Operation subclasses should have a builder style setup where setXXX/addXXX methods 425 * can be chainable together: 426 * . For example: 427 * Scan scan = new Scan() 428 * .setFoo(foo) 429 * .setBar(bar) 430 * .setBuz(buz) 431 * 432 * This test ensures that all methods starting with "set" returns the declaring object 433 */ 434 435 // TODO: We should ensure all subclasses of Operation is checked. 436 Class[] classes = new Class[] { 437 Operation.class, 438 OperationWithAttributes.class, 439 Mutation.class, 440 Query.class, 441 Delete.class, 442 Increment.class, 443 Append.class, 444 Put.class, 445 Get.class, 446 Scan.class}; 447 448 BuilderStyleTest.assertClassesAreBuilderStyle(classes); 449 } 450 451 } 452 453