Added: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/webapp/TestAMWebServicesTasks.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/webapp/TestAMWebServicesTasks.java?rev=1227801&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/webapp/TestAMWebServicesTasks.java (added)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-app/src/test/java/org/apache/hadoop/mapreduce/v2/app/webapp/TestAMWebServicesTasks.java Thu Jan 5 20:01:20 2012
@@ -0,0 +1,821 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.mapreduce.v2.app.webapp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.StringReader;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.mapreduce.v2.api.records.JobId;
+import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
+import org.apache.hadoop.mapreduce.v2.api.records.TaskReport;
+import org.apache.hadoop.mapreduce.v2.app.AppContext;
+import org.apache.hadoop.mapreduce.v2.app.MockJobs;
+import org.apache.hadoop.mapreduce.v2.app.job.Job;
+import org.apache.hadoop.mapreduce.v2.app.job.Task;
+import org.apache.hadoop.mapreduce.v2.util.MRApps;
+import org.apache.hadoop.yarn.Clock;
+import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
+import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.apache.hadoop.yarn.event.EventHandler;
+import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
+import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+import com.google.inject.servlet.ServletModule;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+
+/**
+ * Test the app master web service Rest API for getting tasks, a specific task,
+ * and task counters.
+ *
+ * /ws/v1/mapreduce/jobs/{jobid}/tasks
+ * /ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}
+ * /ws/v1/mapreduce/jobs/{jobid}/tasks/{taskid}/counters
+ */
+public class TestAMWebServicesTasks extends JerseyTest {
+
+ private static Configuration conf = new Configuration();
+ private static TestAppContext appContext;
+
+ static class TestAppContext implements AppContext {
+ final ApplicationAttemptId appAttemptID;
+ final ApplicationId appID;
+ final String user = MockJobs.newUserName();
+ final Map<JobId, Job> jobs;
+ final long startTime = System.currentTimeMillis();
+
+ TestAppContext(int appid, int numJobs, int numTasks, int numAttempts) {
+ appID = MockJobs.newAppID(appid);
+ appAttemptID = MockJobs.newAppAttemptID(appID, 0);
+ jobs = MockJobs.newJobs(appID, numJobs, numTasks, numAttempts);
+ }
+
+ TestAppContext() {
+ this(0, 1, 2, 1);
+ }
+
+ @Override
+ public ApplicationAttemptId getApplicationAttemptId() {
+ return appAttemptID;
+ }
+
+ @Override
+ public ApplicationId getApplicationID() {
+ return appID;
+ }
+
+ @Override
+ public CharSequence getUser() {
+ return user;
+ }
+
+ @Override
+ public Job getJob(JobId jobID) {
+ return jobs.get(jobID);
+ }
+
+ @Override
+ public Map<JobId, Job> getAllJobs() {
+ return jobs; // OK
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EventHandler getEventHandler() {
+ return null;
+ }
+
+ @Override
+ public Clock getClock() {
+ return null;
+ }
+
+ @Override
+ public String getApplicationName() {
+ return "TestApp";
+ }
+
+ @Override
+ public long getStartTime() {
+ return startTime;
+ }
+ }
+
+ private Injector injector = Guice.createInjector(new ServletModule() {
+ @Override
+ protected void configureServlets() {
+
+ appContext = new TestAppContext();
+ bind(JAXBContextResolver.class);
+ bind(AMWebServices.class);
+ bind(GenericExceptionHandler.class);
+ bind(AppContext.class).toInstance(appContext);
+ bind(Configuration.class).toInstance(conf);
+
+ serve("/*").with(GuiceContainer.class);
+ }
+ });
+
+ public class GuiceServletConfig extends GuiceServletContextListener {
+
+ @Override
+ protected Injector getInjector() {
+ return injector;
+ }
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ }
+
+ public TestAMWebServicesTasks() {
+ super(new WebAppDescriptor.Builder(
+ "org.apache.hadoop.mapreduce.v2.app.webapp")
+ .contextListenerClass(GuiceServletConfig.class)
+ .filterClass(com.google.inject.servlet.GuiceFilter.class)
+ .contextPath("jersey-guice-filter").servletPath("/").build());
+ }
+
+ @Test
+ public void testTasks() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject tasks = json.getJSONObject("tasks");
+ JSONArray arr = tasks.getJSONArray("task");
+ assertEquals("incorrect number of elements", 2, arr.length());
+
+ verifyAMTask(arr, jobsMap.get(id), null);
+ }
+ }
+
+ @Test
+ public void testTasksDefault() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject tasks = json.getJSONObject("tasks");
+ JSONArray arr = tasks.getJSONArray("task");
+ assertEquals("incorrect number of elements", 2, arr.length());
+
+ verifyAMTask(arr, jobsMap.get(id), null);
+ }
+ }
+
+ @Test
+ public void testTasksSlash() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks/")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject tasks = json.getJSONObject("tasks");
+ JSONArray arr = tasks.getJSONArray("task");
+ assertEquals("incorrect number of elements", 2, arr.length());
+
+ verifyAMTask(arr, jobsMap.get(id), null);
+ }
+ }
+
+ @Test
+ public void testTasksXML() throws JSONException, Exception {
+
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks")
+ .accept(MediaType.APPLICATION_XML).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
+ String xml = response.getEntity(String.class);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xml));
+ Document dom = db.parse(is);
+ NodeList tasks = dom.getElementsByTagName("tasks");
+ assertEquals("incorrect number of elements", 1, tasks.getLength());
+ NodeList task = dom.getElementsByTagName("task");
+ verifyAMTaskXML(task, jobsMap.get(id));
+ }
+ }
+
+ @Test
+ public void testTasksQueryMap() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String type = "m";
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").queryParam("type", type)
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject tasks = json.getJSONObject("tasks");
+ JSONArray arr = tasks.getJSONArray("task");
+ assertEquals("incorrect number of elements", 1, arr.length());
+ verifyAMTask(arr, jobsMap.get(id), type);
+ }
+ }
+
+ @Test
+ public void testTasksQueryReduce() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String type = "r";
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").queryParam("type", type)
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject tasks = json.getJSONObject("tasks");
+ JSONArray arr = tasks.getJSONArray("task");
+ assertEquals("incorrect number of elements", 1, arr.length());
+ verifyAMTask(arr, jobsMap.get(id), type);
+ }
+ }
+
+ @Test
+ public void testTasksQueryInvalid() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ // tasktype must be exactly either "m" or "r"
+ String tasktype = "reduce";
+
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").queryParam("type", tasktype)
+ .accept(MediaType.APPLICATION_JSON).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: tasktype must be either m or r", message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "BadRequestException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.BadRequestException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskId() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid)
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("task");
+ verifyAMSingleTask(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdSlash() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid + "/")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("task");
+ verifyAMSingleTask(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdDefault() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid)
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("task");
+ verifyAMSingleTask(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdBogus() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String tid = "bogustaskid";
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").path(tid).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: Error parsing task ID: bogustaskid", message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "NotFoundException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.NotFoundException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdNonExist() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String tid = "task_1234_0_0_m_0";
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").path(tid).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: task not found with id task_1234_0_0_m_0",
+ message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "NotFoundException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.NotFoundException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdInvalid() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String tid = "task_1234_0_0_d_0";
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").path(tid).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: Unknown task symbol: d", message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "NotFoundException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.NotFoundException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdInvalid2() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String tid = "task_1234_0_m_0";
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").path(tid).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: For input string: \"m\"", message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "NotFoundException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.NotFoundException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdInvalid3() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ String tid = "task_1234_0_0_m";
+ try {
+ r.path("ws").path("v1").path("mapreduce").path("jobs").path(jobId)
+ .path("tasks").path(tid).get(JSONObject.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject msg = response.getEntity(JSONObject.class);
+ JSONObject exception = msg.getJSONObject("RemoteException");
+ assertEquals("incorrect number of elements", 3, exception.length());
+ String message = exception.getString("message");
+ String type = exception.getString("exception");
+ String classname = exception.getString("javaClassName");
+ WebServicesTestUtils.checkStringMatch("exception message",
+ "java.lang.Exception: Error parsing task ID: task_1234_0_0_m",
+ message);
+ WebServicesTestUtils.checkStringMatch("exception type",
+ "NotFoundException", type);
+ WebServicesTestUtils.checkStringMatch("exception classname",
+ "org.apache.hadoop.yarn.webapp.NotFoundException", classname);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdXML() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid)
+ .accept(MediaType.APPLICATION_XML).get(ClientResponse.class);
+
+ assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
+ String xml = response.getEntity(String.class);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xml));
+ Document dom = db.parse(is);
+ NodeList nodes = dom.getElementsByTagName("task");
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element element = (Element) nodes.item(i);
+ verifyAMSingleTaskXML(element, task);
+ }
+ }
+ }
+ }
+
+ public void verifyAMSingleTask(JSONObject info, Task task)
+ throws JSONException {
+ assertEquals("incorrect number of elements", 8, info.length());
+
+ verifyTaskGeneric(task, info.getString("id"), info.getString("state"),
+ info.getString("type"), info.getString("successfulAttempt"),
+ info.getLong("startTime"), info.getLong("finishTime"),
+ info.getLong("elapsedTime"), (float) info.getDouble("progress"));
+ }
+
+ public void verifyAMTask(JSONArray arr, Job job, String type)
+ throws JSONException {
+ for (Task task : job.getTasks().values()) {
+ TaskId id = task.getID();
+ String tid = MRApps.toString(id);
+ Boolean found = false;
+ if (type != null && task.getType() == MRApps.taskType(type)) {
+
+ for (int i = 0; i < arr.length(); i++) {
+ JSONObject info = arr.getJSONObject(i);
+ if (tid.matches(info.getString("id"))) {
+ found = true;
+ verifyAMSingleTask(info, task);
+ }
+ }
+ assertTrue("task with id: " + tid + " not in web service output", found);
+ }
+ }
+ }
+
+ public void verifyTaskGeneric(Task task, String id, String state,
+ String type, String successfulAttempt, long startTime, long finishTime,
+ long elapsedTime, float progress) {
+
+ TaskId taskid = task.getID();
+ String tid = MRApps.toString(taskid);
+ TaskReport report = task.getReport();
+
+ WebServicesTestUtils.checkStringMatch("id", tid, id);
+ WebServicesTestUtils.checkStringMatch("type", task.getType().toString(),
+ type);
+ WebServicesTestUtils.checkStringMatch("state", report.getTaskState()
+ .toString(), state);
+ // not easily checked without duplicating logic, just make sure its here
+ assertNotNull("successfulAttempt null", successfulAttempt);
+ assertEquals("startTime wrong", report.getStartTime(), startTime);
+ assertEquals("finishTime wrong", report.getFinishTime(), finishTime);
+ assertEquals("elapsedTime wrong", finishTime - startTime, elapsedTime);
+ assertEquals("progress wrong", report.getProgress() * 100, progress, 1e-3f);
+ }
+
+ public void verifyAMSingleTaskXML(Element element, Task task) {
+ verifyTaskGeneric(task, WebServicesTestUtils.getXmlString(element, "id"),
+ WebServicesTestUtils.getXmlString(element, "state"),
+ WebServicesTestUtils.getXmlString(element, "type"),
+ WebServicesTestUtils.getXmlString(element, "successfulAttempt"),
+ WebServicesTestUtils.getXmlLong(element, "startTime"),
+ WebServicesTestUtils.getXmlLong(element, "finishTime"),
+ WebServicesTestUtils.getXmlLong(element, "elapsedTime"),
+ WebServicesTestUtils.getXmlFloat(element, "progress"));
+ }
+
+ public void verifyAMTaskXML(NodeList nodes, Job job) {
+
+ assertEquals("incorrect number of elements", 2, nodes.getLength());
+
+ for (Task task : job.getTasks().values()) {
+ TaskId id = task.getID();
+ String tid = MRApps.toString(id);
+ Boolean found = false;
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element element = (Element) nodes.item(i);
+
+ if (tid.matches(WebServicesTestUtils.getXmlString(element, "id"))) {
+ found = true;
+ verifyAMSingleTaskXML(element, task);
+ }
+ }
+ assertTrue("task with id: " + tid + " not in web service output", found);
+ }
+ }
+
+ @Test
+ public void testTaskIdCounters() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid).path("counters")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("jobTaskCounters");
+ verifyAMJobTaskCounters(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdCountersSlash() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid).path("counters/")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("jobTaskCounters");
+ verifyAMJobTaskCounters(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testTaskIdCountersDefault() throws JSONException, Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid).path("counters")
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ JSONObject info = json.getJSONObject("jobTaskCounters");
+ verifyAMJobTaskCounters(info, task);
+ }
+ }
+ }
+
+ @Test
+ public void testJobTaskCountersXML() throws Exception {
+ WebResource r = resource();
+ Map<JobId, Job> jobsMap = appContext.getAllJobs();
+ for (JobId id : jobsMap.keySet()) {
+ String jobId = MRApps.toString(id);
+ for (Task task : jobsMap.get(id).getTasks().values()) {
+
+ String tid = MRApps.toString(task.getID());
+ ClientResponse response = r.path("ws").path("v1").path("mapreduce")
+ .path("jobs").path(jobId).path("tasks").path(tid).path("counters")
+ .accept(MediaType.APPLICATION_XML).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
+ String xml = response.getEntity(String.class);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xml));
+ Document dom = db.parse(is);
+ NodeList info = dom.getElementsByTagName("jobTaskCounters");
+ verifyAMTaskCountersXML(info, task);
+ }
+ }
+ }
+
+ public void verifyAMJobTaskCounters(JSONObject info, Task task)
+ throws JSONException {
+
+ assertEquals("incorrect number of elements", 2, info.length());
+
+ WebServicesTestUtils.checkStringMatch("id", MRApps.toString(task.getID()),
+ info.getString("id"));
+ // just do simple verification of fields - not data is correct
+ // in the fields
+ JSONArray counterGroups = info.getJSONArray("taskCounterGroup");
+ for (int i = 0; i < counterGroups.length(); i++) {
+ JSONObject counterGroup = counterGroups.getJSONObject(i);
+ String name = counterGroup.getString("counterGroupName");
+ assertTrue("name not set", (name != null && !name.isEmpty()));
+ JSONArray counters = counterGroup.getJSONArray("counter");
+ for (int j = 0; j < counters.length(); j++) {
+ JSONObject counter = counters.getJSONObject(i);
+ String counterName = counter.getString("name");
+ assertTrue("name not set",
+ (counterName != null && !counterName.isEmpty()));
+ long value = counter.getLong("value");
+ assertTrue("value >= 0", value >= 0);
+ }
+ }
+ }
+
+ public void verifyAMTaskCountersXML(NodeList nodes, Task task) {
+
+ for (int i = 0; i < nodes.getLength(); i++) {
+
+ Element element = (Element) nodes.item(i);
+ WebServicesTestUtils.checkStringMatch("id",
+ MRApps.toString(task.getID()),
+ WebServicesTestUtils.getXmlString(element, "id"));
+ // just do simple verification of fields - not data is correct
+ // in the fields
+ NodeList groups = element.getElementsByTagName("taskCounterGroup");
+
+ for (int j = 0; j < groups.getLength(); j++) {
+ Element counters = (Element) groups.item(j);
+ assertNotNull("should have counters in the web service info", counters);
+ String name = WebServicesTestUtils.getXmlString(counters,
+ "counterGroupName");
+ assertTrue("name not set", (name != null && !name.isEmpty()));
+ NodeList counterArr = counters.getElementsByTagName("counter");
+ for (int z = 0; z < counterArr.getLength(); z++) {
+ Element counter = (Element) counterArr.item(z);
+ String counterName = WebServicesTestUtils.getXmlString(counter,
+ "name");
+ assertTrue("counter name not set",
+ (counterName != null && !counterName.isEmpty()));
+
+ long value = WebServicesTestUtils.getXmlLong(counter, "value");
+ assertTrue("value not >= 0", value >= 0);
+
+ }
+ }
+ }
+ }
+
+}
Modified: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/HsWebServices.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/HsWebServices.java?rev=1227801&r1=1227800&r2=1227801&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/HsWebServices.java (original)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/HsWebServices.java Thu Jan 5 20:01:20 2012
@@ -31,14 +31,13 @@ import javax.ws.rs.core.UriInfo;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapreduce.v2.api.records.AMInfo;
-import org.apache.hadoop.mapreduce.v2.api.records.JobId;
-import org.apache.hadoop.mapreduce.v2.api.records.TaskAttemptId;
import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
import org.apache.hadoop.mapreduce.v2.api.records.TaskType;
import org.apache.hadoop.mapreduce.v2.app.AppContext;
import org.apache.hadoop.mapreduce.v2.app.job.Job;
import org.apache.hadoop.mapreduce.v2.app.job.Task;
import org.apache.hadoop.mapreduce.v2.app.job.TaskAttempt;
+import org.apache.hadoop.mapreduce.v2.app.webapp.AMWebServices;
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.ConfInfo;
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.JobCounterInfo;
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.JobTaskAttemptCounterInfo;
@@ -131,7 +130,7 @@ public class HsWebServices {
try {
sBegin = Long.parseLong(startedBegin);
} catch (NumberFormatException e) {
- throw new BadRequestException(e.getMessage());
+ throw new BadRequestException("Invalid number format: " + e.getMessage());
}
if (sBegin < 0) {
throw new BadRequestException("startedTimeBegin must be greater than 0");
@@ -142,7 +141,7 @@ public class HsWebServices {
try {
sEnd = Long.parseLong(startedEnd);
} catch (NumberFormatException e) {
- throw new BadRequestException(e.getMessage());
+ throw new BadRequestException("Invalid number format: " + e.getMessage());
}
if (sEnd < 0) {
throw new BadRequestException("startedTimeEnd must be greater than 0");
@@ -158,10 +157,10 @@ public class HsWebServices {
try {
fBegin = Long.parseLong(finishBegin);
} catch (NumberFormatException e) {
- throw new BadRequestException(e.getMessage());
+ throw new BadRequestException("Invalid number format: " + e.getMessage());
}
if (fBegin < 0) {
- throw new BadRequestException("finishTimeBegin must be greater than 0");
+ throw new BadRequestException("finishedTimeBegin must be greater than 0");
}
}
if (finishEnd != null && !finishEnd.isEmpty()) {
@@ -169,15 +168,15 @@ public class HsWebServices {
try {
fEnd = Long.parseLong(finishEnd);
} catch (NumberFormatException e) {
- throw new BadRequestException(e.getMessage());
+ throw new BadRequestException("Invalid number format: " + e.getMessage());
}
if (fEnd < 0) {
- throw new BadRequestException("finishTimeEnd must be greater than 0");
+ throw new BadRequestException("finishedTimeEnd must be greater than 0");
}
}
if (fBegin > fEnd) {
throw new BadRequestException(
- "finishTimeEnd must be greater than finishTimeBegin");
+ "finishedTimeEnd must be greater than finishedTimeBegin");
}
for (Job job : appCtx.getAllJobs().values()) {
@@ -200,7 +199,7 @@ public class HsWebServices {
}
if (userQuery != null && !userQuery.isEmpty()) {
- if (!jobInfo.getName().equals(userQuery)) {
+ if (!jobInfo.getUserName().equals(userQuery)) {
continue;
}
}
@@ -224,14 +223,8 @@ public class HsWebServices {
@Path("/mapreduce/jobs/{jobid}")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public JobInfo getJob(@PathParam("jobid") String jid) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
return new JobInfo(job);
}
@@ -239,14 +232,8 @@ public class HsWebServices {
@Path("/mapreduce/jobs/{jobid}/attempts")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public AMAttemptsInfo getJobAttempts(@PathParam("jobid") String jid) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
AMAttemptsInfo amAttempts = new AMAttemptsInfo();
for (AMInfo amInfo : job.getAMInfos()) {
AMAttemptInfo attempt = new AMAttemptInfo(amInfo, MRApps.toString(job
@@ -261,53 +248,17 @@ public class HsWebServices {
@Path("/mapreduce/jobs/{jobid}/counters")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public JobCounterInfo getJobCounters(@PathParam("jobid") String jid) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- return new JobCounterInfo(this.appCtx, job);
- }
- @GET
- @Path("/mapreduce/jobs/{jobid}/tasks/{taskid}/counters")
- @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
- public JobTaskCounterInfo getSingleTaskCounters(
- @PathParam("jobid") String jid, @PathParam("taskid") String tid) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = this.appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- TaskId taskID = MRApps.toTaskID(tid);
- if (taskID == null) {
- throw new NotFoundException("taskid " + tid + " not found or invalid");
- }
- Task task = job.getTask(taskID);
- if (task == null) {
- throw new NotFoundException("task not found with id " + tid);
- }
- return new JobTaskCounterInfo(task);
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
+ return new JobCounterInfo(this.appCtx, job);
}
@GET
@Path("/mapreduce/jobs/{jobid}/conf")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public ConfInfo getJobConf(@PathParam("jobid") String jid) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
ConfInfo info;
try {
info = new ConfInfo(job, this.conf);
@@ -315,7 +266,6 @@ public class HsWebServices {
throw new NotFoundException("unable to load configuration for job: "
+ jid);
}
-
return info;
}
@@ -324,10 +274,8 @@ public class HsWebServices {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public TasksInfo getJobTasks(@PathParam("jobid") String jid,
@QueryParam("type") String type) {
- Job job = this.appCtx.getJob(MRApps.toJobID(jid));
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
TasksInfo allTasks = new TasksInfo();
for (Task task : job.getTasks().values()) {
TaskType ttype = null;
@@ -351,10 +299,20 @@ public class HsWebServices {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public TaskInfo getJobTask(@PathParam("jobid") String jid,
@PathParam("taskid") String tid) {
- Job job = this.appCtx.getJob(MRApps.toJobID(jid));
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
+ Task task = AMWebServices.getTaskFromTaskIdString(tid, job);
+ return new TaskInfo(task);
+
+ }
+
+ @GET
+ @Path("/mapreduce/jobs/{jobid}/tasks/{taskid}/counters")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public JobTaskCounterInfo getSingleTaskCounters(
+ @PathParam("jobid") String jid, @PathParam("taskid") String tid) {
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
TaskId taskID = MRApps.toTaskID(tid);
if (taskID == null) {
throw new NotFoundException("taskid " + tid + " not found or invalid");
@@ -363,8 +321,7 @@ public class HsWebServices {
if (task == null) {
throw new NotFoundException("task not found with id " + tid);
}
- return new TaskInfo(task);
-
+ return new JobTaskCounterInfo(task);
}
@GET
@@ -372,19 +329,10 @@ public class HsWebServices {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public TaskAttemptsInfo getJobTaskAttempts(@PathParam("jobid") String jid,
@PathParam("taskid") String tid) {
+
TaskAttemptsInfo attempts = new TaskAttemptsInfo();
- Job job = this.appCtx.getJob(MRApps.toJobID(jid));
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- TaskId taskID = MRApps.toTaskID(tid);
- if (taskID == null) {
- throw new NotFoundException("taskid " + tid + " not found or invalid");
- }
- Task task = job.getTask(taskID);
- if (task == null) {
- throw new NotFoundException("task not found with id " + tid);
- }
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
+ Task task = AMWebServices.getTaskFromTaskIdString(tid, job);
for (TaskAttempt ta : task.getAttempts().values()) {
if (ta != null) {
if (task.getType() == TaskType.REDUCE) {
@@ -402,28 +350,11 @@ public class HsWebServices {
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public TaskAttemptInfo getJobTaskAttemptId(@PathParam("jobid") String jid,
@PathParam("taskid") String tid, @PathParam("attemptid") String attId) {
- Job job = this.appCtx.getJob(MRApps.toJobID(jid));
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- TaskId taskID = MRApps.toTaskID(tid);
- if (taskID == null) {
- throw new NotFoundException("taskid " + tid + " not found or invalid");
- }
- Task task = job.getTask(taskID);
- if (task == null) {
- throw new NotFoundException("task not found with id " + tid);
- }
- TaskAttemptId attemptId = MRApps.toTaskAttemptID(attId);
- if (attemptId == null) {
- throw new NotFoundException("task attempt id " + attId
- + " not found or invalid");
- }
- TaskAttempt ta = task.getAttempt(attemptId);
- if (ta == null) {
- throw new NotFoundException("Error getting info on task attempt id "
- + attId);
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
+ Task task = AMWebServices.getTaskFromTaskIdString(tid, job);
+ TaskAttempt ta = AMWebServices.getTaskAttemptFromTaskAttemptString(attId,
+ task);
if (task.getType() == TaskType.REDUCE) {
return new ReduceTaskAttemptInfo(ta, task.getType());
} else {
@@ -437,32 +368,11 @@ public class HsWebServices {
public JobTaskAttemptCounterInfo getJobTaskAttemptIdCounters(
@PathParam("jobid") String jid, @PathParam("taskid") String tid,
@PathParam("attemptid") String attId) {
- JobId jobId = MRApps.toJobID(jid);
- if (jobId == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- Job job = this.appCtx.getJob(jobId);
- if (job == null) {
- throw new NotFoundException("job, " + jid + ", is not found");
- }
- TaskId taskID = MRApps.toTaskID(tid);
- if (taskID == null) {
- throw new NotFoundException("taskid " + tid + " not found or invalid");
- }
- Task task = job.getTask(taskID);
- if (task == null) {
- throw new NotFoundException("task not found with id " + tid);
- }
- TaskAttemptId attemptId = MRApps.toTaskAttemptID(attId);
- if (attemptId == null) {
- throw new NotFoundException("task attempt id " + attId
- + " not found or invalid");
- }
- TaskAttempt ta = task.getAttempt(attemptId);
- if (ta == null) {
- throw new NotFoundException("Error getting info on task attempt id "
- + attId);
- }
+
+ Job job = AMWebServices.getJobFromJobIdString(jid, appCtx);
+ Task task = AMWebServices.getTaskFromTaskIdString(tid, job);
+ TaskAttempt ta = AMWebServices.getTaskAttemptFromTaskAttemptString(attId,
+ task);
return new JobTaskAttemptCounterInfo(ta);
}
Modified: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/JAXBContextResolver.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/JAXBContextResolver.java?rev=1227801&r1=1227800&r2=1227801&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/JAXBContextResolver.java (original)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/JAXBContextResolver.java Thu Jan 5 20:01:20 2012
@@ -42,6 +42,8 @@ import org.apache.hadoop.mapreduce.v2.ap
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskCounterGroupInfo;
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskCounterInfo;
import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TasksInfo;
+import org.apache.hadoop.mapreduce.v2.app.webapp.dao.TaskInfo;
+
import org.apache.hadoop.mapreduce.v2.hs.webapp.dao.AMAttemptInfo;
import org.apache.hadoop.mapreduce.v2.hs.webapp.dao.AMAttemptsInfo;
import org.apache.hadoop.mapreduce.v2.hs.webapp.dao.HistoryInfo;
@@ -57,13 +59,12 @@ public class JAXBContextResolver impleme
// you have to specify all the dao classes here
private final Class[] cTypes = { HistoryInfo.class, JobInfo.class,
- JobsInfo.class, TasksInfo.class, TaskAttemptsInfo.class, ConfInfo.class,
- CounterInfo.class, JobTaskCounterInfo.class,
- JobTaskAttemptCounterInfo.class,
- TaskCounterInfo.class, JobCounterInfo.class, ReduceTaskAttemptInfo.class,
- TaskAttemptInfo.class, TaskAttemptsInfo.class, CounterGroupInfo.class,
- TaskCounterGroupInfo.class,
- AMAttemptInfo.class, AMAttemptsInfo.class};
+ JobsInfo.class, TaskInfo.class, TasksInfo.class, TaskAttemptsInfo.class,
+ ConfInfo.class, CounterInfo.class, JobTaskCounterInfo.class,
+ JobTaskAttemptCounterInfo.class, TaskCounterInfo.class,
+ JobCounterInfo.class, ReduceTaskAttemptInfo.class, TaskAttemptInfo.class,
+ TaskAttemptsInfo.class, CounterGroupInfo.class,
+ TaskCounterGroupInfo.class, AMAttemptInfo.class, AMAttemptsInfo.class };
public JAXBContextResolver() throws Exception {
this.types = new HashSet<Class>(Arrays.asList(cTypes));
Modified: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/AMAttemptInfo.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/AMAttemptInfo.java?rev=1227801&r1=1227800&r2=1227801&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/AMAttemptInfo.java (original)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/AMAttemptInfo.java Thu Jan 5 20:01:20 2012
@@ -26,6 +26,7 @@ import javax.xml.bind.annotation.XmlRoot
import javax.xml.bind.annotation.XmlTransient;
import org.apache.hadoop.mapreduce.v2.api.records.AMInfo;
+import org.apache.hadoop.yarn.api.records.ContainerId;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.util.BuilderUtils;
@@ -48,21 +49,28 @@ public class AMAttemptInfo {
public AMAttemptInfo(AMInfo amInfo, String jobId, String user, String host,
String pathPrefix) {
- this.nodeHttpAddress = amInfo.getNodeManagerHost() + ":"
- + amInfo.getNodeManagerHttpPort();
- NodeId nodeId = BuilderUtils.newNodeId(amInfo.getNodeManagerHost(),
- amInfo.getNodeManagerPort());
- this.nodeId = nodeId.toString();
+ this.nodeHttpAddress = "";
+ this.nodeId = "";
+ String nmHost = amInfo.getNodeManagerHost();
+ int nmPort = amInfo.getNodeManagerHttpPort();
+ if (nmHost != null) {
+ this.nodeHttpAddress = nmHost + ":" + nmPort;
+ NodeId nodeId = BuilderUtils.newNodeId(nmHost, nmPort);
+ this.nodeId = nodeId.toString();
+ }
this.id = amInfo.getAppAttemptId().getAttemptId();
this.startTime = amInfo.getStartTime();
- this.containerId = amInfo.getContainerId().toString();
- this.logsLink = join(
- host,
- pathPrefix,
- ujoin("logs", nodeId.toString(), amInfo.getContainerId().toString(),
- jobId, user));
- this.shortLogsLink = ujoin("logs", nodeId.toString(), amInfo
- .getContainerId().toString(), jobId, user);
+ this.containerId = "";
+ this.logsLink = "";
+ this.shortLogsLink = "";
+ ContainerId containerId = amInfo.getContainerId();
+ if (containerId != null) {
+ this.containerId = containerId.toString();
+ this.logsLink = join(host, pathPrefix,
+ ujoin("logs", this.nodeId, this.containerId, jobId, user));
+ this.shortLogsLink = ujoin("logs", this.nodeId, this.containerId,
+ jobId, user);
+ }
}
public String getNodeHttpAddress() {
Modified: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/JobInfo.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/JobInfo.java?rev=1227801&r1=1227800&r2=1227801&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/JobInfo.java (original)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/main/java/org/apache/hadoop/mapreduce/v2/hs/webapp/dao/JobInfo.java Thu Jan 5 20:01:20 2012
@@ -92,6 +92,7 @@ public class JobInfo {
this.user = job.getUserName();
this.state = job.getState().toString();
this.uberized = job.isUber();
+ this.diagnostics = "";
List<String> diagnostics = job.getDiagnostics();
if (diagnostics != null && !diagnostics.isEmpty()) {
StringBuffer b = new StringBuffer();
Added: hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/java/org/apache/hadoop/mapreduce/v2/hs/webapp/TestHsWebServices.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/java/org/apache/hadoop/mapreduce/v2/hs/webapp/TestHsWebServices.java?rev=1227801&view=auto
==============================================================================
--- hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/java/org/apache/hadoop/mapreduce/v2/hs/webapp/TestHsWebServices.java (added)
+++ hadoop/common/trunk/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-hs/src/test/java/org/apache/hadoop/mapreduce/v2/hs/webapp/TestHsWebServices.java Thu Jan 5 20:01:20 2012
@@ -0,0 +1,360 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.mapreduce.v2.hs.webapp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.StringReader;
+import java.util.Map;
+
+import javax.ws.rs.core.MediaType;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.mapreduce.v2.api.records.JobId;
+import org.apache.hadoop.mapreduce.v2.app.AppContext;
+import org.apache.hadoop.mapreduce.v2.app.MockJobs;
+import org.apache.hadoop.mapreduce.v2.app.job.Job;
+import org.apache.hadoop.mapreduce.v2.hs.HistoryContext;
+import org.apache.hadoop.mapreduce.v2.hs.JobHistory;
+import org.apache.hadoop.util.VersionInfo;
+import org.apache.hadoop.yarn.Clock;
+import org.apache.hadoop.yarn.api.records.ApplicationAttemptId;
+import org.apache.hadoop.yarn.api.records.ApplicationId;
+import org.apache.hadoop.yarn.event.EventHandler;
+import org.apache.hadoop.yarn.webapp.GenericExceptionHandler;
+import org.apache.hadoop.yarn.webapp.WebApp;
+import org.apache.hadoop.yarn.webapp.WebServicesTestUtils;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+import com.google.inject.servlet.ServletModule;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+
+/**
+ * Test the History Server info web services api's. Also test non-existent urls.
+ *
+ * /ws/v1/history
+ * /ws/v1/history/info
+ */
+public class TestHsWebServices extends JerseyTest {
+
+ private static Configuration conf = new Configuration();
+ private static TestAppContext appContext;
+ private static HsWebApp webApp;
+
+ static class TestAppContext implements AppContext {
+ final ApplicationAttemptId appAttemptID;
+ final ApplicationId appID;
+ final String user = MockJobs.newUserName();
+ final Map<JobId, Job> jobs;
+ final long startTime = System.currentTimeMillis();
+
+ TestAppContext(int appid, int numJobs, int numTasks, int numAttempts) {
+ appID = MockJobs.newAppID(appid);
+ appAttemptID = MockJobs.newAppAttemptID(appID, 0);
+ jobs = MockJobs.newJobs(appID, numJobs, numTasks, numAttempts);
+ }
+
+ TestAppContext() {
+ this(0, 1, 1, 1);
+ }
+
+ @Override
+ public ApplicationAttemptId getApplicationAttemptId() {
+ return appAttemptID;
+ }
+
+ @Override
+ public ApplicationId getApplicationID() {
+ return appID;
+ }
+
+ @Override
+ public CharSequence getUser() {
+ return user;
+ }
+
+ @Override
+ public Job getJob(JobId jobID) {
+ return jobs.get(jobID);
+ }
+
+ @Override
+ public Map<JobId, Job> getAllJobs() {
+ return jobs; // OK
+ }
+
+ @SuppressWarnings("rawtypes")
+ @Override
+ public EventHandler getEventHandler() {
+ return null;
+ }
+
+ @Override
+ public Clock getClock() {
+ return null;
+ }
+
+ @Override
+ public String getApplicationName() {
+ return "TestApp";
+ }
+
+ @Override
+ public long getStartTime() {
+ return startTime;
+ }
+ }
+
+ private Injector injector = Guice.createInjector(new ServletModule() {
+ @Override
+ protected void configureServlets() {
+
+ appContext = new TestAppContext();
+ JobHistory jobHistoryService = new JobHistory();
+ HistoryContext historyContext = (HistoryContext) jobHistoryService;
+ webApp = new HsWebApp(historyContext);
+
+ bind(JAXBContextResolver.class);
+ bind(HsWebServices.class);
+ bind(GenericExceptionHandler.class);
+ bind(WebApp.class).toInstance(webApp);
+ bind(AppContext.class).toInstance(appContext);
+ bind(Configuration.class).toInstance(conf);
+
+ serve("/*").with(GuiceContainer.class);
+ }
+ });
+
+ public class GuiceServletConfig extends GuiceServletContextListener {
+
+ @Override
+ protected Injector getInjector() {
+ return injector;
+ }
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public TestHsWebServices() {
+ super(new WebAppDescriptor.Builder(
+ "org.apache.hadoop.mapreduce.v2.hs.webapp")
+ .contextListenerClass(GuiceServletConfig.class)
+ .filterClass(com.google.inject.servlet.GuiceFilter.class)
+ .contextPath("jersey-guice-filter").servletPath("/").build());
+ }
+
+ @Test
+ public void testHS() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testHSSlash() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history/")
+ .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testHSDefault() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history/")
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testHSXML() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .accept(MediaType.APPLICATION_XML).get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
+ String xml = response.getEntity(String.class);
+ verifyHSInfoXML(xml, appContext);
+ }
+
+ @Test
+ public void testInfo() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .path("info").accept(MediaType.APPLICATION_JSON)
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testInfoSlash() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .path("info/").accept(MediaType.APPLICATION_JSON)
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testInfoDefault() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .path("info/").get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
+ JSONObject json = response.getEntity(JSONObject.class);
+ assertEquals("incorrect number of elements", 1, json.length());
+ verifyHSInfo(json.getJSONObject("historyInfo"), appContext);
+ }
+
+ @Test
+ public void testInfoXML() throws JSONException, Exception {
+ WebResource r = resource();
+ ClientResponse response = r.path("ws").path("v1").path("history")
+ .path("info/").accept(MediaType.APPLICATION_XML)
+ .get(ClientResponse.class);
+ assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType());
+ String xml = response.getEntity(String.class);
+ verifyHSInfoXML(xml, appContext);
+ }
+
+ @Test
+ public void testInvalidUri() throws JSONException, Exception {
+ WebResource r = resource();
+ String responseStr = "";
+ try {
+ responseStr = r.path("ws").path("v1").path("history").path("bogus")
+ .accept(MediaType.APPLICATION_JSON).get(String.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ WebServicesTestUtils.checkStringMatch(
+ "error string exists and shouldn't", "", responseStr);
+ }
+ }
+
+ @Test
+ public void testInvalidUri2() throws JSONException, Exception {
+ WebResource r = resource();
+ String responseStr = "";
+ try {
+ responseStr = r.path("ws").path("v1").path("invalid")
+ .accept(MediaType.APPLICATION_JSON).get(String.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.NOT_FOUND, response.getClientResponseStatus());
+ WebServicesTestUtils.checkStringMatch(
+ "error string exists and shouldn't", "", responseStr);
+ }
+ }
+
+ @Test
+ public void testInvalidAccept() throws JSONException, Exception {
+ WebResource r = resource();
+ String responseStr = "";
+ try {
+ responseStr = r.path("ws").path("v1").path("history")
+ .accept(MediaType.TEXT_PLAIN).get(String.class);
+ fail("should have thrown exception on invalid uri");
+ } catch (UniformInterfaceException ue) {
+ ClientResponse response = ue.getResponse();
+ assertEquals(Status.INTERNAL_SERVER_ERROR,
+ response.getClientResponseStatus());
+ WebServicesTestUtils.checkStringMatch(
+ "error string exists and shouldn't", "", responseStr);
+ }
+ }
+
+ public void verifyHsInfoGeneric(String hadoopVersionBuiltOn,
+ String hadoopBuildVersion, String hadoopVersion) {
+ WebServicesTestUtils.checkStringMatch("hadoopVersionBuiltOn",
+ VersionInfo.getDate(), hadoopVersionBuiltOn);
+ WebServicesTestUtils.checkStringMatch("hadoopBuildVersion",
+ VersionInfo.getBuildVersion(), hadoopBuildVersion);
+ WebServicesTestUtils.checkStringMatch("hadoopVersion",
+ VersionInfo.getVersion(), hadoopVersion);
+ }
+
+ public void verifyHSInfo(JSONObject info, TestAppContext ctx)
+ throws JSONException {
+ assertEquals("incorrect number of elements", 3, info.length());
+
+ verifyHsInfoGeneric(info.getString("hadoopVersionBuiltOn"),
+ info.getString("hadoopBuildVersion"), info.getString("hadoopVersion"));
+ }
+
+ public void verifyHSInfoXML(String xml, TestAppContext ctx)
+ throws JSONException, Exception {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ InputSource is = new InputSource();
+ is.setCharacterStream(new StringReader(xml));
+ Document dom = db.parse(is);
+ NodeList nodes = dom.getElementsByTagName("historyInfo");
+ assertEquals("incorrect number of elements", 1, nodes.getLength());
+
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element element = (Element) nodes.item(i);
+ verifyHsInfoGeneric(
+ WebServicesTestUtils.getXmlString(element, "hadoopVersionBuiltOn"),
+ WebServicesTestUtils.getXmlString(element, "hadoopBuildVersion"),
+ WebServicesTestUtils.getXmlString(element, "hadoopVersion"));
+ }
+ }
+
+}
|