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