/*
Copyright (c) 2014 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.
*/
package com.linkedin.restli.client;
import com.linkedin.data.schema.PathSpec;
import com.linkedin.data.template.RecordTemplate;
import com.linkedin.restli.client.test.TestRecord;
import com.linkedin.restli.common.ComplexResourceKey;
import com.linkedin.restli.common.CompoundKey;
import com.linkedin.restli.common.RestConstants;
import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Collections;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* @author Keren Jin
*/
public class TestAbstractRequestBuilder
{
@Test
public void testAddHeaderWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
Assert.assertSame(builder.addHeader("a", "b"), builder);
Assert.assertEquals(builder.getHeader("a"), "b");
builder.addHeader("a", "c");
Assert.assertEquals(builder.getHeader("a"), "b" + AbstractRequestBuilder.HEADER_DELIMITER + "c");
}
@Test
public void testAddHeaderWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addHeader("a", "b");
builder.addHeader("a", null);
builder.addHeader("a", "c");
Assert.assertEquals(builder.getHeader("a"), "b" + AbstractRequestBuilder.HEADER_DELIMITER + "c");
}
@Test
public void testSetHeaderWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
Assert.assertSame(builder.setHeader("a", "b"), builder);
Assert.assertEquals(builder.getHeader("a"), "b");
builder.setHeader("a", "c");
Assert.assertEquals(builder.getHeader("a"), "c");
}
@Test
public void testSetHeaderWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setHeader("a", "b");
builder.setHeader("a", null);
Assert.assertNull(builder.getHeader("a"));
}
@Test
public void testSetHeadersWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setHeader("a", "b");
builder.setHeader("c", "d");
Assert.assertEquals(builder.getHeader("a"), "b");
Assert.assertEquals(builder.getHeader("c"), "d");
final Map<String, String> newHeaders = new HashMap<String, String>();
newHeaders.put("c", "e");
builder.setHeaders(newHeaders);
Assert.assertNull(builder.getHeader("a"));
Assert.assertEquals(builder.getHeader("c"), "e");
newHeaders.put("c", "f");
Assert.assertEquals(builder.getHeader("c"), "e");
}
@Test
public void testSetHeadersWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
final Map<String, String> newHeaders = new HashMap<String, String>();
newHeaders.put("a", "b");
newHeaders.put("c", null);
builder.setHeaders(newHeaders);
Assert.assertEquals(builder.getHeader("a"), "b");
Assert.assertNull(builder.getHeader("c"));
}
@Test
public void testAddCookieWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
List<HttpCookie> cookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
new HttpCookie("Y", "2"),
new HttpCookie("Z", "3")));
Assert.assertSame(builder.addCookie(new HttpCookie("X", "1")), builder);
Assert.assertSame(builder.addCookie(new HttpCookie("Y", "2")), builder);
Assert.assertSame(builder.addCookie(new HttpCookie("Z", "3")), builder);
Assert.assertEquals(builder.getCookies(), cookies);
}
@Test
public void testAddCookieWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
Assert.assertSame(builder.addCookie(new HttpCookie("X", "1")), builder);
Assert.assertSame(builder.addCookie(null), builder);
Assert.assertSame(builder.addCookie(new HttpCookie("Z", "3")), builder);
List<HttpCookie> cookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
new HttpCookie("Z", "3")));
Assert.assertEquals(builder.getCookies(), cookies);
}
@Test
public void testSetCookiesWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
List<HttpCookie> cookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
new HttpCookie("Y", "2"),
new HttpCookie("Z", "3")));
Assert.assertSame(builder.setCookies(cookies), builder);
Assert.assertEquals(builder.getCookies(), cookies);
}
@Test
public void testSetCookiesWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
List<HttpCookie> cookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
null,
new HttpCookie("Z", "3")));
// Null element will not be passed
Assert.assertSame(builder.setCookies(cookies), builder);
List<HttpCookie> resultCookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
new HttpCookie("Z", "3")));
Assert.assertEquals(builder.getCookies(), resultCookies);
}
@Test
public void testClearCookie()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
List<HttpCookie> cookies = new ArrayList<HttpCookie>(Arrays.asList(new HttpCookie("X", "1"),
new HttpCookie("Y", "2"),
new HttpCookie("Z", "3")));
Assert.assertSame(builder.setCookies(cookies), builder);
Assert.assertSame(builder.clearCookies(), builder);
Assert.assertEquals(builder.getCookies(), Collections.emptyList());
}
@Test
public void testSetParamWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setParam("a", "b");
Map<String, Object> queryParams = builder.buildReadOnlyQueryParameters();
Assert.assertEquals(queryParams.get("a"), "b");
}
@Test
public void testSetParamWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setParam("a", null);
Map<String, Object> queryParams = builder.buildReadOnlyQueryParameters();
Assert.assertFalse(queryParams.containsKey("a"));
}
@Test
public void testAddParamWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addParam("a", "b");
Map<String, Object> queryParams = builder.buildReadOnlyQueryParameters();
Assert.assertEquals(queryParams.get("a"), Arrays.asList("b"));
}
@Test(dataProvider = "testQueryParam")
public void testAddParamSameKeyMultipleValues(Object value1, Object value2, Object value3)
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addParam("a", value1);
Assert.assertEquals(builder.getParam("a"), Arrays.asList(value1));
builder.addParam("a", value2);
Assert.assertEquals(builder.getParam("a"), Arrays.asList(value1, value2));
}
@Test
public void testAddParamWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addParam("a", null);
Assert.assertFalse(builder.hasParam("a"));
}
@Test(expectedExceptions = IllegalStateException.class)
public void testSetNonIterableThenAddParam()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setParam("a", "b");
builder.addParam("a", "c");
}
@Test(dataProvider = "testQueryParam")
public void testSetIterableThenAddParam(final Object value1, final Object value2, Object value3)
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
final Iterable<Object> iter = new Iterable<Object>()
{
private final Collection<Object> _coll = Arrays.asList(value1, value2);
@Override
public Iterator<Object> iterator()
{
return _coll.iterator();
}
};
builder.setParam("a", iter);
builder.addParam("a", value3);
Assert.assertEquals(builder.getParam("a"), Arrays.asList(value1, value2, value3));
}
@Test(dataProvider = "testQueryParam")
public void testSetCollectionThenAddParam(Object value1, Object value2, Object value3)
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
// AbstractList returned by Arrays.asList() does not support add()
// need to wrap it with ArrayList
final Collection<Object> testData = new ArrayList<Object>(Arrays.asList(value1, value2));
builder.setParam("a", testData);
builder.addParam("a", value3);
Assert.assertEquals(builder.getParam("a"), Arrays.asList(value1, value2, value3));
}
@Test(dataProvider = "testQueryParam")
public void testAddThenSetParam(Object value1, Object value2, Object value3)
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addParam("a", value1).addParam("a", value2);
builder.setParam("a", value3);
Assert.assertEquals(builder.getParam("a"), value3);
}
@Test
public void testSetReqParamWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setReqParam("a", "b");
Assert.assertEquals(builder.getParam("a"), "b");
}
@Test(expectedExceptions = NullPointerException.class)
public void testSetReqParamWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setReqParam("a", null);
}
@Test
public void testAddReqParamWithNonNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addReqParam("a", "b");
Assert.assertEquals(builder.getParam("a"), Arrays.asList("b"));
}
@Test
public void testAddReqParamSameKeyMultipleValues()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addReqParam("a", "b1");
Assert.assertEquals(builder.getParam("a"), Arrays.asList("b1"));
builder.addReqParam("a", "b2");
Assert.assertEquals(builder.getParam("a"), Arrays.asList("b1", "b2"));
}
@DataProvider(name = "testQueryParam")
public static Object[][] testQueryParamDataProvider()
{
final Object value3 = new ArrayList<String>(Arrays.asList("x", "y"));
return new Object[][] {
{ "a", "b", "z" },
{ "a", "b", value3 },
{ new String[] { "a", "b" }, new String[] { "c", "d" }, "z" },
{ new String[] { "a", "b" }, new String[] { "c", "d" }, value3 },
{ new ArrayList<String>(Arrays.asList("a", "b")), new ArrayList<String>(Arrays.asList("c", "d")), "z" },
{ new ArrayList<String>(Arrays.asList("a", "b")), new ArrayList<String>(Arrays.asList("c", "d")), value3 }
};
}
@Test
public void testAddReqParamWithNullValue()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
try
{
builder.addReqParam("a", null);
Assert.fail("addReqParam should not allow null values");
}
catch (NullPointerException e)
{
}
}
@Test
public void testProjectionFields()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addFields(new PathSpec("firstField"), new PathSpec("secondField", PathSpec.WILDCARD, "thirdField"));
Assert.assertTrue(builder.getParam(RestConstants.FIELDS_PARAM) instanceof PathSpec[]);
final PathSpec[] fieldsPathSpecs = (PathSpec[])builder.getParam(RestConstants.FIELDS_PARAM);
Assert.assertEquals(fieldsPathSpecs[0].toString(), "/firstField", "The path spec(s) should match!");
Assert.assertEquals(fieldsPathSpecs[1].toString(), "/secondField/*/thirdField", "The path spec(s) should match!");
builder.addMetadataFields(new PathSpec(PathSpec.WILDCARD, "fourthField"), new PathSpec("fifthField"));
Assert.assertTrue(builder.getParam(RestConstants.METADATA_FIELDS_PARAM) instanceof PathSpec[]);
final PathSpec[] metadataFieldsPathSpecs = (PathSpec[])builder.getParam(RestConstants.METADATA_FIELDS_PARAM);
Assert.assertEquals(metadataFieldsPathSpecs[0].toString(), "/*/fourthField", "The path spec(s) should match!");
Assert.assertEquals(metadataFieldsPathSpecs[1].toString(), "/fifthField", "The path spec(s) should match!");
builder.addPagingFields(new PathSpec("sixthField", PathSpec.WILDCARD), new PathSpec("seventhField"),
new PathSpec(PathSpec.WILDCARD));
Assert.assertTrue(builder.getParam(RestConstants.PAGING_FIELDS_PARAM) instanceof PathSpec[]);
final PathSpec[] pagingFieldsPathSpecs = (PathSpec[])builder.getParam(RestConstants.PAGING_FIELDS_PARAM);
Assert.assertEquals(pagingFieldsPathSpecs[0].toString(), "/sixthField/*", "The path spec(s) should match!");
Assert.assertEquals(pagingFieldsPathSpecs[1].toString(), "/seventhField", "The path spec(s) should match!");
Assert.assertEquals(builder.buildReadOnlyQueryParameters().size(), 3,
"We should have 3 query parameters, one for each projection type");
}
@Test
@SuppressWarnings("unchecked")
public void testParametersAreReadOnly()
{
final AbstractRequestBuilder<?, ?, ?> builder = new DummyAbstractRequestBuilder();
TestRecord testRecord = new TestRecord();
builder.setParam("abc", testRecord);
Map<String, Object> parameters = builder.buildReadOnlyQueryParameters();
Assert.assertNotSame(parameters.get("abc"), testRecord);
Assert.assertTrue(((RecordTemplate) parameters.get("abc")).data().isMadeReadOnly());
testRecord.data().makeReadOnly();
parameters = builder.buildReadOnlyQueryParameters();
Assert.assertSame(parameters.get("abc"), testRecord);
TestRecord testRecord2 = new TestRecord();
builder.addParam("abc2", testRecord2);
parameters = builder.buildReadOnlyQueryParameters();
List<Object> collectionParam = (List<Object>) parameters.get("abc2");
Assert.assertNotSame(collectionParam.get(0), testRecord2);
Assert.assertTrue(((RecordTemplate)collectionParam.get(0)).data().isMadeReadOnly());
testRecord2.data().makeReadOnly();
parameters = builder.buildReadOnlyQueryParameters();
collectionParam = (List<Object>) parameters.get("abc2");
Assert.assertSame(collectionParam.get(0), testRecord2);
}
@Test
@SuppressWarnings("unchecked")
public void testKeysAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
TestRecord testRecord = new TestRecord();
TestRecord testRecord2 = new TestRecord();
ComplexResourceKey<TestRecord, TestRecord> originalKey =
new ComplexResourceKey<TestRecord, TestRecord>(testRecord, testRecord2);
builder.addKey(originalKey);
Map<String, Object> parameters = builder.buildReadOnlyQueryParameters();
Object key = ((List<Object>)parameters.get("ids")).get(0);
Assert.assertNotSame(key, originalKey);
Assert.assertTrue(((ComplexResourceKey<TestRecord, TestRecord>)key).isReadOnly());
try
{
parameters.put("xyz", "abc");
Assert.fail("The generated parameters should be read-only.");
}
catch (Exception e)
{
}
originalKey.makeReadOnly();
parameters = builder.buildReadOnlyQueryParameters();
key = ((List<Object>)parameters.get("ids")).get(0);
Assert.assertSame(key, originalKey);
}
@Test
@SuppressWarnings("unchecked")
public void testPathKeysAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
TestRecord testRecord = new TestRecord();
TestRecord testRecord2 = new TestRecord();
ComplexResourceKey<TestRecord, TestRecord> originalKey =
new ComplexResourceKey<TestRecord, TestRecord>(testRecord, testRecord2);
builder.pathKey("abc", originalKey);
Map<String, Object> pathKeys = builder.buildReadOnlyPathKeys();
Object key = pathKeys.get("abc");
Assert.assertNotSame(key, originalKey);
Assert.assertTrue(((ComplexResourceKey<TestRecord, TestRecord>)key).isReadOnly());
try
{
pathKeys.put("xyz", "abc");
Assert.fail("The generated path keys should be read-only.");
}
catch (Exception e)
{
}
originalKey.makeReadOnly();
pathKeys = builder.buildReadOnlyPathKeys();
key = pathKeys.get("abc");
Assert.assertSame(key, originalKey);
}
@Test
public void testAssocKeysAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.addAssocKey("abc", 5);
builder.addAssocKey("abc2", 6);
CompoundKey compoundKey = builder.buildReadOnlyAssocKey();
Assert.assertTrue(compoundKey.isReadOnly());
}
@Test
public void testHeadersAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setHeader("abc", "abc");
Map<String, String> headers = builder.buildReadOnlyHeaders();
try
{
headers.put("xyz", "abc");
Assert.fail("The generated headers should be read-only.");
}
catch (Exception e)
{
}
builder.setHeader("abc", "def");
Assert.assertEquals(headers.get("abc"), "abc");
}
@Test
public void testCookiesAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
builder.setCookies(Arrays.asList(new HttpCookie("a", "b"), new HttpCookie("c", "d")));
List<HttpCookie> cookies = builder.buildReadOnlyCookies();
try
{
cookies.add(new HttpCookie("ac", "bb"));
Assert.fail("The generated cookies should be read-only.");
}
catch (Exception e)
{
}
}
@Test
@SuppressWarnings("unchecked")
public void testProjectionFieldsAreReadOnly()
{
final AbstractRequestBuilder<Object, ?, ?> builder = new DummyAbstractRequestBuilder();
PathSpec field = new PathSpec("abc");
PathSpec[] originalFields = new PathSpec[] { field };
builder.addFields(originalFields);
builder.addMetadataFields(originalFields);
builder.addPagingFields(originalFields);
Map<String, Object> parameters = builder.buildReadOnlyQueryParameters();
List<Object> fields = (List<Object>) parameters.get(RestConstants.FIELDS_PARAM);
List<Object> metadataFields = (List<Object>) parameters.get(RestConstants.METADATA_FIELDS_PARAM);
List<Object> pagingFields = (List<Object>) parameters.get(RestConstants.PAGING_FIELDS_PARAM);
PathSpec field2 = new PathSpec("def");
originalFields[0] = field2;
Assert.assertTrue(fields.contains(field));
Assert.assertFalse(fields.contains(field2));
try
{
fields.add("xyz");
Assert.fail("The generated fields should be read-only.");
}
catch (Exception e)
{
}
Assert.assertTrue(metadataFields.contains(field));
Assert.assertFalse(metadataFields.contains(field2));
try
{
metadataFields.add("xyz");
Assert.fail("The generated metadata fields should be read-only.");
}
catch (Exception e)
{
}
Assert.assertTrue(pagingFields.contains(field));
Assert.assertFalse(pagingFields.contains(field2));
try
{
pagingFields.add("xyz");
Assert.fail("The generated paging fields should be read-only.");
}
catch (Exception e)
{
}
}
private static class DummyAbstractRequestBuilder extends AbstractRequestBuilder<Object, Object, Request<Object>>
{
public DummyAbstractRequestBuilder()
{
super(null, null, RestliRequestOptions.DEFAULT_OPTIONS);
}
@Override
public Request<Object> build()
{
return null;
}
}
}