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 * n 090 */ 091 public HBaseTestCase(String name) { 092 super(name); 093 } 094 095 /** 096 * Note that this method must be called after the mini hdfs cluster has started or we end up with 097 * a local file system. 098 */ 099 @Override 100 protected void setUp() throws Exception { 101 super.setUp(); 102 localfs = (conf.get("fs.defaultFS", "file:///").compareTo("file:///") == 0); 103 104 if (fs == null) { 105 this.fs = FileSystem.get(conf); 106 } 107 try { 108 if (localfs) { 109 testDir = getUnitTestdir(getName()); 110 if (fs.exists(testDir)) { 111 fs.delete(testDir, true); 112 } 113 } else { 114 testDir = CommonFSUtils.getRootDir(conf); 115 } 116 } catch (Exception e) { 117 LOG.error(HBaseMarkers.FATAL, "error during setup", e); 118 throw e; 119 } 120 } 121 122 @Override 123 protected void tearDown() throws Exception { 124 try { 125 if (localfs) { 126 if (this.fs.exists(testDir)) { 127 this.fs.delete(testDir, true); 128 } 129 } 130 } catch (Exception e) { 131 LOG.error(HBaseMarkers.FATAL, "error during tear down", e); 132 } 133 super.tearDown(); 134 } 135 136 /** 137 * @see HBaseTestingUtility#getBaseTestDir n * @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 * nnn * @return An {@link HRegion} n 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. nnnn * @return count of what we added. 203 */ 204 public static long addContent(final Region r, final byte[] columnFamily, final byte[] column) 205 throws IOException { 206 byte[] startKey = r.getRegionInfo().getStartKey(); 207 byte[] endKey = r.getRegionInfo().getEndKey(); 208 byte[] startKeyBytes = startKey; 209 if (startKeyBytes == null || startKeyBytes.length == 0) { 210 startKeyBytes = START_KEY_BYTES; 211 } 212 return addContent(new RegionAsTable(r), Bytes.toString(columnFamily), Bytes.toString(column), 213 startKeyBytes, endKey, -1); 214 } 215 216 public static long addContent(final Region r, final byte[] columnFamily) throws IOException { 217 return addContent(r, columnFamily, null); 218 } 219 220 /** 221 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 222 * from 'aaa', 'aab', etc where key and value are the same. n * @return count of what we added. 223 */ 224 public static long addContent(final Table updater, final String columnFamily) throws IOException { 225 return addContent(updater, columnFamily, START_KEY_BYTES, null); 226 } 227 228 public static long addContent(final Table updater, final String family, final String column) 229 throws IOException { 230 return addContent(updater, family, column, START_KEY_BYTES, null); 231 } 232 233 /** 234 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 235 * from 'aaa', 'aab', etc where key and value are the same. 236 * @return count of what we added. n 237 */ 238 public static long addContent(final Table updater, final String columnFamily, 239 final byte[] startKeyBytes, final byte[] endKey) throws IOException { 240 return addContent(updater, columnFamily, null, startKeyBytes, endKey, -1); 241 } 242 243 public static long addContent(final Table updater, final String family, String column, 244 final byte[] startKeyBytes, final byte[] endKey) throws IOException { 245 return addContent(updater, family, column, startKeyBytes, endKey, -1); 246 } 247 248 /** 249 * Add content to region <code>r</code> on the passed column <code>column</code>. Adds data of the 250 * from 'aaa', 'aab', etc where key and value are the same. 251 * @return count of what we added. n 252 */ 253 public static long addContent(final Table updater, final String columnFamily, final String column, 254 final byte[] startKeyBytes, final byte[] endKey, final long ts) throws IOException { 255 long count = 0; 256 // Add rows of three characters. The first character starts with the 257 // 'a' character and runs up to 'z'. Per first character, we run the 258 // second character over same range. And same for the third so rows 259 // (and values) look like this: 'aaa', 'aab', 'aac', etc. 260 char secondCharStart = (char) startKeyBytes[1]; 261 char thirdCharStart = (char) startKeyBytes[2]; 262 EXIT: for (char c = (char) startKeyBytes[0]; c <= LAST_CHAR; c++) { 263 for (char d = secondCharStart; d <= LAST_CHAR; d++) { 264 for (char e = thirdCharStart; e <= LAST_CHAR; e++) { 265 byte[] t = new byte[] { (byte) c, (byte) d, (byte) e }; 266 if (endKey != null && endKey.length > 0 && Bytes.compareTo(endKey, t) <= 0) { 267 break EXIT; 268 } 269 try { 270 Put put; 271 if (ts != -1) { 272 put = new Put(t, ts); 273 } else { 274 put = new Put(t); 275 } 276 try { 277 StringBuilder sb = new StringBuilder(); 278 if (column != null && column.contains(":")) { 279 sb.append(column); 280 } else { 281 if (columnFamily != null) { 282 sb.append(columnFamily); 283 if (!columnFamily.endsWith(":")) { 284 sb.append(":"); 285 } 286 if (column != null) { 287 sb.append(column); 288 } 289 } 290 } 291 byte[][] split = CellUtil.parseColumn(Bytes.toBytes(sb.toString())); 292 if (split.length == 1) { 293 byte[] qualifier = new byte[0]; 294 put.addColumn(split[0], qualifier, t); 295 } else { 296 put.addColumn(split[0], split[1], t); 297 } 298 put.setDurability(Durability.SKIP_WAL); 299 updater.put(put); 300 count++; 301 } catch (RuntimeException ex) { 302 ex.printStackTrace(); 303 throw ex; 304 } catch (IOException ex) { 305 ex.printStackTrace(); 306 throw ex; 307 } 308 } catch (RuntimeException ex) { 309 ex.printStackTrace(); 310 throw ex; 311 } catch (IOException ex) { 312 ex.printStackTrace(); 313 throw ex; 314 } 315 } 316 // Set start character back to FIRST_CHAR after we've done first loop. 317 thirdCharStart = FIRST_CHAR; 318 } 319 secondCharStart = FIRST_CHAR; 320 } 321 return count; 322 } 323 324 protected void assertResultEquals(final HRegion region, final byte[] row, final byte[] family, 325 final byte[] qualifier, final long timestamp, final byte[] value) throws IOException { 326 Get get = new Get(row); 327 get.setTimestamp(timestamp); 328 Result res = region.get(get); 329 NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = res.getMap(); 330 byte[] res_value = map.get(family).get(qualifier).get(timestamp); 331 332 if (value == null) { 333 assertEquals( 334 Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp, 335 null, res_value); 336 } else { 337 if (res_value == null) { 338 fail(Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp 339 + "\" was expected to be \"" + Bytes.toStringBinary(value) + " but was null"); 340 } 341 if (res_value != null) { 342 assertEquals( 343 Bytes.toString(family) + " " + Bytes.toString(qualifier) + " at timestamp " + timestamp, 344 value, new String(res_value, StandardCharsets.UTF_8)); 345 } 346 } 347 } 348 349 /** 350 * Common method to close down a MiniDFSCluster and the associated file system n 351 */ 352 public static void shutdownDfs(MiniDFSCluster cluster) { 353 if (cluster != null) { 354 LOG.info("Shutting down Mini DFS "); 355 try { 356 cluster.shutdown(); 357 } catch (Exception e) { 358 /// Can get a java.lang.reflect.UndeclaredThrowableException thrown 359 // here because of an InterruptedException. Don't let exceptions in 360 // here be cause of test failure. 361 } 362 try { 363 FileSystem fs = cluster.getFileSystem(); 364 if (fs != null) { 365 LOG.info("Shutting down FileSystem"); 366 fs.close(); 367 } 368 FileSystem.closeAll(); 369 } catch (IOException e) { 370 LOG.error("error closing file system", e); 371 } 372 } 373 } 374 375 /** 376 * You must call {@link #closeRootAndMeta()} when done after calling this method. It does cleanup. 377 * n 378 */ 379 protected void createMetaRegion() throws IOException { 380 FSTableDescriptors fsTableDescriptors = new FSTableDescriptors(conf); 381 meta = HBaseTestingUtility.createRegionAndWAL(HRegionInfo.FIRST_META_REGIONINFO, testDir, conf, 382 fsTableDescriptors.get(TableName.META_TABLE_NAME)); 383 } 384 385 protected void closeRootAndMeta() throws IOException { 386 HBaseTestingUtility.closeRegionAndWAL(meta); 387 } 388 389 public static void assertByteEquals(byte[] expected, byte[] actual) { 390 if (Bytes.compareTo(expected, actual) != 0) { 391 throw new junit.framework.AssertionFailedError( 392 "expected:<" + Bytes.toString(expected) + "> but was:<" + Bytes.toString(actual) + ">"); 393 } 394 } 395 396 public static void assertEquals(byte[] expected, byte[] actual) { 397 if (Bytes.compareTo(expected, actual) != 0) { 398 throw new junit.framework.AssertionFailedError("expected:<" + Bytes.toStringBinary(expected) 399 + "> but was:<" + Bytes.toStringBinary(actual) + ">"); 400 } 401 } 402}