2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 package org
.apache
.hadoop
.hbase
.regionserver
;
20 import static org
.hamcrest
.CoreMatchers
.hasItems
;
21 import static org
.hamcrest
.MatcherAssert
.assertThat
;
22 import static org
.junit
.Assert
.assertEquals
;
23 import static org
.mockito
.ArgumentMatchers
.any
;
24 import static org
.mockito
.ArgumentMatchers
.anyInt
;
25 import static org
.mockito
.Mockito
.atLeast
;
26 import static org
.mockito
.Mockito
.atLeastOnce
;
27 import static org
.mockito
.Mockito
.doAnswer
;
28 import static org
.mockito
.Mockito
.mock
;
29 import static org
.mockito
.Mockito
.never
;
30 import static org
.mockito
.Mockito
.times
;
31 import static org
.mockito
.Mockito
.verify
;
32 import static org
.mockito
.Mockito
.when
;
34 import java
.io
.IOException
;
35 import java
.util
.Arrays
;
36 import java
.util
.List
;
37 import java
.util
.concurrent
.CompletableFuture
;
38 import org
.apache
.hadoop
.conf
.Configuration
;
39 import org
.apache
.hadoop
.hbase
.HBaseClassTestRule
;
40 import org
.apache
.hadoop
.hbase
.HBaseConfiguration
;
41 import org
.apache
.hadoop
.hbase
.HBaseRpcServicesBase
;
42 import org
.apache
.hadoop
.hbase
.ServerName
;
43 import org
.apache
.hadoop
.hbase
.Waiter
;
44 import org
.apache
.hadoop
.hbase
.client
.AsyncClusterConnection
;
45 import org
.apache
.hadoop
.hbase
.testclassification
.RegionServerTests
;
46 import org
.apache
.hadoop
.hbase
.testclassification
.SmallTests
;
47 import org
.apache
.hadoop
.hbase
.util
.EnvironmentEdgeManager
;
48 import org
.apache
.hadoop
.hbase
.util
.FutureUtils
;
49 import org
.apache
.hadoop
.hbase
.zookeeper
.MasterAddressTracker
;
50 import org
.junit
.After
;
51 import org
.junit
.Before
;
52 import org
.junit
.ClassRule
;
53 import org
.junit
.Test
;
54 import org
.junit
.experimental
.categories
.Category
;
56 @Category({ RegionServerTests
.class, SmallTests
.class })
57 public class TestBootstrapNodeManager
{
60 public static final HBaseClassTestRule CLASS_RULE
=
61 HBaseClassTestRule
.forClass(TestBootstrapNodeManager
.class);
63 private Configuration conf
;
65 private AsyncClusterConnection conn
;
67 private MasterAddressTracker tracker
;
69 private BootstrapNodeManager manager
;
73 conf
= HBaseConfiguration
.create();
74 conf
.setLong(BootstrapNodeManager
.REQUEST_MASTER_INTERVAL_SECS
, 5);
75 conf
.setLong(BootstrapNodeManager
.REQUEST_MASTER_MIN_INTERVAL_SECS
, 1);
76 conf
.setLong(BootstrapNodeManager
.REQUEST_REGIONSERVER_INTERVAL_SECS
, 1);
77 conf
.setInt(HBaseRpcServicesBase
.CLIENT_BOOTSTRAP_NODE_LIMIT
, 2);
78 conn
= mock(AsyncClusterConnection
.class);
79 when(conn
.getConfiguration()).thenReturn(conf
);
80 tracker
= mock(MasterAddressTracker
.class);
84 public void tearDown() {
85 if (manager
!= null) {
90 private void assertListEquals(List
<ServerName
> expected
, List
<ServerName
> actual
) {
91 assertEquals(expected
.size(), expected
.size());
92 assertThat(actual
, hasItems(expected
.toArray(new ServerName
[0])));
96 public void testNormal() throws Exception
{
97 List
<ServerName
> regionServers
=
98 Arrays
.asList(ServerName
.valueOf("server1", 12345, EnvironmentEdgeManager
.currentTime()),
99 ServerName
.valueOf("server2", 12345, EnvironmentEdgeManager
.currentTime()),
100 ServerName
.valueOf("server3", 12345, EnvironmentEdgeManager
.currentTime()),
101 ServerName
.valueOf("server4", 12345, EnvironmentEdgeManager
.currentTime()));
102 when(conn
.getLiveRegionServers(any(), anyInt()))
103 .thenReturn(CompletableFuture
.completedFuture(regionServers
));
104 when(conn
.getAllBootstrapNodes(any()))
105 .thenReturn(CompletableFuture
.completedFuture(regionServers
));
106 manager
= new BootstrapNodeManager(conn
, tracker
);
108 verify(conn
, times(1)).getLiveRegionServers(any(), anyInt());
109 verify(conn
, atLeastOnce()).getAllBootstrapNodes(any());
110 assertListEquals(regionServers
, manager
.getBootstrapNodes());
113 // if we do not return enough region servers, we will always get from master
115 public void testOnlyMaster() throws Exception
{
116 List
<ServerName
> regionServers
=
117 Arrays
.asList(ServerName
.valueOf("server1", 12345, EnvironmentEdgeManager
.currentTime()));
118 when(conn
.getLiveRegionServers(any(), anyInt()))
119 .thenReturn(CompletableFuture
.completedFuture(regionServers
));
120 when(conn
.getAllBootstrapNodes(any()))
121 .thenReturn(CompletableFuture
.completedFuture(regionServers
));
122 manager
= new BootstrapNodeManager(conn
, tracker
);
124 verify(conn
, atLeast(2)).getLiveRegionServers(any(), anyInt());
125 verify(conn
, never()).getAllBootstrapNodes(any());
126 assertListEquals(regionServers
, manager
.getBootstrapNodes());
130 public void testRegionServerError() throws Exception
{
131 List
<ServerName
> regionServers
=
132 Arrays
.asList(ServerName
.valueOf("server1", 12345, EnvironmentEdgeManager
.currentTime()),
133 ServerName
.valueOf("server2", 12345, EnvironmentEdgeManager
.currentTime()),
134 ServerName
.valueOf("server3", 12345, EnvironmentEdgeManager
.currentTime()),
135 ServerName
.valueOf("server4", 12345, EnvironmentEdgeManager
.currentTime()));
136 List
<ServerName
> newRegionServers
=
137 Arrays
.asList(ServerName
.valueOf("server5", 12345, EnvironmentEdgeManager
.currentTime()),
138 ServerName
.valueOf("server6", 12345, EnvironmentEdgeManager
.currentTime()));
139 when(conn
.getLiveRegionServers(any(), anyInt()))
140 .thenReturn(CompletableFuture
.completedFuture(regionServers
));
141 when(conn
.getAllBootstrapNodes(any())).thenAnswer(invocation
-> {
142 if (invocation
.getArgument(0, ServerName
.class).getHostname().equals("server4")) {
143 return FutureUtils
.failedFuture(new IOException("Inject error"));
145 return CompletableFuture
.completedFuture(regionServers
.subList(0, 3));
148 manager
= new BootstrapNodeManager(conn
, tracker
);
149 // we should remove server4 from the list
150 Waiter
.waitFor(conf
, 30000, () -> manager
.getBootstrapNodes().size() == 3);
151 assertListEquals(regionServers
.subList(0, 3), manager
.getBootstrapNodes());
152 when(conn
.getLiveRegionServers(any(), anyInt()))
153 .thenReturn(CompletableFuture
.completedFuture(newRegionServers
));
154 doAnswer(invocation
-> {
155 String hostname
= invocation
.getArgument(0, ServerName
.class).getHostname();
158 return CompletableFuture
.completedFuture(regionServers
.subList(0, 1));
161 return FutureUtils
.failedFuture(new IOException("Inject error"));
163 return CompletableFuture
.completedFuture(newRegionServers
);
165 }).when(conn
).getAllBootstrapNodes(any());
166 // we should remove server2, server3 from the list and then get the new list from master again
167 Waiter
.waitFor(conf
, 30000, () -> {
168 List
<ServerName
> bootstrapNodes
= manager
.getBootstrapNodes();
169 if (bootstrapNodes
.size() != 2) {
172 String hostname
= bootstrapNodes
.get(0).getHostname();
173 return hostname
.equals("server5") || hostname
.equals("server6");
175 assertListEquals(newRegionServers
, manager
.getBootstrapNodes());