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