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.assertEquals;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.IOException;
26  import java.io.StringWriter;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.NavigableMap;
30  import java.util.Set;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  import org.apache.hadoop.conf.Configuration;
35  import org.apache.hadoop.hbase.HBaseConfiguration;
36  import org.apache.hadoop.hbase.HRegionInfo;
37  import org.apache.hadoop.hbase.HTableDescriptor;
38  import org.apache.hadoop.hbase.MediumTests;
39  import org.apache.hadoop.hbase.ServerName;
40  import org.apache.hadoop.hbase.client.HBaseAdmin;
41  import org.apache.hadoop.hbase.master.AssignmentManager.RegionState;
42  import org.apache.hadoop.hbase.tmpl.master.AssignmentManagerStatusTmpl;
43  import org.apache.hadoop.hbase.tmpl.master.MasterStatusTmpl;
44  import org.apache.hadoop.hbase.util.Bytes;
45  import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
46  import org.junit.Before;
47  import org.junit.Test;
48  import org.junit.experimental.categories.Category;
49  import org.mockito.Mockito;
50  
51  import com.google.common.collect.Lists;
52  import com.google.common.collect.Maps;
53  
54  /**
55   * Tests for the master status page and its template.
56   */
57  @Category(MediumTests.class)
58  public class TestMasterStatusServlet {
59    
60    private HMaster master;
61    private Configuration conf;
62    private HBaseAdmin admin;
63  
64    static final ServerName FAKE_HOST = 
65      new ServerName("fakehost", 12345, 1234567890);
66    static final HTableDescriptor FAKE_TABLE =
67      new HTableDescriptor("mytable");
68    static final HRegionInfo FAKE_HRI =
69        new HRegionInfo(FAKE_TABLE.getName(), Bytes.toBytes("a"), Bytes.toBytes("b"));
70  
71    @Before
72    public void setupBasicMocks() {
73      conf = HBaseConfiguration.create();
74      
75      master = Mockito.mock(HMaster.class);
76      Mockito.doReturn(FAKE_HOST).when(master).getServerName();
77      Mockito.doReturn(conf).when(master).getConfiguration();
78      
79      // Fake ActiveMasterManager
80      ActiveMasterManager amm = Mockito.mock(ActiveMasterManager.class);
81      Mockito.doReturn(amm).when(master).getActiveMasterManager();
82      Mockito.doReturn(FAKE_HOST).when(amm).getActiveMaster();
83  
84      // Fake serverManager
85      ServerManager serverManager = Mockito.mock(ServerManager.class);
86      Mockito.doReturn(1.0).when(serverManager).getAverageLoad();
87      Mockito.doReturn(serverManager).when(master).getServerManager();
88  
89      // Fake AssignmentManager and RIT
90      AssignmentManager am = Mockito.mock(AssignmentManager.class);
91      NavigableMap<String, RegionState> regionsInTransition =
92        Maps.newTreeMap();
93      regionsInTransition.put("r1",
94          new RegionState(FAKE_HRI, RegionState.State.CLOSING, 12345L, FAKE_HOST));
95      Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
96      Mockito.doReturn(am).when(master).getAssignmentManager();
97      
98      // Fake ZKW
99      ZooKeeperWatcher zkw = Mockito.mock(ZooKeeperWatcher.class);
100     Mockito.doReturn("fakequorum").when(zkw).getQuorum();
101     Mockito.doReturn(zkw).when(master).getZooKeeperWatcher();
102 
103     // Mock admin
104     admin = Mockito.mock(HBaseAdmin.class); 
105     Mockito.when(admin.getConfiguration()).thenReturn(conf);
106   }
107   
108 
109   private void setupMockTables() throws IOException {
110     HTableDescriptor tables[] = new HTableDescriptor[] {
111         new HTableDescriptor("foo"),
112         new HTableDescriptor("bar")
113     };
114     Mockito.doReturn(tables).when(admin).listTables();
115   }
116   
117   @Test
118   public void testStatusTemplateNoTables() throws IOException {
119     new MasterStatusTmpl().render(new StringWriter(),
120         master, admin);
121   }
122   
123   @Test
124   public void testStatusTemplateRootAvailable() throws IOException {
125     new MasterStatusTmpl()
126       .setRootLocation(new ServerName("rootserver:123,12345"))
127       .render(new StringWriter(),
128         master, admin);
129   }
130   
131   @Test
132   public void testStatusTemplateRootAndMetaAvailable() throws IOException {
133     setupMockTables();
134     
135     new MasterStatusTmpl()
136       .setRootLocation(new ServerName("rootserver:123,12345"))
137       .setMetaLocation(new ServerName("metaserver:123,12345"))
138       .render(new StringWriter(),
139         master, admin);
140   }
141 
142   @Test
143   public void testStatusTemplateWithServers() throws IOException {
144     setupMockTables();
145     
146     List<ServerName> servers = Lists.newArrayList(
147         new ServerName("rootserver:123,12345"),
148         new ServerName("metaserver:123,12345"));
149     Set<ServerName> deadServers = new HashSet<ServerName>(
150         Lists.newArrayList(
151         new ServerName("badserver:123,12345"),
152         new ServerName("uglyserver:123,12345"))
153     );
154 
155     new MasterStatusTmpl()
156       .setRootLocation(new ServerName("rootserver:123,12345"))
157       .setMetaLocation(new ServerName("metaserver:123,12345"))
158       .setServers(servers)
159       .setDeadServers(deadServers)
160       .render(new StringWriter(),
161         master, admin);
162   }
163   
164   @Test
165   public void testAssignmentManagerTruncatedList() throws IOException {
166     AssignmentManager am = Mockito.mock(AssignmentManager.class);
167     
168     // Add 100 regions as in-transition
169     NavigableMap<String, RegionState> regionsInTransition =
170       Maps.newTreeMap();
171     for (byte i = 0; i < 100; i++) {
172       HRegionInfo hri = new HRegionInfo(FAKE_TABLE.getName(),
173           new byte[]{i}, new byte[]{(byte) (i+1)});
174       regionsInTransition.put(hri.getEncodedName(),
175           new RegionState(hri, RegionState.State.CLOSING, 12345L, FAKE_HOST));
176     }
177     // Add META in transition as well
178     regionsInTransition.put(
179         HRegionInfo.FIRST_META_REGIONINFO.getEncodedName(),
180         new RegionState(HRegionInfo.FIRST_META_REGIONINFO,
181                         RegionState.State.CLOSING, 12345L, FAKE_HOST));
182     Mockito.doReturn(regionsInTransition).when(am).getRegionsInTransition();
183 
184     // Render to a string
185     StringWriter sw = new StringWriter();
186     new AssignmentManagerStatusTmpl()
187       .setLimit(50)
188       .render(sw, am);
189     String result = sw.toString();
190 
191     // Should always include META
192     assertTrue(result.contains(HRegionInfo.FIRST_META_REGIONINFO.getEncodedName()));
193     
194     // Make sure we only see 50 of them
195     Matcher matcher = Pattern.compile("CLOSING").matcher(result);
196     int count = 0;
197     while (matcher.find()) {
198       count++;
199     }
200     assertEquals(50, count);
201   }
202 
203   @org.junit.Rule
204   public org.apache.hadoop.hbase.ResourceCheckerJUnitRule cu =
205     new org.apache.hadoop.hbase.ResourceCheckerJUnitRule();
206 }
207