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.function.Supplier; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.hbase.client.AsyncConnection; 025import org.apache.hadoop.hbase.client.Connection; 026import org.apache.hadoop.hbase.client.ConnectionFactory; 027import org.junit.ClassRule; 028import org.junit.Rule; 029import org.junit.rules.ExternalResource; 030import org.junit.rules.TestRule; 031 032/** 033 * A {@link TestRule} that manages an instance of the {@link MiniHBaseCluster}. Can be used in 034 * either the {@link Rule} or {@link ClassRule} positions. Built on top of an instance of 035 * {@link HBaseTestingUtility}, so be weary of intermixing direct use of that class with this Rule. 036 * </p> 037 * Use in combination with {@link ConnectionRule}, for example: 038 * 039 * <pre> 040 * { 041 * @code 042 * public class TestMyClass { 043 * @ClassRule 044 * public static final MiniClusterRule miniClusterRule = MiniClusterRule.newBuilder().build(); 045 * 046 * @Rule 047 * public final ConnectionRule connectionRule = 048 * ConnectionRule.createAsyncConnectionRule(miniClusterRule::createAsyncConnection); 049 * } 050 * } 051 * </pre> 052 */ 053public final class MiniClusterRule extends ExternalResource { 054 055 /** 056 * A builder for fluent composition of a new {@link MiniClusterRule}. 057 */ 058 public static class Builder { 059 060 private StartMiniClusterOption miniClusterOption; 061 private Configuration conf; 062 063 /** 064 * Use the provided {@link StartMiniClusterOption} to construct the {@link MiniHBaseCluster}. 065 */ 066 public Builder setMiniClusterOption(final StartMiniClusterOption miniClusterOption) { 067 this.miniClusterOption = miniClusterOption; 068 return this; 069 } 070 071 /** 072 * Seed the underlying {@link HBaseTestingUtility} with the provided {@link Configuration}. 073 */ 074 public Builder setConfiguration(final Configuration conf) { 075 this.conf = conf; 076 return this; 077 } 078 079 public Builder setConfiguration(Supplier<Configuration> supplier) { 080 return setConfiguration(supplier.get()); 081 } 082 083 public MiniClusterRule build() { 084 return new MiniClusterRule(conf, 085 miniClusterOption != null ? miniClusterOption : StartMiniClusterOption.builder().build()); 086 } 087 } 088 089 private final HBaseTestingUtility testingUtility; 090 private final StartMiniClusterOption miniClusterOptions; 091 092 private MiniHBaseCluster miniCluster; 093 094 private MiniClusterRule(final Configuration conf, 095 final StartMiniClusterOption miniClusterOptions) { 096 this.testingUtility = new HBaseTestingUtility(conf); 097 this.miniClusterOptions = miniClusterOptions; 098 } 099 100 public static Builder newBuilder() { 101 return new Builder(); 102 } 103 104 /** Returns the underlying instance of {@link HBaseTestingUtility} */ 105 public HBaseTestingUtility getTestingUtility() { 106 return testingUtility; 107 } 108 109 /** 110 * Create a {@link Connection} to the managed {@link MiniHBaseCluster}. It's up to the caller to 111 * {@link Connection#close() close()} the connection when finished. 112 */ 113 public Connection createConnection() { 114 if (miniCluster == null) { 115 throw new IllegalStateException("test cluster not initialized"); 116 } 117 try { 118 return ConnectionFactory.createConnection(miniCluster.getConf()); 119 } catch (IOException e) { 120 throw new RuntimeException(e); 121 } 122 } 123 124 /** 125 * Create a {@link AsyncConnection} to the managed {@link MiniHBaseCluster}. It's up to the caller 126 * to {@link AsyncConnection#close() close()} the connection when finished. 127 */ 128 public CompletableFuture<AsyncConnection> createAsyncConnection() { 129 if (miniCluster == null) { 130 throw new IllegalStateException("test cluster not initialized"); 131 } 132 return ConnectionFactory.createAsyncConnection(miniCluster.getConf()); 133 } 134 135 @Override 136 protected void before() throws Throwable { 137 miniCluster = testingUtility.startMiniCluster(miniClusterOptions); 138 } 139 140 @Override 141 protected void after() { 142 try { 143 testingUtility.shutdownMiniCluster(); 144 } catch (IOException e) { 145 throw new RuntimeException(e); 146 } 147 } 148}