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.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertTrue;
023import static org.junit.Assert.fail;
024
025import java.util.List;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.HTableDescriptor;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.client.Put;
031import org.apache.hadoop.hbase.constraint.TestConstraint.CheckWasRunConstraint;
032import org.apache.hadoop.hbase.constraint.WorksConstraint.NameConstraint;
033import org.apache.hadoop.hbase.testclassification.MiscTests;
034import org.apache.hadoop.hbase.testclassification.SmallTests;
035import org.apache.hadoop.hbase.util.Pair;
036import org.junit.ClassRule;
037import org.junit.Rule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040import org.junit.rules.TestName;
041
042/**
043 * Test reading/writing the constraints into the {@link HTableDescriptor}
044 */
045@Category({ MiscTests.class, SmallTests.class })
046public class TestConstraints {
047
048  @ClassRule
049  public static final HBaseClassTestRule CLASS_RULE =
050    HBaseClassTestRule.forClass(TestConstraints.class);
051
052  @Rule
053  public TestName name = new TestName();
054
055  @SuppressWarnings("unchecked")
056  @Test
057  public void testSimpleReadWrite() throws Throwable {
058    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
059    Constraints.add(desc, WorksConstraint.class);
060
061    List<? extends Constraint> constraints =
062      Constraints.getConstraints(desc, this.getClass().getClassLoader());
063    assertEquals(1, constraints.size());
064
065    assertEquals(WorksConstraint.class, constraints.get(0).getClass());
066
067    // Check that we can add more than 1 constraint and that ordering is
068    // preserved
069    Constraints.add(desc, AlsoWorks.class, NameConstraint.class);
070    constraints = Constraints.getConstraints(desc, this.getClass().getClassLoader());
071    assertEquals(3, constraints.size());
072
073    assertEquals(WorksConstraint.class, constraints.get(0).getClass());
074    assertEquals(AlsoWorks.class, constraints.get(1).getClass());
075    assertEquals(NameConstraint.class, constraints.get(2).getClass());
076
077  }
078
079  @SuppressWarnings("unchecked")
080  @Test
081  public void testReadWriteWithConf() throws Throwable {
082    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
083    Constraints.add(desc, new Pair<>(CheckConfigurationConstraint.class,
084      CheckConfigurationConstraint.getConfiguration()));
085
086    List<? extends Constraint> c =
087      Constraints.getConstraints(desc, this.getClass().getClassLoader());
088    assertEquals(1, c.size());
089
090    assertEquals(CheckConfigurationConstraint.class, c.get(0).getClass());
091
092    // check to make sure that we overwrite configurations
093    Constraints.add(desc, new Pair<>(CheckConfigurationConstraint.class, new Configuration(false)));
094
095    try {
096      Constraints.getConstraints(desc, this.getClass().getClassLoader());
097      fail("No exception thrown  - configuration not overwritten");
098    } catch (IllegalArgumentException e) {
099      // expect to have the exception, so don't do anything
100    }
101  }
102
103  /**
104   * Test that Constraints are properly enabled, disabled, and removed
105   */
106  @SuppressWarnings("unchecked")
107  @Test
108  public void testEnableDisableRemove() throws Exception {
109    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
110    // check general enabling/disabling of constraints
111    // first add a constraint
112    Constraints.add(desc, AllPassConstraint.class);
113    // make sure everything is enabled
114    assertTrue(Constraints.enabled(desc, AllPassConstraint.class));
115    assertTrue(desc.hasCoprocessor(ConstraintProcessor.class.getName()));
116
117    // check disabling
118    Constraints.disable(desc);
119    assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName()));
120    // make sure the added constraints are still present
121    assertTrue(Constraints.enabled(desc, AllPassConstraint.class));
122
123    // check just removing the single constraint
124    Constraints.remove(desc, AllPassConstraint.class);
125    assertFalse(Constraints.has(desc, AllPassConstraint.class));
126
127    // Add back the single constraint
128    Constraints.add(desc, AllPassConstraint.class);
129
130    // and now check that when we remove constraints, all are gone
131    Constraints.remove(desc);
132    assertFalse(desc.hasCoprocessor(ConstraintProcessor.class.getName()));
133    assertFalse(Constraints.has(desc, AllPassConstraint.class));
134
135  }
136
137  /**
138   * Test that when we update a constraint the ordering is not modified.
139   */
140  @SuppressWarnings("unchecked")
141  @Test
142  public void testUpdateConstraint() throws Exception {
143    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
144    Constraints.add(desc, CheckConfigurationConstraint.class, CheckWasRunConstraint.class);
145    Constraints.setConfiguration(desc, CheckConfigurationConstraint.class,
146      CheckConfigurationConstraint.getConfiguration());
147
148    List<? extends Constraint> constraints =
149      Constraints.getConstraints(desc, this.getClass().getClassLoader());
150
151    assertEquals(2, constraints.size());
152
153    // check to make sure the order didn't change
154    assertEquals(CheckConfigurationConstraint.class, constraints.get(0).getClass());
155    assertEquals(CheckWasRunConstraint.class, constraints.get(1).getClass());
156  }
157
158  /**
159   * Test that if a constraint hasn't been set that there are no problems with attempting to remove
160   * it. on failure.
161   */
162  @Test
163  public void testRemoveUnsetConstraint() throws Throwable {
164    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
165    Constraints.remove(desc);
166    Constraints.remove(desc, AlsoWorks.class);
167  }
168
169  @Test
170  public void testConfigurationPreserved() throws Throwable {
171    Configuration conf = new Configuration();
172    conf.setBoolean("_ENABLED", false);
173    conf.setLong("_PRIORITY", 10);
174    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
175    Constraints.add(desc, AlsoWorks.class, conf);
176    Constraints.add(desc, WorksConstraint.class);
177    assertFalse(Constraints.enabled(desc, AlsoWorks.class));
178    List<? extends Constraint> constraints =
179      Constraints.getConstraints(desc, this.getClass().getClassLoader());
180    for (Constraint c : constraints) {
181      Configuration storedConf = c.getConf();
182      if (c instanceof AlsoWorks) assertEquals(10, storedConf.getLong("_PRIORITY", -1));
183      // its just a worksconstraint
184      else assertEquals(2, storedConf.getLong("_PRIORITY", -1));
185
186    }
187
188  }
189
190  // ---------- Constraints just used for testing
191
192  /**
193   * Also just works
194   */
195  public static class AlsoWorks extends BaseConstraint {
196    @Override
197    public void check(Put p) {
198      // NOOP
199    }
200  }
201
202}