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.io.compress.zstd;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import java.io.IOException;
025import java.nio.ByteBuffer;
026import org.apache.hadoop.hbase.nio.ByteBuff;
027import org.apache.hadoop.hbase.nio.MultiByteBuff;
028import org.apache.hadoop.hbase.nio.SingleByteBuff;
029import org.apache.hadoop.hbase.testclassification.SmallTests;
030import org.apache.hadoop.hbase.util.Bytes;
031import org.junit.jupiter.api.Tag;
032import org.junit.jupiter.api.Test;
033
034@Tag(SmallTests.TAG)
035public class TestZstdByteBuffDecompressor {
036  /*
037   * "HBase is fun to use and very fast" compressed with zstd, and then prepended with metadata as a
038   * BlockCompressorStream would. The phrase is split in three parts and put into the payload in
039   * this structure: (block 1: (chunk 1: HBase is), (chunk 2: fun to use)), (block 2: (chunk 1: and
040   * very fast))
041   */
042  private static final byte[] COMPRESSED_PAYLOAD =
043    Bytes.fromHex("000000130000001228b52ffd200949000048426173652069732"
044      + "00000001428b52ffd200b59000066756e20746f207573652"
045      + "00000000d0000001628b52ffd200d690000616e6420766572792066617374");
046
047  @Test
048  public void testCapabilities() {
049    ByteBuff emptySingleHeapBuff = new SingleByteBuff(ByteBuffer.allocate(0));
050    ByteBuff emptyMultiHeapBuff = new MultiByteBuff(ByteBuffer.allocate(0), ByteBuffer.allocate(0));
051    ByteBuff emptySingleDirectBuff = new SingleByteBuff(ByteBuffer.allocateDirect(0));
052    ByteBuff emptyMultiDirectBuff =
053      new MultiByteBuff(ByteBuffer.allocateDirect(0), ByteBuffer.allocateDirect(0));
054    try (ZstdByteBuffDecompressor decompressor = new ZstdByteBuffDecompressor(null)) {
055      assertTrue(decompressor.canDecompress(emptySingleHeapBuff, emptySingleHeapBuff));
056      assertTrue(decompressor.canDecompress(emptySingleDirectBuff, emptySingleDirectBuff));
057      assertTrue(decompressor.canDecompress(emptySingleHeapBuff, emptySingleDirectBuff));
058      assertTrue(decompressor.canDecompress(emptySingleDirectBuff, emptySingleHeapBuff));
059      assertFalse(decompressor.canDecompress(emptyMultiHeapBuff, emptyMultiHeapBuff));
060      assertFalse(decompressor.canDecompress(emptyMultiDirectBuff, emptyMultiDirectBuff));
061      assertFalse(decompressor.canDecompress(emptySingleHeapBuff, emptyMultiHeapBuff));
062      assertFalse(decompressor.canDecompress(emptySingleDirectBuff, emptyMultiDirectBuff));
063    }
064  }
065
066  @Test
067  public void testDecompressHeapToHeap() throws IOException {
068    try (ZstdByteBuffDecompressor decompressor = new ZstdByteBuffDecompressor(null)) {
069      ByteBuff output = new SingleByteBuff(ByteBuffer.allocate(64));
070      ByteBuff input = new SingleByteBuff(ByteBuffer.wrap(COMPRESSED_PAYLOAD));
071      int decompressedSize = decompressor.decompress(output, input, COMPRESSED_PAYLOAD.length);
072      assertEquals("HBase is fun to use and very fast",
073        Bytes.toString(output.toBytes(0, decompressedSize)));
074    }
075  }
076
077  @Test
078  public void testDecompressDirectToDirect() throws IOException {
079    try (ZstdByteBuffDecompressor decompressor = new ZstdByteBuffDecompressor(null)) {
080      ByteBuff output = new SingleByteBuff(ByteBuffer.allocateDirect(64));
081      ByteBuff input = new SingleByteBuff(ByteBuffer.allocateDirect(COMPRESSED_PAYLOAD.length));
082      input.put(COMPRESSED_PAYLOAD);
083      input.rewind();
084      int decompressedSize = decompressor.decompress(output, input, COMPRESSED_PAYLOAD.length);
085      assertEquals("HBase is fun to use and very fast",
086        Bytes.toString(output.toBytes(0, decompressedSize)));
087    }
088  }
089
090  @Test
091  public void testDecompressDirectToHeap() throws IOException {
092    try (ZstdByteBuffDecompressor decompressor = new ZstdByteBuffDecompressor(null)) {
093      ByteBuff output = new SingleByteBuff(ByteBuffer.allocate(64));
094      ByteBuff input = new SingleByteBuff(ByteBuffer.allocateDirect(COMPRESSED_PAYLOAD.length));
095      input.put(COMPRESSED_PAYLOAD);
096      input.rewind();
097      int decompressedSize = decompressor.decompress(output, input, COMPRESSED_PAYLOAD.length);
098      assertEquals("HBase is fun to use and very fast",
099        Bytes.toString(output.toBytes(0, decompressedSize)));
100    }
101  }
102
103  @Test
104  public void testDecompressHeapToDirect() throws IOException {
105    try (ZstdByteBuffDecompressor decompressor = new ZstdByteBuffDecompressor(null)) {
106      ByteBuff output = new SingleByteBuff(ByteBuffer.allocateDirect(64));
107      ByteBuff input = new SingleByteBuff(ByteBuffer.wrap(COMPRESSED_PAYLOAD));
108      int decompressedSize = decompressor.decompress(output, input, COMPRESSED_PAYLOAD.length);
109      assertEquals("HBase is fun to use and very fast",
110        Bytes.toString(output.toBytes(0, decompressedSize)));
111    }
112  }
113}