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.assertNotNull;
022import static org.junit.Assert.assertNull;
023import static org.junit.Assert.assertTrue;
024import static org.junit.Assert.fail;
025
026import java.io.IOException;
027import java.util.Set;
028import java.util.concurrent.Callable;
029import org.apache.hadoop.fs.FileSystem;
030import org.apache.hadoop.fs.Path;
031import org.apache.hadoop.hbase.client.Admin;
032import org.apache.hadoop.hbase.client.Get;
033import org.apache.hadoop.hbase.client.Put;
034import org.apache.hadoop.hbase.client.Table;
035import org.apache.hadoop.hbase.master.HMaster;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.testclassification.MiscTests;
038import org.apache.hadoop.hbase.util.Bytes;
039import org.junit.AfterClass;
040import org.junit.Assert;
041import org.junit.Before;
042import org.junit.BeforeClass;
043import org.junit.ClassRule;
044import org.junit.Rule;
045import org.junit.Test;
046import org.junit.experimental.categories.Category;
047import org.junit.rules.TestName;
048import org.slf4j.Logger;
049import org.slf4j.LoggerFactory;
050
051import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
052
053@Category({MiscTests.class, MediumTests.class})
054public class TestNamespace {
055
056  @ClassRule
057  public static final HBaseClassTestRule CLASS_RULE =
058      HBaseClassTestRule.forClass(TestNamespace.class);
059
060  private static final Logger LOG = LoggerFactory.getLogger(TestNamespace.class);
061  private static HMaster master;
062  protected final static int NUM_SLAVES_BASE = 4;
063  private static HBaseTestingUtility TEST_UTIL;
064  protected static Admin admin;
065  protected static HBaseCluster cluster;
066  private static ZKNamespaceManager zkNamespaceManager;
067  private String prefix = "TestNamespace";
068
069  @Rule
070  public TestName name = new TestName();
071
072  @BeforeClass
073  public static void setUp() throws Exception {
074    TEST_UTIL = new HBaseTestingUtility();
075    TEST_UTIL.startMiniCluster(NUM_SLAVES_BASE);
076    admin = TEST_UTIL.getAdmin();
077    cluster = TEST_UTIL.getHBaseCluster();
078    master = ((MiniHBaseCluster)cluster).getMaster();
079    zkNamespaceManager =
080        new ZKNamespaceManager(master.getZooKeeper());
081    zkNamespaceManager.start();
082    LOG.info("Done initializing cluster");
083  }
084
085  @AfterClass
086  public static void tearDown() throws Exception {
087    TEST_UTIL.shutdownMiniCluster();
088  }
089
090  @Before
091  public void beforeMethod() throws IOException {
092    for (HTableDescriptor desc : admin.listTables(prefix+".*")) {
093      admin.disableTable(desc.getTableName());
094      admin.deleteTable(desc.getTableName());
095    }
096    for (NamespaceDescriptor ns : admin.listNamespaceDescriptors()) {
097      if (ns.getName().startsWith(prefix)) {
098        admin.deleteNamespace(ns.getName());
099      }
100    }
101  }
102
103  @Test
104  public void verifyReservedNS() throws IOException {
105    //verify existence of reserved namespaces
106    NamespaceDescriptor ns =
107        admin.getNamespaceDescriptor(NamespaceDescriptor.DEFAULT_NAMESPACE.getName());
108    assertNotNull(ns);
109    assertEquals(ns.getName(), NamespaceDescriptor.DEFAULT_NAMESPACE.getName());
110    assertNotNull(zkNamespaceManager.get(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR));
111
112    ns = admin.getNamespaceDescriptor(NamespaceDescriptor.SYSTEM_NAMESPACE.getName());
113    assertNotNull(ns);
114    assertEquals(ns.getName(), NamespaceDescriptor.SYSTEM_NAMESPACE.getName());
115    assertNotNull(zkNamespaceManager.get(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR));
116
117    assertEquals(2, admin.listNamespaces().length);
118    assertEquals(2, admin.listNamespaceDescriptors().length);
119
120    //verify existence of system tables
121    Set<TableName> systemTables = Sets.newHashSet(
122        TableName.META_TABLE_NAME,
123        TableName.NAMESPACE_TABLE_NAME);
124    HTableDescriptor[] descs =
125        admin.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE.getName());
126    assertEquals(systemTables.size(), descs.length);
127    for (HTableDescriptor desc : descs) {
128      assertTrue(systemTables.contains(desc.getTableName()));
129    }
130    //verify system tables aren't listed
131    assertEquals(0, admin.listTables().length);
132
133    //Try creating default and system namespaces.
134    boolean exceptionCaught = false;
135    try {
136      admin.createNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE);
137    } catch (IOException exp) {
138      LOG.warn(exp.toString(), exp);
139      exceptionCaught = true;
140    } finally {
141      assertTrue(exceptionCaught);
142    }
143
144    exceptionCaught = false;
145    try {
146      admin.createNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE);
147    } catch (IOException exp) {
148      LOG.warn(exp.toString(), exp);
149      exceptionCaught = true;
150    } finally {
151      assertTrue(exceptionCaught);
152    }
153  }
154
155  @Test
156  public void testDeleteReservedNS() throws Exception {
157    boolean exceptionCaught = false;
158    try {
159      admin.deleteNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR);
160    } catch (IOException exp) {
161      LOG.warn(exp.toString(), exp);
162      exceptionCaught = true;
163    } finally {
164      assertTrue(exceptionCaught);
165    }
166
167    try {
168      admin.deleteNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR);
169    } catch (IOException exp) {
170      LOG.warn(exp.toString(), exp);
171      exceptionCaught = true;
172    } finally {
173      assertTrue(exceptionCaught);
174    }
175  }
176
177  @Test
178  public void createRemoveTest() throws Exception {
179    String nsName = prefix + "_" + name.getMethodName();
180    LOG.info(name.getMethodName());
181
182    //create namespace and verify
183    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
184    assertEquals(3, admin.listNamespaces().length);
185    assertEquals(3, admin.listNamespaceDescriptors().length);
186    TEST_UTIL.waitFor(60000, new Waiter.Predicate<Exception>() {
187      @Override
188      public boolean evaluate() throws Exception {
189        return zkNamespaceManager.list().size() == 3;
190      }
191    });
192    assertNotNull(zkNamespaceManager.get(nsName));
193    //remove namespace and verify
194    admin.deleteNamespace(nsName);
195    assertEquals(2, admin.listNamespaces().length);
196    assertEquals(2, admin.listNamespaceDescriptors().length);
197    assertEquals(2, zkNamespaceManager.list().size());
198    assertNull(zkNamespaceManager.get(nsName));
199  }
200
201  @Test
202  public void createDoubleTest() throws IOException, InterruptedException {
203    String nsName = prefix + "_" + name.getMethodName();
204    LOG.info(name.getMethodName());
205
206    final TableName tableName = TableName.valueOf(name.getMethodName());
207    final TableName tableNameFoo = TableName.valueOf(nsName + ":" + name.getMethodName());
208    //create namespace and verify
209    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
210    TEST_UTIL.createTable(tableName, Bytes.toBytes(nsName));
211    TEST_UTIL.createTable(tableNameFoo,Bytes.toBytes(nsName));
212    assertEquals(2, admin.listTables().length);
213    assertNotNull(admin
214        .getTableDescriptor(tableName));
215    assertNotNull(admin
216        .getTableDescriptor(tableNameFoo));
217    //remove namespace and verify
218    admin.disableTable(tableName);
219    admin.deleteTable(tableName);
220    assertEquals(1, admin.listTables().length);
221  }
222
223  @Test
224  public void createTableTest() throws IOException, InterruptedException {
225    String nsName = prefix + "_" + name.getMethodName();
226    LOG.info(name.getMethodName());
227
228    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(nsName + ":" + name.getMethodName()));
229    HColumnDescriptor colDesc = new HColumnDescriptor("my_cf");
230    desc.addFamily(colDesc);
231    try {
232      admin.createTable(desc);
233      fail("Expected no namespace exists exception");
234    } catch (NamespaceNotFoundException ex) {
235    }
236    //create table and in new namespace
237    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
238    admin.createTable(desc);
239    TEST_UTIL.waitTableAvailable(desc.getTableName().getName(), 10000);
240    FileSystem fs = FileSystem.get(TEST_UTIL.getConfiguration());
241    assertTrue(fs.exists(
242        new Path(master.getMasterFileSystem().getRootDir(),
243            new Path(HConstants.BASE_NAMESPACE_DIR,
244                new Path(nsName, desc.getTableName().getQualifierAsString())))));
245    assertEquals(1, admin.listTables().length);
246
247    //verify non-empty namespace can't be removed
248    try {
249      admin.deleteNamespace(nsName);
250      fail("Expected non-empty namespace constraint exception");
251    } catch (Exception ex) {
252      LOG.info("Caught expected exception: " + ex);
253    }
254
255    //sanity check try to write and read from table
256    Table table = TEST_UTIL.getConnection().getTable(desc.getTableName());
257    Put p = new Put(Bytes.toBytes("row1"));
258    p.addColumn(Bytes.toBytes("my_cf"), Bytes.toBytes("my_col"), Bytes.toBytes("value1"));
259    table.put(p);
260    //flush and read from disk to make sure directory changes are working
261    admin.flush(desc.getTableName());
262    Get g = new Get(Bytes.toBytes("row1"));
263    assertTrue(table.exists(g));
264
265    //normal case of removing namespace
266    TEST_UTIL.deleteTable(desc.getTableName());
267    admin.deleteNamespace(nsName);
268  }
269
270  @Test
271  public void createTableInDefaultNamespace() throws Exception {
272    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
273    HColumnDescriptor colDesc = new HColumnDescriptor("cf1");
274    desc.addFamily(colDesc);
275    admin.createTable(desc);
276    assertTrue(admin.listTables().length == 1);
277    admin.disableTable(desc.getTableName());
278    admin.deleteTable(desc.getTableName());
279  }
280
281  @Test
282  public void createTableInSystemNamespace() throws Exception {
283    final TableName tableName = TableName.valueOf("hbase:" + name.getMethodName());
284    HTableDescriptor desc = new HTableDescriptor(tableName);
285    HColumnDescriptor colDesc = new HColumnDescriptor("cf1");
286    desc.addFamily(colDesc);
287    admin.createTable(desc);
288    assertEquals(0, admin.listTables().length);
289    assertTrue(admin.tableExists(tableName));
290    admin.disableTable(desc.getTableName());
291    admin.deleteTable(desc.getTableName());
292  }
293
294  @Test
295  public void testNamespaceOperations() throws IOException {
296    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
297    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns2").build());
298
299    // create namespace that already exists
300    runWithExpectedException(new Callable<Void>() {
301      @Override
302      public Void call() throws Exception {
303        admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
304        return null;
305      }
306    }, NamespaceExistException.class);
307
308    // create a table in non-existing namespace
309    runWithExpectedException(new Callable<Void>() {
310      @Override
311      public Void call() throws Exception {
312        HTableDescriptor htd =
313            new HTableDescriptor(TableName.valueOf("non_existing_namespace", name.getMethodName()));
314        htd.addFamily(new HColumnDescriptor("family1"));
315        admin.createTable(htd);
316        return null;
317      }
318    }, NamespaceNotFoundException.class);
319
320    // get descriptor for existing namespace
321    admin.getNamespaceDescriptor(prefix + "ns1");
322
323    // get descriptor for non-existing namespace
324    runWithExpectedException(new Callable<NamespaceDescriptor>() {
325      @Override
326      public NamespaceDescriptor call() throws Exception {
327        return admin.getNamespaceDescriptor("non_existing_namespace");
328      }
329    }, NamespaceNotFoundException.class);
330
331    // delete descriptor for existing namespace
332    admin.deleteNamespace(prefix + "ns2");
333
334    // delete descriptor for non-existing namespace
335    runWithExpectedException(new Callable<Void>() {
336      @Override
337      public Void call() throws Exception {
338        admin.deleteNamespace("non_existing_namespace");
339        return null;
340      }
341    }, NamespaceNotFoundException.class);
342
343    // modify namespace descriptor for existing namespace
344    NamespaceDescriptor ns1 = admin.getNamespaceDescriptor(prefix + "ns1");
345    ns1.setConfiguration("foo", "bar");
346    admin.modifyNamespace(ns1);
347
348    // modify namespace descriptor for non-existing namespace
349    runWithExpectedException(new Callable<Void>() {
350      @Override
351      public Void call() throws Exception {
352        admin.modifyNamespace(NamespaceDescriptor.create("non_existing_namespace").build());
353        return null;
354      }
355    }, NamespaceNotFoundException.class);
356
357    // get table descriptors for existing namespace
358    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(prefix + "ns1", name.getMethodName()));
359    htd.addFamily(new HColumnDescriptor("family1"));
360    admin.createTable(htd);
361    HTableDescriptor[] htds = admin.listTableDescriptorsByNamespace(prefix + "ns1");
362    assertNotNull("Should have not returned null", htds);
363    assertEquals("Should have returned non-empty array", 1, htds.length);
364
365    // get table descriptors for non-existing namespace
366    runWithExpectedException(new Callable<Void>() {
367      @Override
368      public Void call() throws Exception {
369        admin.listTableDescriptorsByNamespace("non_existant_namespace");
370        return null;
371      }
372    }, NamespaceNotFoundException.class);
373
374    // get table names for existing namespace
375    TableName[] tableNames = admin.listTableNamesByNamespace(prefix + "ns1");
376    assertNotNull("Should have not returned null", tableNames);
377    assertEquals("Should have returned non-empty array", 1, tableNames.length);
378
379    // get table names for non-existing namespace
380    runWithExpectedException(new Callable<Void>() {
381      @Override
382      public Void call() throws Exception {
383        admin.listTableNamesByNamespace("non_existing_namespace");
384        return null;
385      }
386    }, NamespaceNotFoundException.class);
387
388  }
389
390  private static <V, E> void runWithExpectedException(Callable<V> callable, Class<E> exceptionClass) {
391    try {
392      callable.call();
393    } catch(Exception ex) {
394      Assert.assertEquals(exceptionClass, ex.getClass());
395      return;
396    }
397    fail("Should have thrown exception " + exceptionClass);
398  }
399}