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