mirror of
https://github.com/jlengrand/github-api.git
synced 2026-04-04 15:50:52 +00:00
Handle SSLHandshakeException with connection retry
This commit is contained in:
732
src/test/java/org/kohsuke/github/RequesterRetryTest.java
Normal file
732
src/test/java/org/kohsuke/github/RequesterRetryTest.java
Normal file
@@ -0,0 +1,732 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import com.github.tomakehurst.wiremock.http.Fault;
|
||||
import com.github.tomakehurst.wiremock.stubbing.Scenario;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.github.extras.ImpatientHttpConnector;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.security.Permission;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.StreamHandler;
|
||||
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
* @author Victor Martinez
|
||||
*/
|
||||
public class RequesterRetryTest extends AbstractGitHubWireMockTest {
|
||||
|
||||
private static Logger log = Logger.getLogger(Requester.class.getName()); // matches the logger in the affected class
|
||||
private static OutputStream logCapturingStream;
|
||||
private static StreamHandler customLogHandler;
|
||||
HttpURLConnection connection;
|
||||
int baseRequestCount;
|
||||
|
||||
public RequesterRetryTest() {
|
||||
useDefaultGitHub = false;
|
||||
}
|
||||
|
||||
protected GHRepository getRepository() throws IOException {
|
||||
return getRepository(gitHub);
|
||||
}
|
||||
|
||||
private GHRepository getRepository(GitHub gitHub) throws IOException {
|
||||
return gitHub.getOrganization("github-api-test-org").getRepository("github-api");
|
||||
}
|
||||
|
||||
@Before
|
||||
public void attachLogCapturer() {
|
||||
logCapturingStream = new ByteArrayOutputStream();
|
||||
Handler[] handlers = log.getParent().getHandlers();
|
||||
customLogHandler = new StreamHandler(logCapturingStream, handlers[0].getFormatter());
|
||||
log.addHandler(customLogHandler);
|
||||
}
|
||||
|
||||
public String getTestCapturedLog() throws IOException {
|
||||
customLogHandler.flush();
|
||||
return logCapturingStream.toString();
|
||||
}
|
||||
|
||||
public void resetTestCapturedLog() throws IOException {
|
||||
log.removeHandler(customLogHandler);
|
||||
customLogHandler.close();
|
||||
attachLogCapturer();
|
||||
}
|
||||
|
||||
// Issue #539
|
||||
@Test
|
||||
public void testSocketConnectionAndRetry() throws Exception {
|
||||
// CONNECTION_RESET_BY_PEER errors result in two requests each
|
||||
// to get this failure for "3" tries we have to do 6 queries.
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout"))
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)));
|
||||
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
|
||||
GHRepository repo = getRepository();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
repo.getBranch("test/timeout");
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(HttpException.class));
|
||||
}
|
||||
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 6));
|
||||
}
|
||||
|
||||
// Issue #539
|
||||
@Test
|
||||
public void testSocketConnectionAndRetry_StatusCode() throws Exception {
|
||||
// CONNECTION_RESET_BY_PEER errors result in two requests each
|
||||
// to get this failure for "3" tries we have to do 6 queries.
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout"))
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)));
|
||||
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
// status code is a different code path that should also be covered by this.
|
||||
gitHub.createRequest()
|
||||
.withUrlPath("/repos/github-api-test-org/github-api/branches/test/timeout")
|
||||
.fetchHttpStatusCode();
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(HttpException.class));
|
||||
}
|
||||
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocketConnectionAndRetry_Success() throws Exception {
|
||||
// CONNECTION_RESET_BY_PEER errors result in two requests each
|
||||
// to get this failure for "3" tries we have to do 6 queries.
|
||||
// If there are only 5 errors we succeed.
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout")).atPriority(0)
|
||||
.inScenario("Retry")
|
||||
.whenScenarioStateIs(Scenario.STARTED)
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)))
|
||||
.setNewScenarioState("Retry-1");
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout")).atPriority(0)
|
||||
.inScenario("Retry")
|
||||
.whenScenarioStateIs("Retry-1")
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)))
|
||||
.setNewScenarioState("Retry-2");
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout")).atPriority(0)
|
||||
.inScenario("Retry")
|
||||
.whenScenarioStateIs("Retry-2")
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)))
|
||||
.setNewScenarioState("Retry-3");
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout")).atPriority(0)
|
||||
.inScenario("Retry")
|
||||
.whenScenarioStateIs("Retry-3")
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)))
|
||||
.setNewScenarioState("Retry-4");
|
||||
this.mockGitHub.apiServer()
|
||||
.stubFor(get(urlMatching(".+/branches/test/timeout")).atPriority(0)
|
||||
.atPriority(0)
|
||||
.inScenario("Retry")
|
||||
.whenScenarioStateIs("Retry-4")
|
||||
.willReturn(aResponse().withFault(Fault.CONNECTION_RESET_BY_PEER)))
|
||||
.setNewScenarioState("Retry-5");
|
||||
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
|
||||
GHRepository repo = getRepository();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
GHBranch branch = repo.getBranch("test/timeout");
|
||||
assertThat(branch, notNullValue());
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseCodeFailureExceptions() throws Exception {
|
||||
// No retry for these Exceptions
|
||||
HttpConnector connector = new ResponseCodeThrowingHttpConnector<>(() -> {
|
||||
throw new IOException("Custom");
|
||||
});
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
|
||||
.withConnector(connector)
|
||||
.build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
this.gitHub.getOrganization(GITHUB_API_TEST_ORG);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(HttpException.class));
|
||||
assertThat(e.getCause(), instanceOf(IOException.class));
|
||||
assertThat(e.getCause().getMessage(), is("Custom"));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
|
||||
connector = new ResponseCodeThrowingHttpConnector<>(() -> {
|
||||
throw new FileNotFoundException("Custom");
|
||||
});
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
|
||||
.withConnector(connector)
|
||||
.build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
this.gitHub.getOrganization(GITHUB_API_TEST_ORG);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(FileNotFoundException.class));
|
||||
assertThat(e.getMessage(), is("Custom"));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInputStreamFailureExceptions() throws Exception {
|
||||
// No retry for these Exceptions
|
||||
HttpConnector connector = new InputStreamThrowingHttpConnector<>(() -> {
|
||||
throw new IOException("Custom");
|
||||
});
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
|
||||
.withConnector(connector)
|
||||
.build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
this.gitHub.getOrganization(GITHUB_API_TEST_ORG);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(HttpException.class));
|
||||
assertThat(e.getCause(), instanceOf(IOException.class));
|
||||
assertThat(e.getCause().getMessage(), is("Custom"));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
|
||||
// FileNotFound doesn't need a special connector
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
try {
|
||||
this.gitHub.getOrganization(GITHUB_API_TEST_ORG + "-missing");
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
assertThat(e, instanceOf(GHFileNotFoundException.class));
|
||||
assertThat(e.getCause(), instanceOf(FileNotFoundException.class));
|
||||
assertThat(e.getCause().getMessage(), containsString("github-api-test-org-missing"));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
|
||||
// FileNotFound doesn't need a special connector
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
assertThat(
|
||||
this.gitHub.createRequest()
|
||||
.withUrlPath("/orgs/" + GITHUB_API_TEST_ORG + "-missing")
|
||||
.fetchHttpStatusCode(),
|
||||
equalTo(404));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseCodeConnectionExceptions() throws Exception {
|
||||
// Because the test throws at the very start of getResponseCode, there is only one connection for 3 retries
|
||||
HttpConnector connector = new ResponseCodeThrowingHttpConnector<>(() -> {
|
||||
throw new SocketException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 1);
|
||||
runConnectionExceptionStatusCodeTest(connector, 1);
|
||||
|
||||
connector = new ResponseCodeThrowingHttpConnector<>(() -> {
|
||||
throw new SocketTimeoutException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 1);
|
||||
runConnectionExceptionStatusCodeTest(connector, 1);
|
||||
|
||||
connector = new ResponseCodeThrowingHttpConnector<>(() -> {
|
||||
throw new SSLHandshakeException("TestFailure");
|
||||
});
|
||||
runConnectionExceptionTest(connector, 1);
|
||||
runConnectionExceptionStatusCodeTest(connector, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseMessageConnectionExceptions() throws Exception {
|
||||
// Because the test throws after getResponseCode, there is one connection for each retry
|
||||
HttpConnector connector = new ResponseMessageThrowingHttpConnector<>(() -> {
|
||||
throw new SocketException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 3);
|
||||
|
||||
connector = new ResponseMessageThrowingHttpConnector<>(() -> {
|
||||
throw new SocketTimeoutException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 3);
|
||||
|
||||
connector = new ResponseMessageThrowingHttpConnector<>(() -> {
|
||||
throw new SSLHandshakeException("TestFailure");
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInputStreamConnectionExceptions() throws Exception {
|
||||
// InputStream is where most exceptions get thrown whether connection or simple FNF
|
||||
// Because the test throws after getResponseCode, there is one connection for each retry
|
||||
// However, getStatusCode never calls that and so it does succeeds
|
||||
HttpConnector connector = new InputStreamThrowingHttpConnector<>(() -> {
|
||||
throw new SocketException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 0);
|
||||
|
||||
connector = new InputStreamThrowingHttpConnector<>(() -> {
|
||||
throw new SocketTimeoutException();
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 0);
|
||||
|
||||
connector = new InputStreamThrowingHttpConnector<>(() -> {
|
||||
throw new SSLHandshakeException("TestFailure");
|
||||
});
|
||||
runConnectionExceptionTest(connector, 3);
|
||||
runConnectionExceptionStatusCodeTest(connector, 0);
|
||||
}
|
||||
|
||||
private void runConnectionExceptionTest(HttpConnector connector, int expectedRequestCount) throws IOException {
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
|
||||
.withConnector(connector)
|
||||
.build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
assertThat(this.gitHub.getOrganization(GITHUB_API_TEST_ORG), is(notNullValue()));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + expectedRequestCount));
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
this.gitHub.createRequest().withUrlPath("/orgs/" + GITHUB_API_TEST_ORG).send();
|
||||
capturedLog = getTestCapturedLog();
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + expectedRequestCount));
|
||||
}
|
||||
|
||||
private void runConnectionExceptionStatusCodeTest(HttpConnector connector, int expectedRequestCount)
|
||||
throws IOException {
|
||||
// now wire in the connector
|
||||
this.gitHub = getGitHubBuilder().withEndpoint(mockGitHub.apiServer().baseUrl())
|
||||
.withConnector(connector)
|
||||
.build();
|
||||
|
||||
resetTestCapturedLog();
|
||||
baseRequestCount = this.mockGitHub.getRequestCount();
|
||||
assertThat(this.gitHub.createRequest().withUrlPath("/orgs/" + GITHUB_API_TEST_ORG).fetchHttpStatusCode(),
|
||||
equalTo(200));
|
||||
String capturedLog = getTestCapturedLog();
|
||||
if (expectedRequestCount > 0) {
|
||||
assertTrue(capturedLog.contains("will try 2 more time"));
|
||||
assertTrue(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + expectedRequestCount));
|
||||
} else {
|
||||
// Success without retries
|
||||
assertFalse(capturedLog.contains("will try 2 more time"));
|
||||
assertFalse(capturedLog.contains("will try 1 more time"));
|
||||
assertThat(this.mockGitHub.getRequestCount(), equalTo(baseRequestCount + 1));
|
||||
}
|
||||
}
|
||||
|
||||
class ResponseCodeThrowingHttpConnector<E extends IOException> extends ImpatientHttpConnector {
|
||||
|
||||
ResponseCodeThrowingHttpConnector(final Thrower<E> thrower) {
|
||||
super(new HttpConnector() {
|
||||
final int[] count = { 0 };
|
||||
|
||||
@Override
|
||||
public HttpURLConnection connect(URL url) throws IOException {
|
||||
if (url.toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
count[0]++;
|
||||
}
|
||||
connection = Mockito.spy(new HttpURLConnectionWrapper(url) {
|
||||
@Override
|
||||
public int getResponseCode() throws IOException {
|
||||
// While this is not the way this would go in the real world, it is a fine test
|
||||
// to show that exception handling and retries are working as expected
|
||||
if (getURL().toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
if (count[0] % 3 != 0) {
|
||||
thrower.throwError();
|
||||
}
|
||||
}
|
||||
return super.getResponseCode();
|
||||
}
|
||||
});
|
||||
|
||||
return connection;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ResponseMessageThrowingHttpConnector<E extends IOException> extends ImpatientHttpConnector {
|
||||
|
||||
ResponseMessageThrowingHttpConnector(final Thrower<E> thrower) {
|
||||
super(new HttpConnector() {
|
||||
final int[] count = { 0 };
|
||||
|
||||
@Override
|
||||
public HttpURLConnection connect(URL url) throws IOException {
|
||||
if (url.toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
count[0]++;
|
||||
}
|
||||
connection = Mockito.spy(new HttpURLConnectionWrapper(url) {
|
||||
@Override
|
||||
public String getResponseMessage() throws IOException {
|
||||
// getResponseMessage throwing even though getResponseCode doesn't.
|
||||
// While this is not the way this would go in the real world, it is a fine test
|
||||
// to show that exception handling and retries are working as expected
|
||||
if (getURL().toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
if (count[0] % 3 != 0) {
|
||||
thrower.throwError();
|
||||
}
|
||||
}
|
||||
return super.getResponseMessage();
|
||||
}
|
||||
});
|
||||
|
||||
return connection;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class InputStreamThrowingHttpConnector<E extends IOException> extends ImpatientHttpConnector {
|
||||
|
||||
InputStreamThrowingHttpConnector(final Thrower<E> thrower) {
|
||||
super(new HttpConnector() {
|
||||
final int[] count = { 0 };
|
||||
|
||||
@Override
|
||||
public HttpURLConnection connect(URL url) throws IOException {
|
||||
if (url.toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
count[0]++;
|
||||
}
|
||||
connection = Mockito.spy(new HttpURLConnectionWrapper(url) {
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
// getResponseMessage throwing even though getResponseCode doesn't.
|
||||
// While this is not the way this would go in the real world, it is a fine test
|
||||
// to show that exception handling and retries are working as expected
|
||||
if (getURL().toString().contains(GITHUB_API_TEST_ORG)) {
|
||||
if (count[0] % 3 != 0) {
|
||||
thrower.throwError();
|
||||
}
|
||||
}
|
||||
return super.getInputStream();
|
||||
}
|
||||
});
|
||||
|
||||
return connection;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Thrower<E extends Throwable> {
|
||||
void throwError() throws E;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is not great but it get the job done. Tried to do a spy of HttpURLConnection but it wouldn't work right.
|
||||
* Trying to stub methods caused the spy to say it was already connected.
|
||||
*/
|
||||
static class HttpURLConnectionWrapper extends HttpURLConnection {
|
||||
|
||||
protected final HttpURLConnection httpURLConnection;
|
||||
|
||||
HttpURLConnectionWrapper(URL url) throws IOException {
|
||||
super(new URL("http://nonexistant"));
|
||||
httpURLConnection = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
public void connect() throws IOException {
|
||||
httpURLConnection.connect();
|
||||
}
|
||||
|
||||
public void setConnectTimeout(int timeout) {
|
||||
httpURLConnection.setConnectTimeout(timeout);
|
||||
}
|
||||
|
||||
public int getConnectTimeout() {
|
||||
return httpURLConnection.getConnectTimeout();
|
||||
}
|
||||
|
||||
public void setReadTimeout(int timeout) {
|
||||
httpURLConnection.setReadTimeout(timeout);
|
||||
}
|
||||
|
||||
public int getReadTimeout() {
|
||||
return httpURLConnection.getReadTimeout();
|
||||
}
|
||||
|
||||
public URL getURL() {
|
||||
return httpURLConnection.getURL();
|
||||
}
|
||||
|
||||
public int getContentLength() {
|
||||
return httpURLConnection.getContentLength();
|
||||
}
|
||||
|
||||
public long getContentLengthLong() {
|
||||
return httpURLConnection.getContentLengthLong();
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return httpURLConnection.getContentType();
|
||||
}
|
||||
|
||||
public String getContentEncoding() {
|
||||
return httpURLConnection.getContentEncoding();
|
||||
}
|
||||
|
||||
public long getExpiration() {
|
||||
return httpURLConnection.getExpiration();
|
||||
}
|
||||
|
||||
public long getDate() {
|
||||
return httpURLConnection.getDate();
|
||||
}
|
||||
|
||||
public long getLastModified() {
|
||||
return httpURLConnection.getLastModified();
|
||||
}
|
||||
|
||||
public String getHeaderField(String name) {
|
||||
return httpURLConnection.getHeaderField(name);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeaderFields() {
|
||||
return httpURLConnection.getHeaderFields();
|
||||
}
|
||||
|
||||
public int getHeaderFieldInt(String name, int Default) {
|
||||
return httpURLConnection.getHeaderFieldInt(name, Default);
|
||||
}
|
||||
|
||||
public long getHeaderFieldLong(String name, long Default) {
|
||||
return httpURLConnection.getHeaderFieldLong(name, Default);
|
||||
}
|
||||
|
||||
public Object getContent() throws IOException {
|
||||
return httpURLConnection.getContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getContent(Class[] classes) throws IOException {
|
||||
return httpURLConnection.getContent(classes);
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return httpURLConnection.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return httpURLConnection.getOutputStream();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return httpURLConnection.toString();
|
||||
}
|
||||
|
||||
public void setDoInput(boolean doinput) {
|
||||
httpURLConnection.setDoInput(doinput);
|
||||
}
|
||||
|
||||
public boolean getDoInput() {
|
||||
return httpURLConnection.getDoInput();
|
||||
}
|
||||
|
||||
public void setDoOutput(boolean dooutput) {
|
||||
httpURLConnection.setDoOutput(dooutput);
|
||||
}
|
||||
|
||||
public boolean getDoOutput() {
|
||||
return httpURLConnection.getDoOutput();
|
||||
}
|
||||
|
||||
public void setAllowUserInteraction(boolean allowuserinteraction) {
|
||||
httpURLConnection.setAllowUserInteraction(allowuserinteraction);
|
||||
}
|
||||
|
||||
public boolean getAllowUserInteraction() {
|
||||
return httpURLConnection.getAllowUserInteraction();
|
||||
}
|
||||
|
||||
public void setUseCaches(boolean usecaches) {
|
||||
httpURLConnection.setUseCaches(usecaches);
|
||||
}
|
||||
|
||||
public boolean getUseCaches() {
|
||||
return httpURLConnection.getUseCaches();
|
||||
}
|
||||
|
||||
public void setIfModifiedSince(long ifmodifiedsince) {
|
||||
httpURLConnection.setIfModifiedSince(ifmodifiedsince);
|
||||
}
|
||||
|
||||
public long getIfModifiedSince() {
|
||||
return httpURLConnection.getIfModifiedSince();
|
||||
}
|
||||
|
||||
public boolean getDefaultUseCaches() {
|
||||
return httpURLConnection.getDefaultUseCaches();
|
||||
}
|
||||
|
||||
public void setDefaultUseCaches(boolean defaultusecaches) {
|
||||
httpURLConnection.setDefaultUseCaches(defaultusecaches);
|
||||
}
|
||||
|
||||
public void setRequestProperty(String key, String value) {
|
||||
httpURLConnection.setRequestProperty(key, value);
|
||||
}
|
||||
|
||||
public void addRequestProperty(String key, String value) {
|
||||
httpURLConnection.addRequestProperty(key, value);
|
||||
}
|
||||
|
||||
public String getRequestProperty(String key) {
|
||||
return httpURLConnection.getRequestProperty(key);
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getRequestProperties() {
|
||||
return httpURLConnection.getRequestProperties();
|
||||
}
|
||||
|
||||
public String getHeaderFieldKey(int n) {
|
||||
return httpURLConnection.getHeaderFieldKey(n);
|
||||
}
|
||||
|
||||
public void setFixedLengthStreamingMode(int contentLength) {
|
||||
httpURLConnection.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setFixedLengthStreamingMode(long contentLength) {
|
||||
httpURLConnection.setFixedLengthStreamingMode(contentLength);
|
||||
}
|
||||
|
||||
public void setChunkedStreamingMode(int chunklen) {
|
||||
httpURLConnection.setChunkedStreamingMode(chunklen);
|
||||
}
|
||||
|
||||
public String getHeaderField(int n) {
|
||||
return httpURLConnection.getHeaderField(n);
|
||||
}
|
||||
|
||||
public void setInstanceFollowRedirects(boolean followRedirects) {
|
||||
httpURLConnection.setInstanceFollowRedirects(followRedirects);
|
||||
}
|
||||
|
||||
public boolean getInstanceFollowRedirects() {
|
||||
return httpURLConnection.getInstanceFollowRedirects();
|
||||
}
|
||||
|
||||
public void setRequestMethod(String method) throws ProtocolException {
|
||||
httpURLConnection.setRequestMethod(method);
|
||||
}
|
||||
|
||||
public String getRequestMethod() {
|
||||
return httpURLConnection.getRequestMethod();
|
||||
}
|
||||
|
||||
public int getResponseCode() throws IOException {
|
||||
return httpURLConnection.getResponseCode();
|
||||
}
|
||||
|
||||
public String getResponseMessage() throws IOException {
|
||||
return httpURLConnection.getResponseMessage();
|
||||
}
|
||||
|
||||
public long getHeaderFieldDate(String name, long Default) {
|
||||
return httpURLConnection.getHeaderFieldDate(name, Default);
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
httpURLConnection.disconnect();
|
||||
}
|
||||
|
||||
public boolean usingProxy() {
|
||||
return httpURLConnection.usingProxy();
|
||||
}
|
||||
|
||||
public Permission getPermission() throws IOException {
|
||||
return httpURLConnection.getPermission();
|
||||
}
|
||||
|
||||
public InputStream getErrorStream() {
|
||||
return httpURLConnection.getErrorStream();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user