1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.hadoop.yarn.server.resourcemanager.webapp;
20 
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertTrue;
23 import static org.junit.Assert.fail;
24 import static org.mockito.Matchers.anyBoolean;
25 import static org.mockito.Matchers.isA;
26 import static org.mockito.Mockito.mock;
27 import static org.mockito.Mockito.when;
28 
29 import java.io.StringReader;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.Set;
33 
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
36 import javax.ws.rs.core.MediaType;
37 import javax.xml.parsers.DocumentBuilder;
38 import javax.xml.parsers.DocumentBuilderFactory;
39 
40 import org.apache.hadoop.conf.Configuration;
41 import org.apache.hadoop.service.Service.STATE;
42 import org.apache.hadoop.util.VersionInfo;
43 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest;
44 import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsResponse;
45 import org.apache.hadoop.yarn.api.records.ApplicationId;
46 import org.apache.hadoop.yarn.api.records.ApplicationReport;
47 import org.apache.hadoop.yarn.api.records.QueueState;
48 import org.apache.hadoop.yarn.conf.YarnConfiguration;
49 import org.apache.hadoop.yarn.server.resourcemanager.ClientRMService;
50 import org.apache.hadoop.yarn.server.resourcemanager.ClusterMetrics;
51 import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
52 import org.apache.hadoop.yarn.server.resourcemanager.RMContextImpl;
53 import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager;
54 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.QueueMetrics;
55 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler;
56 import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler;
57 import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo;
58 import org.apache.hadoop.yarn.util.YarnVersionInfo;
59 import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
60 import org.apache.hadoop.yarn.webapp.JerseyTestBase;
61 import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
62 import org.codehaus.jettison.json.JSONException;
63 import org.codehaus.jettison.json.JSONObject;
64 import org.junit.Before;
65 import org.junit.BeforeClass;
66 import org.junit.Test;
67 import org.w3c.dom.Document;
68 import org.w3c.dom.Element;
69 import org.w3c.dom.NodeList;
70 import org.xml.sax.InputSource;
71 
72 import com.google.inject.Guice;
73 import com.google.inject.Injector;
74 import com.google.inject.servlet.GuiceServletContextListener;
75 import com.google.inject.servlet.ServletModule;
76 import com.sun.jersey.api.client.ClientResponse;
77 import com.sun.jersey.api.client.ClientResponse.Status;
78 import com.sun.jersey.api.client.UniformInterfaceException;
79 import com.sun.jersey.api.client.WebResource;
80 import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
81 import com.sun.jersey.test.framework.WebAppDescriptor;
82 
83 public class TestRMWebServices extends JerseyTestBase {
84 
85   private static MockRM rm;
86 
87   private Injector injector = Guice.createInjector(new ServletModule() {
88     @Override
89     protected void configureServlets() {
90       bind(JAXBContextResolver.class);
91       bind(RMWebServices.class);
92       bind(GenericExceptionHandler.class);
93       Configuration conf = new Configuration();
94       conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class,
95           ResourceScheduler.class);
96       rm = new MockRM(conf);
97       bind(ResourceManager.class).toInstance(rm);
98       serve("/*").with(GuiceContainer.class);
99     }
100   });
101 
102   public class GuiceServletConfig extends GuiceServletContextListener {
103 
104     @Override
getInjector()105     protected Injector getInjector() {
106       return injector;
107     }
108   }
109 
110   @Before
111   @Override
setUp()112   public void setUp() throws Exception {
113     super.setUp();
114   }
115 
TestRMWebServices()116   public TestRMWebServices() {
117     super(new WebAppDescriptor.Builder(
118         "org.apache.hadoop.yarn.server.resourcemanager.webapp")
119         .contextListenerClass(GuiceServletConfig.class)
120         .filterClass(com.google.inject.servlet.GuiceFilter.class)
121         .contextPath("jersey-guice-filter").servletPath("/").build());
122   }
123 
124   @BeforeClass
initClusterMetrics()125   public static void initClusterMetrics() {
126     ClusterMetrics clusterMetrics = ClusterMetrics.getMetrics();
127     clusterMetrics.incrDecommisionedNMs();
128     clusterMetrics.incrNumActiveNodes();
129     clusterMetrics.incrNumLostNMs();
130     clusterMetrics.incrNumRebootedNMs();
131     clusterMetrics.incrNumUnhealthyNMs();
132   }
133 
134   @Test
testInfoXML()135   public void testInfoXML() throws JSONException, Exception {
136     WebResource r = resource();
137     ClientResponse response = r.path("ws").path("v1").path("cluster")
138         .path("info").accept("application/xml").get(ClientResponse.class);
139     assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
140     String xml = response.getEntity(String.class);
141     verifyClusterInfoXML(xml);
142   }
143 
144   @Test
testInvalidUri()145   public void testInvalidUri() throws JSONException, Exception {
146     WebResource r = resource();
147     String responseStr = "";
148     try {
149       responseStr = r.path("ws").path("v1").path("cluster").path("bogus")
150           .accept(MediaType.APPLICATION_JSON).get(String.class);
151       fail("should have thrown exception on invalid uri");
152     } catch (UniformInterfaceException ue) {
153       ClientResponse response = ue.getResponse();
154       assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
155 
156       WebServicesTestUtils.checkStringMatch(
157           "error string exists and shouldn't", "", responseStr);
158     }
159   }
160 
161   @Test
testInvalidUri2()162   public void testInvalidUri2() throws JSONException, Exception {
163     WebResource r = resource();
164     String responseStr = "";
165     try {
166       responseStr = r.accept(MediaType.APPLICATION_JSON).get(String.class);
167       fail("should have thrown exception on invalid uri");
168     } catch (UniformInterfaceException ue) {
169       ClientResponse response = ue.getResponse();
170       assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
171       WebServicesTestUtils.checkStringMatch(
172           "error string exists and shouldn't", "", responseStr);
173     }
174   }
175 
176   @Test
testInvalidAccept()177   public void testInvalidAccept() throws JSONException, Exception {
178     WebResource r = resource();
179     String responseStr = "";
180     try {
181       responseStr = r.path("ws").path("v1").path("cluster")
182           .accept(MediaType.TEXT_PLAIN).get(String.class);
183       fail("should have thrown exception on invalid uri");
184     } catch (UniformInterfaceException ue) {
185       ClientResponse response = ue.getResponse();
186       assertEquals(Status.INTERNAL_SERVER_ERROR,
187           response.getClientResponseStatus());
188       WebServicesTestUtils.checkStringMatch(
189           "error string exists and shouldn't", "", responseStr);
190     }
191   }
192 
193   @Test
testCluster()194   public void testCluster() throws JSONException, Exception {
195     WebResource r = resource();
196     ClientResponse response = r.path("ws").path("v1").path("cluster")
197         .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
198 
199     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
200     JSONObject json = response.getEntity(JSONObject.class);
201     verifyClusterInfo(json);
202   }
203 
204   @Test
testClusterSlash()205   public void testClusterSlash() throws JSONException, Exception {
206     WebResource r = resource();
207     // test with trailing "/" to make sure acts same as without slash
208     ClientResponse response = r.path("ws").path("v1").path("cluster/")
209         .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
210 
211     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
212     JSONObject json = response.getEntity(JSONObject.class);
213     verifyClusterInfo(json);
214   }
215 
216   @Test
testClusterDefault()217   public void testClusterDefault() throws JSONException, Exception {
218     WebResource r = resource();
219     // test with trailing "/" to make sure acts same as without slash
220     ClientResponse response = r.path("ws").path("v1").path("cluster")
221         .get(ClientResponse.class);
222 
223     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
224     JSONObject json = response.getEntity(JSONObject.class);
225     verifyClusterInfo(json);
226   }
227 
228   @Test
testInfo()229   public void testInfo() throws JSONException, Exception {
230     WebResource r = resource();
231     ClientResponse response = r.path("ws").path("v1").path("cluster")
232         .path("info").accept(MediaType.APPLICATION_JSON)
233         .get(ClientResponse.class);
234 
235     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
236     JSONObject json = response.getEntity(JSONObject.class);
237     verifyClusterInfo(json);
238   }
239 
240   @Test
testInfoSlash()241   public void testInfoSlash() throws JSONException, Exception {
242     // test with trailing "/" to make sure acts same as without slash
243     WebResource r = resource();
244     ClientResponse response = r.path("ws").path("v1").path("cluster")
245         .path("info/").accept(MediaType.APPLICATION_JSON)
246         .get(ClientResponse.class);
247 
248     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
249     JSONObject json = response.getEntity(JSONObject.class);
250     verifyClusterInfo(json);
251   }
252 
253   @Test
testInfoDefault()254   public void testInfoDefault() throws JSONException, Exception {
255     WebResource r = resource();
256     ClientResponse response = r.path("ws").path("v1").path("cluster")
257         .path("info").get(ClientResponse.class);
258 
259     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
260     JSONObject json = response.getEntity(JSONObject.class);
261     verifyClusterInfo(json);
262   }
263 
verifyClusterInfoXML(String xml)264   public void verifyClusterInfoXML(String xml) throws JSONException, Exception {
265     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
266     DocumentBuilder db = dbf.newDocumentBuilder();
267     InputSource is = new InputSource();
268     is.setCharacterStream(new StringReader(xml));
269     Document dom = db.parse(is);
270     NodeList nodes = dom.getElementsByTagName("clusterInfo");
271     assertEquals("incorrect number of elements", 1, nodes.getLength());
272 
273     for (int i = 0; i < nodes.getLength(); i++) {
274       Element element = (Element) nodes.item(i);
275 
276       verifyClusterGeneric(WebServicesTestUtils.getXmlLong(element, "id"),
277           WebServicesTestUtils.getXmlLong(element, "startedOn"),
278           WebServicesTestUtils.getXmlString(element, "state"),
279           WebServicesTestUtils.getXmlString(element, "haState"),
280           WebServicesTestUtils.getXmlString(
281               element, "haZooKeeperConnectionState"),
282           WebServicesTestUtils.getXmlString(element, "hadoopVersionBuiltOn"),
283           WebServicesTestUtils.getXmlString(element, "hadoopBuildVersion"),
284           WebServicesTestUtils.getXmlString(element, "hadoopVersion"),
285           WebServicesTestUtils.getXmlString(element,
286               "resourceManagerVersionBuiltOn"),
287           WebServicesTestUtils.getXmlString(element,
288               "resourceManagerBuildVersion"),
289           WebServicesTestUtils.getXmlString(element, "resourceManagerVersion"));
290     }
291   }
292 
verifyClusterInfo(JSONObject json)293   public void verifyClusterInfo(JSONObject json) throws JSONException,
294       Exception {
295     assertEquals("incorrect number of elements", 1, json.length());
296     JSONObject info = json.getJSONObject("clusterInfo");
297     assertEquals("incorrect number of elements", 12, info.length());
298     verifyClusterGeneric(info.getLong("id"), info.getLong("startedOn"),
299         info.getString("state"), info.getString("haState"),
300         info.getString("haZooKeeperConnectionState"),
301         info.getString("hadoopVersionBuiltOn"),
302         info.getString("hadoopBuildVersion"), info.getString("hadoopVersion"),
303         info.getString("resourceManagerVersionBuiltOn"),
304         info.getString("resourceManagerBuildVersion"),
305         info.getString("resourceManagerVersion"));
306 
307   }
308 
verifyClusterGeneric(long clusterid, long startedon, String state, String haState, String haZooKeeperConnectionState, String hadoopVersionBuiltOn, String hadoopBuildVersion, String hadoopVersion, String resourceManagerVersionBuiltOn, String resourceManagerBuildVersion, String resourceManagerVersion)309   public void verifyClusterGeneric(long clusterid, long startedon,
310       String state, String haState, String haZooKeeperConnectionState,
311       String hadoopVersionBuiltOn,
312       String hadoopBuildVersion, String hadoopVersion,
313       String resourceManagerVersionBuiltOn, String resourceManagerBuildVersion,
314       String resourceManagerVersion) {
315 
316     assertEquals("clusterId doesn't match: ",
317         ResourceManager.getClusterTimeStamp(), clusterid);
318     assertEquals("startedOn doesn't match: ",
319         ResourceManager.getClusterTimeStamp(), startedon);
320     assertTrue("stated doesn't match: " + state,
321         state.matches(STATE.INITED.toString()));
322     assertTrue("HA state doesn't match: " + haState,
323         haState.matches("INITIALIZING"));
324 
325     WebServicesTestUtils.checkStringMatch("hadoopVersionBuiltOn",
326         VersionInfo.getDate(), hadoopVersionBuiltOn);
327     WebServicesTestUtils.checkStringEqual("hadoopBuildVersion",
328         VersionInfo.getBuildVersion(), hadoopBuildVersion);
329     WebServicesTestUtils.checkStringMatch("hadoopVersion",
330         VersionInfo.getVersion(), hadoopVersion);
331 
332     WebServicesTestUtils.checkStringMatch("resourceManagerVersionBuiltOn",
333         YarnVersionInfo.getDate(), resourceManagerVersionBuiltOn);
334     WebServicesTestUtils.checkStringEqual("resourceManagerBuildVersion",
335         YarnVersionInfo.getBuildVersion(), resourceManagerBuildVersion);
336     WebServicesTestUtils.checkStringMatch("resourceManagerVersion",
337         YarnVersionInfo.getVersion(), resourceManagerVersion);
338   }
339 
340   @Test
testClusterMetrics()341   public void testClusterMetrics() throws JSONException, Exception {
342     WebResource r = resource();
343     ClientResponse response = r.path("ws").path("v1").path("cluster")
344         .path("metrics").accept(MediaType.APPLICATION_JSON)
345         .get(ClientResponse.class);
346 
347     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
348     JSONObject json = response.getEntity(JSONObject.class);
349     verifyClusterMetricsJSON(json);
350   }
351 
352   @Test
testClusterMetricsSlash()353   public void testClusterMetricsSlash() throws JSONException, Exception {
354     WebResource r = resource();
355     ClientResponse response = r.path("ws").path("v1").path("cluster")
356         .path("metrics/").accept(MediaType.APPLICATION_JSON)
357         .get(ClientResponse.class);
358 
359     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
360     JSONObject json = response.getEntity(JSONObject.class);
361     verifyClusterMetricsJSON(json);
362   }
363 
364   @Test
testClusterMetricsDefault()365   public void testClusterMetricsDefault() throws JSONException, Exception {
366     WebResource r = resource();
367     ClientResponse response = r.path("ws").path("v1").path("cluster")
368         .path("metrics").get(ClientResponse.class);
369 
370     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
371     JSONObject json = response.getEntity(JSONObject.class);
372     verifyClusterMetricsJSON(json);
373   }
374 
375   @Test
testClusterMetricsXML()376   public void testClusterMetricsXML() throws JSONException, Exception {
377     WebResource r = resource();
378     ClientResponse response = r.path("ws").path("v1").path("cluster")
379         .path("metrics").accept("application/xml").get(ClientResponse.class);
380     assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
381     String xml = response.getEntity(String.class);
382     verifyClusterMetricsXML(xml);
383   }
384 
verifyClusterMetricsXML(String xml)385   public void verifyClusterMetricsXML(String xml) throws JSONException,
386       Exception {
387     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
388     DocumentBuilder db = dbf.newDocumentBuilder();
389     InputSource is = new InputSource();
390     is.setCharacterStream(new StringReader(xml));
391     Document dom = db.parse(is);
392     NodeList nodes = dom.getElementsByTagName("clusterMetrics");
393     assertEquals("incorrect number of elements", 1, nodes.getLength());
394 
395     for (int i = 0; i < nodes.getLength(); i++) {
396       Element element = (Element) nodes.item(i);
397 
398       verifyClusterMetrics(
399           WebServicesTestUtils.getXmlInt(element, "appsSubmitted"),
400           WebServicesTestUtils.getXmlInt(element, "appsCompleted"),
401           WebServicesTestUtils.getXmlInt(element, "reservedMB"),
402           WebServicesTestUtils.getXmlInt(element, "availableMB"),
403           WebServicesTestUtils.getXmlInt(element, "allocatedMB"),
404           WebServicesTestUtils.getXmlInt(element, "reservedVirtualCores"),
405           WebServicesTestUtils.getXmlInt(element, "availableVirtualCores"),
406           WebServicesTestUtils.getXmlInt(element, "allocatedVirtualCores"),
407           WebServicesTestUtils.getXmlInt(element, "totalVirtualCores"),
408           WebServicesTestUtils.getXmlInt(element, "containersAllocated"),
409           WebServicesTestUtils.getXmlInt(element, "totalMB"),
410           WebServicesTestUtils.getXmlInt(element, "totalNodes"),
411           WebServicesTestUtils.getXmlInt(element, "lostNodes"),
412           WebServicesTestUtils.getXmlInt(element, "unhealthyNodes"),
413           WebServicesTestUtils.getXmlInt(element, "decommissionedNodes"),
414           WebServicesTestUtils.getXmlInt(element, "rebootedNodes"),
415           WebServicesTestUtils.getXmlInt(element, "activeNodes"));
416     }
417   }
418 
verifyClusterMetricsJSON(JSONObject json)419   public void verifyClusterMetricsJSON(JSONObject json) throws JSONException,
420       Exception {
421     assertEquals("incorrect number of elements", 1, json.length());
422     JSONObject clusterinfo = json.getJSONObject("clusterMetrics");
423     assertEquals("incorrect number of elements", 23, clusterinfo.length());
424     verifyClusterMetrics(
425         clusterinfo.getInt("appsSubmitted"), clusterinfo.getInt("appsCompleted"),
426         clusterinfo.getInt("reservedMB"), clusterinfo.getInt("availableMB"),
427         clusterinfo.getInt("allocatedMB"),
428         clusterinfo.getInt("reservedVirtualCores"), clusterinfo.getInt("availableVirtualCores"),
429         clusterinfo.getInt("allocatedVirtualCores"), clusterinfo.getInt("totalVirtualCores"),
430         clusterinfo.getInt("containersAllocated"),
431         clusterinfo.getInt("totalMB"), clusterinfo.getInt("totalNodes"),
432         clusterinfo.getInt("lostNodes"), clusterinfo.getInt("unhealthyNodes"),
433         clusterinfo.getInt("decommissionedNodes"),
434         clusterinfo.getInt("rebootedNodes"),clusterinfo.getInt("activeNodes"));
435   }
436 
verifyClusterMetrics(int submittedApps, int completedApps, int reservedMB, int availableMB, int allocMB, int reservedVirtualCores, int availableVirtualCores, int allocVirtualCores, int totalVirtualCores, int containersAlloc, int totalMB, int totalNodes, int lostNodes, int unhealthyNodes, int decommissionedNodes, int rebootedNodes, int activeNodes)437   public void verifyClusterMetrics(int submittedApps, int completedApps,
438       int reservedMB, int availableMB,
439       int allocMB, int reservedVirtualCores, int availableVirtualCores,
440       int allocVirtualCores, int totalVirtualCores,
441       int containersAlloc, int totalMB, int totalNodes,
442       int lostNodes, int unhealthyNodes, int decommissionedNodes,
443       int rebootedNodes, int activeNodes) throws JSONException, Exception {
444 
445     ResourceScheduler rs = rm.getResourceScheduler();
446     QueueMetrics metrics = rs.getRootQueueMetrics();
447     ClusterMetrics clusterMetrics = ClusterMetrics.getMetrics();
448 
449     long totalMBExpect =
450         metrics.getAvailableMB() + metrics.getAllocatedMB();
451     long totalVirtualCoresExpect =
452         metrics.getAvailableVirtualCores() + metrics.getAllocatedVirtualCores();
453     assertEquals("appsSubmitted doesn't match",
454         metrics.getAppsSubmitted(), submittedApps);
455     assertEquals("appsCompleted doesn't match",
456         metrics.getAppsCompleted(), completedApps);
457     assertEquals("reservedMB doesn't match",
458         metrics.getReservedMB(), reservedMB);
459     assertEquals("availableMB doesn't match",
460         metrics.getAvailableMB(), availableMB);
461     assertEquals("allocatedMB doesn't match",
462         metrics.getAllocatedMB(), allocMB);
463     assertEquals("reservedVirtualCores doesn't match",
464         metrics.getReservedVirtualCores(), reservedVirtualCores);
465     assertEquals("availableVirtualCores doesn't match",
466         metrics.getAvailableVirtualCores(), availableVirtualCores);
467     assertEquals("allocatedVirtualCores doesn't match",
468         totalVirtualCoresExpect, allocVirtualCores);
469     assertEquals("containersAllocated doesn't match", 0, containersAlloc);
470     assertEquals("totalMB doesn't match", totalMBExpect, totalMB);
471     assertEquals(
472         "totalNodes doesn't match",
473         clusterMetrics.getNumActiveNMs() + clusterMetrics.getNumLostNMs()
474             + clusterMetrics.getNumDecommisionedNMs()
475             + clusterMetrics.getNumRebootedNMs()
476             + clusterMetrics.getUnhealthyNMs(), totalNodes);
477     assertEquals("lostNodes doesn't match", clusterMetrics.getNumLostNMs(),
478         lostNodes);
479     assertEquals("unhealthyNodes doesn't match",
480         clusterMetrics.getUnhealthyNMs(), unhealthyNodes);
481     assertEquals("decommissionedNodes doesn't match",
482         clusterMetrics.getNumDecommisionedNMs(), decommissionedNodes);
483     assertEquals("rebootedNodes doesn't match",
484         clusterMetrics.getNumRebootedNMs(), rebootedNodes);
485     assertEquals("activeNodes doesn't match", clusterMetrics.getNumActiveNMs(),
486         activeNodes);
487   }
488 
489   @Test
testClusterSchedulerFifo()490   public void testClusterSchedulerFifo() throws JSONException, Exception {
491     WebResource r = resource();
492     ClientResponse response = r.path("ws").path("v1").path("cluster")
493         .path("scheduler").accept(MediaType.APPLICATION_JSON)
494         .get(ClientResponse.class);
495 
496     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
497     JSONObject json = response.getEntity(JSONObject.class);
498     verifyClusterSchedulerFifo(json);
499   }
500 
501   @Test
testClusterSchedulerFifoSlash()502   public void testClusterSchedulerFifoSlash() throws JSONException, Exception {
503     WebResource r = resource();
504     ClientResponse response = r.path("ws").path("v1").path("cluster")
505         .path("scheduler/").accept(MediaType.APPLICATION_JSON)
506         .get(ClientResponse.class);
507 
508     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
509     JSONObject json = response.getEntity(JSONObject.class);
510     verifyClusterSchedulerFifo(json);
511   }
512 
513   @Test
testClusterSchedulerFifoDefault()514   public void testClusterSchedulerFifoDefault() throws JSONException, Exception {
515     WebResource r = resource();
516     ClientResponse response = r.path("ws").path("v1").path("cluster")
517         .path("scheduler").get(ClientResponse.class);
518 
519     assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
520     JSONObject json = response.getEntity(JSONObject.class);
521     verifyClusterSchedulerFifo(json);
522   }
523 
524   @Test
testClusterSchedulerFifoXML()525   public void testClusterSchedulerFifoXML() throws JSONException, Exception {
526     WebResource r = resource();
527     ClientResponse response = r.path("ws").path("v1").path("cluster")
528         .path("scheduler").accept(MediaType.APPLICATION_XML)
529         .get(ClientResponse.class);
530 
531     assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
532     String xml = response.getEntity(String.class);
533     verifySchedulerFifoXML(xml);
534   }
535 
verifySchedulerFifoXML(String xml)536   public void verifySchedulerFifoXML(String xml) throws JSONException,
537       Exception {
538     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
539     DocumentBuilder db = dbf.newDocumentBuilder();
540     InputSource is = new InputSource();
541     is.setCharacterStream(new StringReader(xml));
542     Document dom = db.parse(is);
543     NodeList nodesSched = dom.getElementsByTagName("scheduler");
544     assertEquals("incorrect number of elements", 1, nodesSched.getLength());
545     NodeList nodes = dom.getElementsByTagName("schedulerInfo");
546     assertEquals("incorrect number of elements", 1, nodes.getLength());
547 
548     for (int i = 0; i < nodes.getLength(); i++) {
549       Element element = (Element) nodes.item(i);
550 
551       verifyClusterSchedulerFifoGeneric(
552           WebServicesTestUtils.getXmlAttrString(element, "xsi:type"),
553           WebServicesTestUtils.getXmlString(element, "qstate"),
554           WebServicesTestUtils.getXmlFloat(element, "capacity"),
555           WebServicesTestUtils.getXmlFloat(element, "usedCapacity"),
556           WebServicesTestUtils.getXmlInt(element, "minQueueMemoryCapacity"),
557           WebServicesTestUtils.getXmlInt(element, "maxQueueMemoryCapacity"),
558           WebServicesTestUtils.getXmlInt(element, "numNodes"),
559           WebServicesTestUtils.getXmlInt(element, "usedNodeCapacity"),
560           WebServicesTestUtils.getXmlInt(element, "availNodeCapacity"),
561           WebServicesTestUtils.getXmlInt(element, "totalNodeCapacity"),
562           WebServicesTestUtils.getXmlInt(element, "numContainers"));
563     }
564   }
565 
verifyClusterSchedulerFifo(JSONObject json)566   public void verifyClusterSchedulerFifo(JSONObject json) throws JSONException,
567       Exception {
568     assertEquals("incorrect number of elements", 1, json.length());
569     JSONObject info = json.getJSONObject("scheduler");
570     assertEquals("incorrect number of elements", 1, info.length());
571     info = info.getJSONObject("schedulerInfo");
572     assertEquals("incorrect number of elements", 11, info.length());
573 
574     verifyClusterSchedulerFifoGeneric(info.getString("type"),
575         info.getString("qstate"), (float) info.getDouble("capacity"),
576         (float) info.getDouble("usedCapacity"),
577         info.getInt("minQueueMemoryCapacity"),
578         info.getInt("maxQueueMemoryCapacity"), info.getInt("numNodes"),
579         info.getInt("usedNodeCapacity"), info.getInt("availNodeCapacity"),
580         info.getInt("totalNodeCapacity"), info.getInt("numContainers"));
581 
582   }
583 
verifyClusterSchedulerFifoGeneric(String type, String state, float capacity, float usedCapacity, int minQueueCapacity, int maxQueueCapacity, int numNodes, int usedNodeCapacity, int availNodeCapacity, int totalNodeCapacity, int numContainers)584   public void verifyClusterSchedulerFifoGeneric(String type, String state,
585       float capacity, float usedCapacity, int minQueueCapacity,
586       int maxQueueCapacity, int numNodes, int usedNodeCapacity,
587       int availNodeCapacity, int totalNodeCapacity, int numContainers)
588       throws JSONException, Exception {
589 
590     assertEquals("type doesn't match", "fifoScheduler", type);
591     assertEquals("qstate doesn't match", QueueState.RUNNING.toString(), state);
592     assertEquals("capacity doesn't match", 1.0, capacity, 0.0);
593     assertEquals("usedCapacity doesn't match", 0.0, usedCapacity, 0.0);
594     assertEquals(
595         "minQueueMemoryCapacity doesn't match",
596         YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB,
597         minQueueCapacity);
598     assertEquals("maxQueueMemoryCapacity doesn't match",
599         YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB,
600         maxQueueCapacity);
601     assertEquals("numNodes doesn't match", 0, numNodes);
602     assertEquals("usedNodeCapacity doesn't match", 0, usedNodeCapacity);
603     assertEquals("availNodeCapacity doesn't match", 0, availNodeCapacity);
604     assertEquals("totalNodeCapacity doesn't match", 0, totalNodeCapacity);
605     assertEquals("numContainers doesn't match", 0, numContainers);
606 
607   }
608 
609   // Test the scenario where the RM removes an app just as we try to
610   // look at it in the apps list
611   @Test
testAppsRace()612   public void testAppsRace() throws Exception {
613     // mock up an RM that returns app reports for apps that don't exist
614     // in the RMApps list
615     ApplicationId appId = ApplicationId.newInstance(1, 1);
616     ApplicationReport mockReport = mock(ApplicationReport.class);
617     when(mockReport.getApplicationId()).thenReturn(appId);
618     GetApplicationsResponse mockAppsResponse =
619         mock(GetApplicationsResponse.class);
620     when(mockAppsResponse.getApplicationList())
621       .thenReturn(Arrays.asList(new ApplicationReport[] { mockReport }));
622     ClientRMService mockClientSvc = mock(ClientRMService.class);
623     when(mockClientSvc.getApplications(isA(GetApplicationsRequest.class),
624         anyBoolean())).thenReturn(mockAppsResponse);
625     ResourceManager mockRM = mock(ResourceManager.class);
626     RMContextImpl rmContext = new RMContextImpl(null, null, null, null, null,
627         null, null, null, null, null);
628     when(mockRM.getRMContext()).thenReturn(rmContext);
629     when(mockRM.getClientRMService()).thenReturn(mockClientSvc);
630 
631     RMWebServices webSvc = new RMWebServices(mockRM, new Configuration(),
632         mock(HttpServletResponse.class));
633 
634     final Set<String> emptySet =
635         Collections.unmodifiableSet(Collections.<String>emptySet());
636 
637     // verify we don't get any apps when querying
638     HttpServletRequest mockHsr = mock(HttpServletRequest.class);
639     AppsInfo appsInfo = webSvc.getApps(mockHsr, null, emptySet, null,
640         null, null, null, null, null, null, null, emptySet, emptySet);
641     assertTrue(appsInfo.getApps().isEmpty());
642 
643     // verify we don't get an NPE when specifying a final status query
644     appsInfo = webSvc.getApps(mockHsr, null, emptySet, "FAILED",
645         null, null, null, null, null, null, null, emptySet, emptySet);
646     assertTrue(appsInfo.getApps().isEmpty());
647   }
648 }
649