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.listNamespaceDescriptors().length);
118
119    //verify existence of system tables
120    Set<TableName> systemTables = Sets.newHashSet(
121        TableName.META_TABLE_NAME,
122        TableName.NAMESPACE_TABLE_NAME);
123    HTableDescriptor[] descs =
124        admin.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE.getName());
125    assertEquals(systemTables.size(), descs.length);
126    for (HTableDescriptor desc : descs) {
127      assertTrue(systemTables.contains(desc.getTableName()));
128    }
129    //verify system tables aren't listed
130    assertEquals(0, admin.listTables().length);
131
132    //Try creating default and system namespaces.
133    boolean exceptionCaught = false;
134    try {
135      admin.createNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE);
136    } catch (IOException exp) {
137      LOG.warn(exp.toString(), exp);
138      exceptionCaught = true;
139    } finally {
140      assertTrue(exceptionCaught);
141    }
142
143    exceptionCaught = false;
144    try {
145      admin.createNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE);
146    } catch (IOException exp) {
147      LOG.warn(exp.toString(), exp);
148      exceptionCaught = true;
149    } finally {
150      assertTrue(exceptionCaught);
151    }
152  }
153
154  @Test
155  public void testDeleteReservedNS() throws Exception {
156    boolean exceptionCaught = false;
157    try {
158      admin.deleteNamespace(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR);
159    } catch (IOException exp) {
160      LOG.warn(exp.toString(), exp);
161      exceptionCaught = true;
162    } finally {
163      assertTrue(exceptionCaught);
164    }
165
166    try {
167      admin.deleteNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR);
168    } catch (IOException exp) {
169      LOG.warn(exp.toString(), exp);
170      exceptionCaught = true;
171    } finally {
172      assertTrue(exceptionCaught);
173    }
174  }
175
176  @Test
177  public void createRemoveTest() throws Exception {
178    String nsName = prefix + "_" + name.getMethodName();
179    LOG.info(name.getMethodName());
180
181    //create namespace and verify
182    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
183    assertEquals(3, admin.listNamespaceDescriptors().length);
184    TEST_UTIL.waitFor(60000, new Waiter.Predicate<Exception>() {
185      @Override
186      public boolean evaluate() throws Exception {
187        return zkNamespaceManager.list().size() == 3;
188      }
189    });
190    assertNotNull(zkNamespaceManager.get(nsName));
191    //remove namespace and verify
192    admin.deleteNamespace(nsName);
193    assertEquals(2, admin.listNamespaceDescriptors().length);
194    assertEquals(2, zkNamespaceManager.list().size());
195    assertNull(zkNamespaceManager.get(nsName));
196  }
197
198  @Test
199  public void createDoubleTest() throws IOException, InterruptedException {
200    String nsName = prefix + "_" + name.getMethodName();
201    LOG.info(name.getMethodName());
202
203    final TableName tableName = TableName.valueOf(name.getMethodName());
204    final TableName tableNameFoo = TableName.valueOf(nsName + ":" + name.getMethodName());
205    //create namespace and verify
206    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
207    TEST_UTIL.createTable(tableName, Bytes.toBytes(nsName));
208    TEST_UTIL.createTable(tableNameFoo,Bytes.toBytes(nsName));
209    assertEquals(2, admin.listTables().length);
210    assertNotNull(admin
211        .getTableDescriptor(tableName));
212    assertNotNull(admin
213        .getTableDescriptor(tableNameFoo));
214    //remove namespace and verify
215    admin.disableTable(tableName);
216    admin.deleteTable(tableName);
217    assertEquals(1, admin.listTables().length);
218  }
219
220  @Test
221  public void createTableTest() throws IOException, InterruptedException {
222    String nsName = prefix + "_" + name.getMethodName();
223    LOG.info(name.getMethodName());
224
225    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(nsName + ":" + name.getMethodName()));
226    HColumnDescriptor colDesc = new HColumnDescriptor("my_cf");
227    desc.addFamily(colDesc);
228    try {
229      admin.createTable(desc);
230      fail("Expected no namespace exists exception");
231    } catch (NamespaceNotFoundException ex) {
232    }
233    //create table and in new namespace
234    admin.createNamespace(NamespaceDescriptor.create(nsName).build());
235    admin.createTable(desc);
236    TEST_UTIL.waitTableAvailable(desc.getTableName().getName(), 10000);
237    FileSystem fs = FileSystem.get(TEST_UTIL.getConfiguration());
238    assertTrue(fs.exists(
239        new Path(master.getMasterFileSystem().getRootDir(),
240            new Path(HConstants.BASE_NAMESPACE_DIR,
241                new Path(nsName, desc.getTableName().getQualifierAsString())))));
242    assertEquals(1, admin.listTables().length);
243
244    //verify non-empty namespace can't be removed
245    try {
246      admin.deleteNamespace(nsName);
247      fail("Expected non-empty namespace constraint exception");
248    } catch (Exception ex) {
249      LOG.info("Caught expected exception: " + ex);
250    }
251
252    //sanity check try to write and read from table
253    Table table = TEST_UTIL.getConnection().getTable(desc.getTableName());
254    Put p = new Put(Bytes.toBytes("row1"));
255    p.addColumn(Bytes.toBytes("my_cf"), Bytes.toBytes("my_col"), Bytes.toBytes("value1"));
256    table.put(p);
257    //flush and read from disk to make sure directory changes are working
258    admin.flush(desc.getTableName());
259    Get g = new Get(Bytes.toBytes("row1"));
260    assertTrue(table.exists(g));
261
262    //normal case of removing namespace
263    TEST_UTIL.deleteTable(desc.getTableName());
264    admin.deleteNamespace(nsName);
265  }
266
267  @Test
268  public void createTableInDefaultNamespace() throws Exception {
269    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(name.getMethodName()));
270    HColumnDescriptor colDesc = new HColumnDescriptor("cf1");
271    desc.addFamily(colDesc);
272    admin.createTable(desc);
273    assertTrue(admin.listTables().length == 1);
274    admin.disableTable(desc.getTableName());
275    admin.deleteTable(desc.getTableName());
276  }
277
278  @Test
279  public void createTableInSystemNamespace() throws Exception {
280    final TableName tableName = TableName.valueOf("hbase:" + name.getMethodName());
281    HTableDescriptor desc = new HTableDescriptor(tableName);
282    HColumnDescriptor colDesc = new HColumnDescriptor("cf1");
283    desc.addFamily(colDesc);
284    admin.createTable(desc);
285    assertEquals(0, admin.listTables().length);
286    assertTrue(admin.tableExists(tableName));
287    admin.disableTable(desc.getTableName());
288    admin.deleteTable(desc.getTableName());
289  }
290
291  @Test
292  public void testNamespaceOperations() throws IOException {
293    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
294    admin.createNamespace(NamespaceDescriptor.create(prefix + "ns2").build());
295
296    // create namespace that already exists
297    runWithExpectedException(new Callable<Void>() {
298      @Override
299      public Void call() throws Exception {
300        admin.createNamespace(NamespaceDescriptor.create(prefix + "ns1").build());
301        return null;
302      }
303    }, NamespaceExistException.class);
304
305    // create a table in non-existing namespace
306    runWithExpectedException(new Callable<Void>() {
307      @Override
308      public Void call() throws Exception {
309        HTableDescriptor htd =
310            new HTableDescriptor(TableName.valueOf("non_existing_namespace", name.getMethodName()));
311        htd.addFamily(new HColumnDescriptor("family1"));
312        admin.createTable(htd);
313        return null;
314      }
315    }, NamespaceNotFoundException.class);
316
317    // get descriptor for existing namespace
318    admin.getNamespaceDescriptor(prefix + "ns1");
319
320    // get descriptor for non-existing namespace
321    runWithExpectedException(new Callable<NamespaceDescriptor>() {
322      @Override
323      public NamespaceDescriptor call() throws Exception {
324        return admin.getNamespaceDescriptor("non_existing_namespace");
325      }
326    }, NamespaceNotFoundException.class);
327
328    // delete descriptor for existing namespace
329    admin.deleteNamespace(prefix + "ns2");
330
331    // delete descriptor for non-existing namespace
332    runWithExpectedException(new Callable<Void>() {
333      @Override
334      public Void call() throws Exception {
335        admin.deleteNamespace("non_existing_namespace");
336        return null;
337      }
338    }, NamespaceNotFoundException.class);
339
340    // modify namespace descriptor for existing namespace
341    NamespaceDescriptor ns1 = admin.getNamespaceDescriptor(prefix + "ns1");
342    ns1.setConfiguration("foo", "bar");
343    admin.modifyNamespace(ns1);
344
345    // modify namespace descriptor for non-existing namespace
346    runWithExpectedException(new Callable<Void>() {
347      @Override
348      public Void call() throws Exception {
349        admin.modifyNamespace(NamespaceDescriptor.create("non_existing_namespace").build());
350        return null;
351      }
352    }, NamespaceNotFoundException.class);
353
354    // get table descriptors for existing namespace
355    HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(prefix + "ns1", name.getMethodName()));
356    htd.addFamily(new HColumnDescriptor("family1"));
357    admin.createTable(htd);
358    HTableDescriptor[] htds = admin.listTableDescriptorsByNamespace(prefix + "ns1");
359    assertNotNull("Should have not returned null", htds);
360    assertEquals("Should have returned non-empty array", 1, htds.length);
361
362    // get table descriptors for non-existing namespace
363    runWithExpectedException(new Callable<Void>() {
364      @Override
365      public Void call() throws Exception {
366        admin.listTableDescriptorsByNamespace("non_existant_namespace");
367        return null;
368      }
369    }, NamespaceNotFoundException.class);
370
371    // get table names for existing namespace
372    TableName[] tableNames = admin.listTableNamesByNamespace(prefix + "ns1");
373    assertNotNull("Should have not returned null", tableNames);
374    assertEquals("Should have returned non-empty array", 1, tableNames.length);
375
376    // get table names for non-existing namespace
377    runWithExpectedException(new Callable<Void>() {
378      @Override
379      public Void call() throws Exception {
380        admin.listTableNamesByNamespace("non_existing_namespace");
381        return null;
382      }
383    }, NamespaceNotFoundException.class);
384
385  }
386
387  private static <V, E> void runWithExpectedException(Callable<V> callable, Class<E> exceptionClass) {
388    try {
389      callable.call();
390    } catch(Exception ex) {
391      Assert.assertEquals(exceptionClass, ex.getClass());
392      return;
393    }
394    fail("Should have thrown exception " + exceptionClass);
395  }
396}