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; 019 020import java.io.IOException; 021import java.util.concurrent.CompletableFuture; 022import java.util.concurrent.ExecutionException; 023import java.util.function.Supplier; 024import org.apache.hadoop.conf.Configuration; 025import org.apache.hadoop.hbase.client.AsyncConnection; 026import org.apache.hadoop.hbase.client.Connection; 027import org.apache.hadoop.hbase.client.ConnectionFactory; 028import org.junit.jupiter.api.extension.AfterAllCallback; 029import org.junit.jupiter.api.extension.BeforeAllCallback; 030import org.junit.jupiter.api.extension.Extension; 031import org.junit.jupiter.api.extension.ExtensionContext; 032 033/** 034 * An {@link Extension} that manages an instance of the {@link SingleProcessHBaseCluster}. Built on 035 * top of an instance of {@link HBaseTestingUtil}, so be weary of intermixing direct use of that 036 * class with this Extension. 037 * </p> 038 * Use in combination with {@link ConnectionExtension}, for example: 039 * 040 * <pre> 041 * { 042 * @code 043 * public class TestMyClass { 044 * 045 * @RegisterExtension 046 * public static final MiniClusterExtension miniClusterExtension = 047 * MiniClusterExtension.newBuilder().build(); 048 * 049 * @RegisterExtension 050 * public final ConnectionExtension connectionExtension = ConnectionExtension 051 * .createAsyncConnectionExtension(miniClusterExtension::createAsyncConnection); 052 * } 053 * } 054 * </pre> 055 */ 056public final class MiniClusterExtension implements BeforeAllCallback, AfterAllCallback { 057 058 /** 059 * A builder for fluent composition of a new {@link MiniClusterExtension}. 060 */ 061 public static final class Builder { 062 063 private StartTestingClusterOption miniClusterOption; 064 private Configuration conf; 065 066 /** 067 * Use the provided {@link StartTestingClusterOption} to construct the 068 * {@link SingleProcessHBaseCluster}. 069 */ 070 public Builder setMiniClusterOption(final StartTestingClusterOption miniClusterOption) { 071 this.miniClusterOption = miniClusterOption; 072 return this; 073 } 074 075 /** 076 * Seed the underlying {@link HBaseTestingUtil} with the provided {@link Configuration}. 077 */ 078 public Builder setConfiguration(final Configuration conf) { 079 this.conf = conf; 080 return this; 081 } 082 083 public Builder setConfiguration(final Supplier<Configuration> supplier) { 084 return setConfiguration(supplier.get()); 085 } 086 087 public MiniClusterExtension build() { 088 return new MiniClusterExtension(conf, 089 miniClusterOption != null 090 ? miniClusterOption 091 : StartTestingClusterOption.builder().build()); 092 } 093 } 094 095 /** 096 * Returns the underlying instance of {@link HBaseTestingUtil} 097 */ 098 private final HBaseTestingUtil testingUtility; 099 private final StartTestingClusterOption miniClusterOptions; 100 101 private SingleProcessHBaseCluster miniCluster; 102 103 private MiniClusterExtension(final Configuration conf, 104 final StartTestingClusterOption miniClusterOptions) { 105 this.testingUtility = new HBaseTestingUtil(conf); 106 this.miniClusterOptions = miniClusterOptions; 107 } 108 109 public static Builder newBuilder() { 110 return new Builder(); 111 } 112 113 /** 114 * Returns the underlying instance of {@link HBaseTestingUtil} 115 */ 116 public HBaseTestingUtil getTestingUtility() { 117 return testingUtility; 118 } 119 120 /** 121 * Create a {@link Connection} to the managed {@link SingleProcessHBaseCluster}. It's up to the 122 * caller to {@link Connection#close() close()} the connection when finished. 123 */ 124 public Connection createConnection() { 125 try { 126 return createAsyncConnection().get().toConnection(); 127 } catch (InterruptedException | ExecutionException e) { 128 Thread.currentThread().interrupt(); 129 throw new RuntimeException(e); 130 } 131 } 132 133 /** 134 * Create a {@link AsyncConnection} to the managed {@link SingleProcessHBaseCluster}. It's up to 135 * the caller to {@link AsyncConnection#close() close()} the connection when finished. 136 */ 137 public CompletableFuture<AsyncConnection> createAsyncConnection() { 138 if (miniCluster == null) { 139 throw new IllegalStateException("test cluster not initialized"); 140 } 141 return ConnectionFactory.createAsyncConnection(miniCluster.getConf()); 142 } 143 144 @Override 145 public void beforeAll(ExtensionContext context) throws Exception { 146 miniCluster = testingUtility.startMiniCluster(miniClusterOptions); 147 } 148 149 @Override 150 public void afterAll(ExtensionContext context) { 151 try { 152 testingUtility.shutdownMiniCluster(); 153 } catch (IOException e) { 154 throw new RuntimeException(e); 155 } 156 } 157}