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.HBaseCommonTestingUtility 040 */ 041@InterfaceAudience.Public 042public class HBaseCommonTestingUtility { 043 protected static final Logger LOG = LoggerFactory.getLogger(HBaseCommonTestingUtility.class); 044 045 /** 046 * Compression algorithms to use in parameterized JUnit 4 tests 047 */ 048 public static final List<Object[]> COMPRESSION_ALGORITHMS_PARAMETERIZED = 049 Arrays.asList(new Object[][] { 050 { Compression.Algorithm.NONE }, 051 { Compression.Algorithm.GZ } 052 }); 053 054 /** 055 * This is for unit tests parameterized with a two booleans. 056 */ 057 public static final List<Object[]> BOOLEAN_PARAMETERIZED = 058 Arrays.asList(new Object[][] { 059 {false}, 060 {true} 061 }); 062 063 /** 064 * Compression algorithms to use in testing 065 */ 066 public static final Compression.Algorithm[] COMPRESSION_ALGORITHMS = { 067 Compression.Algorithm.NONE, Compression.Algorithm.GZ 068 }; 069 070 protected Configuration conf; 071 072 public HBaseCommonTestingUtility() { 073 this(null); 074 } 075 076 public HBaseCommonTestingUtility(Configuration conf) { 077 this.conf = (conf == null ? HBaseConfiguration.create() : conf); 078 } 079 080 /** 081 * Returns this classes's instance of {@link Configuration}. 082 * 083 * @return Instance of Configuration. 084 */ 085 public Configuration getConfiguration() { 086 return this.conf; 087 } 088 089 /** 090 * System property key to get base test directory value 091 */ 092 public static final String BASE_TEST_DIRECTORY_KEY = 093 "test.build.data.basedirectory"; 094 095 /** 096 * Default base directory for test output. 097 */ 098 public static final String DEFAULT_BASE_TEST_DIRECTORY = "target/test-data"; 099 100 /** 101 * Directory where we put the data for this instance of HBaseTestingUtility 102 */ 103 private File dataTestDir = null; 104 105 /** 106 * @return Where to write test data on local filesystem, specific to the test. Useful for tests 107 * that do not use a cluster. Creates it if it does not exist already. 108 */ 109 public Path getDataTestDir() { 110 if (this.dataTestDir == null) { 111 setupDataTestDir(); 112 } 113 return new Path(this.dataTestDir.getAbsolutePath()); 114 } 115 116 /** 117 * @param subdirName the name of the subdirectory in the test data directory 118 * @return Path to a subdirectory named {code subdirName} under 119 * {@link #getDataTestDir()}. Does *NOT* create it if it does not exist. 120 */ 121 public Path getDataTestDir(final String subdirName) { 122 return new Path(getDataTestDir(), subdirName); 123 } 124 125 /** 126 * Sets up a directory for a test to use. 127 * 128 * @return New directory path, if created. 129 */ 130 protected Path setupDataTestDir() { 131 if (this.dataTestDir != null) { 132 LOG.warn("Data test dir already setup in " + 133 dataTestDir.getAbsolutePath()); 134 return null; 135 } 136 Path testPath = getRandomDir(); 137 this.dataTestDir = new File(testPath.toString()).getAbsoluteFile(); 138 // Set this property so if mapreduce jobs run, they will use this as their home dir. 139 System.setProperty("test.build.dir", this.dataTestDir.toString()); 140 141 if (deleteOnExit()) { 142 this.dataTestDir.deleteOnExit(); 143 } 144 145 createSubDir("hbase.local.dir", testPath, "hbase-local-dir"); 146 147 return testPath; 148 } 149 150 /** 151 * @return A dir with a random (uuid) name under the test dir 152 * @see #getBaseTestDir() 153 */ 154 public Path getRandomDir() { 155 return new Path(getBaseTestDir(), getRandomUUID().toString()); 156 } 157 158 public UUID getRandomUUID() { 159 return new UUID(ThreadLocalRandom.current().nextLong(), 160 ThreadLocalRandom.current().nextLong()); 161 } 162 163 protected void createSubDir(String propertyName, Path parent, String subDirName) { 164 Path newPath = new Path(parent, subDirName); 165 File newDir = new File(newPath.toString()).getAbsoluteFile(); 166 167 if (deleteOnExit()) { 168 newDir.deleteOnExit(); 169 } 170 171 conf.set(propertyName, newDir.getAbsolutePath()); 172 } 173 174 /** 175 * @return True if we should delete testing dirs on exit. 176 */ 177 boolean deleteOnExit() { 178 String v = System.getProperty("hbase.testing.preserve.testdir"); 179 // Let default be true, to delete on exit. 180 return v == null ? true : !Boolean.parseBoolean(v); 181 } 182 183 /** 184 * @return True if we removed the test dirs 185 */ 186 public boolean cleanupTestDir() { 187 if (deleteDir(this.dataTestDir)) { 188 this.dataTestDir = null; 189 return true; 190 } 191 return false; 192 } 193 194 /** 195 * @param subdir Test subdir name. 196 * @return True if we removed the test dir 197 */ 198 boolean cleanupTestDir(final String subdir) { 199 if (this.dataTestDir == null) { 200 return false; 201 } 202 return deleteDir(new File(this.dataTestDir, subdir)); 203 } 204 205 /** 206 * @return Where to write test data on local filesystem; usually 207 * {@link #DEFAULT_BASE_TEST_DIRECTORY} 208 * Should not be used by the unit tests, hence its's private. 209 * Unit test will use a subdirectory of this directory. 210 * @see #setupDataTestDir() 211 */ 212 private Path getBaseTestDir() { 213 String PathName = System.getProperty( 214 BASE_TEST_DIRECTORY_KEY, DEFAULT_BASE_TEST_DIRECTORY); 215 216 return new Path(PathName); 217 } 218 219 /** 220 * @param dir Directory to delete 221 * @return True if we deleted it. 222 */ 223 boolean deleteDir(final File dir) { 224 if (dir == null || !dir.exists()) { 225 return true; 226 } 227 int ntries = 0; 228 do { 229 ntries += 1; 230 try { 231 if (deleteOnExit()) { 232 FileUtils.deleteDirectory(dir); 233 } 234 235 return true; 236 } catch (IOException ex) { 237 LOG.warn("Failed to delete " + dir.getAbsolutePath()); 238 } catch (IllegalArgumentException ex) { 239 LOG.warn("Failed to delete " + dir.getAbsolutePath(), ex); 240 } 241 } while (ntries < 30); 242 243 return false; 244 } 245 246 /** 247 * Wrapper method for {@link Waiter#waitFor(Configuration, long, Predicate)}. 248 */ 249 public <E extends Exception> long waitFor(long timeout, Predicate<E> predicate) 250 throws E { 251 return Waiter.waitFor(this.conf, timeout, predicate); 252 } 253 254 /** 255 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, Predicate)}. 256 */ 257 public <E extends Exception> long waitFor(long timeout, long interval, Predicate<E> predicate) 258 throws E { 259 return Waiter.waitFor(this.conf, timeout, interval, predicate); 260 } 261 262 /** 263 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, boolean, Predicate)}. 264 */ 265 public <E extends Exception> long waitFor(long timeout, long interval, 266 boolean failIfTimeout, Predicate<E> predicate) throws E { 267 return Waiter.waitFor(this.conf, timeout, interval, failIfTimeout, predicate); 268 } 269}