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.hamcrest.CoreMatchers.instanceOf;
021import static org.hamcrest.MatcherAssert.assertThat;
022import static org.junit.jupiter.api.Assertions.assertArrayEquals;
023import static org.junit.jupiter.api.Assertions.assertEquals;
024import static org.junit.jupiter.api.Assertions.assertFalse;
025import static org.junit.jupiter.api.Assertions.assertNull;
026import static org.junit.jupiter.api.Assertions.assertTrue;
027import static org.junit.jupiter.api.Assertions.fail;
028
029import java.io.File;
030import java.io.FileOutputStream;
031import java.io.IOException;
032import java.nio.ByteBuffer;
033import java.util.Arrays;
034import java.util.Base64;
035import java.util.List;
036import java.util.Set;
037import org.apache.hadoop.conf.Configuration;
038import org.apache.hadoop.hbase.HBaseConfiguration;
039import org.apache.hadoop.hbase.filter.Filter;
040import org.apache.hadoop.hbase.filter.FilterList;
041import org.apache.hadoop.hbase.filter.KeyOnlyFilter;
042import org.apache.hadoop.hbase.security.access.Permission;
043import org.apache.hadoop.hbase.security.visibility.Authorizations;
044import org.apache.hadoop.hbase.testclassification.ClientTests;
045import org.apache.hadoop.hbase.testclassification.SmallTests;
046import org.apache.hadoop.hbase.util.Bytes;
047import org.junit.jupiter.api.Tag;
048import org.junit.jupiter.api.Test;
049
050import org.apache.hbase.thirdparty.com.google.common.base.Throwables;
051
052import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
053import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
054
055// TODO: cover more test cases
056@Tag(ClientTests.TAG)
057@Tag(SmallTests.TAG)
058public class TestGet {
059
060  private static final byte[] ROW = new byte[] { 'r' };
061
062  private static final String PB_GET = "CgNyb3ciEwoPdGVzdC5Nb2NrRmlsdGVyEgAwATgB";
063  private static final String PB_GET_WITH_FILTER_LIST =
064    "CgFyIosBCilvcmcuYXBhY2hlLmhhZG9vcC5oYmFzZS5maWx0ZXIuRmlsdGVyTGlzdBJeCAESEwoP"
065      + "dGVzdC5Nb2NrRmlsdGVyEgASEQoNbXkuTW9ja0ZpbHRlchIAEjIKLG9yZy5hcGFjaGUuaGFkb29w"
066      + "LmhiYXNlLmZpbHRlci5LZXlPbmx5RmlsdGVyEgIIADABOAE=";
067
068  private static final String MOCK_FILTER_JAR =
069    "UEsDBBQACAgIANWDlEMAAAAAAAAAAAAAAAAJAAQATUVUQS1JTkYv/soAAAMAUEsHCAAAAAACAAAA"
070      + "AAAAAFBLAwQUAAgICADVg5RDAAAAAAAAAAAAAAAAFAAAAE1FVEEtSU5GL01BTklGRVNULk1G803M"
071      + "y0xLLS7RDUstKs7Mz7NSMNQz4OVyLkpNLElN0XWqBAmY6xnEG1gqaPgXJSbnpCo45xcV5BcllgCV"
072      + "a/Jy8XIBAFBLBwgxyqRbQwAAAEQAAABQSwMEFAAICAgAUoOUQwAAAAAAAAAAAAAAABMAAABteS9N"
073      + "b2NrRmlsdGVyLmNsYXNzdZHPTsJAEMa/LYVCRVFQMd68gQc38YrxUJUTetGQGE7bstrVwjbbYsSn"
074      + "0hOJJj6AD2WcFoP/4iYzX+bb32xmd9/en18B7GPLhY11BxsurEw3GUoHaqzSQ4ZCq91nsI/0UDLU"
075      + "emoszyYjX5oL4Ufk1Hs6EFFfGJXVn6adhirJ6NGUn+rgtquiVJoOQyUWJpFdo0cMjdbAa/8hnNj3"
076      + "pqmkbmvgMbgn94GMU6XHiYMm1ed6YgJJeDbNV+fejbgTVRRRYlj+cSZDW5trLmIRhJKHYqh1zENf"
077      + "JJJf5QCfcx45DJ3/WLmYgx/LRNJ1I/UgMmMxIXbo9WxkywLLZqHsUMVJGWlxdwb2lG+XKZdys4kK"
078      + "5eocgIsl0grVy0Q5+e9Y+V75BdblDIXHX/3b3/rLWEGNdJXCJmeNop7zjQ9QSwcI1kzyMToBAADs"
079      + "AQAAUEsDBBQACAgIAFKDlEMAAAAAAAAAAAAAAAAVAAAAdGVzdC9Nb2NrRmlsdGVyLmNsYXNzdVHB"
080      + "TsJAFJwthUJFERQx3ryBBzfxivFQlRN60ZAYTtuy2tXCNtti1K/SE4kmfoAfZXwtBg3RTd6bzOy8"
081      + "zezux+frO4ADbLuwsemg6cLKcIuhdKgmKj1iKLQ7Awb7WI8kQ62vJvJ8OvaluRR+REqjrwMRDYRR"
082      + "Gf8W7TRUCUO9n8ok5Wc6uOupKJWmy1CJhUlkz+gxQ7M99Dp/eJzY9x5JZrCGHoN7+hDIOFV6kjho"
083      + "Eb/QUxNIsmeJfib3b8W9qKKIEslLpzJ0tLnhIhZBKHkoRlrHPPRFIvl1buBzn0cKQ/c/r1wk4Scy"
084      + "kXTpSD2JTFhkxC69oY1sWWBZGuoOMU7ICIt7M7CXfLtMvZSLLVSoV+cGuFghrBBfJZeT/5GV75Xf"
085      + "YF3NUHhemt/5NV/GGmqE61Q2KXWqRu7f+AJQSwcIrS5nKDoBAADyAQAAUEsBAhQAFAAICAgA1YOU"
086      + "QwAAAAACAAAAAAAAAAkABAAAAAAAAAAAAAAAAAAAAE1FVEEtSU5GL/7KAABQSwECFAAUAAgICADV"
087      + "g5RDMcqkW0MAAABEAAAAFAAAAAAAAAAAAAAAAAA9AAAATUVUQS1JTkYvTUFOSUZFU1QuTUZQSwEC"
088      + "FAAUAAgICABSg5RD1kzyMToBAADsAQAAEwAAAAAAAAAAAAAAAADCAAAAbXkvTW9ja0ZpbHRlci5j"
089      + "bGFzc1BLAQIUABQACAgIAFKDlEOtLmcoOgEAAPIBAAAVAAAAAAAAAAAAAAAAAD0CAAB0ZXN0L01v"
090      + "Y2tGaWx0ZXIuY2xhc3NQSwUGAAAAAAQABAABAQAAugMAAAAA";
091
092  @Test
093  public void testAttributesSerialization() throws IOException {
094    Get get = new Get(Bytes.toBytes("row"));
095    get.setAttribute("attribute1", Bytes.toBytes("value1"));
096    get.setAttribute("attribute2", Bytes.toBytes("value2"));
097    get.setAttribute("attribute3", Bytes.toBytes("value3"));
098
099    ClientProtos.Get getProto = ProtobufUtil.toGet(get);
100
101    Get get2 = ProtobufUtil.toGet(getProto);
102    assertNull(get2.getAttribute("absent"));
103    assertTrue(Arrays.equals(Bytes.toBytes("value1"), get2.getAttribute("attribute1")));
104    assertTrue(Arrays.equals(Bytes.toBytes("value2"), get2.getAttribute("attribute2")));
105    assertTrue(Arrays.equals(Bytes.toBytes("value3"), get2.getAttribute("attribute3")));
106    assertEquals(3, get2.getAttributesMap().size());
107  }
108
109  @Test
110  public void testGetAttributes() {
111    Get get = new Get(ROW);
112    assertTrue(get.getAttributesMap().isEmpty());
113    assertNull(get.getAttribute("absent"));
114
115    get.setAttribute("absent", null);
116    assertTrue(get.getAttributesMap().isEmpty());
117    assertNull(get.getAttribute("absent"));
118
119    // adding attribute
120    get.setAttribute("attribute1", Bytes.toBytes("value1"));
121    assertTrue(Arrays.equals(Bytes.toBytes("value1"), get.getAttribute("attribute1")));
122    assertEquals(1, get.getAttributesMap().size());
123    assertTrue(Arrays.equals(Bytes.toBytes("value1"), get.getAttributesMap().get("attribute1")));
124
125    // overriding attribute value
126    get.setAttribute("attribute1", Bytes.toBytes("value12"));
127    assertTrue(Arrays.equals(Bytes.toBytes("value12"), get.getAttribute("attribute1")));
128    assertEquals(1, get.getAttributesMap().size());
129    assertTrue(Arrays.equals(Bytes.toBytes("value12"), get.getAttributesMap().get("attribute1")));
130
131    // adding another attribute
132    get.setAttribute("attribute2", Bytes.toBytes("value2"));
133    assertTrue(Arrays.equals(Bytes.toBytes("value2"), get.getAttribute("attribute2")));
134    assertEquals(2, get.getAttributesMap().size());
135    assertTrue(Arrays.equals(Bytes.toBytes("value2"), get.getAttributesMap().get("attribute2")));
136
137    // removing attribute
138    get.setAttribute("attribute2", null);
139    assertNull(get.getAttribute("attribute2"));
140    assertEquals(1, get.getAttributesMap().size());
141    assertNull(get.getAttributesMap().get("attribute2"));
142
143    // removing non-existed attribute
144    get.setAttribute("attribute2", null);
145    assertNull(get.getAttribute("attribute2"));
146    assertEquals(1, get.getAttributesMap().size());
147    assertNull(get.getAttributesMap().get("attribute2"));
148
149    // removing another attribute
150    get.setAttribute("attribute1", null);
151    assertNull(get.getAttribute("attribute1"));
152    assertTrue(get.getAttributesMap().isEmpty());
153    assertNull(get.getAttributesMap().get("attribute1"));
154  }
155
156  @Test
157  public void testNullQualifier() {
158    Get get = new Get(ROW);
159    byte[] family = Bytes.toBytes("family");
160    get.addColumn(family, null);
161    Set<byte[]> qualifiers = get.getFamilyMap().get(family);
162    assertEquals(1, qualifiers.size());
163  }
164
165  @Test
166  public void TestGetRowFromGetCopyConstructor() throws Exception {
167    Get get = new Get(ROW);
168    get.setFilter(null);
169    get.setAuthorizations(new Authorizations("foo"));
170    get.setACL("u", new Permission(Permission.Action.READ));
171    get.setConsistency(Consistency.TIMELINE);
172    get.setReplicaId(2);
173    get.setIsolationLevel(IsolationLevel.READ_UNCOMMITTED);
174    get.setCheckExistenceOnly(true);
175    get.setTimeRange(3, 4);
176    get.readVersions(11);
177    get.setMaxResultsPerColumnFamily(10);
178    get.setRowOffsetPerColumnFamily(11);
179    get.setCacheBlocks(true);
180    get.setQueryMetricsEnabled(true);
181
182    Get copyGet = new Get(get);
183    assertEquals(0, Bytes.compareTo(get.getRow(), copyGet.getRow()));
184
185    // from OperationWithAttributes
186    assertEquals(get.getId(), copyGet.getId());
187
188    // from Query class
189    assertEquals(get.getFilter(), copyGet.getFilter());
190    assertTrue(get.getAuthorizations().toString().equals(copyGet.getAuthorizations().toString()));
191    assertTrue(Bytes.equals(get.getACL(), copyGet.getACL()));
192    assertEquals(get.getConsistency(), copyGet.getConsistency());
193    assertEquals(get.getReplicaId(), copyGet.getReplicaId());
194    assertEquals(get.getIsolationLevel(), copyGet.getIsolationLevel());
195    assertTrue(get.isQueryMetricsEnabled());
196
197    // from Get class
198    assertEquals(get.isCheckExistenceOnly(), copyGet.isCheckExistenceOnly());
199    assertTrue(get.getTimeRange().equals(copyGet.getTimeRange()));
200    assertEquals(get.getMaxVersions(), copyGet.getMaxVersions());
201    assertEquals(get.getMaxResultsPerColumnFamily(), copyGet.getMaxResultsPerColumnFamily());
202    assertEquals(get.getRowOffsetPerColumnFamily(), copyGet.getRowOffsetPerColumnFamily());
203    assertEquals(get.getCacheBlocks(), copyGet.getCacheBlocks());
204    assertEquals(get.getId(), copyGet.getId());
205  }
206
207  @Test
208  public void testDynamicFilter() throws Exception {
209    Configuration conf = HBaseConfiguration.create();
210    String localPath = conf.get("hbase.local.dir") + File.separator + "jars" + File.separator;
211    File jarFile = new File(localPath, "MockFilter.jar");
212    jarFile.delete();
213    assertFalse(jarFile.exists(), "Should be deleted: " + jarFile.getPath());
214
215    ClientProtos.Get getProto1 = ClientProtos.Get.parseFrom(Base64.getDecoder().decode(PB_GET));
216    ClientProtos.Get getProto2 =
217      ClientProtos.Get.parseFrom(Base64.getDecoder().decode(PB_GET_WITH_FILTER_LIST));
218    try {
219      ProtobufUtil.toGet(getProto1);
220      fail("Should not be able to load the filter class");
221    } catch (IOException ioe) {
222      assertTrue(ioe.getCause() instanceof ClassNotFoundException);
223    }
224    try {
225      ProtobufUtil.toGet(getProto2);
226      fail("Should not be able to load the filter class");
227    } catch (IOException ioe) {
228      // This test is deserializing a FilterList, and one of the sub-filters is not found.
229      // So the actual caused by is buried a few levels deep.
230      assertThat(Throwables.getRootCause(ioe), instanceOf(ClassNotFoundException.class));
231    }
232    FileOutputStream fos = new FileOutputStream(jarFile);
233    fos.write(Base64.getDecoder().decode(MOCK_FILTER_JAR));
234    fos.close();
235
236    Get get1 = ProtobufUtil.toGet(getProto1);
237    assertEquals("test.MockFilter", get1.getFilter().getClass().getName());
238
239    Get get2 = ProtobufUtil.toGet(getProto2);
240    assertTrue(get2.getFilter() instanceof FilterList);
241    List<Filter> filters = ((FilterList) get2.getFilter()).getFilters();
242    assertEquals(3, filters.size());
243    assertEquals("test.MockFilter", filters.get(0).getClass().getName());
244    assertEquals("my.MockFilter", filters.get(1).getClass().getName());
245    assertTrue(filters.get(2) instanceof KeyOnlyFilter);
246  }
247
248  @Test
249  public void testGetRowConstructor() {
250    byte[] row1 = Bytes.toBytes("testRow");
251    byte[] row2 = Bytes.toBytes("testtestRow");
252    ByteBuffer rowBuffer = ByteBuffer.wrap(row1);
253    Get get1 = new Get(rowBuffer);
254    Get get2 = new Get(row2, 4, 7);
255    assertArrayEquals(get1.getRow(), get2.getRow());
256  }
257}