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.rest.model;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertThrows;
022import static org.junit.jupiter.api.Assertions.assertTrue;
023
024import com.fasterxml.jackson.core.JsonParseException;
025import com.fasterxml.jackson.databind.JsonMappingException;
026import com.fasterxml.jackson.databind.node.ObjectNode;
027import org.apache.hadoop.hbase.rest.ScannerResultGenerator;
028import org.apache.hadoop.hbase.testclassification.RestTests;
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(RestTests.TAG)
035@Tag(SmallTests.TAG)
036public class TestScannerModel extends TestModelBase<ScannerModel> {
037
038  private static final String PRIVATE = "private";
039  private static final String PUBLIC = "public";
040  private static final byte[] START_ROW = Bytes.toBytes("abracadabra");
041  private static final byte[] END_ROW = Bytes.toBytes("zzyzx");
042  private static final byte[] COLUMN1 = Bytes.toBytes("column1");
043  private static final byte[] COLUMN2 = Bytes.toBytes("column2:foo");
044  private static final long START_TIME = 1245219839331L;
045  private static final long END_TIME = 1245393318192L;
046  private static final int CACHING = 1000;
047  private static final int LIMIT = 10000;
048  private static final int BATCH = 100;
049  private static final boolean CACHE_BLOCKS = false;
050
051  public TestScannerModel() throws Exception {
052    super(ScannerModel.class);
053
054    AS_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
055      + "<Scanner batch=\"100\" cacheBlocks=\"false\" caching=\"1000\" endRow=\"enp5eng=\" endTime=\"1245393318192\""
056      + " limit=\"10000\" maxVersions=\"2147483647\" startRow=\"YWJyYWNhZGFicmE=\" startTime=\"1245219839331\">"
057      + "<column>Y29sdW1uMQ==</column> <column>Y29sdW1uMjpmb28=</column>"
058      + "<labels>private</labels> <labels>public</labels></Scanner>";
059
060    AS_JSON = "{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
061      + "\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
062      + "\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
063      + "\"labels\":[\"private\",\"public\"]," + "\"limit\":10000}";
064
065    AS_PB = "CgthYnJhY2FkYWJyYRIFenp5engaB2NvbHVtbjEaC2NvbHVtbjI6Zm9vIGQo47qL554kMLDi57mfJDj"
066      + "/////B0joB1IHcHJpdmF0ZVIGcHVibGljWABgkE4=";
067  }
068
069  @Override
070  protected ScannerModel buildTestModel() {
071    ScannerModel model = new ScannerModel();
072    model.setStartRow(START_ROW);
073    model.setEndRow(END_ROW);
074    model.addColumn(COLUMN1);
075    model.addColumn(COLUMN2);
076    model.setStartTime(START_TIME);
077    model.setEndTime(END_TIME);
078    model.setBatch(BATCH);
079    model.setCaching(CACHING);
080    model.addLabel(PRIVATE);
081    model.addLabel(PUBLIC);
082    model.setCacheBlocks(CACHE_BLOCKS);
083    model.setLimit(LIMIT);
084    return model;
085  }
086
087  @Override
088  protected void checkModel(ScannerModel model) {
089    assertTrue(Bytes.equals(model.getStartRow(), START_ROW));
090    assertTrue(Bytes.equals(model.getEndRow(), END_ROW));
091    boolean foundCol1 = false, foundCol2 = false;
092    for (byte[] column : model.getColumns()) {
093      if (Bytes.equals(column, COLUMN1)) {
094        foundCol1 = true;
095      } else if (Bytes.equals(column, COLUMN2)) {
096        foundCol2 = true;
097      }
098    }
099    assertTrue(foundCol1);
100    assertTrue(foundCol2);
101    assertEquals(START_TIME, model.getStartTime());
102    assertEquals(END_TIME, model.getEndTime());
103    assertEquals(BATCH, model.getBatch());
104    assertEquals(LIMIT, model.getLimit());
105    assertEquals(CACHING, model.getCaching());
106    assertEquals(CACHE_BLOCKS, model.getCacheBlocks());
107    boolean foundLabel1 = false;
108    boolean foundLabel2 = false;
109    if (model.getLabels() != null && !model.getLabels().isEmpty()) {
110      for (String label : model.getLabels()) {
111        if (label.equals(PRIVATE)) {
112          foundLabel1 = true;
113        } else if (label.equals(PUBLIC)) {
114          foundLabel2 = true;
115        }
116      }
117      assertTrue(foundLabel1);
118      assertTrue(foundLabel2);
119    }
120  }
121
122  @Test
123  public void testExistingFilter() throws Exception {
124    final String CORRECT_FILTER = "{\"type\": \"PrefixFilter\", \"value\": \"cg==\"}";
125    verifyException(CORRECT_FILTER);
126  }
127
128  @Test
129  public void testNonExistingFilter() throws Exception {
130    final String UNKNOWN_FILTER = "{\"type\": \"UnknownFilter\", \"value\": \"cg==\"}";
131    assertThrows(IllegalArgumentException.class, () -> verifyException(UNKNOWN_FILTER));
132  }
133
134  @Test
135  public void testIncorrectFilterThrowsJME() throws Exception {
136    final String JME_FILTER = "{\"invalid_tag\": \"PrefixFilter\", \"value\": \"cg==\"}";
137    assertThrows(JsonMappingException.class, () -> verifyException(JME_FILTER));
138  }
139
140  @Test
141  public void tesIncorrectFilterThrowsJPE() throws Exception {
142    final String JPE_FILTER = "{\"type\": \"PrefixFilter\",, \"value\": \"cg==\"}";
143    assertThrows(JsonParseException.class, () -> verifyException(JPE_FILTER));
144  }
145
146  private void verifyException(final String FILTER) throws Exception {
147    ScannerModel model = new ScannerModel();
148    model.setFilter(FILTER);
149    ScannerResultGenerator.buildFilterFromModel(model);
150  }
151
152  @Test
153  public void testToJsonWithIncludeStartRowAndIncludeStopRow() throws Exception {
154    String jsonStr =
155      "{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
156        + "\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
157        + "\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
158        + "\"labels\":[\"private\",\"public\"]," + "\"limit\":10000,"
159        + "\"includeStartRow\":false,\"includeStopRow\":true}";
160
161    ObjectNode expObj = mapper.readValue(jsonStr, ObjectNode.class);
162    ObjectNode actObj = mapper.readValue(
163      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(false, true)), ObjectNode.class);
164    assertEquals(expObj, actObj);
165
166    jsonStr = "{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
167      + "\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
168      + "\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
169      + "\"labels\":[\"private\",\"public\"]," + "\"limit\":10000," + "\"includeStopRow\":true}";
170
171    expObj = mapper.readValue(jsonStr, ObjectNode.class);
172    actObj = mapper.readValue(
173      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(true, true)), ObjectNode.class);
174    assertEquals(expObj, actObj);
175
176    jsonStr = "{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
177      + "\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
178      + "\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
179      + "\"labels\":[\"private\",\"public\"]," + "\"limit\":10000," + "\"includeStartRow\":false}";
180
181    expObj = mapper.readValue(jsonStr, ObjectNode.class);
182    actObj = mapper.readValue(
183      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(false, false)), ObjectNode.class);
184    assertEquals(expObj, actObj);
185
186  }
187
188  protected ScannerModel buildTestModelWithIncludeStartRowAndIncludeStopRow(boolean includeStartRow,
189    boolean includeStopRow) {
190    ScannerModel model = new ScannerModel();
191    model.setStartRow(START_ROW);
192    model.setEndRow(END_ROW);
193    model.addColumn(COLUMN1);
194    model.addColumn(COLUMN2);
195    model.setStartTime(START_TIME);
196    model.setEndTime(END_TIME);
197    model.setBatch(BATCH);
198    model.setCaching(CACHING);
199    model.addLabel(PRIVATE);
200    model.addLabel(PUBLIC);
201    model.setCacheBlocks(CACHE_BLOCKS);
202    model.setLimit(LIMIT);
203    model.setIncludeStartRow(includeStartRow);
204    model.setIncludeStopRow(includeStopRow);
205    return model;
206  }
207}