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