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 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = 051 HBaseClassTestRule.forClass(TestTableDescriptorBuilder.class); 052 053 private static final Logger LOG = LoggerFactory.getLogger(TestTableDescriptorBuilder.class); 054 055 @Rule 056 public TestName name = new TestName(); 057 058 @Test (expected=IOException.class) 059 public void testAddCoprocessorTwice() throws IOException { 060 String cpName = "a.b.c.d"; 061 TableDescriptor htd 062 = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) 063 .setCoprocessor(cpName) 064 .setCoprocessor(cpName) 065 .build(); 066 } 067 068 @Test 069 public void testPb() throws DeserializationException, IOException { 070 final int v = 123; 071 TableDescriptor htd 072 = TableDescriptorBuilder.newBuilder(TableName.META_TABLE_NAME) 073 .setMaxFileSize(v) 074 .setDurability(Durability.ASYNC_WAL) 075 .setReadOnly(true) 076 .setRegionReplication(2) 077 .build(); 078 079 byte [] bytes = TableDescriptorBuilder.toByteArray(htd); 080 TableDescriptor deserializedHtd = TableDescriptorBuilder.parseFrom(bytes); 081 assertEquals(htd, deserializedHtd); 082 assertEquals(v, deserializedHtd.getMaxFileSize()); 083 assertTrue(deserializedHtd.isReadOnly()); 084 assertEquals(Durability.ASYNC_WAL, deserializedHtd.getDurability()); 085 assertEquals(2, deserializedHtd.getRegionReplication()); 086 } 087 088 /** 089 * Test cps in the table description 090 * @throws Exception 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 * @throws Exception 110 */ 111 @Test 112 public void testSetListRemoveCP() throws Exception { 113 TableDescriptor desc 114 = TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())).build(); 115 // Check that any coprocessor is present. 116 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 117 118 // simple CP 119 String className1 = "org.apache.hadoop.hbase.coprocessor.SimpleRegionObserver"; 120 String className2 = "org.apache.hadoop.hbase.coprocessor.SampleRegionWALObserver"; 121 desc = TableDescriptorBuilder.newBuilder(desc) 122 .setCoprocessor(className1) // Add the 1 coprocessor and check if present. 123 .build(); 124 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 125 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 126 .anyMatch(name -> name.equals(className1))); 127 128 desc = TableDescriptorBuilder.newBuilder(desc) 129 // Add the 2nd coprocessor and check if present. 130 // remove it and check that it is gone 131 .setCoprocessor(className2) 132 .build(); 133 assertTrue(desc.getCoprocessorDescriptors().size() == 2); 134 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 135 .anyMatch(name -> name.equals(className2))); 136 137 desc = TableDescriptorBuilder.newBuilder(desc) 138 // Remove one and check 139 .removeCoprocessor(className1) 140 .build(); 141 assertTrue(desc.getCoprocessorDescriptors().size() == 1); 142 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 143 .anyMatch(name -> name.equals(className1))); 144 assertTrue(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 145 .anyMatch(name -> name.equals(className2))); 146 147 desc = TableDescriptorBuilder.newBuilder(desc) 148 // Remove the last and check 149 .removeCoprocessor(className2) 150 .build(); 151 assertTrue(desc.getCoprocessorDescriptors().isEmpty()); 152 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 153 .anyMatch(name -> name.equals(className1))); 154 assertFalse(desc.getCoprocessorDescriptors().stream().map(CoprocessorDescriptor::getClassName) 155 .anyMatch(name -> name.equals(className2))); 156 } 157 158 /** 159 * Test that we add and remove strings from settings properly. 160 * @throws Exception 161 */ 162 @Test 163 public void testRemoveString() throws Exception { 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}