blob: 6d534399bdd8ff2853c4d2c8a569ecc9791b7472 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.master.http;
import static org.apache.hadoop.hbase.client.hamcrest.BytesMatchers.bytesAsStringBinary;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletRequest;
import org.apache.hadoop.hbase.ClearUserNamespacesAndTablesRule;
import org.apache.hadoop.hbase.ConnectionRule;
import org.apache.hadoop.hbase.HBaseClassTestRule;
import org.apache.hadoop.hbase.MiniClusterRule;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.AsyncAdmin;
import org.apache.hadoop.hbase.client.AsyncConnection;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.master.RegionState;
import org.apache.hadoop.hbase.testclassification.MasterTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.apache.hadoop.hbase.util.RegionSplitter;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.RuleChain;
import org.junit.rules.TestName;
import org.junit.rules.TestRule;
import org.apache.hbase.thirdparty.org.apache.commons.collections4.IterableUtils;
/**
* Cluster-backed correctness tests for the functionality provided by {@link MetaBrowser}.
*/
@Category({ MasterTests.class, MediumTests.class})
public class TestMetaBrowser {
@ClassRule
public static final HBaseClassTestRule testRule =
HBaseClassTestRule.forClass(TestMetaBrowser.class);
@ClassRule
public static final MiniClusterRule miniClusterRule = MiniClusterRule.newBuilder().build();
private final ConnectionRule connectionRule =
new ConnectionRule(miniClusterRule::createConnection);
private final ClearUserNamespacesAndTablesRule clearUserNamespacesAndTablesRule =
new ClearUserNamespacesAndTablesRule(connectionRule::getConnection);
@Rule
public TestRule rule = RuleChain.outerRule(connectionRule)
.around(clearUserNamespacesAndTablesRule);
@Rule
public TestName testNameRule = new TestName();
private AsyncConnection connection;
private AsyncAdmin admin;
@Before
public void before() {
connection = connectionRule.getConnection();
admin = connection.getAdmin();
}
@Test
public void noFilters() {
final String namespaceName = testNameRule.getMethodName();
final TableName a = TableName.valueOf("a");
final TableName b = TableName.valueOf(namespaceName, "b");
CompletableFuture.allOf(
createTable(a),
createNamespace(namespaceName).thenCompose(_void -> createTable(b, 2)))
.join();
final HttpServletRequest request = new MockRequestBuilder().build();
final List<RegionReplicaInfo> rows;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request).getResults()) {
rows = IterableUtils.toList(results);
}
assertThat(rows, contains(
hasProperty("row", bytesAsStringBinary(startsWith(a + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",80000000")))));
}
@Test
public void limit() {
final String tableName = testNameRule.getMethodName();
createTable(TableName.valueOf(tableName), 8).join();
final HttpServletRequest request = new MockRequestBuilder()
.setLimit(5)
.build();
final List<RegionReplicaInfo> rows;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request).getResults()) {
rows = IterableUtils.toList(results);
}
assertThat(rows, contains(
hasProperty("row", bytesAsStringBinary(startsWith(tableName + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(tableName + ",20000000"))),
hasProperty("row", bytesAsStringBinary(startsWith(tableName + ",40000000"))),
hasProperty("row", bytesAsStringBinary(startsWith(tableName + ",60000000"))),
hasProperty("row", bytesAsStringBinary(startsWith(tableName + ",80000000")))));
}
@Test
public void regionStateFilter() {
final String namespaceName = testNameRule.getMethodName();
final TableName foo = TableName.valueOf(namespaceName, "foo");
final TableName bar = TableName.valueOf(namespaceName, "bar");
createNamespace(namespaceName)
.thenCompose(_void1 -> CompletableFuture.allOf(
createTable(foo, 2).thenCompose(_void2 -> admin.disableTable(foo)),
createTable(bar, 2)))
.join();
final HttpServletRequest request = new MockRequestBuilder()
.setLimit(10_000)
.setRegionState(RegionState.State.OPEN)
.setTable(namespaceName)
.build();
final List<RegionReplicaInfo> rows;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request).getResults()) {
rows = IterableUtils.toList(results);
}
assertThat(rows, contains(
hasProperty("row", bytesAsStringBinary(startsWith(bar.toString() + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(bar.toString() + ",80000000")))));
}
@Test
public void scanTableFilter() {
final String namespaceName = testNameRule.getMethodName();
final TableName a = TableName.valueOf("a");
final TableName b = TableName.valueOf(namespaceName, "b");
CompletableFuture.allOf(
createTable(a),
createNamespace(namespaceName).thenCompose(_void -> createTable(b, 2)))
.join();
final HttpServletRequest request = new MockRequestBuilder()
.setTable(namespaceName)
.build();
final List<RegionReplicaInfo> rows;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request).getResults()) {
rows = IterableUtils.toList(results);
}
assertThat(rows, contains(
hasProperty("row", bytesAsStringBinary(startsWith(b + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",80000000")))));
}
@Test
public void paginateWithReplicas() {
final String namespaceName = testNameRule.getMethodName();
final TableName a = TableName.valueOf("a");
final TableName b = TableName.valueOf(namespaceName, "b");
CompletableFuture.allOf(
createTableWithReplicas(a, 2),
createNamespace(namespaceName).thenCompose(_void -> createTable(b, 2)))
.join();
final HttpServletRequest request1 = new MockRequestBuilder()
.setLimit(2)
.build();
final List<RegionReplicaInfo> rows1;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request1).getResults()) {
rows1 = IterableUtils.toList(results);
}
assertThat(rows1, contains(
allOf(
hasProperty("regionName", bytesAsStringBinary(startsWith(a + ",,"))),
hasProperty("replicaId", equalTo(0))),
allOf(
hasProperty("regionName", bytesAsStringBinary(startsWith(a + ",,"))),
hasProperty("replicaId", equalTo(1)))));
final HttpServletRequest request2 = new MockRequestBuilder()
.setLimit(2)
.setStart(MetaBrowser.buildStartParamFrom(rows1.get(rows1.size() - 1).getRow()))
.build();
final List<RegionReplicaInfo> rows2;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request2).getResults()) {
rows2 = IterableUtils.toList(results);
}
assertThat(rows2, contains(
hasProperty("row", bytesAsStringBinary(startsWith(b + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",80000000")))));
}
@Test
public void paginateWithTableFilter() {
final String namespaceName = testNameRule.getMethodName();
final TableName a = TableName.valueOf("a");
final TableName b = TableName.valueOf(namespaceName, "b");
CompletableFuture.allOf(
createTable(a),
createNamespace(namespaceName).thenCompose(_void -> createTable(b, 5)))
.join();
final HttpServletRequest request1 = new MockRequestBuilder()
.setLimit(2)
.setTable(namespaceName)
.build();
final List<RegionReplicaInfo> rows1;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request1).getResults()) {
rows1 = IterableUtils.toList(results);
}
assertThat(rows1, contains(
hasProperty("row", bytesAsStringBinary(startsWith(b + ",,"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",33333333")))));
final HttpServletRequest request2 = new MockRequestBuilder()
.setLimit(2)
.setTable(namespaceName)
.setStart(MetaBrowser.buildStartParamFrom(rows1.get(rows1.size() - 1).getRow()))
.build();
final List<RegionReplicaInfo> rows2;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request2).getResults()) {
rows2 = IterableUtils.toList(results);
}
assertThat(rows2, contains(
hasProperty("row", bytesAsStringBinary(startsWith(b + ",66666666"))),
hasProperty("row", bytesAsStringBinary(startsWith(b + ",99999999")))));
final HttpServletRequest request3 = new MockRequestBuilder()
.setLimit(2)
.setTable(namespaceName)
.setStart(MetaBrowser.buildStartParamFrom(rows2.get(rows2.size() - 1).getRow()))
.build();
final List<RegionReplicaInfo> rows3;
try (final MetaBrowser.Results results = new MetaBrowser(connection, request3).getResults()) {
rows3 = IterableUtils.toList(results);
}
assertThat(rows3, contains(
hasProperty("row", bytesAsStringBinary(startsWith(b + ",cccccccc")))));
}
private ColumnFamilyDescriptor columnFamilyDescriptor() {
return ColumnFamilyDescriptorBuilder.of("f1");
}
private TableDescriptor tableDescriptor(final TableName tableName) {
return TableDescriptorBuilder.newBuilder(tableName)
.setColumnFamily(columnFamilyDescriptor())
.build();
}
private TableDescriptor tableDescriptor(final TableName tableName, final int replicaCount) {
return TableDescriptorBuilder.newBuilder(tableName)
.setRegionReplication(replicaCount)
.setColumnFamily(columnFamilyDescriptor())
.build();
}
private CompletableFuture<Void> createTable(final TableName tableName) {
return admin.createTable(tableDescriptor(tableName));
}
private CompletableFuture<Void> createTable(final TableName tableName, final int splitCount) {
return admin.createTable(
tableDescriptor(tableName),
new RegionSplitter.HexStringSplit().split(splitCount));
}
private CompletableFuture<Void> createTableWithReplicas(final TableName tableName,
final int replicaCount) {
return admin.createTable(tableDescriptor(tableName, replicaCount));
}
private CompletableFuture<Void> createNamespace(final String namespace) {
final NamespaceDescriptor descriptor = NamespaceDescriptor.create(namespace).build();
return admin.createNamespace(descriptor);
}
/**
* Helper for mocking an {@link HttpServletRequest} relevant to the test.
*/
static class MockRequestBuilder {
private String limit = null;
private String regionState = null;
private String start = null;
private String table = null;
public MockRequestBuilder setLimit(final int value) {
this.limit = Integer.toString(value);
return this;
}
public MockRequestBuilder setLimit(final String value) {
this.limit = value;
return this;
}
public MockRequestBuilder setRegionState(final RegionState.State value) {
this.regionState = value.toString();
return this;
}
public MockRequestBuilder setRegionState(final String value) {
this.regionState = value;
return this;
}
public MockRequestBuilder setStart(final String value) {
this.start = value;
return this;
}
public MockRequestBuilder setTable(final String value) {
this.table = value;
return this;
}
public HttpServletRequest build() {
final HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getRequestURI()).thenReturn("/table.jsp");
when(request.getParameter("name")).thenReturn("hbase%3Ameta");
when(request.getParameter("scan_limit")).thenReturn(limit);
when(request.getParameter("scan_region_state")).thenReturn(regionState);
when(request.getParameter("scan_start")).thenReturn(start);
when(request.getParameter("scan_table")).thenReturn(table);
return request;
}
}
}