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