mirror of https://github.com/apache/jclouds.git
fix issue #1289 bug in zero length put
This commit is contained in:
parent
d3bf1288df
commit
9723c62f0f
|
@ -247,8 +247,10 @@ public class JavaUrlHttpCommandExecutorService extends BaseHttpCommandExecutorSe
|
||||||
} else {
|
} else {
|
||||||
connection.setRequestProperty(CONTENT_LENGTH, "0");
|
connection.setRequestProperty(CONTENT_LENGTH, "0");
|
||||||
// for some reason POST/PUT undoes the content length header above.
|
// for some reason POST/PUT undoes the content length header above.
|
||||||
if (ImmutableSet.of("POST", "PUT").contains(connection.getRequestMethod()))
|
if (ImmutableSet.of("POST", "PUT").contains(connection.getRequestMethod())) {
|
||||||
connection.setFixedLengthStreamingMode(0);
|
connection.setFixedLengthStreamingMode(0);
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,4 +278,9 @@ public abstract class BaseHttpCommandExecutorServiceIntegrationTest extends Base
|
||||||
TimeoutException {
|
TimeoutException {
|
||||||
assertEquals(client.downloadAndParse(""), "whoppers");
|
assertEquals(client.downloadAndParse(""), "whoppers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(invocationCount = 5, timeOut = 5000)
|
||||||
|
public void testZeroLengthPut() {
|
||||||
|
client.putNothing("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.http;
|
package org.jclouds.http;
|
||||||
|
|
||||||
import static com.google.common.base.Throwables.propagate;
|
import static com.google.common.base.Throwables.getStackTraceAsString;
|
||||||
import static com.google.common.collect.Maps.newHashMap;
|
import static com.google.common.hash.Hashing.md5;
|
||||||
import static com.google.common.io.ByteStreams.copy;
|
import static com.google.common.io.ByteStreams.copy;
|
||||||
import static com.google.common.io.ByteStreams.join;
|
import static com.google.common.io.ByteStreams.join;
|
||||||
import static com.google.common.io.ByteStreams.newInputStreamSupplier;
|
import static com.google.common.io.ByteStreams.newInputStreamSupplier;
|
||||||
|
@ -40,8 +40,8 @@ import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -50,7 +50,6 @@ import java.util.zip.GZIPInputStream;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
|
@ -59,19 +58,19 @@ import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||||
import org.jclouds.Constants;
|
|
||||||
import org.jclouds.ContextBuilder;
|
import org.jclouds.ContextBuilder;
|
||||||
import org.jclouds.crypto.CryptoStreams;
|
import org.jclouds.crypto.CryptoStreams;
|
||||||
import org.jclouds.io.InputSuppliers;
|
import org.jclouds.io.InputSuppliers;
|
||||||
import org.jclouds.providers.AnonymousProviderMetadata;
|
import org.jclouds.providers.AnonymousProviderMetadata;
|
||||||
import org.jclouds.rest.RestContext;
|
import org.jclouds.rest.RestContext;
|
||||||
import org.jclouds.util.Strings2;
|
import org.testng.annotations.AfterClass;
|
||||||
import org.testng.annotations.AfterTest;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.BeforeTest;
|
|
||||||
import org.testng.annotations.Optional;
|
import org.testng.annotations.Optional;
|
||||||
import org.testng.annotations.Parameters;
|
import org.testng.annotations.Parameters;
|
||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.LinkedHashMultimap;
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
@ -94,43 +93,42 @@ public abstract class BaseJettyTest {
|
||||||
protected String md5;
|
protected String md5;
|
||||||
static final Pattern actionPattern = Pattern.compile("/objects/(.*)/action/([a-z]*);?(.*)");
|
static final Pattern actionPattern = Pattern.compile("/objects/(.*)/action/([a-z]*);?(.*)");
|
||||||
|
|
||||||
@BeforeTest
|
@BeforeClass
|
||||||
@Parameters( { "test-jetty-port" })
|
@Parameters({ "test-jetty-port" })
|
||||||
public void setUpJetty(@Optional("8123") final int testPort) throws Exception {
|
public void setUpJetty(@Optional("8123") final int testPort) throws Exception {
|
||||||
this.testPort = testPort;
|
this.testPort = testPort;
|
||||||
|
|
||||||
final InputSupplier<InputStream> oneHundredOneConstitutions = getTestDataSupplier();
|
final InputSupplier<InputStream> oneHundredOneConstitutions = getTestDataSupplier();
|
||||||
|
|
||||||
md5 = CryptoStreams.md5Base64(oneHundredOneConstitutions);
|
md5 = CryptoStreams.md5Base64(oneHundredOneConstitutions);
|
||||||
|
|
||||||
Handler server1Handler = new AbstractHandler() {
|
Handler server1Handler = new AbstractHandler() {
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
InputStream body = request.getInputStream();
|
|
||||||
try {
|
|
||||||
if (failIfNoContentLength(request, response)) {
|
if (failIfNoContentLength(request, response)) {
|
||||||
return;
|
return;
|
||||||
} else if (target.indexOf("sleep") > 0) {
|
} else if (target.indexOf("sleep") > 0) {
|
||||||
try {
|
sleepUninterruptibly(100, TimeUnit.MILLISECONDS);
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
propagate(e);
|
|
||||||
}
|
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
} else if (target.indexOf("redirect") > 0) {
|
} else if (target.indexOf("redirect") > 0) {
|
||||||
|
// in OpenJDK 7.0, expect continue handling is enforced, so we
|
||||||
|
// have to consume the stream.
|
||||||
|
// http://hg.openjdk.java.net/jdk7/tl/jdk/rev/045aeb76b0ff
|
||||||
|
// getInputStream address the expect-continue, per jetty docs
|
||||||
|
// http://wiki.eclipse.org/Jetty/Feature/1xx_Responses#100_Continue
|
||||||
|
toStringAndClose(request.getInputStream());
|
||||||
response.sendRedirect("https://localhost:" + (testPort + 1) + "/");
|
response.sendRedirect("https://localhost:" + (testPort + 1) + "/");
|
||||||
} else if (target.indexOf("101constitutions") > 0) {
|
} else if (target.indexOf("101constitutions") > 0) {
|
||||||
response.setContentType("text/plain");
|
response.setContentType("text/plain");
|
||||||
response.setHeader("Content-MD5", md5);
|
response.setHeader("Content-MD5", md5);
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
copy(oneHundredOneConstitutions.getInput(), response.getOutputStream());
|
copy(oneHundredOneConstitutions, response.getOutputStream());
|
||||||
} else if (request.getMethod().equals("PUT")) {
|
} else if (request.getMethod().equals("PUT")) {
|
||||||
if (request.getContentLength() > 0) {
|
if (request.getContentLength() > 0) {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.getWriter().println(Strings2.toStringAndClose(body) + "PUT");
|
response.getWriter().println(toStringAndClose(request.getInputStream()) + "PUT");
|
||||||
} else {
|
} else {
|
||||||
response.sendError(500, "no content");
|
response.setStatus(SC_OK);
|
||||||
}
|
}
|
||||||
} else if (request.getMethod().equals("POST")) {
|
} else if (request.getMethod().equals("POST")) {
|
||||||
// don't redirect large objects
|
// don't redirect large objects
|
||||||
|
@ -147,27 +145,20 @@ public abstract class BaseJettyTest {
|
||||||
response.sendError(404, "no content");
|
response.sendError(404, "no content");
|
||||||
} else if (request.getHeader("test") != null) {
|
} else if (request.getHeader("test") != null) {
|
||||||
response.setContentType("text/plain");
|
response.setContentType("text/plain");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.getWriter().println("test");
|
response.getWriter().println("test");
|
||||||
} else if (request.getMethod().equals("HEAD")) {
|
} else if (request.getMethod().equals("HEAD")) {
|
||||||
/*
|
// by HTML specification, HEAD response MUST NOT include a body
|
||||||
* NOTE: by HTML specification, HEAD response MUST NOT include a body
|
|
||||||
*/
|
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
} else {
|
} else {
|
||||||
if (failEveryTenRequests(request, response))
|
if (failEveryTenRequests(request, response))
|
||||||
return;
|
return;
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.getWriter().println(XML);
|
response.getWriter().println(XML);
|
||||||
}
|
}
|
||||||
((Request) request).setHandled(true);
|
Request.class.cast(request).setHandled(true);
|
||||||
} catch (IOException e) {
|
|
||||||
if (body != null)
|
|
||||||
closeQuietly(body);
|
|
||||||
response.sendError(500, Throwables.getStackTraceAsString(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -196,26 +187,25 @@ public abstract class BaseJettyTest {
|
||||||
realMd5FromRequest = CryptoStreams.md5Base64(InputSuppliers.of(body));
|
realMd5FromRequest = CryptoStreams.md5Base64(InputSuppliers.of(body));
|
||||||
boolean matched = expectedMd5.equals(realMd5FromRequest);
|
boolean matched = expectedMd5.equals(realMd5FromRequest);
|
||||||
if (matched) {
|
if (matched) {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.addHeader("x-Content-MD5", realMd5FromRequest);
|
response.addHeader("x-Content-MD5", realMd5FromRequest);
|
||||||
} else {
|
} else {
|
||||||
response.sendError(500, "didn't match");
|
response.sendError(500, "didn't match");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String responseString = (request.getContentLength() < 10240) ? Strings2.toStringAndClose(body) + "POST"
|
String responseString = (request.getContentLength() < 10240) ? toStringAndClose(body) + "POST" : "POST";
|
||||||
: "POST";
|
|
||||||
body = null;
|
body = null;
|
||||||
for (String header : new String[] { CONTENT_DISPOSITION, CONTENT_LANGUAGE, CONTENT_ENCODING })
|
for (String header : new String[] { CONTENT_DISPOSITION, CONTENT_LANGUAGE, CONTENT_ENCODING })
|
||||||
if (request.getHeader(header) != null) {
|
if (request.getHeader(header) != null) {
|
||||||
response.addHeader("x-" + header, request.getHeader(header));
|
response.addHeader("x-" + header, request.getHeader(header));
|
||||||
}
|
}
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.getWriter().println(responseString);
|
response.getWriter().println(responseString);
|
||||||
}
|
}
|
||||||
|
Request.class.cast(request).setHandled(true);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (body != null)
|
|
||||||
closeQuietly(body);
|
closeQuietly(body);
|
||||||
response.sendError(500, Throwables.getStackTraceAsString(e));
|
response.sendError(500, getStackTraceAsString(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,13 +213,10 @@ public abstract class BaseJettyTest {
|
||||||
Handler server2Handler = new AbstractHandler() {
|
Handler server2Handler = new AbstractHandler() {
|
||||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||||
throws IOException, ServletException {
|
throws IOException, ServletException {
|
||||||
InputStream body = request.getInputStream();
|
|
||||||
try {
|
|
||||||
if (request.getMethod().equals("PUT")) {
|
if (request.getMethod().equals("PUT")) {
|
||||||
String text = Strings2.toStringAndClose(body);
|
|
||||||
body = null;
|
|
||||||
if (request.getContentLength() > 0) {
|
if (request.getContentLength() > 0) {
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
|
String text = toStringAndClose(request.getInputStream());
|
||||||
response.getWriter().println(text + "PUTREDIRECT");
|
response.getWriter().println(text + "PUTREDIRECT");
|
||||||
}
|
}
|
||||||
} else if (request.getMethod().equals("POST")) {
|
} else if (request.getMethod().equals("POST")) {
|
||||||
|
@ -239,22 +226,15 @@ public abstract class BaseJettyTest {
|
||||||
handleAction(request, response);
|
handleAction(request, response);
|
||||||
}
|
}
|
||||||
} else if (request.getMethod().equals("HEAD")) {
|
} else if (request.getMethod().equals("HEAD")) {
|
||||||
/*
|
// by HTML specification, HEAD response MUST NOT include a body
|
||||||
* NOTE: by HTML specification, HEAD response MUST NOT include a body
|
|
||||||
*/
|
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
} else {
|
} else {
|
||||||
response.setContentType("text/xml");
|
response.setContentType("text/xml");
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
response.setStatus(SC_OK);
|
||||||
response.getWriter().println(XML2);
|
response.getWriter().println(XML2);
|
||||||
}
|
}
|
||||||
((Request) request).setHandled(true);
|
Request.class.cast(request).setHandled(true);
|
||||||
} catch (IOException e) {
|
|
||||||
if (body != null)
|
|
||||||
closeQuietly(body);
|
|
||||||
response.sendError(500, Throwables.getStackTraceAsString(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,7 +250,7 @@ public abstract class BaseJettyTest {
|
||||||
ssl.setTrustStore("src/test/resources/test.jks");
|
ssl.setTrustStore("src/test/resources/test.jks");
|
||||||
ssl.setTrustStorePassword("jclouds");
|
ssl.setTrustStorePassword("jclouds");
|
||||||
|
|
||||||
server2.setConnectors(new Connector[]{ ssl_connector });
|
server2.setConnectors(new Connector[] { ssl_connector });
|
||||||
|
|
||||||
server2.start();
|
server2.start();
|
||||||
}
|
}
|
||||||
|
@ -289,18 +269,18 @@ public abstract class BaseJettyTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ContextBuilder newBuilder(int testPort, Properties properties, Module... connectionModules) {
|
public static ContextBuilder newBuilder(int testPort, Properties properties, Module... connectionModules) {
|
||||||
properties.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
|
properties.setProperty(PROPERTY_TRUST_ALL_CERTS, "true");
|
||||||
properties.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
|
properties.setProperty(PROPERTY_RELAX_HOSTNAME, "true");
|
||||||
return ContextBuilder.newBuilder(
|
return ContextBuilder
|
||||||
AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(IntegrationTestClient.class, IntegrationTestAsyncClient.class,
|
.newBuilder(
|
||||||
"http://localhost:" + testPort))
|
AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint(IntegrationTestClient.class,
|
||||||
.modules(ImmutableSet.<Module> copyOf(connectionModules))
|
IntegrationTestAsyncClient.class, "http://localhost:" + testPort))
|
||||||
.overrides(properties);
|
.modules(ImmutableSet.<Module> copyOf(connectionModules)).overrides(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterTest
|
@AfterClass
|
||||||
public void tearDownJetty() throws Exception {
|
public void tearDownJetty() throws Exception {
|
||||||
context.close();
|
closeQuietly(context);
|
||||||
if (server2 != null)
|
if (server2 != null)
|
||||||
server2.stop();
|
server2.stop();
|
||||||
server.stop();
|
server.stop();
|
||||||
|
@ -321,7 +301,7 @@ public abstract class BaseJettyTest {
|
||||||
protected boolean failEveryTenRequests(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
protected boolean failEveryTenRequests(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
if (cycle.incrementAndGet() % 10 == 0) {
|
if (cycle.incrementAndGet() % 10 == 0) {
|
||||||
response.sendError(500, "unlucky 10");
|
response.sendError(500, "unlucky 10");
|
||||||
((Request) request).setHandled(true);
|
Request.class.cast(request).setHandled(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -331,7 +311,7 @@ public abstract class BaseJettyTest {
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (cycle.incrementAndGet() % 20 == 0) {
|
if (cycle.incrementAndGet() % 20 == 0) {
|
||||||
response.sendRedirect("http://localhost:" + (testPort + 1) + "/");
|
response.sendRedirect("http://localhost:" + (testPort + 1) + "/");
|
||||||
((Request) request).setHandled(true);
|
Request.class.cast(request).setHandled(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -351,7 +331,7 @@ public abstract class BaseJettyTest {
|
||||||
response.getWriter().println("no content length!");
|
response.getWriter().println("no content length!");
|
||||||
response.getWriter().println(realHeaders.toString());
|
response.getWriter().println(realHeaders.toString());
|
||||||
response.sendError(500, "no content length!");
|
response.sendError(500, "no content length!");
|
||||||
((Request) request).setHandled(true);
|
Request.class.cast(request).setHandled(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -363,20 +343,15 @@ public abstract class BaseJettyTest {
|
||||||
if (matchFound) {
|
if (matchFound) {
|
||||||
String objectId = matcher.group(1);
|
String objectId = matcher.group(1);
|
||||||
String action = matcher.group(2);
|
String action = matcher.group(2);
|
||||||
Map<String, String> options = newHashMap();
|
Builder<String, String> options = ImmutableMap.<String, String> builder();
|
||||||
if (matcher.groupCount() == 3) {
|
if (matcher.groupCount() == 3) {
|
||||||
String optionsGroup = matcher.group(3);
|
options.putAll(Splitter.on(';').withKeyValueSeparator("=").split(matcher.group(3)));
|
||||||
for (String entry : optionsGroup.split(";")) {
|
|
||||||
if (entry.indexOf('=') >= 0) {
|
|
||||||
String[] keyValue = entry.split("=");
|
|
||||||
options.put(keyValue[0], keyValue[1]);
|
|
||||||
}
|
}
|
||||||
}
|
response.setStatus(SC_OK);
|
||||||
}
|
response.getWriter().println(objectId + "->" + action + ":" + options.build());
|
||||||
response.setStatus(HttpServletResponse.SC_OK);
|
|
||||||
response.getWriter().println(objectId + "->" + action + ":" + options);
|
|
||||||
} else {
|
} else {
|
||||||
response.sendError(500, "no content");
|
response.sendError(500, "no content");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@ import com.google.inject.Provides;
|
||||||
/**
|
/**
|
||||||
* Sample test for the behaviour of our Integration Test jetty server.
|
* Sample test for the behaviour of our Integration Test jetty server.
|
||||||
*
|
*
|
||||||
|
* @see IntegrationTestClient
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*/
|
*/
|
||||||
public interface IntegrationTestAsyncClient {
|
public interface IntegrationTestAsyncClient {
|
||||||
|
@ -192,6 +193,10 @@ public interface IntegrationTestAsyncClient {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/objects/{id}")
|
||||||
|
ListenableFuture<Void> putNothing(@PathParam("id") String id);
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StringBuilder newStringBuilder();
|
StringBuilder newStringBuilder();
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,8 @@ public interface IntegrationTestClient {
|
||||||
|
|
||||||
String downloadAndParse(String id);
|
String downloadAndParse(String id);
|
||||||
|
|
||||||
|
void putNothing(String id);
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StringBuilder newStringBuilder();
|
StringBuilder newStringBuilder();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue