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