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; 026 027import org.apache.commons.io.FileUtils; 028import org.apache.hadoop.conf.Configuration; 029import org.apache.hadoop.fs.Path; 030import org.apache.hadoop.hbase.Waiter.Predicate; 031import org.apache.hadoop.hbase.io.compress.Compression; 032import org.apache.yetus.audience.InterfaceAudience; 033import org.slf4j.Logger; 034import org.slf4j.LoggerFactory; 035 036/** 037 * Common helpers for testing HBase that do not depend on specific server/etc. things. 038 * @see org.apache.hadoop.hbase.HBaseCommonTestingUtility 039 * 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(), UUID.randomUUID().toString()); 149 } 150 151 protected void createSubDir(String propertyName, Path parent, String subDirName) { 152 Path newPath = new Path(parent, subDirName); 153 File newDir = new File(newPath.toString()).getAbsoluteFile(); 154 if (deleteOnExit()) newDir.deleteOnExit(); 155 conf.set(propertyName, newDir.getAbsolutePath()); 156 } 157 158 /** 159 * @return True if we should delete testing dirs on exit. 160 */ 161 boolean deleteOnExit() { 162 String v = System.getProperty("hbase.testing.preserve.testdir"); 163 // Let default be true, to delete on exit. 164 return v == null ? true : !Boolean.parseBoolean(v); 165 } 166 167 /** 168 * @return True if we removed the test dirs 169 * @throws IOException 170 */ 171 public boolean cleanupTestDir() throws IOException { 172 if (deleteDir(this.dataTestDir)) { 173 this.dataTestDir = null; 174 return true; 175 } 176 return false; 177 } 178 179 /** 180 * @param subdir Test subdir name. 181 * @return True if we removed the test dir 182 * @throws IOException 183 */ 184 boolean cleanupTestDir(final String subdir) throws IOException { 185 if (this.dataTestDir == null) { 186 return false; 187 } 188 return deleteDir(new File(this.dataTestDir, subdir)); 189 } 190 191 /** 192 * @return Where to write test data on local filesystem; usually 193 * {@link #DEFAULT_BASE_TEST_DIRECTORY} 194 * Should not be used by the unit tests, hence its's private. 195 * Unit test will use a subdirectory of this directory. 196 * @see #setupDataTestDir() 197 */ 198 private Path getBaseTestDir() { 199 String PathName = System.getProperty( 200 BASE_TEST_DIRECTORY_KEY, DEFAULT_BASE_TEST_DIRECTORY); 201 202 return new Path(PathName); 203 } 204 205 /** 206 * @param dir Directory to delete 207 * @return True if we deleted it. 208 * @throws IOException 209 */ 210 boolean deleteDir(final File dir) throws IOException { 211 if (dir == null || !dir.exists()) { 212 return true; 213 } 214 int ntries = 0; 215 do { 216 ntries += 1; 217 try { 218 if (deleteOnExit()) FileUtils.deleteDirectory(dir); 219 return true; 220 } catch (IOException ex) { 221 LOG.warn("Failed to delete " + dir.getAbsolutePath()); 222 } catch (IllegalArgumentException ex) { 223 LOG.warn("Failed to delete " + dir.getAbsolutePath(), ex); 224 } 225 } while (ntries < 30); 226 227 return false; 228 } 229 230 /** 231 * Wrapper method for {@link Waiter#waitFor(Configuration, long, Predicate)}. 232 */ 233 public <E extends Exception> long waitFor(long timeout, Predicate<E> predicate) 234 throws E { 235 return Waiter.waitFor(this.conf, timeout, predicate); 236 } 237 238 /** 239 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, Predicate)}. 240 */ 241 public <E extends Exception> long waitFor(long timeout, long interval, Predicate<E> predicate) 242 throws E { 243 return Waiter.waitFor(this.conf, timeout, interval, predicate); 244 } 245 246 /** 247 * Wrapper method for {@link Waiter#waitFor(Configuration, long, long, boolean, Predicate)}. 248 */ 249 public <E extends Exception> long waitFor(long timeout, long interval, 250 boolean failIfTimeout, Predicate<E> predicate) throws E { 251 return Waiter.waitFor(this.conf, timeout, interval, failIfTimeout, predicate); 252 } 253}