/** * Copyright 2007 The Apache Software Foundation * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hbase; import java.io.IOException; import junit.framework.TestCase; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HColumnDescriptor.CompressionType; import org.apache.hadoop.io.Text; /** * Abstract base class for test cases. Performs all static initialization */ public abstract class HBaseTestCase extends TestCase { protected final static String COLFAMILY_NAME1 = "colfamily1:"; protected final static String COLFAMILY_NAME2 = "colfamily2:"; protected final static String COLFAMILY_NAME3 = "colfamily3:"; protected Path testDir = null; protected FileSystem localFs = null; protected static final char FIRST_CHAR = 'a'; protected static final char LAST_CHAR = 'z'; protected static final byte [] START_KEY_BYTES = {FIRST_CHAR, FIRST_CHAR, FIRST_CHAR}; protected static final int MAXVERSIONS = 3; static { StaticTestEnvironment.initialize(); } protected volatile Configuration conf; /** constructor */ public HBaseTestCase() { super(); conf = new HBaseConfiguration(); } /** * @param name */ public HBaseTestCase(String name) { super(name); conf = new HBaseConfiguration(); } /** {@inheritDoc} */ @Override protected void setUp() throws Exception { super.setUp(); this.testDir = getUnitTestdir(getName()); this.localFs = FileSystem.getLocal(this.conf); if (localFs.exists(testDir)) { localFs.delete(testDir); } } /** {@inheritDoc} */ @Override protected void tearDown() throws Exception { if (this.localFs != null && this.testDir != null && this.localFs.exists(testDir)) { this.localFs.delete(testDir); } super.tearDown(); } protected Path getUnitTestdir(String testName) { return new Path(StaticTestEnvironment.TEST_DIRECTORY_KEY, testName); } protected HRegion createNewHRegion(Path dir, Configuration c, HTableDescriptor desc, long regionId, Text startKey, Text endKey) throws IOException { HRegionInfo info = new HRegionInfo(regionId, desc, startKey, endKey); Path regionDir = HRegion.getRegionDir(dir, info.regionName); FileSystem fs = dir.getFileSystem(c); fs.mkdirs(regionDir); return new HRegion(dir, new HLog(fs, new Path(regionDir, HConstants.HREGION_LOGDIR_NAME), conf), fs, conf, info, null); } protected HTableDescriptor createTableDescriptor(final String name) { return createTableDescriptor(name, MAXVERSIONS); } protected HTableDescriptor createTableDescriptor(final String name, final int versions) { HTableDescriptor htd = new HTableDescriptor(name); htd.addFamily(new HColumnDescriptor(new Text(COLFAMILY_NAME1), versions, CompressionType.NONE, false, Integer.MAX_VALUE, null)); htd.addFamily(new HColumnDescriptor(new Text(COLFAMILY_NAME2), versions, CompressionType.NONE, false, Integer.MAX_VALUE, null)); htd.addFamily(new HColumnDescriptor(new Text(COLFAMILY_NAME3), versions, CompressionType.NONE, false, Integer.MAX_VALUE, null)); return htd; } /** * Add content to region <code>r</code> on the passed column * <code>column</code>. * Adds data of the from 'aaa', 'aab', etc where key and value are the same. * @param r * @param column * @throws IOException */ protected static void addContent(final HRegion r, final String column) throws IOException { Text startKey = r.getRegionInfo().getStartKey(); Text endKey = r.getRegionInfo().getEndKey(); byte [] startKeyBytes = startKey.getBytes(); if (startKeyBytes == null || startKeyBytes.length == 0) { startKeyBytes = START_KEY_BYTES; } addContent(new HRegionIncommon(r), column, startKeyBytes, endKey, -1); } /** * Add content to region <code>r</code> on the passed column * <code>column</code>. * Adds data of the from 'aaa', 'aab', etc where key and value are the same. * @param updater An instance of {@link Incommon}. * @param column * @throws IOException */ protected static void addContent(final Incommon updater, final String column) throws IOException { addContent(updater, column, START_KEY_BYTES, null); } /** * Add content to region <code>r</code> on the passed column * <code>column</code>. * Adds data of the from 'aaa', 'aab', etc where key and value are the same. * @param updater An instance of {@link Incommon}. * @param column * @param startKeyBytes Where to start the rows inserted * @param endKey Where to stop inserting rows. * @throws IOException */ protected static void addContent(final Incommon updater, final String column, final byte [] startKeyBytes, final Text endKey) throws IOException { addContent(updater, column, startKeyBytes, endKey, -1); } /** * Add content to region <code>r</code> on the passed column * <code>column</code>. * Adds data of the from 'aaa', 'aab', etc where key and value are the same. * @param updater An instance of {@link Incommon}. * @param column * @param startKeyBytes Where to start the rows inserted * @param endKey Where to stop inserting rows. * @param ts Timestamp to write the content with. * @throws IOException */ protected static void addContent(final Incommon updater, final String column, final byte [] startKeyBytes, final Text endKey, final long ts) throws IOException { // Add rows of three characters. The first character starts with the // 'a' character and runs up to 'z'. Per first character, we run the // second character over same range. And same for the third so rows // (and values) look like this: 'aaa', 'aab', 'aac', etc. char secondCharStart = (char)startKeyBytes[1]; char thirdCharStart = (char)startKeyBytes[2]; EXIT: for (char c = (char)startKeyBytes[0]; c <= LAST_CHAR; c++) { for (char d = secondCharStart; d <= LAST_CHAR; d++) { for (char e = thirdCharStart; e <= LAST_CHAR; e++) { byte [] bytes = new byte [] {(byte)c, (byte)d, (byte)e}; Text t = new Text(new String(bytes, HConstants.UTF8_ENCODING)); if (endKey != null && endKey.getLength() > 0 && endKey.compareTo(t) <= 0) { break EXIT; } long lockid = updater.startBatchUpdate(t); try { updater.put(lockid, new Text(column), bytes); if (ts == -1) { updater.commit(lockid); } else { updater.commit(lockid, ts); } lockid = -1; } finally { if (lockid != -1) { updater.abort(lockid); } } } // Set start character back to FIRST_CHAR after we've done first loop. thirdCharStart = FIRST_CHAR; } secondCharStart = FIRST_CHAR; } } /** * Implementors can flushcache. */ public static interface FlushCache { public void flushcache() throws IOException; } /** * Interface used by tests so can do common operations against an HTable * or an HRegion. * * TOOD: Come up w/ a better name for this interface. */ public static interface Incommon { public byte [] get(Text row, Text column) throws IOException; public byte [][] get(Text row, Text column, int versions) throws IOException; public byte [][] get(Text row, Text column, long ts, int versions) throws IOException; public long startBatchUpdate(final Text row) throws IOException; public void put(long lockid, Text column, byte val[]) throws IOException; public void delete(long lockid, Text column) throws IOException; public void deleteAll(Text row, Text column, long ts) throws IOException; public void commit(long lockid) throws IOException; public void commit(long lockid, long ts) throws IOException; public void abort(long lockid) throws IOException; public HScannerInterface getScanner(Text [] columns, Text firstRow, long ts) throws IOException; } /** * A class that makes a {@link Incommon} out of a {@link HRegion} */ public static class HRegionIncommon implements Incommon { final HRegion region; public HRegionIncommon(final HRegion HRegion) { super(); this.region = HRegion; } public void abort(long lockid) throws IOException { this.region.abort(lockid); } public void commit(long lockid) throws IOException { this.region.commit(lockid); } public void commit(long lockid, final long ts) throws IOException { this.region.commit(lockid, ts); } public void put(long lockid, Text column, byte[] val) throws IOException { this.region.put(lockid, column, val); } public void delete(long lockid, Text column) throws IOException { this.region.delete(lockid, column); } public void deleteAll(Text row, Text column, long ts) throws IOException { this.region.deleteAll(row, column, ts); } public long startBatchUpdate(Text row) throws IOException { return this.region.startUpdate(row); } public HScannerInterface getScanner(Text [] columns, Text firstRow, long ts) throws IOException { return this.region.getScanner(columns, firstRow, ts, null); } public byte[] get(Text row, Text column) throws IOException { return this.region.get(row, column); } public byte[][] get(Text row, Text column, int versions) throws IOException { return this.region.get(row, column, versions); } public byte[][] get(Text row, Text column, long ts, int versions) throws IOException { return this.region.get(row, column, ts, versions); } } /** * A class that makes a {@link Incommon} out of a {@link HTable} */ public static class HTableIncommon implements Incommon { final HTable table; public HTableIncommon(final HTable table) { super(); this.table = table; } public void abort(long lockid) throws IOException { this.table.abort(lockid); } public void commit(long lockid) throws IOException { this.table.commit(lockid); } public void commit(long lockid, final long ts) throws IOException { this.table.commit(lockid, ts); } public void put(long lockid, Text column, byte[] val) throws IOException { this.table.put(lockid, column, val); } public void delete(long lockid, Text column) throws IOException { this.table.delete(lockid, column); } public void deleteAll(Text row, Text column, long ts) throws IOException { this.table.deleteAll(row, column, ts); } public long startBatchUpdate(Text row) { return this.table.startUpdate(row); } public HScannerInterface getScanner(Text [] columns, Text firstRow, long ts) throws IOException { return this.table.obtainScanner(columns, firstRow, ts, null); } public byte[] get(Text row, Text column) throws IOException { return this.table.get(row, column); } public byte[][] get(Text row, Text column, int versions) throws IOException { return this.table.get(row, column, versions); } public byte[][] get(Text row, Text column, long ts, int versions) throws IOException { return this.table.get(row, column, ts, versions); } } }