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.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertThrows; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024 025import java.io.IOException; 026import java.util.Optional; 027import java.util.concurrent.Future; 028import org.apache.hadoop.hbase.HBaseTestingUtil; 029import org.apache.hadoop.hbase.ServerName; 030import org.apache.hadoop.hbase.master.assignment.MockMasterServices; 031import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher; 032import org.apache.hadoop.hbase.testclassification.MasterTests; 033import org.apache.hadoop.hbase.testclassification.MediumTests; 034import org.junit.jupiter.api.AfterEach; 035import org.junit.jupiter.api.BeforeEach; 036import org.junit.jupiter.api.Tag; 037import org.junit.jupiter.api.Test; 038import org.junit.jupiter.api.TestInfo; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042@Tag(MasterTests.TAG) 043@Tag(MediumTests.TAG) 044public class TestReloadQuotasProcedure { 045 private static final Logger LOG = LoggerFactory.getLogger(TestReloadQuotasProcedure.class); 046 private String testMethodName; 047 048 @BeforeEach 049 public void setTestMethod(TestInfo testInfo) { 050 testMethodName = testInfo.getTestMethod().get().getName(); 051 } 052 053 private HBaseTestingUtil util; 054 private MockMasterServices master; 055 private TestServerRemoteProcedure.MockRSProcedureDispatcher rsDispatcher; 056 057 @BeforeEach 058 public void setUp() throws Exception { 059 util = new HBaseTestingUtil(); 060 master = new MockMasterServices(util.getConfiguration()); 061 rsDispatcher = new TestServerRemoteProcedure.MockRSProcedureDispatcher(master); 062 master.start(2, rsDispatcher); 063 } 064 065 @AfterEach 066 public void tearDown() throws Exception { 067 master.stop("tearDown"); 068 } 069 070 @Test 071 public void itHandlesClassNotFoundExceptionGracefully() throws Exception { 072 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 073 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 074 075 ClassNotFoundException classNotFound = 076 new ClassNotFoundException("ReloadQuotasCallable not found"); 077 IOException wrappedException = new IOException("Remote call failed", classNotFound); 078 079 boolean result = 080 procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), wrappedException); 081 082 assertTrue(result); 083 } 084 085 @Test 086 public void itReturnsFailureForOtherExceptions() throws Exception { 087 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 088 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 089 090 IOException otherException = new IOException("Some other error"); 091 092 boolean result = 093 procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), otherException); 094 095 assertFalse(result); 096 } 097 098 @Test 099 public void itReturnsSuccessForNoError() throws Exception { 100 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 101 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 102 103 boolean result = procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), null); 104 105 assertTrue(result); 106 } 107 108 @Test 109 public void itCorrectlyDetectsCauseClass() { 110 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(); 111 112 ClassNotFoundException classNotFound = new ClassNotFoundException("test"); 113 IOException wrappedException = new IOException("wrapper", classNotFound); 114 RuntimeException outerWrapper = new RuntimeException("outer", wrappedException); 115 116 assertTrue(procedure.containsCause(outerWrapper, ClassNotFoundException.class)); 117 assertFalse(procedure.containsCause(outerWrapper, IllegalArgumentException.class)); 118 assertTrue(procedure.containsCause(classNotFound, ClassNotFoundException.class)); 119 } 120 121 @Test 122 public void itValidatesServerNameInRemoteCallBuild() throws Exception { 123 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 124 ServerName wrongServer = master.getServerManager().getOnlineServersList().get(1); 125 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 126 127 MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment(); 128 129 Optional<RemoteProcedureDispatcher.RemoteOperation> result = 130 procedure.remoteCallBuild(env, targetServer); 131 assertTrue(result.isPresent()); 132 assertTrue(result.get() instanceof RSProcedureDispatcher.ServerOperation); 133 134 assertThrows(IllegalArgumentException.class, () -> { 135 procedure.remoteCallBuild(env, wrongServer); 136 }); 137 } 138 139 @Test 140 public void itCreatesCorrectRemoteOperation() throws Exception { 141 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 142 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 143 MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment(); 144 145 Optional<RemoteProcedureDispatcher.RemoteOperation> operation = 146 procedure.remoteCallBuild(env, targetServer); 147 148 assertTrue(operation.isPresent()); 149 RSProcedureDispatcher.ServerOperation serverOp = 150 (RSProcedureDispatcher.ServerOperation) operation.get(); 151 assertEquals(serverOp.getRemoteProcedure(), procedure); 152 assertEquals(serverOp.buildRequest().getProcId(), procedure.getProcId()); 153 } 154 155 @Test 156 public void itThrowsUnsupportedOperationExceptionOnRollback() throws Exception { 157 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 158 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 159 MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment(); 160 161 assertThrows(UnsupportedOperationException.class, () -> { 162 procedure.rollback(env); 163 }); 164 } 165 166 @Test 167 public void itReturnsFalseOnAbort() throws Exception { 168 ServerName targetServer = master.getServerManager().getOnlineServersList().get(0); 169 ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer); 170 MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment(); 171 172 boolean result = procedure.abort(env); 173 174 assertFalse(result); 175 } 176 177 private Future<byte[]> submitProcedure(ReloadQuotasProcedure procedure) { 178 return ProcedureSyncWait.submitProcedure(master.getMasterProcedureExecutor(), procedure); 179 } 180}