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;
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.io.IOException;
026import java.util.Arrays;
027import java.util.regex.Pattern;
028import org.apache.hadoop.hbase.client.Durability;
029import org.apache.hadoop.hbase.exceptions.DeserializationException;
030import org.apache.hadoop.hbase.testclassification.MiscTests;
031import org.apache.hadoop.hbase.testclassification.SmallTests;
032import org.apache.hadoop.hbase.util.BuilderStyleTest;
033import org.apache.hadoop.hbase.util.Bytes;
034import org.junit.ClassRule;
035import org.junit.Rule;
036import org.junit.Test;
037import org.junit.experimental.categories.Category;
038import org.junit.rules.TestName;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042/**
043 * Test setting values in the descriptor
044 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0 together with
045 *             {@link HTableDescriptor}.
046 */
047@Category({ MiscTests.class, SmallTests.class })
048@Deprecated
049public class TestHTableDescriptor {
050
051  @ClassRule
052  public static final HBaseClassTestRule CLASS_RULE =
053    HBaseClassTestRule.forClass(TestHTableDescriptor.class);
054
055  private static final Logger LOG = LoggerFactory.getLogger(TestHTableDescriptor.class);
056
057  @Rule
058  public TestName name = new TestName();
059
060  @Test(expected = IOException.class)
061  public void testAddCoprocessorTwice() throws IOException {
062    HTableDescriptor htd = new HTableDescriptor(TableName.META_TABLE_NAME);
063    String cpName = "a.b.c.d";
064    htd.addCoprocessor(cpName);
065    htd.addCoprocessor(cpName);
066  }
067
068  @Test
069  public void testAddCoprocessorWithSpecStr() throws IOException {
070    HTableDescriptor htd = new HTableDescriptor(TableName.META_TABLE_NAME);
071    String cpName = "a.b.c.d";
072    try {
073      htd.addCoprocessorWithSpec(cpName);
074      fail();
075    } catch (IllegalArgumentException iae) {
076      // Expected as cpName is invalid
077    }
078
079    // Try minimal spec.
080    try {
081      htd.addCoprocessorWithSpec("file:///some/path" + "|" + cpName);
082      fail();
083    } catch (IllegalArgumentException iae) {
084      // Expected to be invalid
085    }
086
087    // Try more spec.
088    String spec = "hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2";
089    htd.addCoprocessorWithSpec(spec);
090
091    // Try double add of same coprocessor
092    try {
093      htd.addCoprocessorWithSpec(spec);
094      fail();
095    } catch (IOException ioe) {
096      // Expect that the coprocessor already exists
097    }
098  }
099
100  @Test
101  public void testPb() throws DeserializationException, IOException {
102    HTableDescriptor htd = new HTableDescriptor(TableName.META_TABLE_NAME);
103    final int v = 123;
104    htd.setMaxFileSize(v);
105    htd.setDurability(Durability.ASYNC_WAL);
106    htd.setReadOnly(true);
107    htd.setRegionReplication(2);
108    byte[] bytes = htd.toByteArray();
109    HTableDescriptor deserializedHtd = HTableDescriptor.parseFrom(bytes);
110    assertEquals(htd, deserializedHtd);
111    assertEquals(v, deserializedHtd.getMaxFileSize());
112    assertTrue(deserializedHtd.isReadOnly());
113    assertEquals(Durability.ASYNC_WAL, deserializedHtd.getDurability());
114    assertEquals(2, deserializedHtd.getRegionReplication());
115  }
116
117  /**
118   * Test cps in the table description.
119   * @throws Exception if adding a coprocessor fails
120   */
121  @Test
122  public void testGetSetRemoveCP() throws Exception {
123    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
124    // simple CP
125    String className = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver";
126    // add and check that it is present
127    desc.addCoprocessor(className);
128    assertTrue(desc.hasCoprocessor(className));
129    // remove it and check that it is gone
130    desc.removeCoprocessor(className);
131    assertFalse(desc.hasCoprocessor(className));
132  }
133
134  /**
135   * Test cps in the table description.
136   * @throws Exception if adding a coprocessor fails
137   */
138  @Test
139  public void testSetListRemoveCP() throws Exception {
140    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
141    // simple CP
142    String className1 = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver";
143    String className2 = "org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver";
144    // Check that any coprocessor is present.
145    assertTrue(desc.getCoprocessors().isEmpty());
146
147    // Add the 1 coprocessor and check if present.
148    desc.addCoprocessor(className1);
149    assertTrue(desc.getCoprocessors().size() == 1);
150    assertTrue(desc.getCoprocessors().contains(className1));
151
152    // Add the 2nd coprocessor and check if present.
153    // remove it and check that it is gone
154    desc.addCoprocessor(className2);
155    assertTrue(desc.getCoprocessors().size() == 2);
156    assertTrue(desc.getCoprocessors().contains(className2));
157
158    // Remove one and check
159    desc.removeCoprocessor(className1);
160    assertTrue(desc.getCoprocessors().size() == 1);
161    assertFalse(desc.getCoprocessors().contains(className1));
162    assertTrue(desc.getCoprocessors().contains(className2));
163
164    // Remove the last and check
165    desc.removeCoprocessor(className2);
166    assertTrue(desc.getCoprocessors().isEmpty());
167    assertFalse(desc.getCoprocessors().contains(className1));
168    assertFalse(desc.getCoprocessors().contains(className2));
169  }
170
171  /**
172   * Test that we add and remove strings from settings properly.
173   */
174  @Test
175  public void testAddGetRemoveString() {
176    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
177    String key = "Some";
178    String value = "value";
179    desc.setValue(key, value);
180    assertEquals(value, desc.getValue(key));
181    desc.remove(key);
182    assertEquals(null, desc.getValue(key));
183    String keyShouldNotNull = "Some2";
184    String valueIsNull = null;
185    desc.setValue(keyShouldNotNull, valueIsNull);
186    assertEquals(valueIsNull, desc.getValue(keyShouldNotNull));
187    desc.remove(keyShouldNotNull);
188    assertEquals(null, desc.getValue(keyShouldNotNull));
189  }
190
191  String[] legalTableNames = { "foo", "with-dash_under.dot", "_under_start_ok",
192    "with-dash.with_underscore", "02-01-2012.my_table_01-02", "xyz._mytable_", "9_9_0.table_02",
193    "dot1.dot2.table", "new.-mytable", "with-dash.with.dot", "legal..t2", "legal..legal.t2",
194    "trailingdots..", "trailing.dots...", "ns:mytable", "ns:_mytable_", "ns:my_table_01-02", "汉",
195    "汉:字", "_字_", "foo:字", "foo.字", "字.foo" };
196  // Avoiding "zookeeper" in here as it's tough to encode in regex
197  String[] illegalTableNames = { ".dot_start_illegal", "-dash_start_illegal", "spaces not ok",
198    "-dash-.start_illegal", "new.table with space", "01 .table", "ns:-illegaldash",
199    "new:.illegaldot", "new:illegalcolon1:", "new:illegalcolon1:2", String.valueOf((char) 130),
200    String.valueOf((char) 5), String.valueOf((char) 65530) };
201
202  @Test
203  public void testLegalHTableNames() {
204    for (String tn : legalTableNames) {
205      TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn));
206    }
207  }
208
209  @Test
210  public void testIllegalHTableNames() {
211    for (String tn : illegalTableNames) {
212      try {
213        TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn));
214        fail("invalid tablename " + tn + " should have failed");
215      } catch (Exception e) {
216        // expected
217      }
218    }
219  }
220
221  @Test
222  public void testIllegalZooKeeperName() {
223    for (String name : Arrays.asList("zookeeper", "ns:zookeeper", "zookeeper:table")) {
224      try {
225        TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(name));
226        fail("invalid tablename " + name + " should have failed");
227      } catch (Exception e) {
228        // expected
229      }
230    }
231  }
232
233  @Test
234  public void testLegalHTableNamesRegex() {
235    for (String tn : legalTableNames) {
236      TableName tName = TableName.valueOf(tn);
237      assertTrue("Testing: '" + tn + "'",
238        Pattern.matches(TableName.VALID_USER_TABLE_REGEX, tName.getNameAsString()));
239    }
240  }
241
242  @Test
243  public void testIllegalHTableNamesRegex() {
244    for (String tn : illegalTableNames) {
245      LOG.info("Testing: '" + tn + "'");
246      assertFalse(Pattern.matches(TableName.VALID_USER_TABLE_REGEX, tn));
247    }
248  }
249
250  /**
251   * Test default value handling for maxFileSize
252   */
253  @Test
254  public void testGetMaxFileSize() {
255    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
256    assertEquals(-1, desc.getMaxFileSize());
257    desc.setMaxFileSize(1111L);
258    assertEquals(1111L, desc.getMaxFileSize());
259  }
260
261  /**
262   * Test default value handling for memStoreFlushSize
263   */
264  @Test
265  public void testGetMemStoreFlushSize() {
266    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
267    assertEquals(-1, desc.getMemStoreFlushSize());
268    desc.setMemStoreFlushSize(1111L);
269    assertEquals(1111L, desc.getMemStoreFlushSize());
270  }
271
272  /**
273   * Test that we add and remove strings from configuration properly.
274   */
275  @Test
276  public void testAddGetRemoveConfiguration() throws Exception {
277    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
278    String key = "Some";
279    String value = "value";
280    desc.setConfiguration(key, value);
281    assertEquals(value, desc.getConfigurationValue(key));
282    desc.removeConfiguration(key);
283    assertEquals(null, desc.getConfigurationValue(key));
284  }
285
286  @Test
287  public void testClassMethodsAreBuilderStyle() {
288    /*
289     * HTableDescriptor should have a builder style setup where setXXX/addXXX methods can be
290     * chainable together: . For example: HTableDescriptor htd = new HTableDescriptor() .setFoo(foo)
291     * .setBar(bar) .setBuz(buz) This test ensures that all methods starting with "set" returns the
292     * declaring object
293     */
294
295    BuilderStyleTest.assertClassesAreBuilderStyle(HTableDescriptor.class);
296  }
297
298  @Test
299  public void testModifyFamily() {
300    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
301    byte[] familyName = Bytes.toBytes("cf");
302    HColumnDescriptor hcd = new HColumnDescriptor(familyName);
303    hcd.setBlocksize(1000);
304    hcd.setDFSReplication((short) 3);
305    htd.addFamily(hcd);
306    assertEquals(1000, htd.getFamily(familyName).getBlocksize());
307    assertEquals(3, htd.getFamily(familyName).getDFSReplication());
308    hcd = new HColumnDescriptor(familyName);
309    hcd.setBlocksize(2000);
310    hcd.setDFSReplication((short) 1);
311    htd.modifyFamily(hcd);
312    assertEquals(2000, htd.getFamily(familyName).getBlocksize());
313    assertEquals(1, htd.getFamily(familyName).getDFSReplication());
314  }
315
316  @Test(expected = IllegalArgumentException.class)
317  public void testModifyInexistentFamily() {
318    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
319    byte[] familyName = Bytes.toBytes("cf");
320    HColumnDescriptor hcd = new HColumnDescriptor(familyName);
321    htd.modifyFamily(hcd);
322  }
323
324  @Test(expected = IllegalArgumentException.class)
325  public void testAddDuplicateFamilies() {
326    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
327    byte[] familyName = Bytes.toBytes("cf");
328    HColumnDescriptor hcd = new HColumnDescriptor(familyName);
329    hcd.setBlocksize(1000);
330    htd.addFamily(hcd);
331    assertEquals(1000, htd.getFamily(familyName).getBlocksize());
332    hcd = new HColumnDescriptor(familyName);
333    hcd.setBlocksize(2000);
334    htd.addFamily(hcd);
335  }
336
337  @Test
338  public void testPriority() {
339    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
340    htd.setPriority(42);
341    assertEquals(42, htd.getPriority());
342  }
343}