1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master.handler;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertTrue;
25  
26  import java.io.IOException;
27  import java.util.Set;
28  
29  import org.apache.hadoop.fs.FileStatus;
30  import org.apache.hadoop.fs.FileSystem;
31  import org.apache.hadoop.fs.Path;
32  import org.apache.hadoop.hbase.HBaseTestingUtility;
33  import org.apache.hadoop.hbase.HColumnDescriptor;
34  import org.apache.hadoop.hbase.HTableDescriptor;
35  import org.apache.hadoop.hbase.LargeTests;
36  import org.apache.hadoop.hbase.client.HBaseAdmin;
37  import org.apache.hadoop.hbase.master.MasterFileSystem;
38  import org.apache.hadoop.hbase.util.Bytes;
39  import org.apache.hadoop.hbase.util.FSTableDescriptors;
40  import org.junit.AfterClass;
41  import org.junit.BeforeClass;
42  import org.junit.Test;
43  import org.junit.experimental.categories.Category;
44  
45  /**
46   * Verify that the HTableDescriptor is updated after
47   * addColumn(), deleteColumn() and modifyTable() operations.
48   */
49  @Category(LargeTests.class)
50  public class TestTableDescriptorModification {
51  
52    private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
53    private static final byte[] TABLE_NAME = Bytes.toBytes("table");
54    private static final byte[] FAMILY_0 = Bytes.toBytes("cf0");
55    private static final byte[] FAMILY_1 = Bytes.toBytes("cf1");
56  
57    /**
58     * Start up a mini cluster and put a small table of empty regions into it.
59     *
60     * @throws Exception
61     */
62    @BeforeClass
63    public static void beforeAllTests() throws Exception {
64      TEST_UTIL.startMiniCluster(1);
65    }
66  
67    @AfterClass
68    public static void afterAllTests() throws Exception {
69      TEST_UTIL.shutdownMiniCluster();
70    }
71  
72    @Test
73    public void testModifyTable() throws IOException {
74      HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
75      // Create a table with one family
76      HTableDescriptor baseHtd = new HTableDescriptor(TABLE_NAME);
77      baseHtd.addFamily(new HColumnDescriptor(FAMILY_0));
78      admin.createTable(baseHtd);
79      admin.disableTable(TABLE_NAME);
80      try {
81        // Verify the table descriptor
82        verifyTableDescriptor(TABLE_NAME, FAMILY_0);
83  
84        // Modify the table adding another family and verify the descriptor
85        HTableDescriptor modifiedHtd = new HTableDescriptor(TABLE_NAME);
86        modifiedHtd.addFamily(new HColumnDescriptor(FAMILY_0));
87        modifiedHtd.addFamily(new HColumnDescriptor(FAMILY_1));
88        admin.modifyTable(TABLE_NAME, modifiedHtd);
89        verifyTableDescriptor(TABLE_NAME, FAMILY_0, FAMILY_1);
90      } finally {
91        admin.deleteTable(TABLE_NAME);
92      }
93    }
94  
95    @Test
96    public void testAddColumn() throws IOException {
97      HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
98      // Create a table with two families
99      HTableDescriptor baseHtd = new HTableDescriptor(TABLE_NAME);
100     baseHtd.addFamily(new HColumnDescriptor(FAMILY_0));
101     admin.createTable(baseHtd);
102     admin.disableTable(TABLE_NAME);
103     try {
104       // Verify the table descriptor
105       verifyTableDescriptor(TABLE_NAME, FAMILY_0);
106 
107       // Modify the table removing one family and verify the descriptor
108       admin.addColumn(TABLE_NAME, new HColumnDescriptor(FAMILY_1));
109       verifyTableDescriptor(TABLE_NAME, FAMILY_0, FAMILY_1);
110     } finally {
111       admin.deleteTable(TABLE_NAME);
112     }
113   }
114 
115   @Test
116   public void testDeleteColumn() throws IOException {
117     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
118     // Create a table with two families
119     HTableDescriptor baseHtd = new HTableDescriptor(TABLE_NAME);
120     baseHtd.addFamily(new HColumnDescriptor(FAMILY_0));
121     baseHtd.addFamily(new HColumnDescriptor(FAMILY_1));
122     admin.createTable(baseHtd);
123     admin.disableTable(TABLE_NAME);
124     try {
125       // Verify the table descriptor
126       verifyTableDescriptor(TABLE_NAME, FAMILY_0, FAMILY_1);
127 
128       // Modify the table removing one family and verify the descriptor
129       admin.deleteColumn(TABLE_NAME, FAMILY_1);
130       verifyTableDescriptor(TABLE_NAME, FAMILY_0);
131     } finally {
132       admin.deleteTable(TABLE_NAME);
133     }
134   }
135 
136   private void verifyTableDescriptor(final byte[] tableName, final byte[]... families)
137       throws IOException {
138     HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
139 
140     // Verify descriptor from master
141     HTableDescriptor htd = admin.getTableDescriptor(tableName);
142     verifyTableDescriptor(htd, tableName, families);
143 
144     // Verify descriptor from HDFS
145     MasterFileSystem mfs = TEST_UTIL.getMiniHBaseCluster().getMaster().getMasterFileSystem();
146     Path tableDir = HTableDescriptor.getTableDir(mfs.getRootDir(), tableName);
147     htd = FSTableDescriptors.getTableDescriptor(mfs.getFileSystem(), tableDir);
148     verifyTableDescriptor(htd, tableName, families);
149   }
150 
151   private void verifyTableDescriptor(final HTableDescriptor htd,
152       final byte[] tableName, final byte[]... families) {
153     Set<byte[]> htdFamilies = htd.getFamiliesKeys();
154     assertTrue(Bytes.equals(tableName, htd.getName()));
155     assertEquals(families.length, htdFamilies.size());
156     for (byte[] familyName: families) {
157       assertTrue("Expected family " + Bytes.toString(familyName), htdFamilies.contains(familyName));
158     }
159   }
160 }