View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertTrue;
24  import static org.junit.Assert.fail;
25  
26  import java.io.IOException;
27  import java.util.regex.Pattern;
28  
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  import org.apache.hadoop.hbase.client.Durability;
32  import org.apache.hadoop.hbase.exceptions.DeserializationException;
33  import org.apache.hadoop.hbase.testclassification.SmallTests;
34  import org.apache.hadoop.hbase.util.BuilderStyleTest;
35  import org.apache.hadoop.hbase.util.Bytes;
36  import org.junit.Test;
37  import org.junit.experimental.categories.Category;
38  
39  /**
40   * Test setting values in the descriptor
41   */
42  @Category(SmallTests.class)
43  public class TestHTableDescriptor {
44    private static final Log LOG = LogFactory.getLog(TestHTableDescriptor.class);
45  
46    @Test (expected=IOException.class)
47    public void testAddCoprocessorTwice() throws IOException {
48      HTableDescriptor htd = new HTableDescriptor(TableName.META_TABLE_NAME);
49      String cpName = "a.b.c.d";
50      htd.addCoprocessor(cpName);
51      htd.addCoprocessor(cpName);
52    }
53  
54    @Test
55    public void testAddCoprocessorWithSpecStr() throws IOException {
56      HTableDescriptor htd = new HTableDescriptor(TableName.META_TABLE_NAME);
57      String cpName = "a.b.c.d";
58      try {
59        htd.addCoprocessorWithSpec(cpName);
60        fail();
61      } catch (IllegalArgumentException iae) {
62        // Expected as cpName is invalid
63      }
64  
65      // Try minimal spec.
66      try {
67        htd.addCoprocessorWithSpec("file:///some/path" + "|" + cpName);
68        fail();
69      } catch (IllegalArgumentException iae) {
70        // Expected to be invalid
71      }
72  
73      // Try more spec.
74      String spec = "hdfs:///foo.jar|com.foo.FooRegionObserver|1001|arg1=1,arg2=2";
75      try {
76        htd.addCoprocessorWithSpec(spec);
77      } catch (IllegalArgumentException iae) {
78        fail();
79      }
80  
81      // Try double add of same coprocessor
82      try {
83        htd.addCoprocessorWithSpec(spec);
84        fail();
85      } catch (IOException ioe) {
86        // Expect that the coprocessor already exists
87      }
88    }
89  
90    @Test
91    public void testPb() throws DeserializationException, IOException {
92      HTableDescriptor htd = new HTableDescriptor(HTableDescriptor.META_TABLEDESC);
93      final int v = 123;
94      htd.setMaxFileSize(v);
95      htd.setDurability(Durability.ASYNC_WAL);
96      htd.setReadOnly(true);
97      htd.setRegionReplication(2);
98      byte [] bytes = htd.toByteArray();
99      HTableDescriptor deserializedHtd = HTableDescriptor.parseFrom(bytes);
100     assertEquals(htd, deserializedHtd);
101     assertEquals(v, deserializedHtd.getMaxFileSize());
102     assertTrue(deserializedHtd.isReadOnly());
103     assertEquals(Durability.ASYNC_WAL, deserializedHtd.getDurability());
104     assertEquals(2, deserializedHtd.getRegionReplication());
105   }
106 
107   /**
108    * Test cps in the table description.
109    *
110    * @throws Exception if adding a coprocessor fails
111    */
112   @Test
113   public void testGetSetRemoveCP() throws Exception {
114     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("table"));
115     // simple CP
116     String className = "org.apache.hadoop.hbase.coprocessor.BaseRegionObserver";
117     // add and check that it is present
118     desc.addCoprocessor(className);
119     assertTrue(desc.hasCoprocessor(className));
120     // remove it and check that it is gone
121     desc.removeCoprocessor(className);
122     assertFalse(desc.hasCoprocessor(className));
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 testSetListRemoveCP() throws Exception {
132     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("testGetSetRemoveCP"));
133     // simple CP
134     String className1 = "org.apache.hadoop.hbase.coprocessor.BaseRegionObserver";
135     String className2 = "org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver";
136     // Check that any coprocessor is present.
137     assertTrue(desc.getCoprocessors().size() == 0);
138 
139     // Add the 1 coprocessor and check if present.
140     desc.addCoprocessor(className1);
141     assertTrue(desc.getCoprocessors().size() == 1);
142     assertTrue(desc.getCoprocessors().contains(className1));
143 
144     // Add the 2nd coprocessor and check if present.
145     // remove it and check that it is gone
146     desc.addCoprocessor(className2);
147     assertTrue(desc.getCoprocessors().size() == 2);
148     assertTrue(desc.getCoprocessors().contains(className2));
149 
150     // Remove one and check
151     desc.removeCoprocessor(className1);
152     assertTrue(desc.getCoprocessors().size() == 1);
153     assertFalse(desc.getCoprocessors().contains(className1));
154     assertTrue(desc.getCoprocessors().contains(className2));
155 
156     // Remove the last and check
157     desc.removeCoprocessor(className2);
158     assertTrue(desc.getCoprocessors().size() == 0);
159     assertFalse(desc.getCoprocessors().contains(className1));
160     assertFalse(desc.getCoprocessors().contains(className2));
161   }
162 
163   /**
164    * Test that we add and remove strings from settings properly.
165    */
166   @Test
167   public void testRemoveString() {
168     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("table"));
169     String key = "Some";
170     String value = "value";
171     desc.setValue(key, value);
172     assertEquals(value, desc.getValue(key));
173     desc.remove(key);
174     assertEquals(null, desc.getValue(key));
175   }
176 
177   String[] legalTableNames = { "foo", "with-dash_under.dot", "_under_start_ok",
178     "with-dash.with_underscore", "02-01-2012.my_table_01-02", "xyz._mytable_", "9_9_0.table_02",
179     "dot1.dot2.table", "new.-mytable", "with-dash.with.dot", "legal..t2", "legal..legal.t2",
180     "trailingdots..", "trailing.dots...", "ns:mytable", "ns:_mytable_", "ns:my_table_01-02"};
181   String[] illegalTableNames = { ".dot_start_illegal", "-dash_start_illegal", "spaces not ok",
182     "-dash-.start_illegal", "new.table with space", "01 .table", "ns:-illegaldash",
183     "new:.illegaldot", "new:illegalcolon1:", "new:illegalcolon1:2"};
184 
185   @Test
186   public void testLegalHTableNames() {
187     for (String tn : legalTableNames) {
188       TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn));
189     }
190   }
191 
192   @Test
193   public void testIllegalHTableNames() {
194     for (String tn : illegalTableNames) {
195       try {
196         TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn));
197         fail("invalid tablename " + tn + " should have failed");
198       } catch (Exception e) {
199         // expected
200       }
201     }
202   }
203 
204   @Test
205   public void testLegalHTableNamesRegex() {
206     for (String tn : legalTableNames) {
207       TableName tName = TableName.valueOf(tn);
208       assertTrue("Testing: '" + tn + "'", Pattern.matches(TableName.VALID_USER_TABLE_REGEX,
209           tName.getNameAsString()));
210     }
211   }
212 
213   @Test
214   public void testIllegalHTableNamesRegex() {
215     for (String tn : illegalTableNames) {
216       LOG.info("Testing: '" + tn + "'");
217       assertFalse(Pattern.matches(TableName.VALID_USER_TABLE_REGEX, tn));
218     }
219   }
220 
221     /**
222    * Test default value handling for maxFileSize
223    */
224   @Test
225   public void testGetMaxFileSize() {
226     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("table"));
227     assertEquals(-1, desc.getMaxFileSize());
228     desc.setMaxFileSize(1111L);
229     assertEquals(1111L, desc.getMaxFileSize());
230   }
231 
232   /**
233    * Test default value handling for memStoreFlushSize
234    */
235   @Test
236   public void testGetMemStoreFlushSize() {
237     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("table"));
238     assertEquals(-1, desc.getMemStoreFlushSize());
239     desc.setMemStoreFlushSize(1111L);
240     assertEquals(1111L, desc.getMemStoreFlushSize());
241   }
242 
243   /**
244    * Test that we add and remove strings from configuration properly.
245    */
246   @Test
247   public void testAddGetRemoveConfiguration() throws Exception {
248     HTableDescriptor desc = new HTableDescriptor(TableName.valueOf("table"));
249     String key = "Some";
250     String value = "value";
251     desc.setConfiguration(key, value);
252     assertEquals(value, desc.getConfigurationValue(key));
253     desc.removeConfiguration(key);
254     assertEquals(null, desc.getConfigurationValue(key));
255   }
256 
257   @Test
258   public void testClassMethodsAreBuilderStyle() {
259     /* HTableDescriptor should have a builder style setup where setXXX/addXXX methods
260      * can be chainable together:
261      * . For example:
262      * HTableDescriptor htd
263      *   = new HTableDescriptor()
264      *     .setFoo(foo)
265      *     .setBar(bar)
266      *     .setBuz(buz)
267      *
268      * This test ensures that all methods starting with "set" returns the declaring object
269      */
270 
271     BuilderStyleTest.assertClassesAreBuilderStyle(HTableDescriptor.class);
272   }
273 
274   @Test
275   public void testModifyFamily() {
276     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("table"));
277     byte[] familyName = Bytes.toBytes("cf");
278     HColumnDescriptor hcd = new HColumnDescriptor(familyName);
279     hcd.setBlocksize(1000);
280     hcd.setDFSReplication((short) 3);
281     htd.addFamily(hcd);
282     assertEquals(1000, htd.getFamily(familyName).getBlocksize());
283     assertEquals(3, htd.getFamily(familyName).getDFSReplication());
284     hcd = new HColumnDescriptor(familyName);
285     hcd.setBlocksize(2000);
286     hcd.setDFSReplication((short) 1);
287     htd.modifyFamily(hcd);
288     assertEquals(2000, htd.getFamily(familyName).getBlocksize());
289     assertEquals(1, htd.getFamily(familyName).getDFSReplication());
290   }
291 
292   @Test(expected=IllegalArgumentException.class)
293   public void testModifyInexistentFamily() {
294     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("table"));
295     byte[] familyName = Bytes.toBytes("cf");
296     HColumnDescriptor hcd = new HColumnDescriptor(familyName);
297     htd.modifyFamily(hcd);
298   }
299 
300   @Test(expected=IllegalArgumentException.class)
301   public void testAddDuplicateFamilies() {
302     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("table"));
303     byte[] familyName = Bytes.toBytes("cf");
304     HColumnDescriptor hcd = new HColumnDescriptor(familyName);
305     hcd.setBlocksize(1000);
306     htd.addFamily(hcd);
307     assertEquals(1000, htd.getFamily(familyName).getBlocksize());
308     hcd = new HColumnDescriptor(familyName);
309     hcd.setBlocksize(2000);
310     htd.addFamily(hcd);
311   }
312 
313   @Test
314   public void testPriority() {
315     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("table"));
316     htd.setPriority(42);
317     assertEquals(42, htd.getPriority());
318   }
319 
320   @Test
321   public void testSetEmptyValue() {
322     HTableDescriptor htd = new HTableDescriptor(TableName.valueOf("table"));
323     String testValue = "TestValue";
324     // test setValue
325     htd.setValue(testValue, "2");
326     assertEquals("2", htd.getValue(testValue));
327     htd.setValue(testValue, "");
328     assertNull(htd.getValue(Bytes.toBytes(testValue)));
329 
330     // test setFlushPolicyClassName
331     htd.setFlushPolicyClassName("class");
332     assertEquals("class", htd.getFlushPolicyClassName());
333     htd.setFlushPolicyClassName("");
334     assertNull(htd.getFlushPolicyClassName());
335   }
336 }