ndimiduk commented on a change in pull request #1020: HBASE-23653 Expose content of meta table in web ui URL: https://github.com/apache/hbase/pull/1020#discussion_r366098608
########## File path: hbase-server/src/test/java/org/apache/hadoop/hbase/ClearUserNamespacesAndTablesRule.java ########## @@ -0,0 +1,136 @@ +/* + * 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; + +import java.util.List; +import java.util.Objects; +import java.util.StringJoiner; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import org.apache.hadoop.hbase.client.AsyncAdmin; +import org.apache.hadoop.hbase.client.AsyncConnection; +import org.junit.Rule; +import org.junit.rules.ExternalResource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A {@link Rule} that clears all user tables and namespaces before the test executes. + */ +public class ClearUserNamespacesAndTablesRule extends ExternalResource { + private static final Logger logger = + LoggerFactory.getLogger(ClearUserNamespacesAndTablesRule.class); + + private final Supplier<AsyncConnection> connectionSupplier; + private AsyncAdmin admin; + + public ClearUserNamespacesAndTablesRule(final Supplier<AsyncConnection> connectionSupplier) { + this.connectionSupplier = connectionSupplier; + } + + @Override + protected void before() throws Throwable { + final AsyncConnection connection = Objects.requireNonNull(connectionSupplier.get()); + admin = connection.getAdmin(); + + clearTablesAndNamespaces().join(); + } + + private CompletableFuture<Void> clearTablesAndNamespaces() { + return deleteUserTables().thenCompose(_void -> deleteUserNamespaces()); + } + + private CompletableFuture<Void> deleteUserTables() { + return listTableNames() + .thenApply(tableNames -> tableNames.stream() + .map(tableName -> disableIfEnabled(tableName).thenCompose(_void -> deleteTable(tableName))) + .toArray(CompletableFuture[]::new)) + .thenCompose(CompletableFuture::allOf); + } + + private CompletableFuture<List<TableName>> listTableNames() { + return CompletableFuture.runAsync(() -> logger.info("listing tables")) + .thenCompose(_void -> admin.listTableNames(false)) + .thenApply(tableNames -> { + final StringJoiner joiner = new StringJoiner(", ", "[", "]"); + tableNames.stream().map(TableName::getNameAsString).forEach(joiner::add); + logger.info("found existing tables {}", joiner.toString()); + return tableNames; + }); + } + + private CompletableFuture<Boolean> isTableEnabled(final TableName tableName) { + return admin.isTableEnabled(tableName) + .thenApply(isEnabled -> { + logger.info("table {} is enabled.", tableName); + return isEnabled; + }); + } + + private CompletableFuture<Void> disableIfEnabled(final TableName tableName) { + return isTableEnabled(tableName) + .thenCompose(isEnabled -> { + if (isEnabled) { return disableTable(tableName); } + return CompletableFuture.completedFuture(null); + }); + } + + private CompletableFuture<Void> disableTable(final TableName tableName) { + return CompletableFuture.runAsync(() -> logger.info("disabling enabled table {}", tableName)) + .thenCompose(_void -> admin.disableTable(tableName)); + } + + private CompletableFuture<Void> deleteTable(final TableName tableName) { + return CompletableFuture.runAsync(() -> logger.info("deleting disabled table {}", tableName)) + .thenCompose(_void -> admin.deleteTable(tableName)); + } + + private CompletableFuture<List<String>> listUserNamespaces() { + return CompletableFuture.runAsync(() -> logger.info("listing namespaces")) + .thenCompose(_void -> admin.listNamespaceDescriptors()) + .thenApply(namespaceDescriptors -> { + final StringJoiner joiner = new StringJoiner(", ", "[", "]"); + final List<String> names = namespaceDescriptors.stream() + .map(NamespaceDescriptor::getName) + .peek(joiner::add) + .collect(Collectors.toList()); + logger.info("found existing namespaces {}", joiner.toString()); + return names; + }) + .thenApply(namespaces -> namespaces.stream() + .filter(namespace -> !Objects.equals( + namespace, NamespaceDescriptor.SYSTEM_NAMESPACE.getName())) + .filter(namespace -> !Objects.equals( + namespace, NamespaceDescriptor.DEFAULT_NAMESPACE.getName())) + .collect(Collectors.toList())); + } + + private CompletableFuture<Void> deleteNamespace(final String namespace) { + return CompletableFuture.runAsync(() -> logger.info("deleting namespace {}", namespace)) + .thenCompose(_void -> admin.deleteNamespace(namespace)); + } + + private CompletableFuture<Void> deleteUserNamespaces() { + return listUserNamespaces() + .thenCompose(namespaces -> CompletableFuture.allOf( + namespaces.stream() + .map(this::deleteNamespace) + .toArray(CompletableFuture[]::new))); + } +} Review comment: I'm writing tests over the content of meta. So I can 1. clean up after each test method; or 1. tear down and spin up a new mini cluster for each test method; or 1. create a fixed set of tables `@BeforeClass` and write all test methods around those tables. I chose the first option because (2) would make for a really slow test run and (3) is very inflexible in terms of how each test method is written, and renders all other test methods brittle to tweaks of any one of them. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services