/*
* Copyright (c) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* 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.google.api.client.http;
import com.google.api.client.json.Json;
import com.google.api.client.testing.http.HttpTesting;
import com.google.api.client.testing.http.MockHttpTransport;
import com.google.api.client.testing.http.MockLowLevelHttpRequest;
import com.google.api.client.testing.http.MockLowLevelHttpResponse;
import com.google.api.client.testing.util.LogRecordingHandler;
import com.google.api.client.testing.util.TestableByteArrayInputStream;
import com.google.api.client.util.Key;
import junit.framework.TestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.logging.Level;
/**
* Tests {@link HttpResponse}.
*
* @author Yaniv Inbar
*/
public class HttpResponseTest extends TestCase {
public HttpResponseTest() {
}
public HttpResponseTest(String name) {
super(name);
}
public void testParseAsString_none() throws Exception {
HttpTransport transport = new MockHttpTransport();
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
assertEquals("", response.parseAsString());
}
private static final String SAMPLE = "123\u05D9\u05e0\u05D9\u05D1";
private static final String SAMPLE2 = "123abc";
public void testParseAsString_utf8() throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.setContentType(Json.MEDIA_TYPE);
result.setContent(SAMPLE);
return result;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
assertEquals(SAMPLE, response.parseAsString());
}
public void testParseAsString_noContentType() throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.setContent(SAMPLE2);
return result;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
assertEquals(SAMPLE2, response.parseAsString());
}
public void testStatusCode_negative_dontThrowException() throws Exception {
subtestStatusCode_negative(false);
}
public void testStatusCode_negative_throwException() throws Exception {
subtestStatusCode_negative(true);
}
private void subtestStatusCode_negative(boolean throwExceptionOnExecuteError) throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest().setResponse(
new MockLowLevelHttpResponse().setStatusCode(-1));
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setThrowExceptionOnExecuteError(throwExceptionOnExecuteError);
try {
// HttpResponse converts a negative status code to zero
HttpResponse response = request.execute();
assertEquals(0, response.getStatusCode());
assertFalse(throwExceptionOnExecuteError);
} catch (HttpResponseException e) {
// exception should be thrown only if throwExceptionOnExecuteError is true
assertTrue(throwExceptionOnExecuteError);
assertEquals(0, e.getStatusCode());
}
}
public static class MyHeaders extends HttpHeaders {
@Key
public String foo;
@Key
public Object obj;
@Key
String[] r;
}
static final String ETAG_VALUE = "\"abc\"";
public void testHeaderParsing() throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.addHeader("accept", "value");
result.addHeader("foo", "bar");
result.addHeader("goo", "car");
result.addHeader("hoo", "dar");
result.addHeader("hoo", "far");
result.addHeader("obj", "o");
result.addHeader("r", "a1");
result.addHeader("r", "a2");
result.addHeader("ETAG", ETAG_VALUE);
return result;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setResponseHeaders(new MyHeaders());
HttpResponse response = request.execute();
assertEquals("value", response.getHeaders().getAccept());
assertEquals("bar", ((MyHeaders) response.getHeaders()).foo);
assertEquals(Arrays.asList("o"), ((MyHeaders) response.getHeaders()).obj);
assertEquals(Arrays.asList("a1", "a2"), Arrays.asList(((MyHeaders) response.getHeaders()).r));
assertEquals(Arrays.asList("car"), response.getHeaders().get("goo"));
assertEquals(Arrays.asList("dar", "far"), response.getHeaders().get("hoo"));
assertEquals(ETAG_VALUE, response.getHeaders().getETag());
}
public void testParseAs_noParser() throws Exception {
try {
new MockHttpTransport().createRequestFactory()
.buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL).execute().parseAs(Object.class);
fail("expected " + NullPointerException.class);
} catch (NullPointerException e) {
// expected
}
}
public void testParseAs_classNoContent() throws Exception {
final MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
for (final int status : new int[] {
HttpStatusCodes.STATUS_CODE_NO_CONTENT, HttpStatusCodes.STATUS_CODE_NOT_MODIFIED, 102}) {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
result.setStatusCode(status);
result.setContentType(null);
result.setContent(new ByteArrayInputStream(new byte[0]));
return result;
}
};
}
};
// Confirm that 'null' is returned when getting the response object of a
// request with no message body.
Object parsed = transport.createRequestFactory()
.buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL)
.setThrowExceptionOnExecuteError(false)
.execute()
.parseAs(Object.class);
assertNull(parsed);
}
}
public void testParseAs_typeNoContent() throws Exception {
final MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
for (final int status : new int[] {
HttpStatusCodes.STATUS_CODE_NO_CONTENT, HttpStatusCodes.STATUS_CODE_NOT_MODIFIED, 102}) {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
result.setStatusCode(status);
result.setContentType(null);
result.setContent(new ByteArrayInputStream(new byte[0]));
return result;
}
};
}
};
// Confirm that 'null' is returned when getting the response object of a
// request with no message body.
Object parsed = transport.createRequestFactory()
.buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL)
.setThrowExceptionOnExecuteError(false)
.execute()
.parseAs((Type) Object.class);
assertNull(parsed);
}
}
public void testDownload() throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.setContentType(Json.MEDIA_TYPE);
result.setContent(SAMPLE);
return result;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
response.download(outputStream);
assertEquals(SAMPLE, outputStream.toString("UTF-8"));
}
public void testDisconnectWithContent() throws Exception {
final MockLowLevelHttpResponse lowLevelHttpResponse =
new MockLowLevelHttpResponse();
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
lowLevelHttpResponse.setContentType(Json.MEDIA_TYPE);
lowLevelHttpResponse.setContent(SAMPLE);
return lowLevelHttpResponse;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
assertFalse(lowLevelHttpResponse.isDisconnected());
TestableByteArrayInputStream content =
(TestableByteArrayInputStream) lowLevelHttpResponse.getContent();
assertFalse(content.isClosed());
response.disconnect();
assertTrue(lowLevelHttpResponse.isDisconnected());
assertTrue(content.isClosed());
}
public void testDisconnectWithNoContent() throws Exception {
final MockLowLevelHttpResponse lowLevelHttpResponse =
new MockLowLevelHttpResponse();
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
return lowLevelHttpResponse;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
HttpResponse response = request.execute();
assertFalse(lowLevelHttpResponse.isDisconnected());
response.disconnect();
assertTrue(lowLevelHttpResponse.isDisconnected());
}
public void testContentLoggingLimitWithLoggingEnabledAndDisabled() throws Exception {
subtestContentLoggingLimit("", 2, false);
subtestContentLoggingLimit("A", 2, false);
subtestContentLoggingLimit("ABC" + '\0' + "DEF", 20, true, "Total: 7 bytes", "ABC DEF");
subtestContentLoggingLimit("A", 2, true, "Total: 1 byte", "A");
try {
subtestContentLoggingLimit("ABC", -1, true);
fail("Expected: " + IllegalArgumentException.class);
} catch (IllegalArgumentException e) {
// Expected.
}
subtestContentLoggingLimit("ABC", 0, true, "Total: 3 bytes");
subtestContentLoggingLimit("ABC", 2, true, "Total: 3 bytes (logging first 2 bytes)", "AB");
subtestContentLoggingLimit("ABC", 3, true, "Total: 3 bytes", "ABC");
subtestContentLoggingLimit("ABC", 4, true, "Total: 3 bytes", "ABC");
char[] a = new char[18000];
Arrays.fill(a, 'x');
String big = new String(a);
subtestContentLoggingLimit(big, Integer.MAX_VALUE, true, "Total: 18,000 bytes", big);
subtestContentLoggingLimit(big, 4, true, "Total: 18,000 bytes (logging first 4 bytes)", "xxxx");
}
public void subtestContentLoggingLimit(final String content, int contentLoggingLimit,
boolean loggingEnabled, String... expectedMessages) throws Exception {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.setContent(content);
result.setContentType("text/plain");
return result;
}
};
}
};
HttpTransport.LOGGER.setLevel(Level.CONFIG);
HttpRequest request =
transport.createRequestFactory().buildGetRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.setLoggingEnabled(loggingEnabled);
HttpResponse response = request.execute();
assertEquals(loggingEnabled, response.isLoggingEnabled());
response.setContentLoggingLimit(contentLoggingLimit);
LogRecordingHandler recorder = new LogRecordingHandler();
HttpTransport.LOGGER.addHandler(recorder);
response.parseAsString();
assertEquals(Arrays.asList(expectedMessages), recorder.messages());
}
public void testGetContent_gzipNoContent() throws IOException {
HttpTransport transport = new MockHttpTransport() {
@Override
public LowLevelHttpRequest buildRequest(String method, final String url) throws IOException {
return new MockLowLevelHttpRequest() {
@Override
public LowLevelHttpResponse execute() throws IOException {
MockLowLevelHttpResponse result = new MockLowLevelHttpResponse();
result.setContent("");
result.setContentEncoding("gzip");
result.setContentType("text/plain");
return result;
}
};
}
};
HttpRequest request =
transport.createRequestFactory().buildHeadRequest(HttpTesting.SIMPLE_GENERIC_URL);
request.execute().getContent();
}
}