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