/*
Copyright (c) 2012 LinkedIn Corp.
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.
*/
/* $Id$ */
package test.r2.caprep.db;
import com.linkedin.data.ByteString;
import com.linkedin.r2.caprep.db.DefaultMessageSerializer;
import com.linkedin.r2.caprep.db.MessageSerializer;
import com.linkedin.r2.message.rest.RestMessage;
import com.linkedin.r2.message.rest.RestMethod;
import com.linkedin.r2.message.rest.RestRequest;
import com.linkedin.r2.message.rest.RestRequestBuilder;
import com.linkedin.r2.message.rest.RestResponse;
import com.linkedin.r2.message.rest.RestResponseBuilder;
import com.linkedin.r2.message.rest.RestStatus;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* @author Chris Pettitt
* @version $Revision$
*/
public class TestDefaultMessageSerializer
{
private MessageSerializer _serializer;
@BeforeMethod
public void setUp()
{
_serializer = new DefaultMessageSerializer();
}
@Test
public void testSimpleRestReq() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("simple-rest-req.txt")));
}
@Test
public void testRestReqWithHeaders() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.setHeader("field-name1", "field-val1")
.setHeader("field-name2", "field-val2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-headers.txt")));
}
@Test
public void testRestReqWithCookies() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.addCookie("cookie-name1=cookie-value1")
.addCookie("cookie-name2=cookie-value2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-cookies.txt")));
}
@Test
public void testRestReqWithHeadersAndCookies() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.addCookie("cookie-name1=cookie-value1")
.addCookie("cookie-name2=cookie-value2")
.addHeaderValue("header-field1", "header-value1")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-headers-and-cookies.txt")));
}
@Test
public void testRestResWithCookies() throws IOException
{
final RestResponse expected = new RestResponseBuilder()
.addCookie("cookie-name1=cookie-value1")
.addCookie("cookie-name2=cookie-value2")
.build();
assertMsgEquals(expected, _serializer.readRestResponse(getResource("rest-res-with-cookies.txt")));
}
@Test
public void testRestResWithHeadersAndCookies() throws IOException
{
final RestResponse expected = new RestResponseBuilder()
.addCookie("cookie-name1=cookie-value1")
.addCookie("cookie-name2=cookie-value2")
.addHeaderValue("header-field1", "header-value1")
.build();
assertMsgEquals(expected, _serializer.readRestResponse(getResource("rest-res-with-headers-and-cookies.txt")));
}
@Test
public void testRestReqWithHeaderMultiValue1() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.addHeaderValue("field-name1", "field-val1")
.addHeaderValue("field-name1", "field-val2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-header-multi-value1.txt")));
}
@Test
public void testRestReqWithHeaderMultiValue2() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.addHeaderValue("field-name1", "field-val1")
.addHeaderValue("field-name1", "field-val2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-header-multi-value2.txt")));
}
@Test
public void testRestReqWithEntity() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.setEntity(ByteString.copyString("This is a simple entity!", "ASCII"))
.setHeader("field-name1", "field-val1")
.setHeader("field-name2", "field-val2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-entity.txt")));
}
@Test
public void testSimpleRestRes() throws IOException
{
final RestResponse expected = new RestResponseBuilder()
.build();
assertMsgEquals(expected, _serializer.readRestResponse(getResource("simple-rest-res.txt")));
}
@Test
public void testRpcReqWithEmptyHeaderValue() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.setHeader("field-name1", "")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-empty-header-value.txt")));
}
@Test
public void testRestReqWithUppercaseHeaderNames() throws IOException
{
// Note that we're using lowercase field names here. We expect that canonicalization will
// treat these the same
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.setHeader("field-name1", "field-val1")
.setHeader("field-name2", "field-val2")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-uppercase-header-names.txt")));
}
@Test
public void testRestReqWithMultilineHeader() throws IOException
{
final RestRequest expected = new RestRequestBuilder(URI.create("http://localhost:1234"))
.setHeader("field-name1", "field-val1\ncontinuation-of-last-field:abc")
.build();
assertMsgEquals(expected, _serializer.readRestRequest(getResource("rest-req-with-multiline-header.txt")));
}
@Test
public void testRestReqWithMalformedHeader() throws Exception
{
expectIOException(new ThrowingRunnable()
{
@Override
public void run()
throws Exception
{
_serializer.readRestRequest(getResource("rest-req-with-malformed-header.txt"));
}
});
}
@Test
public void testRpcResWith500StatusCode() throws Exception
{
expectIOException(new ThrowingRunnable()
{
@Override
public void run()
throws Exception
{
_serializer.readRestRequest(getResource("rpc-res-with-500-status-code.txt"));
}
});
}
@Test
public void testRestReqWithExtraSpaceInReqLine() throws Exception
{
expectIOException(new ThrowingRunnable()
{
@Override
public void run()
throws Exception
{
_serializer.readRestRequest(getResource("rest-req-with-extra-space-in-req-line.txt"));
}
});
}
@Test
public void testRestResWithExtraSpaceInStatusLine() throws Exception
{
expectIOException(new ThrowingRunnable()
{
@Override
public void run()
throws Exception
{
_serializer.readRestResponse(getResource("rest-res-with-extra-space-in-status-line.txt"));
}
});
}
@Test
public void testRestReqMissingVersion() throws Exception
{
expectIOException(new ThrowingRunnable()
{
@Override
public void run()
throws Exception
{
_serializer.readRestRequest(getResource("rest-req-missing-version.txt"));
}
});
}
@Test
public void testRestRequestReversible1() throws IOException
{
final RestRequest req = createRestRequest();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestReversible2() throws IOException
{
final RestRequest req = createRestRequest().builder()
.setMethod(RestMethod.POST)
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestReversible3() throws IOException
{
final RestRequest req = createRestRequest().builder()
.setEntity(new byte[]{1, 2, 3, 4})
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestReversible4() throws IOException
{
final RestRequest req = createRestRequest().builder()
.setHeader("field-key1", "field-val1")
.setHeader("field-key2", "field-val2")
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestReversible5() throws IOException
{
final RestRequest req = createRestRequest().builder()
.setHeader("field-key1", "multi-line\nfield-value\nhere")
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestReversible6() throws IOException
{
final RestRequest req = createRestRequest().builder()
.setHeader("set-cookie", "field-value1")
.addCookie("cookie-key1=cookie-value1")
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestRequestBinaryEntity() throws IOException
{
final int byteRange = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
final byte[] entity = new byte[byteRange];
for (int b = 0; b < byteRange; b++) {
entity[b] = (byte) (Byte.MIN_VALUE + b);
}
final RestRequest req = createRestRequest().builder()
.setEntity(entity)
.build();
assertMsgEquals(req, readRestReq(writeReq(req)));
}
@Test
public void testRestResponseReversible1() throws IOException
{
final RestResponse res = createRestResponse();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseReversible2() throws IOException
{
final RestResponse res = createRestResponse().builder()
.setStatus(RestStatus.INTERNAL_SERVER_ERROR)
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseReversible3() throws IOException
{
final RestResponse res = createRestResponse().builder()
.setEntity(new byte[]{1, 2, 3, 4})
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseReversible4() throws IOException
{
final RestResponse res = createRestResponse().builder()
.setHeader("field-key1", "field-val1")
.setHeader("field-key2", "field-val2")
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseReversible5() throws IOException
{
final RestResponse res = createRestResponse().builder()
.addHeaderValue("field-key1", "field-val1")
.addHeaderValue("field-key1", "field-val2")
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseReversible6() throws IOException
{
final RestResponse res = createRestResponse().builder()
.setHeader("cookie", "field-value1")
.addCookie("cookie-key1=cookie-value1")
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
@Test
public void testRestResponseBinaryEntity() throws IOException
{
final int byteRange = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
final byte[] entity = new byte[byteRange];
for (int b = 0; b < byteRange; b++) {
entity[b] = (byte) (Byte.MIN_VALUE + b);
}
final RestResponse res = createRestResponse().builder()
.setEntity(entity)
.build();
assertMsgEquals(res, readRestRes(writeRes(res)));
}
private RestRequest createRestRequest()
{
return new RestRequestBuilder(URI.create("http://linkedin.com")).build();
}
private RestResponse createRestResponse()
{
return new RestResponseBuilder().build();
}
private byte[] writeReq(RestRequest req) throws IOException
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
_serializer.writeRequest(baos, req);
return baos.toByteArray();
}
private byte[] writeRes(RestResponse res) throws IOException
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
_serializer.writeResponse(baos, res);
return baos.toByteArray();
}
private RestRequest readRestReq(byte[] bytes) throws IOException
{
return _serializer.readRestRequest(new ByteArrayInputStream(bytes));
}
private RestResponse readRestRes(byte[] bytes) throws IOException
{
return _serializer.readRestResponse(new ByteArrayInputStream(bytes));
}
private void assertMsgEquals(RestMessage expected, RestMessage actual)
{
Assert.assertEquals(actual.builder().buildCanonical(), expected.builder().buildCanonical());
}
private InputStream getResource(String name)
{
final InputStream in = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("test/r2/caprep/db/" + name);
if (in == null)
{
throw new RuntimeException("No such resource: " + name);
}
return in;
}
private void expectIOException(ThrowingRunnable runnable) throws Exception
{
try
{
runnable.run();
Assert.fail("Should have thrown IOException");
}
catch(IOException e)
{
// Expected case
}
}
private static interface ThrowingRunnable
{
void run() throws Exception;
}
}