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.http;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.assertFalse;
022import static org.junit.jupiter.api.Assertions.assertNotNull;
023import static org.junit.jupiter.api.Assertions.assertNull;
024
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.HashMap;
029import java.util.List;
030import java.util.Map;
031import java.util.Optional;
032import org.apache.hadoop.conf.Configuration;
033import org.apache.hadoop.hbase.HBaseConfiguration;
034import org.apache.hadoop.hbase.ServerName;
035import org.apache.hadoop.hbase.TableDescriptors;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.client.RegionInfo;
038import org.apache.hadoop.hbase.client.RegionInfoBuilder;
039import org.apache.hadoop.hbase.client.TableDescriptor;
040import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
041import org.apache.hadoop.hbase.master.DeadServer;
042import org.apache.hadoop.hbase.master.HMaster;
043import org.apache.hadoop.hbase.master.RegionState;
044import org.apache.hadoop.hbase.master.ServerManager;
045import org.apache.hadoop.hbase.master.assignment.AssignmentManager;
046import org.apache.hadoop.hbase.master.assignment.RegionStateNode;
047import org.apache.hadoop.hbase.master.assignment.RegionStates;
048import org.apache.hadoop.hbase.testclassification.MasterTests;
049import org.apache.hadoop.hbase.testclassification.SmallTests;
050import org.apache.hadoop.hbase.util.Bytes;
051import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
052import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
053import org.junit.jupiter.api.BeforeEach;
054import org.junit.jupiter.api.Tag;
055import org.junit.jupiter.api.Test;
056import org.mockito.Mockito;
057
058@Tag(MasterTests.TAG)
059@Tag(SmallTests.TAG)
060public class TestMasterStatusUtil {
061
062  private HMaster master;
063  private Configuration conf;
064
065  static final ServerName FAKE_HOST = ServerName.valueOf("fakehost", 12345, 1234567890);
066  static final TableDescriptor FAKE_TABLE =
067    TableDescriptorBuilder.newBuilder(TableName.valueOf("mytable")).build();
068
069  static final RegionInfo FAKE_HRI = RegionInfoBuilder.newBuilder(FAKE_TABLE.getTableName())
070    .setStartKey(Bytes.toBytes("a")).setEndKey(Bytes.toBytes("b")).build();
071
072  @BeforeEach
073  public void setupBasicMocks() {
074    conf = HBaseConfiguration.create();
075
076    master = Mockito.mock(HMaster.class);
077    Mockito.doReturn(FAKE_HOST).when(master).getServerName();
078    Mockito.doReturn(conf).when(master).getConfiguration();
079    Mockito.doReturn(true).when(master).isInitialized();
080
081    // Fake DeadServer
082    DeadServer deadServer = Mockito.mock(DeadServer.class);
083    // Fake serverManager
084    ServerManager serverManager = Mockito.mock(ServerManager.class);
085    Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
086    Mockito.doReturn(serverManager).when(master).getServerManager();
087    Mockito.doReturn(deadServer).when(serverManager).getDeadServers();
088
089    // Fake AssignmentManager and RIT
090    AssignmentManager am = Mockito.mock(AssignmentManager.class);
091    RegionStates rs = Mockito.mock(RegionStates.class);
092    List<RegionState> regionsInTransition = new ArrayList<>();
093    regionsInTransition
094      .add(new RegionState(FAKE_HRI, RegionState.State.CLOSING, 12345L, FAKE_HOST));
095    Mockito.doReturn(rs).when(am).getRegionStates();
096    Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
097    Mockito.doReturn(am).when(master).getAssignmentManager();
098    Mockito.doReturn(serverManager).when(master).getServerManager();
099
100    // Fake ZKW
101    ZKWatcher zkw = Mockito.mock(ZKWatcher.class);
102    Mockito.doReturn(new ZNodePaths(conf)).when(zkw).getZNodePaths();
103    Mockito.doReturn("fakequorum").when(zkw).getQuorum();
104    Mockito.doReturn(zkw).when(master).getZooKeeper();
105
106    // Fake ActiveMaster
107    Mockito.doReturn(Optional.of(FAKE_HOST)).when(master).getActiveMaster();
108  }
109
110  @Test
111  public void testGetUserTables() throws IOException {
112    Map<String, TableDescriptor> mockTables = new HashMap<>();
113    mockTables.put("foo", TableDescriptorBuilder.newBuilder(TableName.valueOf("foo")).build());
114    mockTables.put("bar", TableDescriptorBuilder.newBuilder(TableName.valueOf("bar")).build());
115
116    TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
117    Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
118
119    Mockito.doReturn(mockTables).when(tableDescriptors).getAll();
120
121    List<TableDescriptor> tables = new ArrayList<>();
122
123    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
124
125    assertNull(errorMessage);
126    assertEquals(2, tables.size());
127  }
128
129  @Test
130  public void testGetUserTablesFilterOutSystemTables() throws IOException {
131    Map<String, TableDescriptor> mockTables = new HashMap<>();
132    mockTables.put("foo", TableDescriptorBuilder.newBuilder(TableName.valueOf("foo")).build());
133    mockTables.put("bar", TableDescriptorBuilder.newBuilder(TableName.valueOf("bar")).build());
134    mockTables.put("meta",
135      TableDescriptorBuilder.newBuilder(TableName.valueOf("hbase", "meta")).build());
136
137    TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
138    Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
139
140    Mockito.doReturn(mockTables).when(tableDescriptors).getAll();
141
142    List<TableDescriptor> tables = new ArrayList<>();
143
144    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
145
146    assertNull(errorMessage);
147    assertEquals(2, tables.size());
148  }
149
150  @Test
151  public void testGetUserTablesNoUserTables() throws IOException {
152    Map<Object, Object> emptyMap = Collections.emptyMap();
153
154    TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
155    Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
156
157    Mockito.doReturn(emptyMap).when(tableDescriptors).getAll();
158
159    List<TableDescriptor> tables = new ArrayList<>();
160
161    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
162
163    assertNull(errorMessage);
164    assertEquals(0, tables.size());
165  }
166
167  @Test
168  public void testGetUserTablesMasterNotInitialized() {
169    Mockito.doReturn(false).when(master).isInitialized();
170
171    List<TableDescriptor> tables = new ArrayList<>();
172
173    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
174
175    assertNull(errorMessage);
176    assertEquals(0, tables.size());
177  }
178
179  @Test
180  public void testGetUserTablesException() throws IOException {
181    TableDescriptors tableDescriptors = Mockito.mock(TableDescriptors.class);
182    Mockito.doReturn(tableDescriptors).when(master).getTableDescriptors();
183
184    Mockito.doThrow(new IOException("some error")).when(tableDescriptors).getAll();
185
186    List<TableDescriptor> tables = new ArrayList<>();
187    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
188    assertEquals("Got user tables error, some error", errorMessage);
189  }
190
191  @Test
192  public void testGetFragmentationInfoTurnedOff() throws IOException {
193    conf.setBoolean("hbase.master.ui.fragmentation.enabled", false);
194    assertNull(MasterStatusUtil.getFragmentationInfo(master, conf));
195  }
196
197  @Test
198  public void testGetFragmentationInfoTurnedOn() throws IOException {
199    conf.setBoolean("hbase.master.ui.fragmentation.enabled", true);
200    Map<String, Integer> fragmentationInfo = MasterStatusUtil.getFragmentationInfo(master, conf);
201    assertNotNull(fragmentationInfo);
202    assertFalse(fragmentationInfo.isEmpty());
203  }
204
205  @Test
206  public void testGetMetaLocationOrNull() {
207    mockMetaLocation(true);
208
209    ServerName location = MasterStatusUtil.getMetaLocationOrNull(master);
210    assertNotNull(location);
211    assertEquals(FAKE_HOST, location);
212  }
213
214  @Test
215  public void testGetMetaLocationOrNullNotOpen() {
216    mockMetaLocation(false);
217
218    ServerName location = MasterStatusUtil.getMetaLocationOrNull(master);
219    assertNull(location);
220  }
221
222  private void mockMetaLocation(boolean isOpen) {
223    RegionStates rs = master.getAssignmentManager().getRegionStates();
224    RegionStateNode rsn = Mockito.mock(RegionStateNode.class);
225    Mockito.doReturn(rsn).when(rs).getRegionStateNode(RegionInfoBuilder.FIRST_META_REGIONINFO);
226    Mockito.doReturn(isOpen).when(rsn).isInState(RegionState.State.OPEN);
227    if (isOpen) {
228      Mockito.doReturn(FAKE_HOST).when(rsn).getRegionLocation();
229    }
230  }
231
232  @Test
233  public void testServerNameLink() {
234    Mockito.doReturn(16030).when(master).getRegionServerInfoPort(FAKE_HOST);
235
236    String link = MasterStatusUtil.serverNameLink(master, FAKE_HOST);
237
238    assertNotNull(link);
239    assertEquals("<a href=\"//fakehost:16030/regionserver.jsp\">fakehost,12345,1234567890</a>",
240      link);
241  }
242
243  @Test
244  public void testServerNameLinkNoInfoPort() {
245    Mockito.doReturn(-1).when(master).getRegionServerInfoPort(FAKE_HOST);
246
247    String link = MasterStatusUtil.serverNameLink(master, FAKE_HOST);
248
249    assertNotNull(link);
250    assertEquals("fakehost,12345,1234567890", link);
251  }
252}