001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase; 020 021import java.io.File; 022import java.io.IOException; 023import java.util.Arrays; 024import java.util.List; 025import java.util.UUID; 026import java.util.concurrent.ThreadLocalRandom; 027 028import org.apache.commons.io.FileUtils; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.fs.Path; 031import org.apache.hadoop.hbase.Waiter.Predicate; 032import org.apache.hadoop.hbase.io.compress.Compression; 033import org.apache.yetus.audience.InterfaceAudience; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * Common helpers for testing HBase that do not depend on specific server/etc. things. 039 * {@see org.apache.hadoop.hbase.HBaseTestingUtility} 040 */ 041@InterfaceAudience.Public 042public class HBaseCommonTestingUtility { 043 protected static final Logger LOG = LoggerFactory.getLogger(HBaseCommonTestingUtility.class); 044 045 /** Compression algorithms to use in parameterized JUnit 4 tests */ 046 public static final List<Object[]> COMPRESSION_ALGORITHMS_PARAMETERIZED = 047 Arrays.asList(new Object[][] { 048 { Compression.Algorithm.NONE }, 049 { Compression.Algorithm.GZ } 050 }); 051 052 /** This is for unit tests parameterized with a two booleans. */ 053 public static final List<Object[]> BOOLEAN_PARAMETERIZED = 054 Arrays.asList(new Object[][] { 055 {false}, 056 {true} 057 }); 058 059 /** Compression algorithms to use in testing */ 060 public static final Compression.Algorithm[] COMPRESSION_ALGORITHMS = { 061 Compression.Algorithm.NONE, Compression.Algorithm.GZ 062 }; 063 064 protected Configuration conf; 065 066 public HBaseCommonTestingUtility() { 067 this(null); 068 } 069 070 public HBaseCommonTestingUtility(Configuration conf) { 071 this.conf = (conf == null ? HBaseConfiguration.create() : conf); 072 } 073 074 /** 075 * Returns this classes's instance of {@link Configuration}. 076 * 077 * @return Instance of Configuration. 078 */ 079 public Configuration getConfiguration() { 080 return this.conf; 081 } 082 083 /** 084 * System property key to get base test directory value 085 */ 086 public static final String BASE_TEST_DIRECTORY_KEY = 087 "test.build.data.basedirectory"; 088 089 /** 090 * Default base directory for test output. 091 */ 092 public static final String DEFAULT_BASE_TEST_DIRECTORY = "target/test-data"; 093 094 /** 095 * Directory where we put the data for this instance of HBaseTestingUtility 096 */ 097 private File dataTestDir = null; 098 099 /** 100 * @return Where to write test data on local filesystem, specific to 101 * the test. Useful for tests that do not use a cluster. 102 * Creates it if it does not exist already. 103 */ 104 public Path getDataTestDir() { 105 if (this.dataTestDir == null) { 106 setupDataTestDir(); 107 } 108 return new Path(this.dataTestDir.getAbsolutePath()); 109 } 110 111 /** 112 * @param subdirName 113 * @return Path to a subdirectory named <code>subdirName</code> under 114 * {@link #getDataTestDir()}. 115 * Does *NOT* create it if it does not exist. 116 */ 117 public Path getDataTestDir(final String subdirName) { 118 return new Path(getDataTestDir(), subdirName); 119 } 120 121 /** 122 * Sets up a directory for a test to use. 123 * 124 * @return New directory path, if created. 125 */ 126 protected Path setupDataTestDir() { 127 if (this.dataTestDir != null) { 128 LOG.warn("Data test dir already setup in " + 129 dataTestDir.getAbsolutePath()); 130 return null; 131 } 132 Path testPath = getRandomDir(); 133 this.dataTestDir = new File(testPath.toString()).getAbsoluteFile(); 134 // Set this property so if mapreduce jobs run, they will use this as their home dir. 135 System.setProperty("test.build.dir", this.dataTestDir.toString()); 136 if (deleteOnExit()) this.dataTestDir.deleteOnExit(); 137 138 createSubDir("hbase.local.dir", testPath, "hbase-local-dir"); 139 140 return testPath; 141 } 142 143 /** 144 * @return A dir with a random (uuid) name under the test dir 145 * @see #getBaseTestDir() 146 */ 147 public Path getRandomDir() { 148 return new Path(getBaseTestDir(), getRandomUUID().toString()); 149 } 150 151 public UUID getRandomUUID() { 152 return new UUID(ThreadLocalRandom.current().nextLong(), 153 ThreadLocalRandom.current().nextLong()); 154 } 155 156 157 protected void createSubDir(String propertyName, Path parent, String subDirName) { 158 Path newPath = new Path(parent, subDirName); 159 File newDir = new File(newPath.toString()).getAbsoluteFile(); 160 if (deleteOnExit()) newDir.deleteOnExit(); 161 conf.set(propertyName, newDir.getAbsolutePath()); 162 } 163 164 /** 165 * @return True if we should delete testing dirs on exit. 166 */ 167 boolean deleteOnExit() { 168 String v = System.getProperty("hbase.testing.preserve.testdir"); 169 // Let default be true, to delete on exit. 170 return v == null ? true : !Boolean.parseBoolean(v); 171 } 172 173 /** 174 * @return True if we removed the test dirs 175 * @throws IOException 176 */ 177 public boolean cleanupTestDir() throws IOException { 178 if (deleteDir(this.dataTestDir)) { 179 this.dataTestDir = null; 180 return true; 181 } 182 return false; 183 } 184 185 /** 186 * @param subdir Test subdir name. 187 * @return True if we removed the test dir 188 * @throws IOException 189 */ 190 boolean cleanupTestDir(final String subdir) throws IOException { 191 if (this.dataTestDir == null) { 192 return false; 193 } 194 return deleteDir(new File(this.dataTestDir, subdir)); 195 } 196 197 /** 198 * @return Where to write test data on local filesystem; usually 199 * {@link #DEFAULT_BASE_TEST_DIRECTORY} 200 * Should not be used by the unit tests, hence its's private. 201 * Unit test will use a subdirectory of this directory. 202 * @see #setupDataTestDir() 203 */ 204 private Path getBaseTestDir() { 205 String PathName = System.getProperty( 206 BASE_TEST_DIRECTORY_KEY, DEFAULT_BASE_TEST_DIRECTORY); 207 208 return new Path(PathName); 209 } 210 211 /** 212 * @param dir Directory to delete 213 * @return True if we deleted it. 214 * @throws IOException 215 */ 216 boolean deleteDir(final File dir) throws IOException { 217 if (dir == null || !dir.exists()) { 218 return true; 219 } 220 int ntries = 0; 221 do { 222 ntries += 1; 223 try { 224 if (deleteOnExit()) FileUtils.deleteDirectory(dir); 225 return true; 226 } catch (IOException ex) { 227 LOG.warn("Failed to delete " + dir.getAbsolutePath()); 228 } catch (IllegalArgumentException ex) { 229 LOG.warn("Failed to delete " + dir.getAbsolutePath(), ex); 230 } 231 } while (ntries < 30); 232 233 return false; 234 } 235 236 /** 237 * Wrapper method for {@link Waiter#waitFor(Configuration, long, Predicate)}. 238 */ 239 public <E extends Exception> long waitFor(long timeout, Predicate<E> predicate) 240 throws E { 241 return Waiter.waitFor(this.conf, timeout, predicate); 242 } 243 244 /** 245 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, Predicate)}. 246 */ 247 public <E extends Exception> long waitFor(long timeout, long interval, Predicate<E> predicate) 248 throws E { 249 return Waiter.waitFor(this.conf, timeout, interval, predicate); 250 } 251 252 /** 253 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, boolean, Predicate)}. 254 */ 255 public <E extends Exception> long waitFor(long timeout, long interval, 256 boolean failIfTimeout, Predicate<E> predicate) throws E { 257 return Waiter.waitFor(this.conf, timeout, interval, failIfTimeout, predicate); 258 } 259}