HttpURLConnection.setRequestMethod(String)
* The implementation of Sun Microsystems is throwing a ProtocolException
diff --git a/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaTest.java b/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaTest.java
index 3fccbba958..d46adecbbe 100644
--- a/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaTest.java
+++ b/core/src/test/java/org/jclouds/http/BackoffLimitedRetryJavaTest.java
@@ -16,38 +16,37 @@
*/
package org.jclouds.http;
+import static com.google.common.io.Closeables.close;
+import static org.jclouds.Constants.PROPERTY_MAX_RETRIES;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
-import java.io.IOException;
import java.util.Properties;
-import java.util.concurrent.ExecutionException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.eclipse.jetty.server.Request;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.testng.annotations.Test;
import com.google.inject.Module;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
/**
* Tests the retry behavior of the default {@link RetryHandler} implementation
- * {@link BackoffLimitedRetryHandler} to ensure that retries up to the default limit succeed.
- *
- * TODO: Should either explicitly set retry limit or get it from Guice, rather than assuming it's 5.
+ * {@link BackoffLimitedRetryHandler} to ensure that retries up to the default
+ * limit succeed.
*
* @author James Murty
+ * @author Ignasi Barrera
*/
-@Test(sequential = true)
-public class BackoffLimitedRetryJavaTest extends BaseJettyTest {
- private int beginToFailOnRequestNumber = 0;
- private int endFailuresOnRequestNumber = 0;
- private int requestCount = 0;
+@Test(groups = "integration")
+public class BackoffLimitedRetryJavaTest extends BaseMockWebServerTest {
+
+ private final int maxRetries = 5;
@Override
- protected void addConnectionProperties(Properties props) {
+ protected void addOverrideProperties(Properties props) {
+ props.setProperty(PROPERTY_MAX_RETRIES, "" + maxRetries);
}
@Override
@@ -55,84 +54,98 @@ public class BackoffLimitedRetryJavaTest extends BaseJettyTest {
return new JavaUrlHttpCommandExecutorServiceModule();
}
- @Override
- protected boolean failEveryTenRequests(HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- requestCount++;
- boolean shouldFail = requestCount >= beginToFailOnRequestNumber
- && requestCount <= endFailuresOnRequestNumber;
- if (shouldFail) {
- response.sendError(500);
- ((Request) request).setHandled(true);
- return true;
- } else {
- return false;
- }
- }
-
- protected String submitGetRequest() throws InterruptedException, ExecutionException {
- return client.download("");
+ protected IntegrationTestClient client(String url) {
+ return api(IntegrationTestClient.class, url);
}
@Test
- public void testNoRetriesSuccessful() throws InterruptedException, ExecutionException {
- beginToFailOnRequestNumber = 1;
- endFailuresOnRequestNumber = 1;
- requestCount = 0;
-
- assertEquals(submitGetRequest().trim(), XML);
- }
-
- @Test
- public void testSingleRetrySuccessful() throws InterruptedException, ExecutionException {
- beginToFailOnRequestNumber = 0;
- endFailuresOnRequestNumber = 1;
- requestCount = 0;
-
- assertEquals(submitGetRequest().trim(), XML);
- }
-
- @Test
- public void testMaximumRetriesSuccessful() throws InterruptedException, ExecutionException {
- beginToFailOnRequestNumber = 0;
- endFailuresOnRequestNumber = 5;
- requestCount = 0;
-
- assertEquals(submitGetRequest().trim(), XML);
- }
-
- @Test
- public void testMaximumRetriesExceeded() throws InterruptedException, ExecutionException {
- beginToFailOnRequestNumber = 0;
- endFailuresOnRequestNumber = 6;
- requestCount = 0;
-
+ public void testNoRetriesSuccessful() throws Exception {
+ MockWebServer server = mockWebServer(new MockResponse());
+ IntegrationTestClient client = client(server.getUrl("/").toString());
try {
- submitGetRequest();
- fail("Request should not succeed within " + endFailuresOnRequestNumber + " requests");
- } catch (HttpResponseException e) {
- assertEquals(e.getResponse().getStatusCode(), 500);
+ client.download("");
+ assertEquals(server.getRequestCount(), 1);
+ } finally {
+ close(client, true);
+ server.shutdown();
}
}
@Test
- public void testInterleavedSuccessesAndFailures() throws InterruptedException,
- ExecutionException {
- beginToFailOnRequestNumber = 3;
- endFailuresOnRequestNumber = 3 + 5; // Force third request to fail completely
- requestCount = 0;
-
- assertEquals(submitGetRequest().trim(), XML);
- assertEquals(submitGetRequest().trim(), XML);
-
+ public void testSingleRetrySuccessful() throws Exception {
+ MockWebServer server = mockWebServer(new MockResponse().setResponseCode(500), new MockResponse());
+ IntegrationTestClient client = client(server.getUrl("/").toString());
try {
- submitGetRequest();
- fail("Third request should not succeed by attempt number " + requestCount);
- } catch (HttpResponseException e) {
- assertEquals(e.getResponse().getStatusCode(), 500);
+ client.download("");
+ assertEquals(server.getRequestCount(), 2);
+ } finally {
+ close(client, true);
+ server.shutdown();
+ }
+ }
+
+ @Test
+ public void testMaximumRetriesSuccessful() throws Exception {
+ MockWebServer server = mockWebServer();
+ for (int i = 0; i < maxRetries - 1; i++) {
+ server.enqueue(new MockResponse().setResponseCode(500));
+ }
+ server.enqueue(new MockResponse());
+
+ IntegrationTestClient client = client(server.getUrl("/").toString());
+ try {
+ client.download("");
+ assertEquals(server.getRequestCount(), maxRetries);
+ } finally {
+ close(client, true);
+ server.shutdown();
+ }
+ }
+
+ @Test
+ public void testMaximumRetriesExceeded() throws Exception {
+ MockWebServer server = mockWebServer();
+ for (int i = 0; i <= maxRetries; i++) {
+ server.enqueue(new MockResponse().setResponseCode(500));
}
- assertEquals(submitGetRequest().trim(), XML);
+ IntegrationTestClient client = client(server.getUrl("/").toString());
+ try {
+
+ client.download("");
+ fail("Request should not succeed within " + maxRetries + " requests");
+ } catch (HttpResponseException ex) {
+ assertEquals(ex.getResponse().getStatusCode(), 500);
+ assertEquals(server.getRequestCount(), maxRetries + 1);
+ } finally {
+ close(client, true);
+ server.shutdown();
+ }
+ }
+
+ @Test
+ public void testInterleavedSuccessesAndFailures() throws Exception {
+ MockWebServer server = mockWebServer(new MockResponse(), new MockResponse());
+ for (int i = 0; i <= maxRetries; i++) {
+ server.enqueue(new MockResponse().setResponseCode(500));
+ }
+
+ IntegrationTestClient client = client(server.getUrl("/").toString());
+ try {
+ client.download("");
+ client.download("");
+
+ try {
+ client.download("");
+ fail("Request should not succeed within " + maxRetries + " requests");
+ } catch (HttpResponseException ex) {
+ assertEquals(ex.getResponse().getStatusCode(), 500);
+ assertEquals(server.getRequestCount(), maxRetries + 3);
+ }
+ } finally {
+ close(client, true);
+ server.shutdown();
+ }
}
}
diff --git a/core/src/test/java/org/jclouds/http/BaseHttpCommandExecutorServiceIntegrationTest.java b/core/src/test/java/org/jclouds/http/BaseHttpCommandExecutorServiceIntegrationTest.java
index 40855c2a21..dbd3fcfcc8 100644
--- a/core/src/test/java/org/jclouds/http/BaseHttpCommandExecutorServiceIntegrationTest.java
+++ b/core/src/test/java/org/jclouds/http/BaseHttpCommandExecutorServiceIntegrationTest.java
@@ -18,72 +18,148 @@ package org.jclouds.http;
import static com.google.common.hash.Hashing.md5;
import static com.google.common.io.BaseEncoding.base64;
-import static java.lang.String.format;
+import static com.google.common.io.ByteStreams.join;
+import static com.google.common.io.ByteStreams.newInputStreamSupplier;
+import static com.google.common.io.ByteStreams.toByteArray;
+import static com.google.common.io.Closeables.close;
+import static com.google.common.io.Files.asByteSource;
import static org.jclouds.http.options.GetOptions.Builder.tail;
import static org.jclouds.io.ByteSources.asByteSource;
-import static org.jclouds.io.Payloads.newFilePayload;
-import static org.jclouds.io.Payloads.newStringPayload;
-import static org.jclouds.util.Closeables2.closeQuietly;
-import static org.jclouds.util.Throwables2.getFirstThrowableOfType;
+import static org.jclouds.io.Payloads.newByteSourcePayload;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Writer;
-import java.net.MalformedURLException;
-import java.net.URI;
+import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.Random;
+import java.util.zip.GZIPInputStream;
import org.jclouds.io.Payload;
import org.jclouds.util.Strings2;
+import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
+import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
+import com.google.common.io.ByteSource;
import com.google.common.io.CharSink;
import com.google.common.io.Files;
+import com.google.common.io.InputSupplier;
+import com.squareup.okhttp.mockwebserver.Dispatcher;
+import com.squareup.okhttp.mockwebserver.MockResponse;
+import com.squareup.okhttp.mockwebserver.MockWebServer;
+import com.squareup.okhttp.mockwebserver.RecordedRequest;
/**
- * Tests for functionality all {@link HttpCommandExecutorService http executor
- * services} must express. These tests will operate against an in-memory http
+ * Tests for functionality all {@link HttpCommandExecutorService} http executor
+ * services must express. These tests will operate against an in-memory http
* engine, so as to ensure end-to-end functionality works.
*
* @author Adrian Cole
+ * @author Ignasi Barrera
*/
-@Test(threadPoolSize = 10, groups = "integration")
-public abstract class BaseHttpCommandExecutorServiceIntegrationTest extends BaseJettyTest {
+@Test(groups = "integration")
+public abstract class BaseHttpCommandExecutorServiceIntegrationTest extends BaseMockWebServerTest {
- @Test(invocationCount = 25, timeOut = 5000)
- public void testRequestFilter() {
- assertEquals(client.downloadFilter("", "filterme").trim(), "test");
+ private static final String XML = "
+ * Unless a concrete HTTP is required, subclasses may want to use the
+ * {@link JavaUrlHttpCommandExecutorServiceModule}.
+ */
+ protected abstract Module createConnectionModule();
+
+}
diff --git a/core/src/test/java/org/jclouds/http/IntegrationTestAsyncClient.java b/core/src/test/java/org/jclouds/http/IntegrationTestAsyncClient.java
index 1ecf08b487..50eb3c93ed 100644
--- a/core/src/test/java/org/jclouds/http/IntegrationTestAsyncClient.java
+++ b/core/src/test/java/org/jclouds/http/IntegrationTestAsyncClient.java
@@ -196,6 +196,10 @@ public interface IntegrationTestAsyncClient extends Closeable {
}
+ @POST
+ @Path("/objects/{id}")
+ ListenableFuture
HttpCommandExecutorService
that uses the
+ * OkHttp client to support modern HTTP methods such as PATCH.
+ *
+ * @author Ignasi Barrera
+ */
+@Singleton
+public class OkHttpCommandExecutorService extends JavaUrlHttpCommandExecutorService {
+
+ @Inject
+ public OkHttpCommandExecutorService(HttpUtils utils, ContentMetadataCodec contentMetadataCodec,
+ @Named(Constants.PROPERTY_IO_WORKER_THREADS) ListeningExecutorService ioExecutor,
+ DelegatingRetryHandler retryHandler, IOExceptionRetryHandler ioRetryHandler,
+ DelegatingErrorHandler errorHandler, HttpWire wire, @Named("untrusted") HostnameVerifier verifier,
+ @Named("untrusted") Supplier