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.master.procedure; 019 020import static org.junit.jupiter.api.Assertions.assertNotNull; 021import static org.junit.jupiter.api.Assertions.assertNull; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023 024import java.io.IOException; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HBaseTestingUtil; 027import org.apache.hadoop.hbase.NamespaceDescriptor; 028import org.apache.hadoop.hbase.NamespaceExistException; 029import org.apache.hadoop.hbase.NamespaceNotFoundException; 030import org.apache.hadoop.hbase.constraint.ConstraintException; 031import org.apache.hadoop.hbase.procedure2.Procedure; 032import org.apache.hadoop.hbase.procedure2.ProcedureExecutor; 033import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility; 034import org.apache.hadoop.hbase.testclassification.MasterTests; 035import org.apache.hadoop.hbase.testclassification.MediumTests; 036import org.junit.jupiter.api.AfterAll; 037import org.junit.jupiter.api.AfterEach; 038import org.junit.jupiter.api.BeforeAll; 039import org.junit.jupiter.api.BeforeEach; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042import org.slf4j.Logger; 043import org.slf4j.LoggerFactory; 044 045@Tag(MasterTests.TAG) 046@Tag(MediumTests.TAG) 047public class TestCreateNamespaceProcedure { 048 049 private static final Logger LOG = LoggerFactory.getLogger(TestCreateNamespaceProcedure.class); 050 051 protected static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 052 053 private static void setupConf(Configuration conf) { 054 conf.setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1); 055 } 056 057 @BeforeAll 058 public static void setupCluster() throws Exception { 059 setupConf(UTIL.getConfiguration()); 060 UTIL.startMiniCluster(1); 061 } 062 063 @AfterAll 064 public static void cleanupTest() throws Exception { 065 try { 066 UTIL.shutdownMiniCluster(); 067 } catch (Exception e) { 068 LOG.warn("failure shutting down cluster", e); 069 } 070 } 071 072 @BeforeEach 073 public void setup() throws Exception { 074 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); 075 } 076 077 @AfterEach 078 public void tearDown() throws Exception { 079 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(getMasterProcedureExecutor(), false); 080 } 081 082 @Test 083 public void testCreateNamespace() throws Exception { 084 final NamespaceDescriptor nsd = NamespaceDescriptor.create("testCreateNamespace").build(); 085 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 086 087 long procId = 088 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 089 // Wait the completion 090 ProcedureTestingUtility.waitProcedure(procExec, procId); 091 ProcedureTestingUtility.assertProcNotFailed(procExec, procId); 092 093 validateNamespaceCreated(nsd); 094 } 095 096 @Test 097 public void testCreateSameNamespaceTwice() throws Exception { 098 final NamespaceDescriptor nsd = 099 NamespaceDescriptor.create("testCreateSameNamespaceTwice").build(); 100 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 101 102 long procId1 = 103 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 104 // Wait the completion 105 ProcedureTestingUtility.waitProcedure(procExec, procId1); 106 ProcedureTestingUtility.assertProcNotFailed(procExec, procId1); 107 108 // Create the namespace that exists 109 long procId2 = 110 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 111 // Wait the completion 112 ProcedureTestingUtility.waitProcedure(procExec, procId2); 113 114 // Second create should fail with NamespaceExistException 115 Procedure<?> result = procExec.getResult(procId2); 116 assertTrue(result.isFailed()); 117 LOG.debug("Create namespace failed with exception: " + result.getException()); 118 assertTrue( 119 ProcedureTestingUtility.getExceptionCause(result) instanceof NamespaceExistException); 120 } 121 122 @Test 123 public void testCreateSystemNamespace() throws Exception { 124 final NamespaceDescriptor nsd = 125 UTIL.getAdmin().getNamespaceDescriptor(NamespaceDescriptor.SYSTEM_NAMESPACE.getName()); 126 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 127 128 long procId = 129 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 130 // Wait the completion 131 ProcedureTestingUtility.waitProcedure(procExec, procId); 132 Procedure<?> result = procExec.getResult(procId); 133 assertTrue(result.isFailed()); 134 LOG.debug("Create namespace failed with exception: " + result.getException()); 135 assertTrue( 136 ProcedureTestingUtility.getExceptionCause(result) instanceof NamespaceExistException); 137 } 138 139 @Test 140 public void testCreateNamespaceWithInvalidRegionCount() throws Exception { 141 final NamespaceDescriptor nsd = 142 NamespaceDescriptor.create("testCreateNamespaceWithInvalidRegionCount").build(); 143 final String nsKey = "hbase.namespace.quota.maxregions"; 144 final String nsValue = "-1"; 145 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 146 147 nsd.setConfiguration(nsKey, nsValue); 148 149 long procId = 150 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 151 // Wait the completion 152 ProcedureTestingUtility.waitProcedure(procExec, procId); 153 Procedure<?> result = procExec.getResult(procId); 154 assertTrue(result.isFailed()); 155 LOG.debug("Create namespace failed with exception: " + result.getException()); 156 assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); 157 } 158 159 @Test 160 public void testCreateNamespaceWithInvalidTableCount() throws Exception { 161 final NamespaceDescriptor nsd = 162 NamespaceDescriptor.create("testCreateNamespaceWithInvalidTableCount").build(); 163 final String nsKey = "hbase.namespace.quota.maxtables"; 164 final String nsValue = "-1"; 165 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 166 167 nsd.setConfiguration(nsKey, nsValue); 168 169 long procId = 170 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 171 // Wait the completion 172 ProcedureTestingUtility.waitProcedure(procExec, procId); 173 Procedure<?> result = procExec.getResult(procId); 174 assertTrue(result.isFailed()); 175 LOG.debug("Create namespace failed with exception: " + result.getException()); 176 assertTrue(ProcedureTestingUtility.getExceptionCause(result) instanceof ConstraintException); 177 } 178 179 @Test 180 public void testRecoveryAndDoubleExecution() throws Exception { 181 final NamespaceDescriptor nsd = 182 NamespaceDescriptor.create("testRecoveryAndDoubleExecution").build(); 183 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 184 185 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 186 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 187 188 // Start the CreateNamespace procedure && kill the executor 189 long procId = 190 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 191 192 // Restart the executor and execute the step twice 193 MasterProcedureTestingUtility.testRecoveryAndDoubleExecution(procExec, procId); 194 195 // Validate the creation of namespace 196 ProcedureTestingUtility.assertProcNotFailed(procExec, procId); 197 validateNamespaceCreated(nsd); 198 } 199 200 @Test 201 public void testRollbackAndDoubleExecution() throws Exception { 202 final NamespaceDescriptor nsd = 203 NamespaceDescriptor.create("testRollbackAndDoubleExecution").build(); 204 final ProcedureExecutor<MasterProcedureEnv> procExec = getMasterProcedureExecutor(); 205 206 ProcedureTestingUtility.waitNoProcedureRunning(procExec); 207 ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(procExec, true); 208 209 // Start the CreateNamespace procedure && kill the executor 210 long procId = 211 procExec.submitProcedure(new CreateNamespaceProcedure(procExec.getEnvironment(), nsd)); 212 213 int lastStep = 2; // failing before CREATE_NAMESPACE_CREATE_DIRECTORY 214 MasterProcedureTestingUtility.testRollbackAndDoubleExecution(procExec, procId, lastStep); 215 216 // Validate the non-existence of namespace 217 try { 218 NamespaceDescriptor nsDescriptor = UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 219 assertNull(nsDescriptor); 220 } catch (NamespaceNotFoundException nsnfe) { 221 // Expected 222 LOG.info("The namespace " + nsd.getName() + " is not created."); 223 } 224 } 225 226 private ProcedureExecutor<MasterProcedureEnv> getMasterProcedureExecutor() { 227 return UTIL.getHBaseCluster().getMaster().getMasterProcedureExecutor(); 228 } 229 230 private void validateNamespaceCreated(NamespaceDescriptor nsd) throws IOException { 231 NamespaceDescriptor createdNsDescriptor = UTIL.getAdmin().getNamespaceDescriptor(nsd.getName()); 232 assertNotNull(createdNsDescriptor); 233 } 234}