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.assertFalse; 021import static org.junit.Assert.assertTrue; 022import static org.junit.Assert.fail; 023import static org.mockito.ArgumentMatchers.contains; 024import static org.mockito.Mockito.mock; 025import static org.mockito.Mockito.verify; 026 027import java.io.IOException; 028import java.lang.reflect.Field; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.HBaseClassTestRule; 031import org.apache.hadoop.hbase.HBaseTestingUtil; 032import org.apache.hadoop.hbase.HConstants; 033import org.apache.hadoop.hbase.TableName; 034import org.apache.hadoop.hbase.testclassification.ClientTests; 035import org.apache.hadoop.hbase.testclassification.LargeTests; 036import org.apache.hadoop.hbase.util.Bytes; 037import org.apache.hadoop.hbase.util.TableDescriptorChecker; 038import org.junit.AfterClass; 039import org.junit.BeforeClass; 040import org.junit.ClassRule; 041import org.junit.Rule; 042import org.junit.Test; 043import org.junit.experimental.categories.Category; 044import org.junit.rules.TestName; 045import org.slf4j.Logger; 046 047@Category({ LargeTests.class, ClientTests.class }) 048public class TestIllegalTableDescriptor { 049 050 @ClassRule 051 public static final HBaseClassTestRule CLASS_RULE = 052 HBaseClassTestRule.forClass(TestIllegalTableDescriptor.class); 053 054 // NOTE: Increment tests were moved to their own class, TestIncrementsFromClientSide. 055 private static final Logger LOGGER; 056 057 protected final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil(); 058 059 private static byte[] FAMILY = Bytes.toBytes("testFamily"); 060 061 @Rule 062 public TestName name = new TestName(); 063 064 static { 065 LOGGER = mock(Logger.class); 066 } 067 068 @BeforeClass 069 public static void setUpBeforeClass() throws Exception { 070 // replacing HMaster.LOG with our mock logger for verifying logging 071 Field field = TableDescriptorChecker.class.getDeclaredField("LOG"); 072 field.setAccessible(true); 073 field.set(null, LOGGER); 074 Configuration conf = TEST_UTIL.getConfiguration(); 075 conf.setBoolean(TableDescriptorChecker.TABLE_SANITY_CHECKS, true); // enable for below tests 076 TEST_UTIL.startMiniCluster(1); 077 } 078 079 @AfterClass 080 public static void tearDownAfterClass() throws Exception { 081 TEST_UTIL.shutdownMiniCluster(); 082 } 083 084 @Test 085 public void testIllegalTableDescriptor() throws Exception { 086 TableDescriptorBuilder builder = 087 TableDescriptorBuilder.newBuilder(TableName.valueOf(name.getMethodName())); 088 ColumnFamilyDescriptorBuilder cfBuilder = ColumnFamilyDescriptorBuilder.newBuilder(FAMILY); 089 090 // create table with 0 families 091 checkTableIsIllegal(builder.build()); 092 checkTableIsLegal(builder.setColumnFamily(cfBuilder.build()).build()); 093 094 builder.setMaxFileSize(1024); // 1K 095 checkTableIsIllegal(builder.build()); 096 builder.setMaxFileSize(0); 097 checkTableIsIllegal(builder.build()); 098 builder.setMaxFileSize(1024 * 1024 * 1024); // 1G 099 checkTableIsLegal(builder.build()); 100 101 builder.setMemStoreFlushSize(1024); 102 checkTableIsIllegal(builder.build()); 103 builder.setMemStoreFlushSize(0); 104 checkTableIsIllegal(builder.build()); 105 builder.setMemStoreFlushSize(128 * 1024 * 1024); // 128M 106 checkTableIsLegal(builder.build()); 107 108 builder.setRegionSplitPolicyClassName("nonexisting.foo.class"); 109 checkTableIsIllegal(builder.build()); 110 builder.setRegionSplitPolicyClassName(null); 111 checkTableIsLegal(builder.build()); 112 113 builder.setValue(HConstants.HBASE_REGION_SPLIT_POLICY_KEY, "nonexisting.foo.class"); 114 checkTableIsIllegal(builder.build()); 115 builder.removeValue(Bytes.toBytes(HConstants.HBASE_REGION_SPLIT_POLICY_KEY)); 116 checkTableIsLegal(builder.build()); 117 118 cfBuilder.setBlocksize(0); 119 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 120 cfBuilder.setBlocksize(1024 * 1024 * 128); // 128M 121 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 122 cfBuilder.setBlocksize(1024); 123 checkTableIsLegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 124 125 cfBuilder.setTimeToLive(0); 126 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 127 cfBuilder.setTimeToLive(-1); 128 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 129 cfBuilder.setTimeToLive(1); 130 checkTableIsLegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 131 132 cfBuilder.setMinVersions(-1); 133 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 134 cfBuilder.setMinVersions(3); 135 try { 136 cfBuilder.setMaxVersions(2); 137 fail(); 138 } catch (IllegalArgumentException ex) { 139 // expected 140 cfBuilder.setMaxVersions(10); 141 } 142 checkTableIsLegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 143 144 // HBASE-13776 Setting illegal versions for HColumnDescriptor 145 // does not throw IllegalArgumentException 146 // finally, minVersions must be less than or equal to maxVersions 147 cfBuilder.setMaxVersions(4); 148 cfBuilder.setMinVersions(5); 149 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 150 cfBuilder.setMinVersions(3); 151 152 cfBuilder.setScope(-1); 153 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 154 cfBuilder.setScope(0); 155 checkTableIsLegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 156 157 cfBuilder.setValue(ColumnFamilyDescriptorBuilder.IN_MEMORY_COMPACTION, "INVALID"); 158 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 159 cfBuilder.setValue(ColumnFamilyDescriptorBuilder.IN_MEMORY_COMPACTION, "NONE"); 160 checkTableIsLegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 161 162 try { 163 cfBuilder.setDFSReplication((short) -1); 164 fail("Illegal value for setDFSReplication did not throw"); 165 } catch (IllegalArgumentException e) { 166 // pass 167 } 168 // set an illegal DFS replication value by hand 169 cfBuilder.setValue(ColumnFamilyDescriptorBuilder.DFS_REPLICATION, "-1"); 170 checkTableIsIllegal(builder.modifyColumnFamily(cfBuilder.build()).build()); 171 try { 172 cfBuilder.setDFSReplication((short) -1); 173 fail("Should throw exception if an illegal value is explicitly being set"); 174 } catch (IllegalArgumentException e) { 175 // pass 176 } 177 178 // check the conf settings to disable sanity checks 179 builder.setMemStoreFlushSize(0); 180 181 // Check that logs warn on invalid table but allow it. 182 builder.setValue(TableDescriptorChecker.TABLE_SANITY_CHECKS, Boolean.FALSE.toString()); 183 checkTableIsLegal(builder.build()); 184 185 verify(LOGGER).warn(contains("MEMSTORE_FLUSHSIZE for table " 186 + "descriptor or \"hbase.hregion.memstore.flush.size\" (0) is too small, which might " 187 + "cause very frequent flushing.")); 188 } 189 190 private void checkTableIsLegal(TableDescriptor tableDescriptor) throws IOException { 191 Admin admin = TEST_UTIL.getAdmin(); 192 admin.createTable(tableDescriptor); 193 assertTrue(admin.tableExists(tableDescriptor.getTableName())); 194 TEST_UTIL.deleteTable(tableDescriptor.getTableName()); 195 } 196 197 private void checkTableIsIllegal(TableDescriptor tableDescriptor) throws IOException { 198 Admin admin = TEST_UTIL.getAdmin(); 199 try { 200 admin.createTable(tableDescriptor); 201 fail(); 202 } catch (Exception ex) { 203 // should throw ex 204 } 205 assertFalse(admin.tableExists(tableDescriptor.getTableName())); 206 } 207}