/*
* Copyright 2011-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 com.amazonaws.http.timers.client;
import static com.amazonaws.http.timers.ClientExecutionAndRequestTimerTestUtils.assertClientExecutionTimerExecutorNotCreated;
import static com.amazonaws.http.timers.ClientExecutionAndRequestTimerTestUtils.assertNumberOfTasksTriggered;
import static com.amazonaws.http.timers.ClientExecutionAndRequestTimerTestUtils.interruptCurrentThreadAfterDelay;
import static com.amazonaws.http.timers.TimeoutTestConstants.CLIENT_EXECUTION_TIMEOUT;
import static com.amazonaws.http.timers.TimeoutTestConstants.PRECISION_MULTIPLIER;
import static com.amazonaws.http.timers.TimeoutTestConstants.TEST_TIMEOUT;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.SocketTimeoutException;
import org.junit.BeforeClass;
import org.junit.Test;
import com.amazonaws.AmazonClientException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.TestPreConditions;
import com.amazonaws.http.AmazonHttpClient;
import com.amazonaws.http.ExecutionContext;
import com.amazonaws.http.UnresponsiveMockServerTestBase;
import com.amazonaws.http.exception.HttpRequestTimeoutException;
import com.amazonaws.http.response.NullErrorResponseHandler;
import com.amazonaws.http.response.NullResponseHandler;
import com.amazonaws.retry.FixedTimeBackoffStrategy;
import com.amazonaws.retry.PredefinedRetryPolicies;
import com.amazonaws.retry.RetryPolicy;
public class UnresponsiveServerIntegrationTests extends UnresponsiveMockServerTestBase {
private static final int LONGER_SOCKET_TIMEOUT = CLIENT_EXECUTION_TIMEOUT * PRECISION_MULTIPLIER;
private static final int SHORTER_SOCKET_TIMEOUT = CLIENT_EXECUTION_TIMEOUT / PRECISION_MULTIPLIER;
private static final int LONGER_REQUEST_TIMEOUT = CLIENT_EXECUTION_TIMEOUT * PRECISION_MULTIPLIER;
private static final int SHORTER_REQUEST_TIMEOUT = CLIENT_EXECUTION_TIMEOUT / PRECISION_MULTIPLIER;
private AmazonHttpClient httpClient;
@BeforeClass
public static void preConditions() {
TestPreConditions.assumeNotJava6();
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutDisabled_SocketTimeoutExceptionIsThrown_NoThreadsCreated() {
httpClient = new AmazonHttpClient(new ClientConfiguration().withSocketTimeout(1 * 1000).withMaxErrorRetry(0));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e.getCause(), instanceOf(SocketTimeoutException.class));
assertClientExecutionTimerExecutorNotCreated(httpClient.getClientExecutionTimer());
}
}
/**
* The client execution timer uses interrupts to abort the client but if another thread
* interrupts the current thread for another reason we don't want to squash the
* {@link InterruptedException}. We should set the thread's interrupted status and throw the
* exception back out (we can't throw the actual {@link InterruptedException} because it's
* checked)
*/
@Test(timeout = TEST_TIMEOUT)
public void interruptCausedBySomethingOtherThanTimer_PropagatesInterruptToCaller() {
final int socketTimeoutInMillis = 100;
httpClient = new AmazonHttpClient(new ClientConfiguration().withSocketTimeout(socketTimeoutInMillis)
.withClientExecutionTimeout(CLIENT_EXECUTION_TIMEOUT)
.withRetryPolicy(new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION,
new FixedTimeBackoffStrategy(CLIENT_EXECUTION_TIMEOUT), 1, false)));
// We make sure the first connection has failed due to the socket timeout before
// interrupting so we know that we are sleeping per the backoff strategy. Apache HTTP
// client doesn't seem to honor interrupts reliably but Thread.sleep does
interruptCurrentThreadAfterDelay(socketTimeoutInMillis * 2);
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertTrue(Thread.currentThread().isInterrupted());
assertThat(e.getCause(), instanceOf(InterruptedException.class));
}
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutEnabled_WithLongerSocketTimeout_ThrowsClientExecutionTimeoutException()
throws IOException {
httpClient = new AmazonHttpClient(new ClientConfiguration().withClientExecutionTimeout(CLIENT_EXECUTION_TIMEOUT)
.withSocketTimeout(LONGER_SOCKET_TIMEOUT).withMaxErrorRetry(0));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e, instanceOf(ClientExecutionTimeoutException.class));
assertNumberOfTasksTriggered(httpClient.getClientExecutionTimer(), 1);
}
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutEnabled_WithShorterSocketTimeout_ThrowsSocketTimeoutException()
throws IOException {
httpClient = new AmazonHttpClient(new ClientConfiguration().withClientExecutionTimeout(CLIENT_EXECUTION_TIMEOUT)
.withSocketTimeout(SHORTER_SOCKET_TIMEOUT).withMaxErrorRetry(0));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e.getCause(), instanceOf(SocketTimeoutException.class));
assertNumberOfTasksTriggered(httpClient.getClientExecutionTimer(), 0);
}
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutEnabled_WithShorterClientExecutionTimeout_ThrowsClientExecutionTimeoutException()
throws IOException {
httpClient = new AmazonHttpClient(new ClientConfiguration().withClientExecutionTimeout(CLIENT_EXECUTION_TIMEOUT)
.withRequestTimeout(LONGER_REQUEST_TIMEOUT).withMaxErrorRetry(0));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e, instanceOf(ClientExecutionTimeoutException.class));
assertNumberOfTasksTriggered(httpClient.getClientExecutionTimer(), 1);
assertNumberOfTasksTriggered(httpClient.getHttpRequestTimer(), 0);
}
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutEnabled_WithShorterRequestTimeout_ThrowsHttpRequestTimeoutException()
throws IOException {
httpClient = new AmazonHttpClient(new ClientConfiguration().withClientExecutionTimeout(CLIENT_EXECUTION_TIMEOUT)
.withRequestTimeout(SHORTER_REQUEST_TIMEOUT).withMaxErrorRetry(0));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e.getCause(), instanceOf(HttpRequestTimeoutException.class));
// Completed tasks means the client execution was aborted by the timer
assertNumberOfTasksTriggered(httpClient.getClientExecutionTimer(), 0);
assertNumberOfTasksTriggered(httpClient.getHttpRequestTimer(), 1);
}
}
@Test(timeout = TEST_TIMEOUT)
public void clientExecutionTimeoutEnabled_WithShorterRequestTimeoutAndRetry_ThrowsClientExecutionTimeoutException()
throws IOException {
final int clientExecutionTimeout = 1500;
final int requestTimeout = 1000;
final int backoffTime = 300;
httpClient = new AmazonHttpClient(new ClientConfiguration().withClientExecutionTimeout(clientExecutionTimeout)
.withRequestTimeout(requestTimeout)
.withRetryPolicy(new RetryPolicy(PredefinedRetryPolicies.DEFAULT_RETRY_CONDITION,
new FixedTimeBackoffStrategy(backoffTime), Integer.MAX_VALUE, false)));
try {
httpClient.requestExecutionBuilder().request(newGetRequest()).execute();
fail("Exception expected");
} catch (AmazonClientException e) {
assertThat(e, instanceOf(ClientExecutionTimeoutException.class));
// Completed tasks means the client execution was aborted by the timer
assertNumberOfTasksTriggered(httpClient.getClientExecutionTimer(), 1);
assertNumberOfTasksTriggered(httpClient.getHttpRequestTimer(), 1);
}
}
}