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.coprocessor; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.mockito.ArgumentMatchers.any; 022import static org.mockito.Mockito.clearInvocations; 023import static org.mockito.Mockito.doAnswer; 024import static org.mockito.Mockito.doReturn; 025import static org.mockito.Mockito.mock; 026import static org.mockito.Mockito.reset; 027import static org.mockito.Mockito.verify; 028import static org.mockito.Mockito.verifyNoMoreInteractions; 029 030import java.io.IOException; 031import java.util.List; 032import java.util.Map; 033import java.util.Optional; 034import org.apache.hadoop.conf.Configuration; 035import org.apache.hadoop.hbase.HBaseTestingUtil; 036import org.apache.hadoop.hbase.HRegionLocation; 037import org.apache.hadoop.hbase.RegionLocations; 038import org.apache.hadoop.hbase.ServerName; 039import org.apache.hadoop.hbase.client.AsyncConnectionImpl; 040import org.apache.hadoop.hbase.client.ConnectionFactory; 041import org.apache.hadoop.hbase.client.ConnectionRegistry; 042import org.apache.hadoop.hbase.client.RegionInfoBuilder; 043import org.apache.hadoop.hbase.master.HMaster; 044import org.apache.hadoop.hbase.master.MasterRpcServices; 045import org.apache.hadoop.hbase.testclassification.CoprocessorTests; 046import org.apache.hadoop.hbase.testclassification.MediumTests; 047import org.junit.jupiter.api.AfterAll; 048import org.junit.jupiter.api.BeforeAll; 049import org.junit.jupiter.api.BeforeEach; 050import org.junit.jupiter.api.Tag; 051import org.junit.jupiter.api.Test; 052import org.slf4j.Logger; 053import org.slf4j.LoggerFactory; 054 055/** 056 * Tests invocation of the {@link MasterObserver} interface hooks at all appropriate times during 057 * normal HMaster operations. 058 */ 059@Tag(CoprocessorTests.TAG) 060@Tag(MediumTests.TAG) 061public class TestClientMetaCoprocessor { 062 private static final Logger LOG = LoggerFactory.getLogger(TestClientMetaCoprocessor.class); 063 064 private static final HBaseTestingUtil UTIL = new HBaseTestingUtil(); 065 066 private static final ServerName SERVER_NAME = ServerName.valueOf("localhost", 1234, 12345); 067 068 public static class TestCoprocessor implements ClientMetaCoprocessor { 069 protected final ClientMetaObserver observer; 070 071 public TestCoprocessor() { 072 observer = mock(ClientMetaObserver.class); 073 resetMock(); 074 } 075 076 protected void resetMock() { 077 reset(observer); 078 079 try { 080 doAnswer(answer -> answer.getArgument(1, String.class)).when(observer) 081 .postGetClusterId(any(), any()); 082 doAnswer(answer -> { 083 return answer.getArgument(1, ServerName.class); 084 }).when(observer).postGetActiveMaster(any(), any()); 085 doAnswer(answer -> answer.getArgument(1, Map.class)).when(observer).postGetMasters(any(), 086 any()); 087 doAnswer(answer -> answer.getArgument(1, List.class)).when(observer) 088 .postGetBootstrapNodes(any(), any()); 089 doAnswer(answer -> answer.getArgument(1, List.class)).when(observer) 090 .postGetMetaLocations(any(), any()); 091 } catch (IOException e) { 092 throw new IllegalStateException("Could not setup observer mock.", e); 093 } 094 } 095 096 @Override 097 public Optional<ClientMetaObserver> getClientMetaObserver() { 098 return Optional.of(observer); 099 } 100 } 101 102 private static TestCoprocessor getCoprocessor() { 103 HMaster master = UTIL.getMiniHBaseCluster().getMaster(); 104 MasterRpcServices masterRpcServices = master.getMasterRpcServices(); 105 106 return masterRpcServices.getClientMetaCoprocessorHost().findCoprocessor(TestCoprocessor.class); 107 } 108 109 private static ClientMetaObserver getObserverMock() { 110 return getCoprocessor().getClientMetaObserver().get(); 111 } 112 113 private static void resetObserverMock() { 114 getCoprocessor().resetMock(); 115 } 116 117 @BeforeAll 118 public static void setupBeforeClass() throws Exception { 119 Configuration conf = UTIL.getConfiguration(); 120 conf.set(CoprocessorHost.CLIENT_META_COPROCESSOR_CONF_KEY, TestCoprocessor.class.getName()); 121 122 UTIL.startMiniCluster(); 123 } 124 125 @AfterAll 126 public static void tearDownAfterClass() throws Exception { 127 UTIL.shutdownMiniCluster(); 128 } 129 130 @BeforeEach 131 public void setupBefore() { 132 resetObserverMock(); 133 } 134 135 @Test 136 public void testGetClusterId() throws Exception { 137 ClientMetaObserver observer = getObserverMock(); 138 139 try (AsyncConnectionImpl asyncConnection = (AsyncConnectionImpl) ConnectionFactory 140 .createAsyncConnection(UTIL.getConfiguration()).get()) { 141 ConnectionRegistry connectionRegistry = asyncConnection.getConnectionRegistry(); 142 143 doReturn("cluster-id").when(observer).postGetClusterId(any(), any()); 144 clearInvocations(observer); 145 146 String clusterId = connectionRegistry.getClusterId().get(); 147 assertEquals("cluster-id", clusterId); 148 149 verify(observer).preGetClusterId(any()); 150 verify(observer).postGetClusterId(any(), any()); 151 verifyNoMoreInteractions(observer); 152 } 153 } 154 155 @Test 156 public void testGetActiveMaster() throws Exception { 157 ClientMetaObserver observer = getObserverMock(); 158 159 try (AsyncConnectionImpl asyncConnection = (AsyncConnectionImpl) ConnectionFactory 160 .createAsyncConnection(UTIL.getConfiguration()).get()) { 161 ConnectionRegistry connectionRegistry = asyncConnection.getConnectionRegistry(); 162 163 doReturn(SERVER_NAME).when(observer).postGetActiveMaster(any(), any()); 164 clearInvocations(observer); 165 166 ServerName activeMaster = connectionRegistry.getActiveMaster().get(); 167 assertEquals(SERVER_NAME, activeMaster); 168 169 verify(observer).preGetActiveMaster(any()); 170 verify(observer).postGetActiveMaster(any(), any()); 171 verifyNoMoreInteractions(observer); 172 } 173 } 174 175 @Test 176 public void testGetMetaRegionLocations() throws Exception { 177 ClientMetaObserver observer = getObserverMock(); 178 179 try (AsyncConnectionImpl asyncConnection = (AsyncConnectionImpl) ConnectionFactory 180 .createAsyncConnection(UTIL.getConfiguration()).get()) { 181 ConnectionRegistry connectionRegistry = asyncConnection.getConnectionRegistry(); 182 183 HRegionLocation metaRegionLocation = 184 new HRegionLocation(RegionInfoBuilder.FIRST_META_REGIONINFO, SERVER_NAME); 185 doReturn(List.of(metaRegionLocation)).when(observer).postGetMetaLocations(any(), any()); 186 clearInvocations(observer); 187 188 RegionLocations regionLocations = connectionRegistry.getMetaRegionLocations().get(); 189 HRegionLocation actualMetaRegionLocation = regionLocations.getDefaultRegionLocation(); 190 191 assertEquals(metaRegionLocation, actualMetaRegionLocation); 192 193 verify(observer).preGetMetaLocations(any()); 194 verify(observer).postGetMetaLocations(any(), any()); 195 verifyNoMoreInteractions(observer); 196 } 197 } 198}