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.constraint; 019 020import static org.junit.Assert.assertFalse; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023 024import org.apache.hadoop.hbase.HBaseClassTestRule; 025import org.apache.hadoop.hbase.HBaseTestingUtility; 026import org.apache.hadoop.hbase.HColumnDescriptor; 027import org.apache.hadoop.hbase.HTableDescriptor; 028import org.apache.hadoop.hbase.TableName; 029import org.apache.hadoop.hbase.client.Put; 030import org.apache.hadoop.hbase.client.Table; 031import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.testclassification.MiscTests; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.junit.After; 036import org.junit.AfterClass; 037import org.junit.BeforeClass; 038import org.junit.ClassRule; 039import org.junit.Test; 040import org.junit.experimental.categories.Category; 041import org.slf4j.Logger; 042import org.slf4j.LoggerFactory; 043 044/** 045 * Do the complex testing of constraints against a minicluster 046 */ 047@Category({MiscTests.class, MediumTests.class}) 048public class TestConstraint { 049 050 @ClassRule 051 public static final HBaseClassTestRule CLASS_RULE = 052 HBaseClassTestRule.forClass(TestConstraint.class); 053 054 private static final Logger LOG = LoggerFactory 055 .getLogger(TestConstraint.class); 056 057 private static HBaseTestingUtility util; 058 private static final TableName tableName = TableName.valueOf("test"); 059 private static final byte[] dummy = Bytes.toBytes("dummy"); 060 private static final byte[] row1 = Bytes.toBytes("r1"); 061 private static final byte[] test = Bytes.toBytes("test"); 062 063 @BeforeClass 064 public static void setUpBeforeClass() throws Exception { 065 util = new HBaseTestingUtility(); 066 util.getConfiguration().setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, false); 067 util.startMiniCluster(); 068 } 069 070 /** 071 * Test that we run a passing constraint 072 * @throws Exception 073 */ 074 @SuppressWarnings("unchecked") 075 @Test 076 public void testConstraintPasses() throws Exception { 077 // create the table 078 // it would be nice if this was also a method on the util 079 HTableDescriptor desc = new HTableDescriptor(tableName); 080 for (byte[] family : new byte[][] { dummy, test }) { 081 desc.addFamily(new HColumnDescriptor(family)); 082 } 083 // add a constraint 084 Constraints.add(desc, CheckWasRunConstraint.class); 085 086 util.getAdmin().createTable(desc); 087 Table table = util.getConnection().getTable(tableName); 088 try { 089 // test that we don't fail on a valid put 090 Put put = new Put(row1); 091 byte[] value = Bytes.toBytes(Integer.toString(10)); 092 byte[] qualifier = new byte[0]; 093 put.addColumn(dummy, qualifier, value); 094 table.put(put); 095 } finally { 096 table.close(); 097 } 098 assertTrue(CheckWasRunConstraint.wasRun); 099 } 100 101 /** 102 * Test that constraints will fail properly 103 * @throws Exception 104 */ 105 @SuppressWarnings("unchecked") 106 @Test 107 public void testConstraintFails() throws Exception { 108 109 // create the table 110 // it would be nice if this was also a method on the util 111 HTableDescriptor desc = new HTableDescriptor(tableName); 112 for (byte[] family : new byte[][] { dummy, test }) { 113 desc.addFamily(new HColumnDescriptor(family)); 114 } 115 116 // add a constraint that is sure to fail 117 Constraints.add(desc, AllFailConstraint.class); 118 119 util.getAdmin().createTable(desc); 120 Table table = util.getConnection().getTable(tableName); 121 122 // test that we do fail on violation 123 Put put = new Put(row1); 124 byte[] qualifier = new byte[0]; 125 put.addColumn(dummy, qualifier, Bytes.toBytes("fail")); 126 LOG.warn("Doing put in table"); 127 try { 128 table.put(put); 129 fail("This put should not have suceeded - AllFailConstraint was not run!"); 130 } catch (ConstraintException e) { 131 // expected 132 } 133 table.close(); 134 } 135 136 /** 137 * Check that if we just disable one constraint, then 138 * @throws Throwable 139 */ 140 @SuppressWarnings("unchecked") 141 @Test 142 public void testDisableConstraint() throws Throwable { 143 // create the table 144 HTableDescriptor desc = new HTableDescriptor(tableName); 145 // add a family to the table 146 for (byte[] family : new byte[][] { dummy, test }) { 147 desc.addFamily(new HColumnDescriptor(family)); 148 } 149 // add a constraint to make sure it others get run 150 Constraints.add(desc, CheckWasRunConstraint.class); 151 152 // Add Constraint to check 153 Constraints.add(desc, AllFailConstraint.class); 154 155 // and then disable the failing constraint 156 Constraints.disableConstraint(desc, AllFailConstraint.class); 157 158 util.getAdmin().createTable(desc); 159 Table table = util.getConnection().getTable(tableName); 160 try { 161 // test that we don't fail because its disabled 162 Put put = new Put(row1); 163 byte[] qualifier = new byte[0]; 164 put.addColumn(dummy, qualifier, Bytes.toBytes("pass")); 165 table.put(put); 166 } finally { 167 table.close(); 168 } 169 assertTrue(CheckWasRunConstraint.wasRun); 170 } 171 172 /** 173 * Test that if we disable all constraints, then nothing gets run 174 * @throws Throwable 175 */ 176 @SuppressWarnings("unchecked") 177 @Test 178 public void testDisableConstraints() throws Throwable { 179 // create the table 180 HTableDescriptor desc = new HTableDescriptor(tableName); 181 // add a family to the table 182 for (byte[] family : new byte[][] { dummy, test }) { 183 desc.addFamily(new HColumnDescriptor(family)); 184 } 185 // add a constraint to check to see if is run 186 Constraints.add(desc, CheckWasRunConstraint.class); 187 188 // then disable all the constraints 189 Constraints.disable(desc); 190 191 util.getAdmin().createTable(desc); 192 Table table = util.getConnection().getTable(tableName); 193 try { 194 // test that we do fail on violation 195 Put put = new Put(row1); 196 byte[] qualifier = new byte[0]; 197 put.addColumn(dummy, qualifier, Bytes.toBytes("pass")); 198 LOG.warn("Doing put in table"); 199 table.put(put); 200 } finally { 201 table.close(); 202 } 203 assertFalse(CheckWasRunConstraint.wasRun); 204 } 205 206 /** 207 * Check to make sure a constraint is unloaded when it fails 208 * @throws Exception 209 */ 210 @Test 211 public void testIsUnloaded() throws Exception { 212 // create the table 213 HTableDescriptor desc = new HTableDescriptor(tableName); 214 // add a family to the table 215 for (byte[] family : new byte[][] { dummy, test }) { 216 desc.addFamily(new HColumnDescriptor(family)); 217 } 218 // make sure that constraints are unloaded 219 Constraints.add(desc, RuntimeFailConstraint.class); 220 // add a constraint to check to see if is run 221 Constraints.add(desc, CheckWasRunConstraint.class); 222 CheckWasRunConstraint.wasRun = false; 223 224 util.getAdmin().createTable(desc); 225 Table table = util.getConnection().getTable(tableName); 226 227 // test that we do fail on violation 228 Put put = new Put(row1); 229 byte[] qualifier = new byte[0]; 230 put.addColumn(dummy, qualifier, Bytes.toBytes("pass")); 231 232 try{ 233 table.put(put); 234 fail("RuntimeFailConstraint wasn't triggered - this put shouldn't work!"); 235 } catch (Exception e) {// NOOP 236 } 237 238 // try the put again, this time constraints are not used, so it works 239 table.put(put); 240 // and we make sure that constraints were not run... 241 assertFalse(CheckWasRunConstraint.wasRun); 242 table.close(); 243 } 244 245 @After 246 public void cleanup() throws Exception { 247 // cleanup 248 CheckWasRunConstraint.wasRun = false; 249 util.getAdmin().disableTable(tableName); 250 util.getAdmin().deleteTable(tableName); 251 } 252 253 @AfterClass 254 public static void tearDownAfterClass() throws Exception { 255 util.shutdownMiniCluster(); 256 } 257 258 /** 259 * Constraint to check that it was actually run (or not) 260 */ 261 public static class CheckWasRunConstraint extends BaseConstraint { 262 public static boolean wasRun = false; 263 264 @Override 265 public void check(Put p) { 266 wasRun = true; 267 } 268 } 269 270}