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.shaded.protobuf;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertNotNull;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.lang.reflect.Method;
026import java.nio.ByteBuffer;
027import java.util.Collections;
028import java.util.List;
029import org.apache.hadoop.hbase.ArrayBackedTag;
030import org.apache.hadoop.hbase.ByteBufferKeyValue;
031import org.apache.hadoop.hbase.Cell;
032import org.apache.hadoop.hbase.CellBuilderType;
033import org.apache.hadoop.hbase.CellComparatorImpl;
034import org.apache.hadoop.hbase.ExtendedCell;
035import org.apache.hadoop.hbase.ExtendedCellBuilder;
036import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
037import org.apache.hadoop.hbase.HConstants;
038import org.apache.hadoop.hbase.KeyValue;
039import org.apache.hadoop.hbase.PrivateCellUtil;
040import org.apache.hadoop.hbase.Tag;
041import org.apache.hadoop.hbase.client.Append;
042import org.apache.hadoop.hbase.client.Delete;
043import org.apache.hadoop.hbase.client.Get;
044import org.apache.hadoop.hbase.client.Increment;
045import org.apache.hadoop.hbase.client.Put;
046import org.apache.hadoop.hbase.client.SlowLogParams;
047import org.apache.hadoop.hbase.io.TimeRange;
048import org.apache.hadoop.hbase.testclassification.SmallTests;
049import org.apache.hadoop.hbase.util.Bytes;
050import org.junit.jupiter.api.Test;
051
052import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
053import org.apache.hbase.thirdparty.com.google.protobuf.Any;
054import org.apache.hbase.thirdparty.com.google.protobuf.ByteString;
055import org.apache.hbase.thirdparty.com.google.protobuf.BytesValue;
056import org.apache.hbase.thirdparty.com.google.protobuf.InvalidProtocolBufferException;
057
058import org.apache.hadoop.hbase.shaded.protobuf.generated.CellProtos;
059import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
060import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.Column;
061import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto;
062import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.ColumnValue;
063import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.ColumnValue.QualifierValue;
064import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.DeleteType;
065import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.MutationProto.MutationType;
066import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
067import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.NameBytesPair;
068import org.apache.hadoop.hbase.shaded.protobuf.generated.LockServiceProtos;
069import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos;
070import org.apache.hadoop.hbase.shaded.protobuf.generated.ProcedureProtos;
071import org.apache.hadoop.hbase.shaded.protobuf.generated.RegionServerStatusProtos;
072
073@org.junit.jupiter.api.Tag(SmallTests.TAG)
074public class TestProtobufUtil {
075
076  private static final String TAG_STR = "tag-1";
077  private static final byte TAG_TYPE = (byte) 10;
078  private static final HBaseProtos.ServerName SERVER_NAME =
079    HBaseProtos.ServerName.newBuilder().setHostName("a.b.com").build();
080  private static final HBaseProtos.RegionSpecifier REGION =
081    HBaseProtos.RegionSpecifier.newBuilder().setValue(ByteString.copyFromUtf8("test"))
082      .setType(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME).build();
083
084  public TestProtobufUtil() {
085  }
086
087  @Test
088  public void testException() throws IOException {
089    NameBytesPair.Builder builder = NameBytesPair.newBuilder();
090    final String omg = "OMG!!!";
091    builder.setName("java.io.IOException");
092    builder.setValue(ByteString.copyFrom(Bytes.toBytes(omg)));
093    Throwable t = ProtobufUtil.toException(builder.build());
094    assertEquals(omg, t.getMessage());
095    builder.clear();
096    builder.setName("org.apache.hadoop.ipc.RemoteException");
097    builder.setValue(ByteString.copyFrom(Bytes.toBytes(omg)));
098    t = ProtobufUtil.toException(builder.build());
099    assertEquals(omg, t.getMessage());
100  }
101
102  /**
103   * Test basic Get conversions.
104   * @throws IOException if the conversion to a {@link Get} fails
105   */
106  @Test
107  public void testGet() throws IOException {
108    ClientProtos.Get.Builder getBuilder = ClientProtos.Get.newBuilder();
109    getBuilder.setRow(ByteString.copyFromUtf8("row"));
110    Column.Builder columnBuilder = Column.newBuilder();
111    columnBuilder.setFamily(ByteString.copyFromUtf8("f1"));
112    columnBuilder.addQualifier(ByteString.copyFromUtf8("c1"));
113    columnBuilder.addQualifier(ByteString.copyFromUtf8("c2"));
114    getBuilder.addColumn(columnBuilder.build());
115
116    columnBuilder.clear();
117    columnBuilder.setFamily(ByteString.copyFromUtf8("f2"));
118    getBuilder.addColumn(columnBuilder.build());
119    getBuilder.setLoadColumnFamiliesOnDemand(true);
120    ClientProtos.Get proto = getBuilder.build();
121    // default fields
122    assertEquals(1, proto.getMaxVersions());
123    assertEquals(true, proto.getCacheBlocks());
124
125    // set the default value for equal comparison
126    getBuilder = ClientProtos.Get.newBuilder(proto);
127    getBuilder.setMaxVersions(1);
128    getBuilder.setCacheBlocks(true);
129    getBuilder.setTimeRange(ProtobufUtil.toTimeRange(TimeRange.allTime()));
130    getBuilder.setQueryMetricsEnabled(false);
131    Get get = ProtobufUtil.toGet(proto);
132    assertEquals(getBuilder.build(), ProtobufUtil.toGet(get));
133  }
134
135  /**
136   * Test Delete Mutate conversions.
137   * @throws IOException if the conversion to a {@link Delete} or a
138   *                     {@link org.apache.hadoop.hbase.client.Mutation} fails
139   */
140  @Test
141  public void testDelete() throws IOException {
142    MutationProto.Builder mutateBuilder = MutationProto.newBuilder();
143    mutateBuilder.setRow(ByteString.copyFromUtf8("row"));
144    mutateBuilder.setMutateType(MutationType.DELETE);
145    mutateBuilder.setTimestamp(111111);
146    ColumnValue.Builder valueBuilder = ColumnValue.newBuilder();
147    valueBuilder.setFamily(ByteString.copyFromUtf8("f1"));
148    QualifierValue.Builder qualifierBuilder = QualifierValue.newBuilder();
149    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c1"));
150    qualifierBuilder.setDeleteType(DeleteType.DELETE_ONE_VERSION);
151    qualifierBuilder.setTimestamp(111222);
152    valueBuilder.addQualifierValue(qualifierBuilder.build());
153    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c2"));
154    qualifierBuilder.setDeleteType(DeleteType.DELETE_MULTIPLE_VERSIONS);
155    qualifierBuilder.setTimestamp(111333);
156    valueBuilder.addQualifierValue(qualifierBuilder.build());
157    mutateBuilder.addColumnValue(valueBuilder.build());
158
159    MutationProto proto = mutateBuilder.build();
160    // default fields
161    assertEquals(MutationProto.Durability.USE_DEFAULT, proto.getDurability());
162
163    // set the default value for equal comparison
164    mutateBuilder = MutationProto.newBuilder(proto);
165    mutateBuilder.setDurability(MutationProto.Durability.USE_DEFAULT);
166
167    Delete delete = ProtobufUtil.toDelete(proto);
168
169    // delete always have empty value,
170    // add empty value to the original mutate
171    for (ColumnValue.Builder column : mutateBuilder.getColumnValueBuilderList()) {
172      for (QualifierValue.Builder qualifier : column.getQualifierValueBuilderList()) {
173        qualifier.setValue(ByteString.EMPTY);
174      }
175    }
176    assertEquals(mutateBuilder.build(), ProtobufUtil.toMutation(MutationType.DELETE, delete));
177  }
178
179  /**
180   * Test Put Mutate conversions.
181   * @throws IOException if the conversion to a {@link Put} or a
182   *                     {@link org.apache.hadoop.hbase.client.Mutation} fails
183   */
184  @Test
185  public void testPut() throws IOException {
186    MutationProto.Builder mutateBuilder = MutationProto.newBuilder();
187    mutateBuilder.setRow(ByteString.copyFromUtf8("row"));
188    mutateBuilder.setMutateType(MutationType.PUT);
189    mutateBuilder.setTimestamp(111111);
190    ColumnValue.Builder valueBuilder = ColumnValue.newBuilder();
191    valueBuilder.setFamily(ByteString.copyFromUtf8("f1"));
192    QualifierValue.Builder qualifierBuilder = QualifierValue.newBuilder();
193    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c1"));
194    qualifierBuilder.setValue(ByteString.copyFromUtf8("v1"));
195    valueBuilder.addQualifierValue(qualifierBuilder.build());
196    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c2"));
197    qualifierBuilder.setValue(ByteString.copyFromUtf8("v2"));
198    qualifierBuilder.setTimestamp(222222);
199    valueBuilder.addQualifierValue(qualifierBuilder.build());
200    mutateBuilder.addColumnValue(valueBuilder.build());
201
202    MutationProto proto = mutateBuilder.build();
203    // default fields
204    assertEquals(MutationProto.Durability.USE_DEFAULT, proto.getDurability());
205
206    // set the default value for equal comparison
207    mutateBuilder = MutationProto.newBuilder(proto);
208    mutateBuilder.setDurability(MutationProto.Durability.USE_DEFAULT);
209
210    Put put = ProtobufUtil.toPut(proto);
211
212    // put value always use the default timestamp if no
213    // value level timestamp specified,
214    // add the timestamp to the original mutate
215    long timestamp = put.getTimestamp();
216    for (ColumnValue.Builder column : mutateBuilder.getColumnValueBuilderList()) {
217      for (QualifierValue.Builder qualifier : column.getQualifierValueBuilderList()) {
218        if (!qualifier.hasTimestamp()) {
219          qualifier.setTimestamp(timestamp);
220        }
221      }
222    }
223    assertEquals(mutateBuilder.build(), ProtobufUtil.toMutation(MutationType.PUT, put));
224  }
225
226  /**
227   * Test basic Scan conversions.
228   * @throws IOException if the conversion to a {@link org.apache.hadoop.hbase.client.Scan} fails
229   */
230  @Test
231  public void testScan() throws IOException {
232    ClientProtos.Scan.Builder scanBuilder = ClientProtos.Scan.newBuilder();
233    scanBuilder.setStartRow(ByteString.copyFromUtf8("row1"));
234    scanBuilder.setStopRow(ByteString.copyFromUtf8("row2"));
235    Column.Builder columnBuilder = Column.newBuilder();
236    columnBuilder.setFamily(ByteString.copyFromUtf8("f1"));
237    columnBuilder.addQualifier(ByteString.copyFromUtf8("c1"));
238    columnBuilder.addQualifier(ByteString.copyFromUtf8("c2"));
239    scanBuilder.addColumn(columnBuilder.build());
240
241    columnBuilder.clear();
242    columnBuilder.setFamily(ByteString.copyFromUtf8("f2"));
243    scanBuilder.addColumn(columnBuilder.build());
244
245    ClientProtos.Scan proto = scanBuilder.build();
246
247    // Verify default values
248    assertEquals(1, proto.getMaxVersions());
249    assertEquals(true, proto.getCacheBlocks());
250
251    // Verify fields survive ClientProtos.Scan -> Scan -> ClientProtos.Scan
252    // conversion
253    scanBuilder = ClientProtos.Scan.newBuilder(proto);
254    scanBuilder.setMaxVersions(2);
255    scanBuilder.setCacheBlocks(false);
256    scanBuilder.setCaching(1024);
257    scanBuilder.setTimeRange(ProtobufUtil.toTimeRange(TimeRange.allTime()));
258    scanBuilder.setIncludeStopRow(false);
259    scanBuilder.setQueryMetricsEnabled(false);
260    ClientProtos.Scan expectedProto = scanBuilder.build();
261
262    ClientProtos.Scan actualProto = ProtobufUtil.toScan(ProtobufUtil.toScan(expectedProto));
263    assertEquals(expectedProto, actualProto);
264  }
265
266  @Test
267  public void testToCell() {
268    KeyValue kv1 =
269      new KeyValue(Bytes.toBytes("aaa"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), new byte[30]);
270    KeyValue kv2 =
271      new KeyValue(Bytes.toBytes("bbb"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), new byte[30]);
272    KeyValue kv3 =
273      new KeyValue(Bytes.toBytes("ccc"), Bytes.toBytes("f1"), Bytes.toBytes("q1"), new byte[30]);
274    byte[] arr = new byte[kv1.getLength() + kv2.getLength() + kv3.getLength()];
275    System.arraycopy(kv1.getBuffer(), kv1.getOffset(), arr, 0, kv1.getLength());
276    System.arraycopy(kv2.getBuffer(), kv2.getOffset(), arr, kv1.getLength(), kv2.getLength());
277    System.arraycopy(kv3.getBuffer(), kv3.getOffset(), arr, kv1.getLength() + kv2.getLength(),
278      kv3.getLength());
279    ByteBuffer dbb = ByteBuffer.allocateDirect(arr.length);
280    dbb.put(arr);
281    ByteBufferKeyValue offheapKV = new ByteBufferKeyValue(dbb, kv1.getLength(), kv2.getLength());
282    CellProtos.Cell cell = ProtobufUtil.toCell(offheapKV, false);
283    Cell newOffheapKV = ProtobufUtil
284      .toCell(ExtendedCellBuilderFactory.create(CellBuilderType.SHALLOW_COPY), cell, false);
285    assertTrue(CellComparatorImpl.COMPARATOR.compare(offheapKV, newOffheapKV) == 0);
286  }
287
288  /**
289   * Test Increment Mutate conversions.
290   * @throws IOException if converting to an {@link Increment} or
291   *                     {@link org.apache.hadoop.hbase.client.Mutation} fails
292   */
293  @Test
294  public void testIncrement() throws IOException {
295
296    MutationProto proto = getIncrementMutation(111111L);
297    // default fields
298    assertEquals(MutationProto.Durability.USE_DEFAULT, proto.getDurability());
299
300    // set the default value for equal comparison
301    MutationProto.Builder mutateBuilder = MutationProto.newBuilder(proto);
302    mutateBuilder.setDurability(MutationProto.Durability.USE_DEFAULT);
303
304    Increment increment = ProtobufUtil.toIncrement(proto, null);
305    mutateBuilder.setTimestamp(increment.getTimestamp());
306    mutateBuilder.setTimeRange(ProtobufUtil.toTimeRange(increment.getTimeRange()));
307    assertEquals(mutateBuilder.build(), ProtobufUtil.toMutation(MutationType.INCREMENT, increment));
308  }
309
310  private MutationProto getIncrementMutation(Long timestamp) {
311    MutationProto.Builder mutateBuilder = MutationProto.newBuilder();
312    mutateBuilder.setRow(ByteString.copyFromUtf8("row"));
313    mutateBuilder.setMutateType(MutationProto.MutationType.INCREMENT);
314    ColumnValue.Builder valueBuilder = ColumnValue.newBuilder();
315    valueBuilder.setFamily(ByteString.copyFromUtf8("f1"));
316    QualifierValue.Builder qualifierBuilder = QualifierValue.newBuilder();
317    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c1"));
318    qualifierBuilder.setValue(ByteString.copyFrom(Bytes.toBytes(11L)));
319
320    if (timestamp != null) {
321      qualifierBuilder.setTimestamp(timestamp);
322    }
323
324    valueBuilder.addQualifierValue(qualifierBuilder.build());
325    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c2"));
326    qualifierBuilder.setValue(ByteString.copyFrom(Bytes.toBytes(22L)));
327    valueBuilder.addQualifierValue(qualifierBuilder.build());
328    mutateBuilder.addColumnValue(valueBuilder.build());
329
330    return mutateBuilder.build();
331  }
332
333  /**
334   * Older clients may not send along a timestamp in the MutationProto. Check that we default
335   * correctly.
336   */
337  @Test
338  public void testIncrementNoTimestamp() throws IOException {
339    MutationProto mutation = getIncrementMutation(null);
340    Increment increment = ProtobufUtil.toIncrement(mutation, null);
341    assertEquals(HConstants.LATEST_TIMESTAMP, increment.getTimestamp());
342    increment.getFamilyCellMap().values().forEach(cells -> cells
343      .forEach(cell -> assertEquals(HConstants.LATEST_TIMESTAMP, cell.getTimestamp())));
344  }
345
346  /**
347   * Test Append Mutate conversions.
348   * @throws IOException if converting to an {@link Append} fails
349   */
350  @Test
351  public void testAppend() throws IOException {
352    MutationProto proto = getAppendMutation(111111L);
353    // default fields
354    assertEquals(MutationProto.Durability.USE_DEFAULT, proto.getDurability());
355
356    // set the default value for equal comparison
357    MutationProto.Builder mutateBuilder = MutationProto.newBuilder(proto);
358    mutateBuilder.setDurability(MutationProto.Durability.USE_DEFAULT);
359
360    Append append = ProtobufUtil.toAppend(proto, null);
361
362    // append always use the latest timestamp,
363    // reset the timestamp to the original mutate
364    mutateBuilder.setTimestamp(append.getTimestamp());
365    mutateBuilder.setTimeRange(ProtobufUtil.toTimeRange(append.getTimeRange()));
366    assertEquals(mutateBuilder.build(), ProtobufUtil.toMutation(MutationType.APPEND, append));
367  }
368
369  /**
370   * Older clients may not send along a timestamp in the MutationProto. Check that we default
371   * correctly.
372   */
373  @Test
374  public void testAppendNoTimestamp() throws IOException {
375    MutationProto mutation = getAppendMutation(null);
376    Append append = ProtobufUtil.toAppend(mutation, null);
377    assertEquals(HConstants.LATEST_TIMESTAMP, append.getTimestamp());
378    append.getFamilyCellMap().values().forEach(cells -> cells
379      .forEach(cell -> assertEquals(HConstants.LATEST_TIMESTAMP, cell.getTimestamp())));
380  }
381
382  private MutationProto getAppendMutation(Long timestamp) {
383    MutationProto.Builder mutateBuilder = MutationProto.newBuilder();
384    mutateBuilder.setRow(ByteString.copyFromUtf8("row"));
385    mutateBuilder.setMutateType(MutationType.APPEND);
386    if (timestamp != null) {
387      mutateBuilder.setTimestamp(timestamp);
388    }
389    ColumnValue.Builder valueBuilder = ColumnValue.newBuilder();
390    valueBuilder.setFamily(ByteString.copyFromUtf8("f1"));
391    QualifierValue.Builder qualifierBuilder = QualifierValue.newBuilder();
392    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c1"));
393    qualifierBuilder.setValue(ByteString.copyFromUtf8("v1"));
394    if (timestamp != null) {
395      qualifierBuilder.setTimestamp(timestamp);
396    }
397    valueBuilder.addQualifierValue(qualifierBuilder.build());
398    qualifierBuilder.setQualifier(ByteString.copyFromUtf8("c2"));
399    qualifierBuilder.setValue(ByteString.copyFromUtf8("v2"));
400    valueBuilder.addQualifierValue(qualifierBuilder.build());
401    mutateBuilder.addColumnValue(valueBuilder.build());
402
403    return mutateBuilder.build();
404  }
405
406  private static ProcedureProtos.Procedure.Builder createProcedureBuilder(long procId) {
407    ProcedureProtos.Procedure.Builder builder = ProcedureProtos.Procedure.newBuilder();
408    builder.setProcId(procId);
409    builder.setClassName("java.lang.Object");
410    builder.setSubmittedTime(0);
411    builder.setState(ProcedureProtos.ProcedureState.RUNNABLE);
412    builder.setLastUpdate(0);
413
414    return builder;
415  }
416
417  private static ProcedureProtos.Procedure createProcedure(long procId) {
418    return createProcedureBuilder(procId).build();
419  }
420
421  private static LockServiceProtos.LockedResource createLockedResource(
422    LockServiceProtos.LockedResourceType resourceType, String resourceName,
423    LockServiceProtos.LockType lockType, ProcedureProtos.Procedure exclusiveLockOwnerProcedure,
424    int sharedLockCount) {
425    LockServiceProtos.LockedResource.Builder build = LockServiceProtos.LockedResource.newBuilder();
426    build.setResourceType(resourceType);
427    build.setResourceName(resourceName);
428    build.setLockType(lockType);
429    if (exclusiveLockOwnerProcedure != null) {
430      build.setExclusiveLockOwnerProcedure(exclusiveLockOwnerProcedure);
431    }
432    build.setSharedLockCount(sharedLockCount);
433
434    return build.build();
435  }
436
437  @Test
438  public void testProcedureInfo() {
439    ProcedureProtos.Procedure.Builder builder = createProcedureBuilder(1);
440    ByteString stateBytes = ByteString.copyFrom(new byte[] { 65 });
441    BytesValue state = BytesValue.newBuilder().setValue(stateBytes).build();
442    builder.addStateMessage(Any.pack(state));
443    ProcedureProtos.Procedure procedure = builder.build();
444
445    String procJson = ProtobufUtil.toProcedureJson(Lists.newArrayList(procedure));
446    assertEquals("[{" + "\"className\":\"java.lang.Object\"," + "\"procId\":\"1\","
447      + "\"submittedTime\":\"0\"," + "\"state\":\"RUNNABLE\"," + "\"lastUpdate\":\"0\","
448      + "\"stateMessage\":[{\"value\":\"QQ==\"}]" + "}]", procJson);
449  }
450
451  @Test
452  public void testServerLockInfo() {
453    LockServiceProtos.LockedResource resource =
454      createLockedResource(LockServiceProtos.LockedResourceType.SERVER, "server",
455        LockServiceProtos.LockType.SHARED, null, 2);
456
457    String lockJson = ProtobufUtil.toLockJson(Lists.newArrayList(resource));
458    assertEquals("[{" + "\"resourceType\":\"SERVER\"," + "\"resourceName\":\"server\","
459      + "\"lockType\":\"SHARED\"," + "\"sharedLockCount\":2" + "}]", lockJson);
460  }
461
462  @Test
463  public void testNamespaceLockInfo() {
464    LockServiceProtos.LockedResource resource =
465      createLockedResource(LockServiceProtos.LockedResourceType.NAMESPACE, "ns",
466        LockServiceProtos.LockType.EXCLUSIVE, createProcedure(2), 0);
467
468    String lockJson = ProtobufUtil.toLockJson(Lists.newArrayList(resource));
469    assertEquals("[{" + "\"resourceType\":\"NAMESPACE\"," + "\"resourceName\":\"ns\","
470      + "\"lockType\":\"EXCLUSIVE\"," + "\"exclusiveLockOwnerProcedure\":{"
471      + "\"className\":\"java.lang.Object\"," + "\"procId\":\"2\"," + "\"submittedTime\":\"0\","
472      + "\"state\":\"RUNNABLE\"," + "\"lastUpdate\":\"0\"" + "}," + "\"sharedLockCount\":0" + "}]",
473      lockJson);
474  }
475
476  @Test
477  public void testTableLockInfo() {
478    LockServiceProtos.LockedResource resource =
479      createLockedResource(LockServiceProtos.LockedResourceType.TABLE, "table",
480        LockServiceProtos.LockType.SHARED, null, 2);
481
482    String lockJson = ProtobufUtil.toLockJson(Lists.newArrayList(resource));
483    assertEquals("[{" + "\"resourceType\":\"TABLE\"," + "\"resourceName\":\"table\","
484      + "\"lockType\":\"SHARED\"," + "\"sharedLockCount\":2" + "}]", lockJson);
485  }
486
487  @Test
488  public void testRegionLockInfo() {
489    LockServiceProtos.LockedResource resource =
490      createLockedResource(LockServiceProtos.LockedResourceType.REGION, "region",
491        LockServiceProtos.LockType.EXCLUSIVE, createProcedure(3), 0);
492
493    String lockJson = ProtobufUtil.toLockJson(Lists.newArrayList(resource));
494    assertEquals("[{" + "\"resourceType\":\"REGION\"," + "\"resourceName\":\"region\","
495      + "\"lockType\":\"EXCLUSIVE\"," + "\"exclusiveLockOwnerProcedure\":{"
496      + "\"className\":\"java.lang.Object\"," + "\"procId\":\"3\"," + "\"submittedTime\":\"0\","
497      + "\"state\":\"RUNNABLE\"," + "\"lastUpdate\":\"0\"" + "}," + "\"sharedLockCount\":0" + "}]",
498      lockJson);
499  }
500
501  /**
502   * Test {@link ProtobufUtil#toCell(ExtendedCell, boolean)} and
503   * {@link ProtobufUtil#toCell(ExtendedCellBuilder, CellProtos.Cell, boolean)} conversion methods
504   * when it contains tags and encode/decode tags is set to true.
505   */
506  @Test
507  public void testCellConversionWithTags() {
508    ExtendedCell cell = getCellWithTags();
509    CellProtos.Cell protoCell = ProtobufUtil.toCell(cell, true);
510    assertNotNull(protoCell);
511
512    ExtendedCell decodedCell = getCellFromProtoResult(protoCell, true);
513    List<Tag> decodedTags = PrivateCellUtil.getTags(decodedCell);
514    assertEquals(1, decodedTags.size());
515    Tag decodedTag = decodedTags.get(0);
516    assertEquals(TAG_TYPE, decodedTag.getType());
517    assertEquals(TAG_STR, Tag.getValueAsString(decodedTag));
518  }
519
520  private ExtendedCell getCellWithTags() {
521    Tag tag = new ArrayBackedTag(TAG_TYPE, TAG_STR);
522    ExtendedCellBuilder cellBuilder = ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY);
523    cellBuilder.setRow(Bytes.toBytes("row1"));
524    cellBuilder.setFamily(Bytes.toBytes("f1"));
525    cellBuilder.setQualifier(Bytes.toBytes("q1"));
526    cellBuilder.setValue(Bytes.toBytes("value1"));
527    cellBuilder.setType(Cell.Type.Delete);
528    cellBuilder.setTags(Collections.singletonList(tag));
529    return cellBuilder.build();
530  }
531
532  private ExtendedCell getCellFromProtoResult(CellProtos.Cell protoCell, boolean decodeTags) {
533    ExtendedCellBuilder decodedBuilder =
534      ExtendedCellBuilderFactory.create(CellBuilderType.DEEP_COPY);
535    return ProtobufUtil.toCell(decodedBuilder, protoCell, decodeTags);
536  }
537
538  /**
539   * Test {@link ProtobufUtil#toCell(Cell, boolean)} and
540   * {@link ProtobufUtil#toCell(ExtendedCellBuilder, CellProtos.Cell, boolean)} conversion methods
541   * when it contains tags and encode/decode tags is set to false.
542   */
543  @Test
544  public void testCellConversionWithoutTags() {
545    ExtendedCell cell = getCellWithTags();
546    CellProtos.Cell protoCell = ProtobufUtil.toCell(cell, false);
547    assertNotNull(protoCell);
548
549    ExtendedCell decodedCell = getCellFromProtoResult(protoCell, false);
550    List<Tag> decodedTags = PrivateCellUtil.getTags(decodedCell);
551    assertEquals(0, decodedTags.size());
552  }
553
554  /**
555   * Test {@link ProtobufUtil#toCell(Cell, boolean)} and
556   * {@link ProtobufUtil#toCell(ExtendedCellBuilder, CellProtos.Cell, boolean)} conversion methods
557   * when it contains tags and encoding of tags is set to false and decoding of tags is set to true.
558   */
559  @Test
560  public void testTagEncodeFalseDecodeTrue() {
561    ExtendedCell cell = getCellWithTags();
562    CellProtos.Cell protoCell = ProtobufUtil.toCell(cell, false);
563    assertNotNull(protoCell);
564
565    ExtendedCell decodedCell = getCellFromProtoResult(protoCell, true);
566    List<Tag> decodedTags = PrivateCellUtil.getTags(decodedCell);
567    assertEquals(0, decodedTags.size());
568  }
569
570  /**
571   * Test {@link ProtobufUtil#toCell(Cell, boolean)} and
572   * {@link ProtobufUtil#toCell(ExtendedCellBuilder, CellProtos.Cell, boolean)} conversion methods
573   * when it contains tags and encoding of tags is set to true and decoding of tags is set to false.
574   */
575  @Test
576  public void testTagEncodeTrueDecodeFalse() {
577    ExtendedCell cell = getCellWithTags();
578    CellProtos.Cell protoCell = ProtobufUtil.toCell(cell, true);
579    assertNotNull(protoCell);
580
581    ExtendedCell decodedCell = getCellFromProtoResult(protoCell, false);
582    List<Tag> decodedTags = PrivateCellUtil.getTags(decodedCell);
583    assertEquals(0, decodedTags.size());
584  }
585
586  /**
587   * Used to confirm that we only consider truncatedMessage as EOF
588   */
589  @Test
590  public void testIsEOF() throws Exception {
591    for (Method method : InvalidProtocolBufferException.class.getDeclaredMethods()) {
592      if (
593        method.getParameterCount() == 0
594          && method.getReturnType() == InvalidProtocolBufferException.class
595      ) {
596        method.setAccessible(true);
597        InvalidProtocolBufferException e = (InvalidProtocolBufferException) method.invoke(null);
598        assertEquals(method.getName().equals("truncatedMessage"), ProtobufUtil.isEOF(e));
599      }
600    }
601  }
602
603  @Test
604  public void testSlowLogParamsMutationProto() {
605    MutationProto mutationProto =
606      ClientProtos.MutationProto.newBuilder().setRow(ByteString.copyFromUtf8("row123")).build();
607
608    SlowLogParams slowLogParams = ProtobufUtil.getSlowLogParams(mutationProto, false);
609
610    assertTrue(slowLogParams.getParams()
611      .contains(Bytes.toStringBinary(mutationProto.getRow().toByteArray())));
612  }
613
614  @Test
615  public void testSlowLogParamsMutateRequest() {
616    MutationProto mutationProto =
617      ClientProtos.MutationProto.newBuilder().setRow(ByteString.copyFromUtf8("row123")).build();
618    ClientProtos.MutateRequest mutateRequest =
619      ClientProtos.MutateRequest.newBuilder().setMutation(mutationProto)
620        .setRegion(HBaseProtos.RegionSpecifier.newBuilder()
621          .setType(HBaseProtos.RegionSpecifier.RegionSpecifierType.REGION_NAME)
622          .setValue(ByteString.EMPTY).build())
623        .build();
624
625    SlowLogParams slowLogParams = ProtobufUtil.getSlowLogParams(mutateRequest, false);
626
627    assertTrue(slowLogParams.getParams()
628      .contains(Bytes.toStringBinary(mutationProto.getRow().toByteArray())));
629  }
630
631  @Test
632  public void testGetShortTextFormatNull() {
633    String actual = ProtobufUtil.getShortTextFormat(null);
634    assertNotNull(actual);
635    assertEquals("null", actual);
636  }
637
638  @Test
639  public void testGetShortTextFormatScanRequest() {
640    ClientProtos.ScanRequest.Builder builder = ClientProtos.ScanRequest.newBuilder();
641    builder.setRegion(REGION);
642    ClientProtos.ScanRequest scanRequest = builder.build();
643
644    String actual = ProtobufUtil.getShortTextFormat(scanRequest);
645
646    assertNotNull(actual);
647    assertEquals("region { type: REGION_NAME value: \"test\" }", actual);
648  }
649
650  @Test
651  public void testGetShortTextFormatRegionServerReportRequest() {
652    RegionServerStatusProtos.RegionServerReportRequest.Builder builder =
653      RegionServerStatusProtos.RegionServerReportRequest.newBuilder();
654    builder.setServer(SERVER_NAME);
655    RegionServerStatusProtos.RegionServerReportRequest request = builder.build();
656
657    String actual = ProtobufUtil.getShortTextFormat(request);
658
659    assertNotNull(actual);
660    assertEquals("server host_name: \"a.b.com\" load { numberOfRequests: 0 }", actual);
661  }
662
663  @Test
664  public void testGetShortTextFormatRegionServerStartupRequest() {
665    RegionServerStatusProtos.RegionServerStartupRequest.Builder builder =
666      RegionServerStatusProtos.RegionServerStartupRequest.newBuilder();
667    builder.setPort(8080);
668    builder.setServerCurrentTime(111111L);
669    builder.setServerStartCode(15L);
670    builder.setUseThisHostnameInstead("some-host-name");
671    RegionServerStatusProtos.RegionServerStartupRequest regionServerStartupRequest =
672      builder.build();
673
674    String actual = ProtobufUtil.getShortTextFormat(regionServerStartupRequest);
675
676    assertNotNull(actual);
677    assertEquals("port: 8080 server_start_code: 15 server_current_time: 111111"
678      + " use_this_hostname_instead: \"some-host-name\"", actual);
679  }
680
681  @Test
682  public void testGetShortTextFormatMutationProto() {
683    MutationProto mutationProto =
684      ClientProtos.MutationProto.newBuilder().setRow(ByteString.copyFromUtf8("row123")).build();
685
686    String actual = ProtobufUtil.getShortTextFormat(mutationProto);
687
688    assertNotNull(actual);
689    assertEquals("row=row123, type=APPEND", actual);
690  }
691
692  @Test
693  public void testGetShortTextFormatGetRequest() throws IOException {
694    ClientProtos.GetRequest getRequest = ClientProtos.GetRequest.newBuilder().setRegion(REGION)
695      .setGet(ProtobufUtil.toGet(new Get(Bytes.toBytes("foo")))).build();
696
697    String actual = ProtobufUtil.getShortTextFormat(getRequest);
698
699    assertNotNull(actual);
700    assertEquals("region= test, row=foo", actual);
701  }
702
703  @Test
704  public void testGetShortTextFormatMultiRequest() throws IOException {
705    ClientProtos.Action action = ClientProtos.Action.newBuilder()
706      .setGet(ProtobufUtil.toGet(new Get(Bytes.toBytes("foo")))).build();
707    ClientProtos.RegionAction regionAction =
708      ClientProtos.RegionAction.newBuilder().addAction(action).setRegion(REGION).build();
709
710    ClientProtos.MultiRequest multiRequest =
711      ClientProtos.MultiRequest.newBuilder().addRegionAction(regionAction).build();
712
713    String actual = ProtobufUtil.getShortTextFormat(multiRequest);
714
715    assertNotNull(actual);
716    assertEquals("region= test, for 1 action(s) and 1st row key=foo", actual);
717  }
718
719  @Test
720  public void testGetShortTextFormatMutateRequest() throws IOException {
721    ClientProtos.MutateRequest mutateRequest = ClientProtos.MutateRequest.newBuilder()
722      .setMutation(
723        ProtobufUtil.toMutation(MutationType.INCREMENT, new Increment(Bytes.toBytes("foo"))))
724      .setRegion(REGION).build();
725
726    String actual = ProtobufUtil.getShortTextFormat(mutateRequest);
727
728    assertNotNull(actual);
729    assertEquals("region= test, row=foo", actual);
730  }
731
732  @Test
733  public void testGetShortTextFormatCoprocessorServiceRequest() {
734    ClientProtos.CoprocessorServiceCall call = ClientProtos.CoprocessorServiceCall.newBuilder()
735      .setRow(ByteString.copyFrom(Bytes.toBytes("foo"))).setMethodName("awesomeMethod")
736      .setServiceName("awesomeService")
737      .setRequest(ByteString.copyFrom(Bytes.toBytes("foo-request"))).build();
738
739    ClientProtos.CoprocessorServiceRequest.Builder builder =
740      ClientProtos.CoprocessorServiceRequest.newBuilder();
741    builder.setRegion(REGION);
742    builder.setCall(call);
743    ClientProtos.CoprocessorServiceRequest coprocessorServiceRequest = builder.build();
744
745    String actual = ProtobufUtil.getShortTextFormat(coprocessorServiceRequest);
746
747    assertNotNull(actual);
748    assertEquals("coprocessorService= awesomeService:awesomeMethod", actual);
749  }
750
751  @Test
752  public void testGetShortTextFormatMoveRegionRequest() {
753    MasterProtos.MoveRegionRequest.Builder builder = MasterProtos.MoveRegionRequest.newBuilder();
754    builder.setRegion(REGION);
755    builder.setDestServerName(SERVER_NAME);
756    MasterProtos.MoveRegionRequest moveRegionRequest = builder.build();
757
758    String actual = ProtobufUtil.getShortTextFormat(moveRegionRequest);
759
760    assertNotNull(actual);
761    assertEquals(
762      "region { type: REGION_NAME value: \"test\" } dest_server_name { host_name: \"a.b.com\" }",
763      actual);
764  }
765}