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.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022import static org.junit.Assert.assertTrue;
023
024import java.io.BufferedReader;
025import java.io.IOException;
026import java.io.InputStreamReader;
027import java.net.HttpURLConnection;
028import java.net.URL;
029import java.util.ArrayList;
030import java.util.List;
031import org.apache.hadoop.conf.Configuration;
032import org.apache.hadoop.fs.Path;
033import org.apache.hadoop.hbase.HBaseClassTestRule;
034import org.apache.hadoop.hbase.HBaseTestingUtil;
035import org.apache.hadoop.hbase.HConstants;
036import org.apache.hadoop.hbase.LocalHBaseCluster;
037import org.apache.hadoop.hbase.ServerName;
038import org.apache.hadoop.hbase.TableName;
039import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
040import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
041import org.apache.hadoop.hbase.client.TableDescriptor;
042import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
043import org.apache.hadoop.hbase.master.HMaster;
044import org.apache.hadoop.hbase.master.ServerManager;
045import org.apache.hadoop.hbase.testclassification.MasterTests;
046import org.apache.hadoop.hbase.testclassification.MediumTests;
047import org.apache.hadoop.hbase.util.CommonFSUtils;
048import org.apache.hadoop.hbase.util.VersionInfo;
049import org.junit.AfterClass;
050import org.junit.BeforeClass;
051import org.junit.ClassRule;
052import org.junit.Rule;
053import org.junit.Test;
054import org.junit.experimental.categories.Category;
055import org.junit.rules.TestName;
056
057@Category({ MasterTests.class, MediumTests.class })
058public class TestMasterStatusPage {
059
060  @ClassRule
061  public static final HBaseClassTestRule CLASS_RULE =
062    HBaseClassTestRule.forClass(TestMasterStatusPage.class);
063
064  private final static HBaseTestingUtil UTIL = new HBaseTestingUtil();
065  public static final String TEST_TABLE_NAME_1 = "TEST_TABLE_1";
066  public static final String TEST_TABLE_NAME_2 = "TEST_TABLE_2";
067
068  private static LocalHBaseCluster CLUSTER;
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("TestMasterStatusPage");
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 testMasterStatusPage() throws Exception {
107    HMaster master = CLUSTER.getActiveMaster();
108
109    createTestTables(master);
110
111    String page = getMasterStatusPageContent();
112
113    String hostname = master.getServerName().getHostname();
114    assertTrue(page.contains("<h1>Master <small>" + hostname + "</small></h1>"));
115    assertTrue(page.contains("<h2><a name=\"regionservers\">Region Servers</a></h2>"));
116    assertRegionServerLinks(master, page);
117
118    assertTrue(page.contains("<h2>Backup Masters</h2>"));
119    assertTrue(page.contains("<h2><a name=\"tables\">Tables</a></h2>"));
120    assertTableLinks(master, page);
121
122    assertTrue(page.contains("<h2><a name=\"region_visualizer\"></a>Region Visualizer</h2>"));
123    assertTrue(page.contains("<h2><a name=\"peers\">Peers</a></h2>"));
124    assertTrue(page.contains("<h2><a name=\"tasks\">Tasks</a></h2>"));
125    assertTrue(page.contains("<h2><a name=\"attributes\">Software Attributes</a></h2>"));
126
127    assertTrue(page.contains(VersionInfo.getVersion()));
128  }
129
130  private String getMasterStatusPageContent() throws IOException {
131    URL url = new URL(getInfoServerHostAndPort() + "/master-status");
132    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
133    conn.connect();
134
135    assertEquals(200, conn.getResponseCode());
136    assertEquals("text/html;charset=utf-8", conn.getContentType());
137
138    return getResponseBody(conn);
139  }
140
141  private static void createTestTables(HMaster master) throws IOException {
142    ColumnFamilyDescriptor cf = ColumnFamilyDescriptorBuilder.of("CF");
143    TableDescriptor tableDescriptor1 = TableDescriptorBuilder
144      .newBuilder(TableName.valueOf(TEST_TABLE_NAME_1)).setColumnFamily(cf).build();
145    master.createTable(tableDescriptor1, null, 0, 0);
146    TableDescriptor tableDescriptor2 = TableDescriptorBuilder
147      .newBuilder(TableName.valueOf(TEST_TABLE_NAME_2)).setColumnFamily(cf).build();
148    master.createTable(tableDescriptor2, null, 0, 0);
149    master.flushMasterStore();
150  }
151
152  private String getInfoServerHostAndPort() {
153    return "http://localhost:" + CLUSTER.getActiveMaster().getInfoServer().getPort();
154  }
155
156  private static String getResponseBody(HttpURLConnection conn) throws IOException {
157    StringBuilder sb = new StringBuilder();
158    BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
159    String output;
160    while ((output = br.readLine()) != null) {
161      sb.append(output);
162    }
163    return sb.toString();
164  }
165
166  private static void assertRegionServerLinks(HMaster master, String responseBody) {
167    ServerManager serverManager = master.getServerManager();
168    List<ServerName> servers = serverManager.getOnlineServersList();
169    assertEquals(1, servers.size());
170    for (ServerName serverName : servers) {
171      String expectedRsLink = MasterStatusUtil.serverNameLink(master, serverName);
172      assertTrue(responseBody.contains(expectedRsLink));
173    }
174  }
175
176  private static void assertTableLinks(HMaster master, String responseBody) {
177    List<TableDescriptor> tables = new ArrayList<>();
178    String errorMessage = MasterStatusUtil.getUserTables(master, tables);
179    assertNull(errorMessage);
180    assertEquals(2, tables.size());
181    for (TableDescriptor table : tables) {
182      String tableName = table.getTableName().getNameAsString();
183      String expectedTableLink = "<a href=table.jsp?name=" + tableName + ">" + tableName + "</a>";
184      assertTrue(responseBody.contains(expectedTableLink));
185    }
186  }
187}