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.regionserver.http;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertTrue;
022
023import java.io.BufferedReader;
024import java.io.IOException;
025import java.io.InputStreamReader;
026import java.net.HttpURLConnection;
027import java.net.URL;
028import java.util.List;
029import org.apache.hadoop.conf.Configuration;
030import org.apache.hadoop.fs.Path;
031import org.apache.hadoop.hbase.HBaseClassTestRule;
032import org.apache.hadoop.hbase.HBaseTestingUtil;
033import org.apache.hadoop.hbase.HConstants;
034import org.apache.hadoop.hbase.LocalHBaseCluster;
035import org.apache.hadoop.hbase.ServerName;
036import org.apache.hadoop.hbase.TableName;
037import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
038import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
039import org.apache.hadoop.hbase.client.TableDescriptor;
040import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
041import org.apache.hadoop.hbase.master.HMaster;
042import org.apache.hadoop.hbase.master.ServerManager;
043import org.apache.hadoop.hbase.testclassification.MediumTests;
044import org.apache.hadoop.hbase.testclassification.RegionServerTests;
045import org.apache.hadoop.hbase.util.CommonFSUtils;
046import org.junit.AfterClass;
047import org.junit.BeforeClass;
048import org.junit.ClassRule;
049import org.junit.Rule;
050import org.junit.Test;
051import org.junit.experimental.categories.Category;
052import org.junit.rules.TestName;
053
054/**
055 * Tests for the region server status page and its template.
056 */
057@Category({ RegionServerTests.class, MediumTests.class })
058public class TestRSStatusPage {
059
060  @ClassRule
061  public static final HBaseClassTestRule CLASS_RULE =
062    HBaseClassTestRule.forClass(TestRSStatusPage.class);
063
064  private static LocalHBaseCluster CLUSTER;
065
066  private final static HBaseTestingUtil UTIL = new HBaseTestingUtil();
067  public static final String TEST_TABLE_NAME_1 = "TEST_TABLE_1";
068  public static final String TEST_TABLE_NAME_2 = "TEST_TABLE_2";
069
070  @Rule
071  public TestName name = new TestName();
072
073  @BeforeClass
074  public static void beforeClass() throws Exception {
075    Configuration conf = UTIL.getConfiguration();
076    UTIL.startMiniZKCluster();
077
078    UTIL.startMiniDFSCluster(1);
079    Path rootdir = UTIL.getDataTestDirOnTestFS("TestRSStatusPage");
080    CommonFSUtils.setRootDir(conf, rootdir);
081
082    // The info servers do not run in tests by default.
083    // Set them to ephemeral ports so they will start
084    // setup configuration
085    conf.setInt(HConstants.MASTER_INFO_PORT, 0);
086    conf.setInt(HConstants.REGIONSERVER_INFO_PORT, 0);
087
088    CLUSTER = new LocalHBaseCluster(conf, 1);
089    CLUSTER.startup();
090    CLUSTER.getActiveMaster().waitForMetaOnline();
091  }
092
093  /**
094   * Helper method to shut down the cluster (if running)
095   */
096  @AfterClass
097  public static void shutDownMiniCluster() throws Exception {
098    if (CLUSTER != null) {
099      CLUSTER.shutdown();
100      CLUSTER.join();
101    }
102    UTIL.shutdownMiniCluster();
103  }
104
105  @Test
106  public void testStatusPage() throws Exception {
107    HMaster master = CLUSTER.getActiveMaster();
108
109    int masterPort = master.getActiveMasterManager().getActiveMasterInfoPort();
110    ServerName activeMaster =
111      master.getActiveMaster().orElseThrow(() -> new IllegalStateException("No active master"));
112    String masterHostname = activeMaster.getHostname();
113
114    createTestTables(master);
115
116    ServerManager serverManager = master.getServerManager();
117    List<ServerName> onlineServersList = serverManager.getOnlineServersList();
118
119    assertEquals(1, onlineServersList.size());
120
121    ServerName firstServerName = onlineServersList.get(0);
122    int infoPort = master.getRegionServerInfoPort(firstServerName);
123    String hostname = firstServerName.getHostname();
124    int port = firstServerName.getPort();
125
126    String page = getRegionServerStatusPageContent(hostname, infoPort);
127
128    assertTrue(page.contains("<title>HBase Region Server: " + masterHostname + "</title>"));
129
130    String expectedPageHeader = "<h1>RegionServer <small>" + hostname + "," + port + ","
131      + firstServerName.getStartCode() + "</small></h1>";
132    assertTrue(page.contains(expectedPageHeader));
133    assertTrue(page.contains("<h2>Server Metrics</h2>"));
134    assertTrue(page.contains("<th>Requests Per Second</th>"));
135    assertTrue(page.contains("<h2>Block Cache</h2>"));
136    assertTrue(page.contains("<h2>Regions</h2>"));
137    assertTrue(page.contains("<h2>Replication Status</h2>"));
138    assertTrue(page.contains("<h2>Software Attributes</h2>"));
139
140    // Should have a link to master
141    String expectedMasterLink = "<a href=\"//" + masterHostname + ":" + masterPort
142      + "/master.jsp\">" + masterHostname + ":" + masterPort + "</a>";
143    assertTrue(page.contains(expectedMasterLink));
144  }
145
146  private static void createTestTables(HMaster master) throws IOException {
147    ColumnFamilyDescriptor cf = ColumnFamilyDescriptorBuilder.of("CF");
148    TableDescriptor tableDescriptor1 = TableDescriptorBuilder
149      .newBuilder(TableName.valueOf(TEST_TABLE_NAME_1)).setColumnFamily(cf).build();
150    master.createTable(tableDescriptor1, null, 0, 0);
151    TableDescriptor tableDescriptor2 = TableDescriptorBuilder
152      .newBuilder(TableName.valueOf(TEST_TABLE_NAME_2)).setColumnFamily(cf).build();
153    master.createTable(tableDescriptor2, null, 0, 0);
154    master.flushMasterStore();
155  }
156
157  private static String getRegionServerStatusPageContent(String hostname, int infoPort)
158    throws IOException {
159    URL url = new URL("http://" + hostname + ":" + infoPort + "/regionserver.jsp");
160    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
161    conn.connect();
162
163    assertEquals(200, conn.getResponseCode());
164    assertEquals("text/html;charset=utf-8", conn.getContentType());
165
166    return getResponseBody(conn);
167  }
168
169  private static String getResponseBody(HttpURLConnection conn) throws IOException {
170    StringBuilder sb = new StringBuilder();
171    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
172    String output;
173    while ((output = br.readLine()) != null) {
174      sb.append(output);
175    }
176    return sb.toString();
177  }
178}