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.coprocessor.CoprocessorHost;
38  import org.apache.hadoop.hbase.util.Bytes;
39  import org.junit.After;
40  import org.junit.AfterClass;
41  import org.junit.BeforeClass;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  /**
46   * Do the complex testing of constraints against a minicluster
47   */
48  @Category(MediumTests.class)
49  public class TestConstraint {
50    private static final Log LOG = LogFactory
51        .getLog(TestConstraint.class);
52  
53    private static HBaseTestingUtility util;
54    private static final byte[] tableName = Bytes.toBytes("test");
55    private static final byte[] dummy = Bytes.toBytes("dummy");
56    private static final byte[] row1 = Bytes.toBytes("r1");
57    private static final byte[] test = Bytes.toBytes("test");
58  
59    @BeforeClass
60    public static void setUpBeforeClass() throws Exception {
61      util = new HBaseTestingUtility();
62      util.getConfiguration().setBoolean(CoprocessorHost.ABORT_ON_ERROR_KEY, false);
63      util.startMiniCluster();
64    }
65  
66    /**
67     * Test that we run a passing constraint
68     * @throws Exception
69     */
70    @SuppressWarnings("unchecked")
71    @Test
72    public void testConstraintPasses() throws Exception {
73      // create the table
74      // it would be nice if this was also a method on the util
75      HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
76      for (byte[] family : new byte[][] { dummy, test }) {
77        desc.addFamily(new HColumnDescriptor(family));
78      }
79      // add a constraint
80      Constraints.add(desc, CheckWasRunConstraint.class);
81  
82      util.getHBaseAdmin().createTable(desc);
83      HTable table = new HTable(util.getConfiguration(), tableName);
84      try {
85        // test that we don't fail on a valid put
86        Put put = new Put(row1);
87        byte[] value = Integer.toString(10).getBytes();
88        put.add(dummy, new byte[0], value);
89        table.put(put);
90      } finally {
91        table.close();
92      }
93      assertTrue(CheckWasRunConstraint.wasRun);
94    }
95  
96    /**
97     * Test that constraints will fail properly
98     * @throws Exception
99     */
100   @SuppressWarnings("unchecked")
101   @Test(timeout = 60000)
102   public void testConstraintFails() throws Exception {
103 
104     // create the table
105     // it would be nice if this was also a method on the util
106     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
107     for (byte[] family : new byte[][] { dummy, test }) {
108       desc.addFamily(new HColumnDescriptor(family));
109     }
110 
111     // add a constraint that is sure to fail
112     Constraints.add(desc, AllFailConstraint.class);
113 
114     util.getHBaseAdmin().createTable(desc);
115     HTable table = new HTable(util.getConfiguration(), tableName);
116 
117     // test that we do fail on violation
118     Put put = new Put(row1);
119     put.add(dummy, new byte[0], "fail".getBytes());
120     LOG.warn("Doing put in table");
121     try {
122       table.put(put);
123       fail("This put should not have suceeded - AllFailConstraint was not run!");
124     } catch (RetriesExhaustedWithDetailsException e) {
125       List<Throwable> causes = e.getCauses();
126       assertEquals(
127           "More than one failure cause - should only be the failure constraint exception",
128           1, causes.size());
129       Throwable t = causes.get(0);
130       assertEquals(ConstraintException.class, t.getClass());
131     }
132     table.close();
133   }
134 
135   /**
136    * Check that if we just disable one constraint, then
137    * @throws Throwable
138    */
139   @SuppressWarnings("unchecked")
140   @Test
141   public void testDisableConstraint() throws Throwable {
142     // create the table
143     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
144     // add a family to the table
145     for (byte[] family : new byte[][] { dummy, test }) {
146       desc.addFamily(new HColumnDescriptor(family));
147     }
148     // add a constraint to make sure it others get run
149     Constraints.add(desc, CheckWasRunConstraint.class);
150 
151     // Add Constraint to check
152     Constraints.add(desc, AllFailConstraint.class);
153 
154     // and then disable the failing constraint
155     Constraints.disableConstraint(desc, AllFailConstraint.class);
156 
157     util.getHBaseAdmin().createTable(desc);
158     HTable table = new HTable(util.getConfiguration(), tableName);
159     try {
160       // test that we don't fail because its disabled
161       Put put = new Put(row1);
162       put.add(dummy, new byte[0], "pass".getBytes());
163       table.put(put);
164     } finally {
165       table.close();
166     }
167     assertTrue(CheckWasRunConstraint.wasRun);
168   }
169 
170   /**
171    * Test that if we disable all constraints, then nothing gets run
172    * @throws Throwable
173    */
174   @SuppressWarnings("unchecked")
175   @Test
176   public void testDisableConstraints() throws Throwable {
177     // create the table
178     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
179     // add a family to the table
180     for (byte[] family : new byte[][] { dummy, test }) {
181       desc.addFamily(new HColumnDescriptor(family));
182     }
183     // add a constraint to check to see if is run
184     Constraints.add(desc, CheckWasRunConstraint.class);
185 
186     // then disable all the constraints
187     Constraints.disable(desc);
188 
189     util.getHBaseAdmin().createTable(desc);
190     HTable table = new HTable(util.getConfiguration(), tableName);
191     try {
192       // test that we do fail on violation
193       Put put = new Put(row1);
194       put.add(dummy, new byte[0], "pass".getBytes());
195       LOG.warn("Doing put in table");
196       table.put(put);
197     } finally {
198       table.close();
199     }
200     assertFalse(CheckWasRunConstraint.wasRun);
201   }
202 
203   /**
204    * Check to make sure a constraint is unloaded when it fails
205    * @throws Exception
206    */
207   @Test
208   public void testIsUnloaded() throws Exception {
209     // create the table
210     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(tableName));
211     // add a family to the table
212     for (byte[] family : new byte[][] { dummy, test }) {
213       desc.addFamily(new HColumnDescriptor(family));
214     }
215     // make sure that constraints are unloaded
216     Constraints.add(desc, RuntimeFailConstraint.class);
217     // add a constraint to check to see if is run
218     Constraints.add(desc, CheckWasRunConstraint.class);
219     CheckWasRunConstraint.wasRun = false;
220 
221     util.getHBaseAdmin().createTable(desc);
222     HTable table = new HTable(util.getConfiguration(), tableName);
223 
224     // test that we do fail on violation
225     Put put = new Put(row1);
226     put.add(dummy, new byte[0], "pass".getBytes());
227     
228     try{
229     table.put(put);
230     fail("RuntimeFailConstraint wasn't triggered - this put shouldn't work!");
231     } catch (Exception e) {// NOOP
232     }
233 
234     // try the put again, this time constraints are not used, so it works
235     table.put(put);
236     // and we make sure that constraints were not run...
237     assertFalse(CheckWasRunConstraint.wasRun);
238     table.close();
239   }
240 
241   @After
242   public void cleanup() throws Exception {
243     // cleanup
244     CheckWasRunConstraint.wasRun = false;
245     util.getHBaseAdmin().disableTable(tableName);
246     util.getHBaseAdmin().deleteTable(tableName);
247   }
248 
249   @AfterClass
250   public static void tearDownAfterClass() throws Exception {
251     util.shutdownMiniCluster();
252   }
253 
254   /**
255    * Constraint to check that it was actually run (or not)
256    */
257   public static class CheckWasRunConstraint extends BaseConstraint {
258     public static boolean wasRun = false;
259 
260     @Override
261     public void check(Put p) {
262       wasRun = true;
263     }
264   }
265 
266 }