View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.constraint;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.fail;
24  
25  import java.util.List;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.apache.hadoop.hbase.HBaseTestingUtility;
30  import org.apache.hadoop.hbase.HColumnDescriptor;
31  import org.apache.hadoop.hbase.HTableDescriptor;
32  import org.apache.hadoop.hbase.testclassification.MediumTests;
33  import org.apache.hadoop.hbase.TableName;
34  import org.apache.hadoop.hbase.client.HTable;
35  import org.apache.hadoop.hbase.client.Put;
36  import org.apache.hadoop.hbase.client.RetriesExhaustedWithDetailsException;
37  import org.apache.hadoop.hbase.client.Table;
38  import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.junit.After;
41  import org.junit.AfterClass;
42  import org.junit.BeforeClass;
43  import org.junit.Test;
44  import org.junit.experimental.categories.Category;
45  
46  /**
47   * Do the complex testing of constraints against a minicluster
48   */
49  @Category(MediumTests.class)
50  public class TestConstraint {
51    private static final Log LOG = LogFactory
52        .getLog(TestConstraint.class);
53  
54    private static HBaseTestingUtility util;
55    private static final TableName tableName = TableName.valueOf("test");
56    private static final byte[] dummy = Bytes.toBytes("dummy");
57    private static final byte[] row1 = Bytes.toBytes("r1");
58    private static final byte[] test = Bytes.toBytes("test");
59  
60    @BeforeClass
61    public static void setUpBeforeClass() throws Exception {
62      util = new HBaseTestingUtility();
63      util.getConfiguration().setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, false);
64      util.startMiniCluster();
65    }
66  
67    /**
68     * Test that we run a passing constraint
69     * @throws Exception
70     */
71    @SuppressWarnings("unchecked")
72    @Test
73    public void testConstraintPasses() throws Exception {
74      // create the table
75      // it would be nice if this was also a method on the util
76      HTableDescriptor desc = new HTableDescriptor(tableName);
77      for (byte[] family : new byte[][] { dummy, test }) {
78        desc.addFamily(new HColumnDescriptor(family));
79      }
80      // add a constraint
81      Constraints.add(desc, CheckWasRunConstraint.class);
82  
83      util.getHBaseAdmin().createTable(desc);
84      Table table = new HTable(util.getConfiguration(), tableName);
85      try {
86        // test that we don't fail on a valid put
87        Put put = new Put(row1);
88        byte[] value = Integer.toString(10).getBytes();
89        put.add(dummy, new byte[0], value);
90        table.put(put);
91      } finally {
92        table.close();
93      }
94      assertTrue(CheckWasRunConstraint.wasRun);
95    }
96  
97    /**
98     * Test that constraints will fail properly
99     * @throws Exception
100    */
101   @SuppressWarnings("unchecked")
102   @Test(timeout = 60000)
103   public void testConstraintFails() throws Exception {
104 
105     // create the table
106     // it would be nice if this was also a method on the util
107     HTableDescriptor desc = new HTableDescriptor(tableName);
108     for (byte[] family : new byte[][] { dummy, test }) {
109       desc.addFamily(new HColumnDescriptor(family));
110     }
111 
112     // add a constraint that is sure to fail
113     Constraints.add(desc, AllFailConstraint.class);
114 
115     util.getHBaseAdmin().createTable(desc);
116     Table table = new HTable(util.getConfiguration(), tableName);
117 
118     // test that we do fail on violation
119     Put put = new Put(row1);
120     put.add(dummy, new byte[0], "fail".getBytes());
121     LOG.warn("Doing put in table");
122     try {
123       table.put(put);
124       fail("This put should not have suceeded - AllFailConstraint was not run!");
125     } catch (RetriesExhaustedWithDetailsException e) {
126       List<Throwable> causes = e.getCauses();
127       assertEquals(
128           "More than one failure cause - should only be the failure constraint exception",
129           1, causes.size());
130       Throwable t = causes.get(0);
131       assertEquals(ConstraintException.class, t.getClass());
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.getHBaseAdmin().createTable(desc);
159     Table table = new HTable(util.getConfiguration(), tableName);
160     try {
161       // test that we don't fail because its disabled
162       Put put = new Put(row1);
163       put.add(dummy, new byte[0], "pass".getBytes());
164       table.put(put);
165     } finally {
166       table.close();
167     }
168     assertTrue(CheckWasRunConstraint.wasRun);
169   }
170 
171   /**
172    * Test that if we disable all constraints, then nothing gets run
173    * @throws Throwable
174    */
175   @SuppressWarnings("unchecked")
176   @Test
177   public void testDisableConstraints() throws Throwable {
178     // create the table
179     HTableDescriptor desc = new HTableDescriptor(tableName);
180     // add a family to the table
181     for (byte[] family : new byte[][] { dummy, test }) {
182       desc.addFamily(new HColumnDescriptor(family));
183     }
184     // add a constraint to check to see if is run
185     Constraints.add(desc, CheckWasRunConstraint.class);
186 
187     // then disable all the constraints
188     Constraints.disable(desc);
189 
190     util.getHBaseAdmin().createTable(desc);
191     Table table = new HTable(util.getConfiguration(), tableName);
192     try {
193       // test that we do fail on violation
194       Put put = new Put(row1);
195       put.add(dummy, new byte[0], "pass".getBytes());
196       LOG.warn("Doing put in table");
197       table.put(put);
198     } finally {
199       table.close();
200     }
201     assertFalse(CheckWasRunConstraint.wasRun);
202   }
203 
204   /**
205    * Check to make sure a constraint is unloaded when it fails
206    * @throws Exception
207    */
208   @Test
209   public void testIsUnloaded() throws Exception {
210     // create the table
211     HTableDescriptor desc = new HTableDescriptor(tableName);
212     // add a family to the table
213     for (byte[] family : new byte[][] { dummy, test }) {
214       desc.addFamily(new HColumnDescriptor(family));
215     }
216     // make sure that constraints are unloaded
217     Constraints.add(desc, RuntimeFailConstraint.class);
218     // add a constraint to check to see if is run
219     Constraints.add(desc, CheckWasRunConstraint.class);
220     CheckWasRunConstraint.wasRun = false;
221 
222     util.getHBaseAdmin().createTable(desc);
223     Table table = new HTable(util.getConfiguration(), tableName);
224 
225     // test that we do fail on violation
226     Put put = new Put(row1);
227     put.add(dummy, new byte[0], "pass".getBytes());
228     
229     try{
230     table.put(put);
231     fail("RuntimeFailConstraint wasn't triggered - this put shouldn't work!");
232     } catch (Exception e) {// NOOP
233     }
234 
235     // try the put again, this time constraints are not used, so it works
236     table.put(put);
237     // and we make sure that constraints were not run...
238     assertFalse(CheckWasRunConstraint.wasRun);
239     table.close();
240   }
241 
242   @After
243   public void cleanup() throws Exception {
244     // cleanup
245     CheckWasRunConstraint.wasRun = false;
246     util.getHBaseAdmin().disableTable(tableName);
247     util.getHBaseAdmin().deleteTable(tableName);
248   }
249 
250   @AfterClass
251   public static void tearDownAfterClass() throws Exception {
252     util.shutdownMiniCluster();
253   }
254 
255   /**
256    * Constraint to check that it was actually run (or not)
257    */
258   public static class CheckWasRunConstraint extends BaseConstraint {
259     public static boolean wasRun = false;
260 
261     @Override
262     public void check(Put p) {
263       wasRun = true;
264     }
265   }
266 
267 }