/*
* R Service Bus
*
* Copyright (c) Copyright of Open Analytics NV, 2010-2015
*
* ===========================================================================
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package eu.openanalytics.rsb;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathNotExists;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.activemq.util.ByteArrayInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.exceptions.XpathException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.internal.matchers.StartsWith;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlFileInput;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.meterware.httpunit.GetMethodWebRequest;
import com.meterware.httpunit.HttpException;
import com.meterware.httpunit.PostMethodWebRequest;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebRequest;
import com.meterware.httpunit.WebResponse;
import eu.openanalytics.httpunit.DeleteMethodWebRequest;
import eu.openanalytics.rsb.config.Configuration;
/**
* @author "OpenAnalytics <rsb.development@openanalytics.eu>"
*/
public class RestJobsITCase extends AbstractITCase {
private String restJobsUri;
private String restResultsUri;
private String uploadFormUri;
@Before
public void prepareTests() throws IOException {
restJobsUri = RSB_BASE_URI + "/api/rest/jobs";
restResultsUri = RSB_BASE_URI + "/api/rest/results";
uploadFormUri = RSB_BASE_URI + "/rsb.html";
}
@After
public void cleanupResults() throws IOException {
final Configuration configuration = getConfiguration();
if (configuration == null) {
return;
}
final File[] testResultFiles = configuration.getResultsDirectory().listFiles(new FilenameFilter() {
public boolean accept(final File dir, final String name) {
return StringUtils.startsWith(name, TEST_APPLICATION_NAME_PREFIX);
}
});
if (testResultFiles == null) {
return;
}
for (final File testResultFile : testResultFiles) {
FileUtils.deleteQuietly(testResultFile);
}
}
// -------- REST API Tests ---------
@Test
public void jobsBadMethod() throws Exception {
doTestUnsupportedDeleteMethod(restJobsUri);
}
@Test
public void jobsBadApplicationName() throws Exception {
final WebConversation wc = new WebConversation();
final WebRequest request = new PostMethodWebRequest(restJobsUri, new ByteArrayInputStream("ignored".getBytes()), "application/xml");
request.setHeaderField("X-RSB-Application-Name", ":bad_app$name!");
try {
wc.sendRequest(request);
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(400, he.getResponseCode());
}
}
@Test
public void jobsBadContentType() throws Exception {
final WebConversation wc = new WebConversation();
final WebRequest request = new PostMethodWebRequest(restJobsUri, new ByteArrayInputStream("ignored".getBytes()),
"application/unsupported");
request.setHeaderField("X-RSB-Application-Name", "myApp");
try {
wc.sendRequest(request);
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(415, he.getResponseCode());
}
}
@Test
public void noResultForApplication() throws Exception {
final WebConversation wc = new WebConversation();
final WebResponse res = wc.sendRequest(new GetMethodWebRequest(restResultsUri + "/fooAppName"));
assertEquals(200, res.getResponseCode());
assertEquals("application/vnd.rsb+xml", res.getHeaderField("Content-Type"));
final String xml = res.getText();
assertXpathExists("/rsb:results", xml);
assertXpathNotExists("/rsb:results/rsb:result", res.getText());
}
@Test
public void noResultForApplicationAsJson() throws Exception {
final WebConversation wc = new WebConversation();
final GetMethodWebRequest request = new GetMethodWebRequest(restResultsUri + "/fooAppName");
request.setHeaderField("Accept", "application/vnd.rsb+json");
final WebResponse res = wc.sendRequest(request);
assertEquals(200, res.getResponseCode());
assertEquals("application/vnd.rsb+json", res.getHeaderField("Content-Type"));
assertEquals("{\"results\":\"\"}", res.getText());
}
@Test
public void resultNotFound() throws Exception {
final WebConversation wc = new WebConversation();
try {
wc.sendRequest(new GetMethodWebRequest(restResultsUri + "/fooAppName/de2e7d40-8253-11e0-885e-0002a5d5c51b"));
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(404, he.getResponseCode());
}
}
@Test
public void submitValidXmlJobAndRetrieveByAppName() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidXmlJob(applicationName);
final String applicationResultsUri = getApplicationResultsUri(resultDoc);
final String resultUri = ponderUntilOneResultAvailable(applicationResultsUri);
retrieveAndValidateXmlResult(resultUri);
}
@Test
public void submitValidXmlJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidXmlJob(applicationName);
final String resultUri = getResultUri(resultDoc);
ponderUntilOneResultAvailable(resultUri);
retrieveAndValidateXmlResult(resultUri);
}
@Test
public void deleteResult() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidXmlJob(applicationName);
final String resultUri = getResultUri(resultDoc);
ponderUntilOneResultAvailable(resultUri);
final WebConversation wc = new WebConversation();
final WebResponse response = wc.sendRequest(new DeleteMethodWebRequest(resultUri));
assertEquals(204, response.getResponseCode());
try {
wc.sendRequest(new GetMethodWebRequest(resultUri));
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(404, he.getResponseCode());
}
}
@Test
public void submitInvalidXmlJobAndRetrieveErrorResult() throws Exception {
final String applicationName = newTestApplicationName();
final Document responseDocument = doSubmitInvalidXmlJob(applicationName);
final String resultUri = getResultUri(responseDocument);
final String jobId = XMLUnit.newXpathEngine().evaluate("/rsb:jobToken/@jobId", responseDocument);
ponderUntilOneResultAvailable(resultUri);
retrieveAndValidateXmlError(resultUri, jobId);
}
@Test
public void submitValidJsonJobAndRetrieveByAppName() throws Exception {
final String applicationName = newTestApplicationName();
final Map<?, ?> responseObject = doSubmitValidJsonJob(applicationName);
final String applicationResultsUri = getApplicationResultsUri(responseObject);
ponderUntilOneResultAvailable(applicationResultsUri);
final String resultUri = getResultUri(responseObject);
retrieveAndValidateJsonResult(resultUri);
}
@Test
public void submitInvalidJsonJob() throws Exception {
final String applicationName = newTestApplicationName();
final Map<?, ?> responseObject = doSubmitInvalidJsonJob(applicationName);
final String applicationResultsUri = getApplicationResultsUri(responseObject);
ponderUntilOneResultAvailable(applicationResultsUri);
final String resultUri = getResultUri(responseObject);
retrieveAndValidateJsonError(resultUri);
}
@Test
public void forwardedProtocol() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doTestSubmitXmlJobWithXmlAck(applicationName, getTestData("r-job-sample.xml"),
Collections.singletonMap("X-Forwarded-Protocol", "foo"));
assertThat(getApplicationResultsUri(resultDoc), is(new StartsWith("foo:/")));
assertThat(getResultUri(resultDoc), is(new StartsWith("foo:/")));
}
@Test
public void submitValidZipJob() throws Exception {
final String applicationName = newTestApplicationName();
@SuppressWarnings("unchecked")
final Document resultDoc = doTestSubmitZipJob(applicationName, getTestData("r-job-sample.zip"), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
@SuppressWarnings("unchecked")
public void submitInvalidZipJob() throws Exception {
final String applicationName = newTestApplicationName();
try {
doTestSubmitZipJob(applicationName, getTestData("invalid-job-subdir.zip"), Collections.EMPTY_MAP);
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(400, he.getResponseCode());
}
}
@Test
public void submitValidZipJobWithCatalogRef() throws Exception {
final String applicationName = newTestApplicationName();
@SuppressWarnings("unchecked")
final Document resultDoc = doTestSubmitZipJob(applicationName, getTestData("r-job-catalog-ref.zip"), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
public void submitValidDataOnlyZipJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doTestSubmitZipJob(applicationName, getTestData("r-job-data-only.zip"),
Collections.singletonMap("X-RSB-Meta-rScript", "test.R"));
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
public void submitValidJobRequiringMeta() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doTestSubmitZipJob(applicationName, getTestData("r-job-meta-required.zip"),
Collections.singletonMap("X-RSB-Meta-reportAuthor", "Jules Verne"));
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
public void submitValidJobRequiringMetaWithoutMeta() throws Exception {
final String applicationName = newTestApplicationName();
@SuppressWarnings("unchecked")
final Document resultDoc = doTestSubmitZipJob(applicationName, getTestData("r-job-meta-required.zip"), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderUntilOneResultAvailable(resultUri);
retrieveAndValidateZipError(resultUri);
}
@Test
@SuppressWarnings("unchecked")
public void submitMultipartValidSingleFileJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName, Collections.singletonList(new UploadedFile("test.R")),
Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
@SuppressWarnings("unchecked")
public void submitMultipartValidMultiFilesJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName,
Arrays.asList(new UploadedFile("testSweave.Rnw"), new UploadedFile("testSweave.R")), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
@SuppressWarnings("unchecked")
public void submitMultipartValidZipJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName,
Collections.singletonList(new UploadedFile("r-job-sample.zip")), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
public void submitMultipartValidDataOnlyZipJob() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName,
Collections.singletonList(new UploadedFile("r-job-data-only.zip")),
Collections.singletonMap("X-RSB-Meta-rScript", "test.R"));
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@Test
public void submitMultipartValidJobRequiringMeta() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName,
Collections.singletonList(new UploadedFile("r-job-meta-required.zip")),
Collections.singletonMap("X-RSB-Meta-reportAuthor", "Jules Verne"));
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@SuppressWarnings("unchecked")
@Test
public void testSubmitMultipartNoAttachedFile() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName, Collections.EMPTY_LIST,
Collections.singletonMap("X-RSB-Meta-rScript", "test.R"));
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
@SuppressWarnings("unchecked")
@Test
public void submitMultipartValidZipJobAsOctetStream() throws Exception {
final String applicationName = newTestApplicationName();
final Document resultDoc = doSubmitValidMultipartJob(applicationName,
Collections.singletonList(new UploadedFile("r-job-sample.zip", "application/octet-stream")), Collections.EMPTY_MAP);
final String resultUri = getResultUri(resultDoc);
ponderRetrieveAndValidateZipResult(resultUri);
}
// -------- Supporting Methods ---------
private void retrieveAndValidateXmlResult(final String resultUri) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "xml");
final String result = getStringResponse(dataUri);
final Document resultDocument = XMLUnit.buildTestDocument(result);
assertXpathEvaluatesTo("provideMeansAndPlotPerDosageGroup", "/statDataPackage/statHeader/RFunction/text()", resultDocument);
}
private void retrieveAndValidateXmlError(final String resultUri, final String jobId) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "xml");
final String result = getStringResponse(dataUri);
final Document resultDocument = XMLUnit.buildTestDocument(result);
assertXpathEvaluatesTo(jobId, "/rsb:errorResult/@jobId", resultDocument);
}
private void retrieveAndValidateJsonResult(final String resultUri) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "json");
final String result = getStringResponse(dataUri);
assertNotNull(Util.fromJson(result, List.class));
}
private void retrieveAndValidateJsonError(final String resultUri) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "json");
final String result = getStringResponse(dataUri);
final Map<?, ?> jsonResult = Util.fromJson(result, Map.class);
assertNotNull(jsonResult);
assertNotNull(jsonResult.get("errorMessage"));
}
private Document doSubmitValidXmlJob(final String applicationName) throws IOException, SAXException, XpathException {
return doSubmitXmlJob(applicationName, getTestData("r-job-sample.xml"));
}
private Map<?, ?> doSubmitValidJsonJob(final String applicationName) throws IOException, SAXException, XpathException {
return doTestSubmitJobWithJsonAck(applicationName, getTestData("r-job-sample.json"));
}
private Map<?, ?> doSubmitInvalidJsonJob(final String applicationName) throws IOException, SAXException, XpathException {
return doTestSubmitJobWithJsonAck(applicationName, new ByteArrayInputStream("not json".getBytes()));
}
private Document doSubmitInvalidXmlJob(final String applicationName) throws IOException, SAXException, XpathException {
return doSubmitXmlJob(applicationName, new ByteArrayInputStream("<bad/>".getBytes()));
}
@SuppressWarnings("unchecked")
private Document doSubmitXmlJob(final String applicationName, final InputStream xmlJob) throws IOException, SAXException,
XpathException {
return doTestSubmitXmlJobWithXmlAck(applicationName, xmlJob, Collections.EMPTY_MAP);
}
private Document doSubmitValidMultipartJob(final String applicationName, final List<UploadedFile> jobFiles,
final Map<String, String> extraFields) throws Exception {
// disable javascript because final we want a final normal form post final to happen and
// final not an final AJAX one final
final WebClient webClient = createNewWebClient();
// get the upload form from RSB web server final
final HtmlPage jobUploadPage = webClient.getPage(uploadFormUri);
final HtmlForm jobUploadForm = jobUploadPage.getFormByName("jobUploadForm");
// fill the form and submit it
if (!jobFiles.isEmpty()) {
final HtmlFileInput fileInput = jobUploadForm.getInputByName("X-RSB-JobFile[]");
final UploadedFile firstFile = jobFiles.get(0);
setUploadedFileOnInputControl(fileInput, firstFile);
for (int i = 1; i < jobFiles.size(); i++) {
final HtmlFileInput extraFileInput = (HtmlFileInput) fileInput.cloneNode(true);
final UploadedFile uploadedFile = jobFiles.get(i);
setUploadedFileOnInputControl(extraFileInput, uploadedFile);
jobUploadForm.appendChild(extraFileInput);
}
}
final HtmlInput applicationNameInput = jobUploadForm.getInputByName("X-RSB-Application-Name");
applicationNameInput.setValueAttribute(applicationName);
// deal with extra meta fields
for (final Entry<String, String> extraField : extraFields.entrySet()) {
final String inputName = extraField.getKey();
HtmlInput input = null;
try {
input = jobUploadForm.getInputByName(inputName);
} catch (final ElementNotFoundException enfe) {
// generate the missing input on the fly (like a dynamic web form would do) by
// cloning an existing one
input = (HtmlInput) applicationNameInput.cloneNode(true);
input.setAttribute("name", inputName);
jobUploadForm.appendChild(input);
}
input.setValueAttribute(extraField.getValue());
}
final Page jobUploadConfirmationPage = jobUploadForm.getInputByName("jobSubmitButton").click();
final com.gargoylesoftware.htmlunit.WebResponse response = jobUploadConfirmationPage.getWebResponse();
// terminate web client and evaluate response validity webClient.closeAllWindows();
return parseJobSubmissionXmlAckResponse(applicationName, response.getStatusCode(), response.getResponseHeaderValue("Content-Type"),
response.getContentAsString());
}
private void setUploadedFileOnInputControl(final HtmlFileInput fileInput, final UploadedFile uploadedFile) {
fileInput.setValueAttribute(getTestFile(uploadedFile.name).getPath());
if (uploadedFile.contentType != null) {
fileInput.setContentType(uploadedFile.contentType);
}
}
private void ponderRetrieveAndValidateZipResult(final String resultUri) throws Exception {
ponderUntilOneResultAvailable(resultUri);
retrieveAndValidateZipResult(resultUri);
}
private void retrieveAndValidateZipResult(final String resultUri) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "zip");
validateZipResult(getStreamResponse(dataUri));
}
private void retrieveAndValidateZipError(final String resultUri) throws Exception {
final String dataUri = doTestResultAvailability(resultUri, "txt");
validateErrorResult(getStreamResponse(dataUri));
}
private Document doTestSubmitZipJob(final String applicationName, final InputStream job, final Map<String, String> extraHeaders)
throws IOException, SAXException, XpathException {
return doTestSubmitJobWithXmlAck(applicationName, job, "application/zip", extraHeaders);
}
private String ponderUntilOneResultAvailable(final String watchUri) throws Exception {
for (int attemptCount = 0; attemptCount < 60; attemptCount++) {
Thread.sleep(500);
final WebConversation wc = new WebConversation();
final WebRequest request = new GetMethodWebRequest(watchUri);
try {
final WebResponse response = wc.sendRequest(request);
final String responseText = response.getText();
final Document responseDocument = XMLUnit.buildTestDocument(responseText);
final String selfUri = XMLUnit.newXpathEngine().evaluate("//rsb:result/@selfUri", responseDocument);
if (StringUtils.isNotBlank(selfUri)) {
return selfUri;
}
} catch (final RuntimeException e) {
// ignore exceptions final due to 404
}
}
fail("Result didn't come on time at URI: " + watchUri);
return null;
}
private Document doTestSubmitXmlJobWithXmlAck(final String applicationName, final InputStream job,
final Map<String, String> extraHeaders) throws IOException, SAXException, XpathException {
return doTestSubmitJobWithXmlAck(applicationName, job, "application/xml", extraHeaders);
}
private Document doTestSubmitJobWithXmlAck(final String applicationName, final InputStream job, final String jobContentType,
final Map<String, String> extraHeaders) throws IOException, SAXException, XpathException {
final WebConversation wc = new WebConversation();
final PostMethodWebRequest request = new PostMethodWebRequest(restJobsUri, job, jobContentType);
request.setHeaderField("X-RSB-Application-Name", applicationName);
for (final Entry<String, String> extraHeader : extraHeaders.entrySet()) {
request.setHeaderField(extraHeader.getKey(), extraHeader.getValue());
}
final WebResponse response = wc.sendRequest(request);
return parseJobSubmissionRsbXmlAckResponse(applicationName, response.getResponseCode(), response.getHeaderField("Content-Type"),
response.getText());
}
private Document parseJobSubmissionRsbXmlAckResponse(final String applicationName, final int statusCode, final String contentType,
final String entity) throws SAXException, IOException, XpathException {
return parseJobSubmissionRsbXmlAckResponse(applicationName, statusCode, "application/vnd.rsb+xml", contentType, entity);
}
private Document parseJobSubmissionXmlAckResponse(final String applicationName, final int statusCode, final String contentType,
final String entity) throws SAXException, IOException, XpathException {
return parseJobSubmissionRsbXmlAckResponse(applicationName, statusCode, "application/xml", contentType, entity);
}
private Document parseJobSubmissionRsbXmlAckResponse(final String applicationName, final int statusCode,
final String expectedContentType, final String contentType, final String entity) throws SAXException, IOException,
XpathException {
assertEquals(202, statusCode);
assertEquals(expectedContentType, contentType);
final Document responseDocument = XMLUnit.buildTestDocument(entity);
assertXpathEvaluatesTo(applicationName, "/rsb:jobToken/@applicationName", responseDocument);
assertXpathExists("/rsb:jobToken/@jobId", responseDocument);
assertXpathExists("/rsb:jobToken/@resultUri", responseDocument);
return responseDocument;
}
private Map<?, ?> doTestSubmitJobWithJsonAck(final String applicationName, final InputStream job) throws IOException, SAXException,
XpathException {
final WebConversation wc = new WebConversation();
final WebRequest request = new PostMethodWebRequest(restJobsUri, job, "application/json");
request.setHeaderField("X-RSB-Application-Name", applicationName);
request.setHeaderField("Accept", "application/vnd.rsb+json");
final WebResponse response = wc.sendRequest(request);
assertEquals(202, response.getResponseCode());
assertEquals("application/vnd.rsb+json", response.getHeaderField("Content-Type"));
final Map<?, ?> jsonResult = (Map<?, ?>) Util.fromJson(response.getText(), Map.class).get("jobToken");
assertEquals(applicationName, jsonResult.get("applicationName"));
assertNotNull(jsonResult.get("jobId"));
assertNotNull(jsonResult.get("resultUri"));
return jsonResult;
}
private String doTestResultAvailability(final String resultUri, final String expectedType) throws Exception {
final WebConversation wc = new WebConversation();
final WebResponse response = wc.sendRequest(new GetMethodWebRequest(resultUri));
assertEquals(200, response.getResponseCode());
assertEquals("application/vnd.rsb+xml", response.getHeaderField("Content-Type"));
final String responseText = response.getText();
final Document responseDocument = XMLUnit.buildTestDocument(responseText);
assertXpathExists("//rsb:result/@jobId", responseDocument);
assertXpathExists("//rsb:result/@applicationName", responseDocument);
assertXpathExists("//rsb:result/@resultTime", responseDocument);
assertXpathExists("//rsb:result/@selfUri", responseDocument);
assertXpathExists("//rsb:result/@type", responseDocument);
assertXpathEvaluatesTo(expectedType, "//rsb:result/@type", responseDocument);
assertXpathExists("//rsb:result/@dataUri", responseDocument);
return XMLUnit.newXpathEngine().evaluate("//rsb:result/@dataUri", responseDocument);
}
private static String getStringResponse(final String resultUri) throws IOException, SAXException {
return getResponse(resultUri).getText();
}
private static InputStream getStreamResponse(final String resultUri) throws IOException, SAXException {
return getResponse(resultUri).getInputStream();
}
private static WebResponse getResponse(final String resultUri) throws IOException, SAXException {
final WebConversation wc = new WebConversation();
final WebRequest request = new GetMethodWebRequest(resultUri);
final WebResponse response = wc.sendRequest(request);
return response;
}
private static String getResultUri(final Document responseDocument) throws XpathException {
return XMLUnit.newXpathEngine().evaluate("/rsb:jobToken/@resultUri", responseDocument);
}
private static String getApplicationResultsUri(final Document responseDocument) throws XpathException {
return XMLUnit.newXpathEngine().evaluate("/rsb:jobToken/@applicationResultsUri", responseDocument);
}
private static String getResultUri(final Map<?, ?> jsonResult) {
return jsonResult.get("resultUri").toString();
}
private static String getApplicationResultsUri(final Map<?, ?> jsonResult) {
return jsonResult.get("applicationResultsUri").toString();
}
private static class UploadedFile {
String name;
String contentType;
UploadedFile(final String name) {
this(name, null);
}
UploadedFile(final String name, final String contentType) {
this.name = name;
this.contentType = contentType;
}
}
private static void doTestUnsupportedDeleteMethod(final String requestUri) throws IOException, SAXException {
final WebConversation wc = new WebConversation();
final WebRequest request = new DeleteMethodWebRequest(requestUri);
try {
wc.sendRequest(request);
fail("an exception should have been raised");
} catch (final HttpException he) {
assertEquals(405, he.getResponseCode());
}
}
private static WebClient createNewWebClient() {
final WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(false);
return webClient;
}
}