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 java.io.IOException; 021import java.lang.reflect.InvocationTargetException; 022import java.lang.reflect.Method; 023import java.lang.reflect.UndeclaredThrowableException; 024import org.apache.commons.lang3.reflect.FieldUtils; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.IntegrationTestingUtility; 028import org.apache.hadoop.hbase.security.UserProvider; 029import org.apache.hadoop.hbase.testclassification.ClientTests; 030import org.apache.hadoop.hbase.testclassification.MediumTests; 031import org.junit.AfterClass; 032import org.junit.Assert; 033import org.junit.BeforeClass; 034import org.junit.ClassRule; 035import org.junit.Test; 036import org.junit.experimental.categories.Category; 037import org.junit.runner.RunWith; 038import org.mockito.Mockito; 039import org.mockito.junit.MockitoJUnitRunner; 040 041@Category({ ClientTests.class, MediumTests.class }) 042@RunWith(MockitoJUnitRunner.class) 043public class TestConnectionImplementationCacheMasterState { 044 @ClassRule 045 public static final HBaseClassTestRule CLASS_RULE = 046 HBaseClassTestRule.forClass(TestConnectionImplementationCacheMasterState.class); 047 private static final IntegrationTestingUtility TEST_UTIL = new IntegrationTestingUtility(); 048 049 @BeforeClass 050 public static void beforeClass() throws Exception { 051 TEST_UTIL.startMiniCluster(1); 052 } 053 054 @AfterClass 055 public static void afterClass() throws Exception { 056 TEST_UTIL.shutdownMiniCluster(); 057 } 058 059 @Test 060 public void testGetMaster_noCachedMasterState() throws IOException, IllegalAccessException { 061 Configuration conf = TEST_UTIL.getConfiguration(); 062 conf.setLong(ConnectionImplementation.MASTER_STATE_CACHE_TIMEOUT_SEC, 0L); 063 ConnectionImplementation conn = 064 new ConnectionImplementation(conf, null, UserProvider.instantiate(conf).getCurrent()); 065 ConnectionImplementation.MasterServiceState masterServiceState = spyMasterServiceState(conn); 066 conn.getMaster(); // This initializes the stubs but don't call isMasterRunning 067 conn.getMaster(); // Calls isMasterRunning since stubs are initialized. Invocation 1 068 conn.getMaster(); // Calls isMasterRunning since stubs are initialized. Invocation 2 069 Mockito.verify(masterServiceState, Mockito.times(2)).isMasterRunning(); 070 conn.close(); 071 } 072 073 @Test 074 public void testGetMaster_masterStateCacheHit() throws IOException, IllegalAccessException { 075 Configuration conf = TEST_UTIL.getConfiguration(); 076 conf.setLong(ConnectionImplementation.MASTER_STATE_CACHE_TIMEOUT_SEC, 15L); 077 ConnectionImplementation conn = 078 new ConnectionImplementation(conf, null, UserProvider.instantiate(conf).getCurrent()); 079 ConnectionImplementation.MasterServiceState masterServiceState = spyMasterServiceState(conn); 080 conn.getMaster(); // This initializes the stubs but don't call isMasterRunning 081 conn.getMaster(); // Uses cached value, don't call isMasterRunning 082 conn.getMaster(); // Uses cached value, don't call isMasterRunning 083 Mockito.verify(masterServiceState, Mockito.times(0)).isMasterRunning(); 084 conn.close(); 085 } 086 087 @Test 088 public void testGetMaster_masterStateCacheMiss() 089 throws IOException, InterruptedException, IllegalAccessException { 090 Configuration conf = TEST_UTIL.getConfiguration(); 091 conf.setLong(ConnectionImplementation.MASTER_STATE_CACHE_TIMEOUT_SEC, 5L); 092 ConnectionImplementation conn = 093 new ConnectionImplementation(conf, null, UserProvider.instantiate(conf).getCurrent()); 094 ConnectionImplementation.MasterServiceState masterServiceState = spyMasterServiceState(conn); 095 conn.getMaster(); // This initializes the stubs but don't call isMasterRunning 096 conn.getMaster(); // Uses cached value, don't call isMasterRunning 097 conn.getMaster(); // Uses cached value, don't call isMasterRunning 098 Thread.sleep(10000); 099 conn.getMaster(); // Calls isMasterRunning after cache expiry. Invocation 1 100 Mockito.verify(masterServiceState, Mockito.times(1)).isMasterRunning(); 101 conn.close(); 102 } 103 104 @Test 105 public void testIsKeepAliveMasterConnectedAndRunning_UndeclaredThrowableException() 106 throws IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { 107 Configuration conf = TEST_UTIL.getConfiguration(); 108 conf.setLong(ConnectionImplementation.MASTER_STATE_CACHE_TIMEOUT_SEC, 0); 109 ConnectionImplementation conn = 110 new ConnectionImplementation(conf, null, UserProvider.instantiate(conf).getCurrent()); 111 conn.getMaster(); // Initializes stubs 112 113 ConnectionImplementation.MasterServiceState masterServiceState = spyMasterServiceState(conn); 114 Mockito.doThrow(new UndeclaredThrowableException(new Exception("DUMMY EXCEPTION"))) 115 .when(masterServiceState).isMasterRunning(); 116 117 // Verify that masterState is "false" because of to injected exception 118 boolean isKeepAliveMasterRunning = 119 (boolean) getIsKeepAliveMasterConnectedAndRunningMethod().invoke(conn); 120 Assert.assertFalse(isKeepAliveMasterRunning); 121 conn.close(); 122 } 123 124 @Test 125 public void testIsKeepAliveMasterConnectedAndRunning_IOException() 126 throws IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { 127 Configuration conf = TEST_UTIL.getConfiguration(); 128 conf.setLong(ConnectionImplementation.MASTER_STATE_CACHE_TIMEOUT_SEC, 0); 129 ConnectionImplementation conn = 130 new ConnectionImplementation(conf, null, UserProvider.instantiate(conf).getCurrent()); 131 conn.getMaster(); 132 133 ConnectionImplementation.MasterServiceState masterServiceState = spyMasterServiceState(conn); 134 Mockito.doThrow(new IOException("DUMMY EXCEPTION")).when(masterServiceState).isMasterRunning(); 135 136 boolean isKeepAliveMasterRunning = 137 (boolean) getIsKeepAliveMasterConnectedAndRunningMethod().invoke(conn); 138 139 // Verify that masterState is "false" because of to injected exception 140 Assert.assertFalse(isKeepAliveMasterRunning); 141 conn.close(); 142 } 143 144 // Spy the masterServiceState object using reflection 145 private ConnectionImplementation.MasterServiceState 146 spyMasterServiceState(ConnectionImplementation conn) throws IllegalAccessException { 147 ConnectionImplementation.MasterServiceState spiedMasterServiceState = 148 Mockito.spy(conn.getMasterServiceState()); 149 FieldUtils.writeDeclaredField(conn, "masterServiceState", spiedMasterServiceState, true); 150 return spiedMasterServiceState; 151 } 152 153 // Get isKeepAliveMasterConnectedAndRunning using reflection 154 private Method getIsKeepAliveMasterConnectedAndRunningMethod() throws NoSuchMethodException { 155 Method method = 156 ConnectionImplementation.class.getDeclaredMethod("isKeepAliveMasterConnectedAndRunning"); 157 method.setAccessible(true); 158 return method; 159 } 160}