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