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.client; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023import static org.junit.Assert.fail; 024 025import java.io.IOException; 026import java.util.regex.Pattern; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HColumnDescriptor; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.exceptions.DeserializationException; 031import org.apache.hadoop.hbase.testclassification.MiscTests; 032import org.apache.hadoop.hbase.testclassification.SmallTests; 033import org.apache.hadoop.hbase.util.BuilderStyleTest; 034import org.apache.hadoop.hbase.util.Bytes; 035import org.junit.ClassRule; 036import org.junit.Rule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039import org.junit.rules.TestName; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043/** 044 * Test setting values in the descriptor. 045 */ 046@Category({MiscTests.class, SmallTests.class}) 047public class TestTableDescriptorBuilder { 048 @ClassRule 049 public static final HBaseClassTestRule CLASS_RULE = 050 HBaseClassTestRule.forClass(TestTableDescriptorBuilder.class); 051 052 private static final Logger LOG = LoggerFactory.getLogger(TestTableDescriptorBuilder.class); 053 054 @Rule 055 public TestName name = new TestName(); 056 057 @Test (expected=IOException.class) 058 public void testAddCoprocessorTwice() throws IOException { 059 String cpName = "a.b.c.d"; 060 TableDescriptor htd 061 = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) 062 .setCoprocessor(cpName) 063 .setCoprocessor(cpName) 064 .build(); 065 } 066 067 @Test 068 public void testPb() throws DeserializationException, IOException { 069 final int v = 123; 070 TableDescriptor htd 071 = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) 072 .setMaxFileSize(v) 073 .setDurability(Durability.ASYNC_WAL) 074 .setReadOnly(true) 075 .setRegionReplication(2) 076 .build(); 077 078 byte [] bytes = TableDescriptorBuilder.toByteArray(htd); 079 TableDescriptor deserializedHtd = TableDescriptorBuilder.parseFrom(bytes); 080 assertEquals(htd, deserializedHtd); 081 assertEquals(v, deserializedHtd.getMaxFileSize()); 082 assertTrue(deserializedHtd.isReadOnly()); 083 assertEquals(Durability.ASYNC_WAL, deserializedHtd.getDurability()); 084 assertEquals(2, deserializedHtd.getRegionReplication()); 085 } 086 087 /** 088 * Test cps in the table description. 089 * 090 * @throws Exception if setting a coprocessor fails 091 */ 092 @Test 093 public void testGetSetRemoveCP() throws Exception { 094 // simple CP 095 String className = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 096 TableDescriptor desc 097 = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 098 .setCoprocessor(className) // add and check that it is present 099 .build(); 100 assertTrue(desc.hasCoprocessor(className)); 101 desc = TableDescriptorBuilder.newBuilder(desc) 102 .removeCoprocessor(className) // remove it and check that it is gone 103 .build(); 104 assertFalse(desc.hasCoprocessor(className)); 105 } 106 107 /** 108 * Test cps in the table description. 109 * 110 * @throws Exception if setting a coprocessor fails 111 */ 112 @Test 113 public void testSetListRemoveCP() throws Exception { 114 TableDescriptor desc 115 = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build(); 116 // Check that any coprocessor is present. 117 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 118 119 // simple CP 120 String className1 = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 121 String className2 = "org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver"; 122 desc = TableDescriptorBuilder.newBuilder(desc) 123 .setCoprocessor(className1) // Add the 1 coprocessor and check if present. 124 .build(); 125 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 126 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 127 .anyMatch(name -> name.equals(className1))); 128 129 desc = TableDescriptorBuilder.newBuilder(desc) 130 // Add the 2nd coprocessor and check if present. 131 // remove it and check that it is gone 132 .setCoprocessor(className2) 133 .build(); 134 assertTrue(desc.getCoprocessorDescriptors().size() == 2); 135 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 136 .anyMatch(name -> name.equals(className2))); 137 138 desc = TableDescriptorBuilder.newBuilder(desc) 139 // Remove one and check 140 .removeCoprocessor(className1) 141 .build(); 142 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 143 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 144 .anyMatch(name -> name.equals(className1))); 145 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 146 .anyMatch(name -> name.equals(className2))); 147 148 desc = TableDescriptorBuilder.newBuilder(desc) 149 // Remove the last and check 150 .removeCoprocessor(className2) 151 .build(); 152 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 153 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 154 .anyMatch(name -> name.equals(className1))); 155 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 156 .anyMatch(name -> name.equals(className2))); 157 } 158 159 /** 160 * Test that we add and remove strings from settings properly. 161 */ 162 @Test 163 public void testRemoveString() { 164 byte[] key = Bytes.toBytes("Some"); 165 byte[] value = Bytes.toBytes("value"); 166 TableDescriptor desc 167 = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 168 .setValue(key, value) 169 .build(); 170 assertTrue(Bytes.equals(value, desc.getValue(key))); 171 desc = TableDescriptorBuilder.newBuilder(desc) 172 .removeValue(key) 173 .build(); 174 assertTrue(desc.getValue(key) == null); 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 testLegalTableNames() { 187 for (String tn : legalTableNames) { 188 TableName.isLegalFullyQualifiedTableName(Bytes.toBytes(tn)); 189 } 190 } 191 192 @Test 193 public void testIllegalTableNames() { 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 testLegalTableNamesRegex() { 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 testIllegalTableNamesRegex() { 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 TableDescriptor desc = TableDescriptorBuilder 227 .newBuilder(TableName.valueOf(name.getMethodName())).build(); 228 assertEquals(-1, desc.getMaxFileSize()); 229 desc = TableDescriptorBuilder 230 .newBuilder(TableName.valueOf(name.getMethodName())) 231 .setMaxFileSize(1111L).build(); 232 assertEquals(1111L, desc.getMaxFileSize()); 233 } 234 235 /** 236 * Test default value handling for memStoreFlushSize 237 */ 238 @Test 239 public void testGetMemStoreFlushSize() { 240 TableDescriptor desc = TableDescriptorBuilder 241 .newBuilder(TableName.valueOf(name.getMethodName())).build(); 242 assertEquals(-1, desc.getMemStoreFlushSize()); 243 desc = TableDescriptorBuilder 244 .newBuilder(TableName.valueOf(name.getMethodName())) 245 .setMemStoreFlushSize(1111L).build(); 246 assertEquals(1111L, desc.getMemStoreFlushSize()); 247 } 248 249 @Test 250 public void testClassMethodsAreBuilderStyle() { 251 BuilderStyleTest.assertClassesAreBuilderStyle(TableDescriptorBuilder.class); 252 } 253 254 @Test 255 public void testModifyFamily() { 256 byte[] familyName = Bytes.toBytes("cf"); 257 ColumnFamilyDescriptor hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 258 .setBlocksize(1000) 259 .setDFSReplication((short) 3) 260 .build(); 261 TableDescriptor htd 262 = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 263 .setColumnFamily(hcd) 264 .build(); 265 266 assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize()); 267 assertEquals(3, htd.getColumnFamily(familyName).getDFSReplication()); 268 hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 269 .setBlocksize(2000) 270 .setDFSReplication((short) 1) 271 .build(); 272 htd = TableDescriptorBuilder.newBuilder(htd) 273 .modifyColumnFamily(hcd) 274 .build(); 275 assertEquals(2000, htd.getColumnFamily(familyName).getBlocksize()); 276 assertEquals(1, htd.getColumnFamily(familyName).getDFSReplication()); 277 } 278 279 @Test(expected=IllegalArgumentException.class) 280 public void testModifyInexistentFamily() { 281 byte[] familyName = Bytes.toBytes("cf"); 282 HColumnDescriptor hcd = new HColumnDescriptor(familyName); 283 TableDescriptor htd = TableDescriptorBuilder 284 .newBuilder(TableName.valueOf(name.getMethodName())) 285 .modifyColumnFamily(hcd) 286 .build(); 287 } 288 289 @Test(expected=IllegalArgumentException.class) 290 public void testAddDuplicateFamilies() { 291 byte[] familyName = Bytes.toBytes("cf"); 292 ColumnFamilyDescriptor hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 293 .setBlocksize(1000) 294 .build(); 295 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 296 .setColumnFamily(hcd) 297 .build(); 298 assertEquals(1000, htd.getColumnFamily(familyName).getBlocksize()); 299 hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 300 .setBlocksize(2000) 301 .build(); 302 // add duplicate column 303 TableDescriptorBuilder.newBuilder(htd).setColumnFamily(hcd).build(); 304 } 305 306 @Test 307 public void testPriority() { 308 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 309 .setPriority(42) 310 .build(); 311 assertEquals(42, htd.getPriority()); 312 } 313 314 @Test 315 public void testStringCustomizedValues() { 316 byte[] familyName = Bytes.toBytes("cf"); 317 ColumnFamilyDescriptor hcd = ColumnFamilyDescriptorBuilder.newBuilder(familyName) 318 .setBlocksize(1000) 319 .build(); 320 TableDescriptor htd = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())) 321 .setColumnFamily(hcd) 322 .setDurability(Durability.ASYNC_WAL) 323 .build(); 324 325 assertEquals( 326 "'testStringCustomizedValues', " + 327 "{TABLE_ATTRIBUTES => {DURABILITY => 'ASYNC_WAL'}}, {NAME => 'cf', BLOCKSIZE => '1000'}", 328 htd.toStringCustomizedValues()); 329 } 330}