1   /**
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master;
21  
22  import static org.junit.Assert.*;
23  
24  import java.io.IOException;
25  import java.io.StringWriter;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.NavigableMap;
29  import java.util.Set;
30  import java.util.regex.Matcher;
31  import java.util.regex.Pattern;
32  
33  import org.apache.hadoop.conf.Configuration;
34  import org.apache.hadoop.hbase.*;
35  import org.apache.hadoop.hbase.client.HBaseAdmin;
36  import org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
37  import org.apache.hadoop.hbase.master.HMaster;
38  import org.apache.hadoop.hbase.master.ServerManager;
39  import org.apache.hadoop.hbase.util.Bytes;
40  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
41  import org.apache.hadoop.hbase.tmpl.master.AssignmentManagerStatusTmpl;
42  import org.apache.hadoop.hbase.tmpl.master.MasterStatusTmpl;
43  import org.junit.Before;
44  import org.junit.Test;
45  import org.junit.experimental.categories.Category;
46  import org.mockito.Mockito;
47  
48  import com.google.common.collect.Lists;
49  import com.google.common.collect.Maps;
50  
51  /**
52   * Tests for the master status page and its template.
53   */
54  @Category(MediumTests.class)
55  public class TestMasterStatusServlet {
56    
57    private HMaster master;
58    private Configuration conf;
59    private HBaseAdmin admin;
60  
61    static final ServerName FAKE_HOST = 
62      new ServerName("fakehost", 12345, 1234567890);
63    static final HTableDescriptor FAKE_TABLE =
64      new HTableDescriptor("mytable");
65    static final HRegionInfo FAKE_HRI =
66        new HRegionInfo(FAKE_TABLE.getName(), Bytes.toBytes("a"), Bytes.toBytes("b"));
67  
68    @Before
69    public void setupBasicMocks() {
70      conf = HBaseConfiguration.create();
71      
72      master = Mockito.mock(HMaster.class);
73      Mockito.doReturn(FAKE_HOST).when(master).getServerName();
74      Mockito.doReturn(conf).when(master).getConfiguration();
75      
76      // Fake serverManager
77      ServerManager serverManager = Mockito.mock(ServerManager.class);
78      Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
79      Mockito.doReturn(serverManager).when(master).getServerManager();
80  
81      // Fake AssignmentManager and RIT
82      AssignmentManager am = Mockito.mock(AssignmentManager.class);
83      NavigableMap<String, RegionState> regionsInTransition =
84        Maps.newTreeMap();
85      regionsInTransition.put("r1",
86          new RegionState(FAKE_HRI, RegionState.State.CLOSING, 12345L, FAKE_HOST));
87      Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
88      Mockito.doReturn(am).when(master).getAssignmentManager();
89      
90      // Fake ZKW
91      ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class);
92      Mockito.doReturn("fakequorum").when(zkw).getQuorum();
93      Mockito.doReturn(zkw).when(master).getZooKeeperWatcher();
94  
95      // Mock admin
96      admin = Mockito.mock(HBaseAdmin.class); 
97    }
98    
99  
100   private void setupMockTables() throws IOException {
101     HTableDescriptor tables[] = new HTableDescriptor[] {
102         new HTableDescriptor("foo"),
103         new HTableDescriptor("bar")
104     };
105     Mockito.doReturn(tables).when(admin).listTables();
106   }
107   
108   @Test
109   public void testStatusTemplateNoTables() throws IOException {
110     new MasterStatusTmpl().render(new StringWriter(),
111         master, admin);
112   }
113   
114   @Test
115   public void testStatusTemplateRootAvailable() throws IOException {
116     new MasterStatusTmpl()
117       .setRootLocation(new ServerName("rootserver:123,12345"))
118       .render(new StringWriter(),
119         master, admin);
120   }
121   
122   @Test
123   public void testStatusTemplateRootAndMetaAvailable() throws IOException {
124     setupMockTables();
125     
126     new MasterStatusTmpl()
127       .setRootLocation(new ServerName("rootserver:123,12345"))
128       .setMetaLocation(new ServerName("metaserver:123,12345"))
129       .render(new StringWriter(),
130         master, admin);
131   }
132 
133   @Test
134   public void testStatusTemplateWithServers() throws IOException {
135     setupMockTables();
136     
137     List<ServerName> servers = Lists.newArrayList(
138         new ServerName("rootserver:123,12345"),
139         new ServerName("metaserver:123,12345"));
140     Set<ServerName> deadServers = new HashSet<ServerName>(
141         Lists.newArrayList(
142         new ServerName("badserver:123,12345"),
143         new ServerName("uglyserver:123,12345"))
144     );
145 
146     new MasterStatusTmpl()
147       .setRootLocation(new ServerName("rootserver:123,12345"))
148       .setMetaLocation(new ServerName("metaserver:123,12345"))
149       .setServers(servers)
150       .setDeadServers(deadServers)
151       .render(new StringWriter(),
152         master, admin);
153   }
154   
155   @Test
156   public void testAssignmentManagerTruncatedList() throws IOException {
157     AssignmentManager am = Mockito.mock(AssignmentManager.class);
158     
159     // Add 100 regions as in-transition
160     NavigableMap<String, RegionState> regionsInTransition =
161       Maps.newTreeMap();
162     for (byte i = 0; i < 100; i++) {
163       HRegionInfo hri = new HRegionInfo(FAKE_TABLE.getName(),
164           new byte[]{i}, new byte[]{(byte) (i+1)});
165       regionsInTransition.put(hri.getEncodedName(),
166           new RegionState(hri, RegionState.State.CLOSING, 12345L, FAKE_HOST));
167     }
168     // Add META in transition as well
169     regionsInTransition.put(
170         HRegionInfo.FIRST_META_REGIONINFO.getEncodedName(),
171         new RegionState(HRegionInfo.FIRST_META_REGIONINFO,
172                         RegionState.State.CLOSING, 12345L, FAKE_HOST));
173     Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
174 
175     // Render to a string
176     StringWriter sw = new StringWriter();
177     new AssignmentManagerStatusTmpl()
178       .setLimit(50)
179       .render(sw, am);
180     String result = sw.toString();
181 
182     // Should always include META
183     assertTrue(result.contains(HRegionInfo.FIRST_META_REGIONINFO.getEncodedName()));
184     
185     // Make sure we only see 50 of them
186     Matcher matcher = Pattern.compile("CLOSING").matcher(result);
187     int count = 0;
188     while (matcher.find()) {
189       count++;
190     }
191     assertEquals(50, count);
192   }
193 
194   @org.junit.Rule
195   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
196     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
197 }
198