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.nio.charset.StandardCharsets; 022import java.util.NavigableMap; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.fs.FileSystem; 025import org.apache.hadoop.fs.Path; 026import org.apache.hadoop.hbase.client.Durability; 027import org.apache.hadoop.hbase.client.Get; 028import org.apache.hadoop.hbase.client.Put; 029import org.apache.hadoop.hbase.client.Result; 030import org.apache.hadoop.hbase.client.Table; 031import org.apache.hadoop.hbase.log.HBaseMarkers; 032import org.apache.hadoop.hbase.regionserver.HRegion; 033import org.apache.hadoop.hbase.regionserver.Region; 034import org.apache.hadoop.hbase.regionserver.RegionAsTable; 035import org.apache.hadoop.hbase.util.Bytes; 036import org.apache.hadoop.hbase.util.CommonFSUtils; 037import org.apache.hadoop.hbase.util.FSTableDescriptors; 038import org.apache.hadoop.hdfs.MiniDFSCluster; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042/** 043 * Abstract HBase test class. Initializes a few things that can come in handly like an 044 * HBaseConfiguration and filesystem. 045 * @deprecated since 2.0.0 and will be removed in 3.0.0. Write junit4 unit tests using 046 * {@link HBaseTestingUtility}. 047 * @see HBaseTestingUtility 048 * @see <a href="https://issues.apache.org/jira/browse/HBASE-11912">HBASE-11912</a> 049 */ 050@Deprecated 051public abstract class HBaseTestCase extends junit.framework.TestCase { 052 private static final Logger LOG = LoggerFactory.getLogger(HBaseTestCase.class); 053 054 protected final static byte[] fam1 = Bytes.toBytes("colfamily11"); 055 protected final static byte[] fam2 = Bytes.toBytes("colfamily21"); 056 protected final static byte[] fam3 = Bytes.toBytes("colfamily31"); 057 058 protected static final byte[][] COLUMNS = { fam1, fam2, fam3 }; 059 060 private boolean localfs = false; 061 protected static Path testDir = null; 062 protected FileSystem fs = null; 063 protected HRegion meta = null; 064 protected static final char FIRST_CHAR = 'a'; 065 protected static final char LAST_CHAR = 'z'; 066 protected static final String PUNCTUATION = "~`@#$%^&*()-_+=:;',.<>/?[]{}|"; 067 protected static final byte[] START_KEY_BYTES = { FIRST_CHAR, FIRST_CHAR, FIRST_CHAR }; 068 protected String START_KEY = new String(START_KEY_BYTES, HConstants.UTF8_CHARSET); 069 protected static final int MAXVERSIONS = 3; 070 071 protected final HBaseTestingUtility testUtil = new HBaseTestingUtility(); 072 073 public volatile Configuration conf = testUtil.getConfiguration(); 074 public final FSTableDescriptors fsTableDescriptors; 075 { 076 try { 077 fsTableDescriptors = new FSTableDescriptors(conf); 078 } catch (IOException e) { 079 throw new RuntimeException("Failed to init descriptors", e); 080 } 081 } 082 083 /** constructor */ 084 public HBaseTestCase() { 085 super(); 086 } 087 088 /** 089 * */ 090 public HBaseTestCase(String name) { 091 super(name); 092 } 093 094 /** 095 * Note that this method must be called after the mini hdfs cluster has started or we end up with 096 * a local file system. 097 */ 098 @Override 099 protected void setUp() throws Exception { 100 super.setUp(); 101 localfs = (conf.get("fs.defaultFS", "file:///").compareTo("file:///") == 0); 102 103 if (fs == null) { 104 this.fs = FileSystem.get(conf); 105 } 106 try { 107 if (localfs) { 108 testDir = getUnitTestdir(getName()); 109 if (fs.exists(testDir)) { 110 fs.delete(testDir, true); 111 } 112 } else { 113 testDir = CommonFSUtils.getRootDir(conf); 114 } 115 } catch (Exception e) { 116 LOG.error(HBaseMarkers.FATAL, "error during setup", e); 117 throw e; 118 } 119 } 120 121 @Override 122 protected void tearDown() throws Exception { 123 try { 124 if (localfs) { 125 if (this.fs.exists(testDir)) { 126 this.fs.delete(testDir, true); 127 } 128 } 129 } catch (Exception e) { 130 LOG.error(HBaseMarkers.FATAL, "error during tear down", e); 131 } 132 super.tearDown(); 133 } 134 135 /** 136 * @see HBaseTestingUtility#getBaseTestDir 137 * @return directory to use for this test 138 */ 139 protected Path getUnitTestdir(String testName) { 140 return testUtil.getDataTestDir(testName); 141 } 142 143 /** 144 * You must call close on the returned region and then close on the log file it created. Do 145 * {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)} to close both the region and the WAL. 146 * @return An {@link HRegion} 147 */ 148 public HRegion createNewHRegion(HTableDescriptor desc, byte[] startKey, byte[] endKey) 149 throws IOException { 150 return createNewHRegion(desc, startKey, endKey, this.conf); 151 } 152 153 public HRegion createNewHRegion(HTableDescriptor desc, byte[] startKey, byte[] endKey, 154 Configuration conf) throws IOException { 155 HRegionInfo hri = new HRegionInfo(desc.getTableName(), startKey, endKey); 156 return HBaseTestingUtility.createRegionAndWAL(hri, testDir, conf, desc); 157 } 158 159 protected HRegion openClosedRegion(final HRegion closedRegion) throws IOException { 160 return HRegion.openHRegion(closedRegion, null); 161 } 162 163 /** 164 * Create a table of name {@code name} with {@link #COLUMNS} for families. 165 * @param name Name to give table. 166 * @return Column descriptor. 167 */ 168 protected HTableDescriptor createTableDescriptor(final String name) { 169 return createTableDescriptor(name, MAXVERSIONS); 170 } 171 172 /** 173 * Create a table of name {@code name} with {@link #COLUMNS} for families. 174 * @param name Name to give table. 175 * @param versions How many versions to allow per column. 176 * @return Column descriptor. 177 */ 178 protected HTableDescriptor createTableDescriptor(final String name, final int versions) { 179 return createTableDescriptor(name, HColumnDescriptor.DEFAULT_MIN_VERSIONS, versions, 180 HConstants.FOREVER, HColumnDescriptor.DEFAULT_KEEP_DELETED); 181 } 182 183 /** 184 * Create a table of name {@code name} with {@link #COLUMNS} for families. 185 * @param name Name to give table. 186 * @param versions How many versions to allow per column. 187 * @return Column descriptor. 188 */ 189 protected HTableDescriptor createTableDescriptor(final String name, final int minVersions, 190 final int versions, final int ttl, KeepDeletedCells keepDeleted) { 191 HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name)); 192 for (byte[] cfName : new byte[][] { fam1, fam2, fam3 }) { 193 htd.addFamily( 194 new HColumnDescriptor(cfName).setMinVersions(minVersions).setMaxVersions(versions) 195 .setKeepDeletedCells(keepDeleted).setBlockCacheEnabled(false).setTimeToLive(ttl)); 196 } 197 return htd; 198 } 199 200 /** 201 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 202 * from 'aaa', 'aab', etc where key and value are the same. 203 * @return count of what we added. 204 */ 205 public static long addContent(final Region r, final byte[] columnFamily, final byte[] column) 206 throws IOException { 207 byte[] startKey = r.getRegionInfo().getStartKey(); 208 byte[] endKey = r.getRegionInfo().getEndKey(); 209 byte[] startKeyBytes = startKey; 210 if (startKeyBytes == null || startKeyBytes.length == 0) { 211 startKeyBytes = START_KEY_BYTES; 212 } 213 return addContent(new RegionAsTable(r), Bytes.toString(columnFamily), Bytes.toString(column), 214 startKeyBytes, endKey, -1); 215 } 216 217 public static long addContent(final Region r, final byte[] columnFamily) throws IOException { 218 return addContent(r, columnFamily, null); 219 } 220 221 /** 222 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 223 * from 'aaa', 'aab', etc where key and value are the same. 224 * @return count of what we added. 225 */ 226 public static long addContent(final Table updater, final String columnFamily) throws IOException { 227 return addContent(updater, columnFamily, START_KEY_BYTES, null); 228 } 229 230 public static long addContent(final Table updater, final String family, final String column) 231 throws IOException { 232 return addContent(updater, family, column, START_KEY_BYTES, null); 233 } 234 235 /** 236 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 237 * from 'aaa', 'aab', etc where key and value are the same. 238 * @return count of what we added. 239 */ 240 public static long addContent(final Table updater, final String columnFamily, 241 final byte[] startKeyBytes, final byte[] endKey) throws IOException { 242 return addContent(updater, columnFamily, null, startKeyBytes, endKey, -1); 243 } 244 245 public static long addContent(final Table updater, final String family, String column, 246 final byte[] startKeyBytes, final byte[] endKey) throws IOException { 247 return addContent(updater, family, column, startKeyBytes, endKey, -1); 248 } 249 250 /** 251 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 252 * from 'aaa', 'aab', etc where key and value are the same. 253 * @return count of what we added. 254 */ 255 public static long addContent(final Table updater, final String columnFamily, final String column, 256 final byte[] startKeyBytes, final byte[] endKey, final long ts) throws IOException { 257 long count = 0; 258 // Add rows of three characters. The first character starts with the 259 // 'a' character and runs up to 'z'. Per first character, we run the 260 // second character over same range. And same for the third so rows 261 // (and values) look like this: 'aaa', 'aab', 'aac', etc. 262 char secondCharStart = (char) startKeyBytes[1]; 263 char thirdCharStart = (char) startKeyBytes[2]; 264 EXIT: for (char c = (char) startKeyBytes[0]; c <= LAST_CHAR; c++) { 265 for (char d = secondCharStart; d <= LAST_CHAR; d++) { 266 for (char e = thirdCharStart; e <= LAST_CHAR; e++) { 267 byte[] t = new byte[] { (byte) c, (byte) d, (byte) e }; 268 if (endKey != null && endKey.length > 0 && Bytes.compareTo(endKey, t) <= 0) { 269 break EXIT; 270 } 271 try { 272 Put put; 273 if (ts != -1) { 274 put = new Put(t, ts); 275 } else { 276 put = new Put(t); 277 } 278 try { 279 StringBuilder sb = new StringBuilder(); 280 if (column != null && column.contains(":")) { 281 sb.append(column); 282 } else { 283 if (columnFamily != null) { 284 sb.append(columnFamily); 285 if (!columnFamily.endsWith(":")) { 286 sb.append(":"); 287 } 288 if (column != null) { 289 sb.append(column); 290 } 291 } 292 } 293 byte[][] split = CellUtil.parseColumn(Bytes.toBytes(sb.toString())); 294 if (split.length == 1) { 295 byte[] qualifier = new byte[0]; 296 put.addColumn(split[0], qualifier, t); 297 } else { 298 put.addColumn(split[0], split[1], t); 299 } 300 put.setDurability(Durability.SKIP_WAL); 301 updater.put(put); 302 count++; 303 } catch (RuntimeException ex) { 304 ex.printStackTrace(); 305 throw ex; 306 } catch (IOException ex) { 307 ex.printStackTrace(); 308 throw ex; 309 } 310 } catch (RuntimeException ex) { 311 ex.printStackTrace(); 312 throw ex; 313 } catch (IOException ex) { 314 ex.printStackTrace(); 315 throw ex; 316 } 317 } 318 // Set start character back to FIRST_CHAR after we've done first loop. 319 thirdCharStart = FIRST_CHAR; 320 } 321 secondCharStart = FIRST_CHAR; 322 } 323 return count; 324 } 325 326 protected void assertResultEquals(final HRegion region, final byte[] row, final byte[] family, 327 final byte[] qualifier, final long timestamp, final byte[] value) throws IOException { 328 Get get = new Get(row); 329 get.setTimestamp(timestamp); 330 Result res = region.get(get); 331 NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = res.getMap(); 332 byte[] res_value = map.get(family).get(qualifier).get(timestamp); 333 334 if (value == null) { 335 assertEquals( 336 Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp, 337 null, res_value); 338 } else { 339 if (res_value == null) { 340 fail(Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp 341 + "\" was expected to be \"" + Bytes.toStringBinary(value) + " but was null"); 342 } 343 if (res_value != null) { 344 assertEquals( 345 Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp, 346 value, new String(res_value, StandardCharsets.UTF_8)); 347 } 348 } 349 } 350 351 /** 352 * Common method to close down a MiniDFSCluster and the associated file system 353 */ 354 public static void shutdownDfs(MiniDFSCluster cluster) { 355 if (cluster != null) { 356 LOG.info("Shutting down Mini DFS "); 357 try { 358 cluster.shutdown(); 359 } catch (Exception e) { 360 /// Can get a java.lang.reflect.UndeclaredThrowableException thrown 361 // here because of an InterruptedException. Don't let exceptions in 362 // here be cause of test failure. 363 } 364 try { 365 FileSystem fs = cluster.getFileSystem(); 366 if (fs != null) { 367 LOG.info("Shutting down FileSystem"); 368 fs.close(); 369 } 370 FileSystem.closeAll(); 371 } catch (IOException e) { 372 LOG.error("error closing file system", e); 373 } 374 } 375 } 376 377 /** 378 * You must call {@link #closeRootAndMeta()} when done after calling this method. It does cleanup. 379 */ 380 protected void createMetaRegion() throws IOException { 381 FSTableDescriptors fsTableDescriptors = new FSTableDescriptors(conf); 382 meta = HBaseTestingUtility.createRegionAndWAL(HRegionInfo.FIRST_META_REGIONINFO, testDir, conf, 383 fsTableDescriptors.get(TableName.META_TABLE_NAME)); 384 } 385 386 protected void closeRootAndMeta() throws IOException { 387 HBaseTestingUtility.closeRegionAndWAL(meta); 388 } 389 390 public static void assertByteEquals(byte[] expected, byte[] actual) { 391 if (Bytes.compareTo(expected, actual) != 0) { 392 throw new junit.framework.AssertionFailedError( 393 "expected:<" + Bytes.toString(expected) + "> but was:<" + Bytes.toString(actual) + ">"); 394 } 395 } 396 397 public static void assertEquals(byte[] expected, byte[] actual) { 398 if (Bytes.compareTo(expected, actual) != 0) { 399 throw new junit.framework.AssertionFailedError("expected:<" + Bytes.toStringBinary(expected) 400 + "> but was:<" + Bytes.toStringBinary(actual) + ">"); 401 } 402 } 403}