Java tutorial
/* * 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; } }