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