blob: 919f897228e498677c395f51c834d2b80a84e91f [file] [log] [blame]
/*
* Copyright 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.gwt.requestfactory.server;
import com.google.gwt.requestfactory.shared.SimpleBarProxy;
import com.google.gwt.requestfactory.shared.SimpleEnum;
import com.google.gwt.requestfactory.shared.SimpleFooProxy;
import com.google.gwt.requestfactory.shared.WriteOperation;
import com.google.gwt.requestfactory.shared.impl.Constants;
import junit.framework.TestCase;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Tests for {@link JsonRequestProcessor} .
*/
public class JsonRequestProcessorTest extends TestCase {
enum Foo {
BAR, BAZ
}
private JsonRequestProcessor requestProcessor;
@Override
public void setUp() {
requestProcessor = new JsonRequestProcessor();
requestProcessor.setOperationRegistry(new ReflectionBasedOperationRegistry(
new DefaultSecurityProvider()));
}
public void testDecodeParameterValue() throws SecurityException,
JSONException, IllegalAccessException, InvocationTargetException,
NoSuchMethodException, InstantiationException {
// primitives
assertTypeAndValueEquals(String.class, "Hello", "Hello");
assertTypeAndValueEquals(Integer.class, 1234, "1234");
assertTypeAndValueEquals(Byte.class, (byte) 100, "100");
assertTypeAndValueEquals(Short.class, (short) 12345, "12345");
assertTypeAndValueEquals(Float.class, 1.234f, "1.234");
assertTypeAndValueEquals(Double.class, 1.234567, "1.234567");
assertTypeAndValueEquals(Long.class, 1234L, "1234");
assertTypeAndValueEquals(Boolean.class, true, "true");
assertTypeAndValueEquals(Boolean.class, false, "false");
// dates
Date now = new Date();
assertTypeAndValueEquals(Date.class, now, "" + now.getTime());
// bigdecimal and biginteger
BigDecimal dec = new BigDecimal("10").pow(100);
assertTypeAndValueEquals(BigDecimal.class, dec, dec.toPlainString());
assertTypeAndValueEquals(BigInteger.class, dec.toBigInteger(),
dec.toBigInteger().toString());
// enums
assertTypeAndValueEquals(Foo.class, Foo.BAR, "" + Foo.BAR.ordinal());
// nulls
assertTypeAndValueEquals(String.class, null, null);
assertTypeAndValueEquals(Integer.class, null, null);
assertTypeAndValueEquals(Byte.class, null, null);
assertTypeAndValueEquals(Short.class, null, null);
assertTypeAndValueEquals(Float.class, null, null);
assertTypeAndValueEquals(Double.class, null, null);
assertTypeAndValueEquals(Long.class, null, null);
assertTypeAndValueEquals(Boolean.class, null, null);
assertTypeAndValueEquals(Date.class, null, null);
assertTypeAndValueEquals(BigDecimal.class, null, null);
assertTypeAndValueEquals(BigInteger.class, null, null);
assertTypeAndValueEquals(Foo.class, null, null);
}
public void testEncodePropertyValue() {
assertEncodedType(String.class, "Hello");
// primitive numbers become doubles
assertEncodedType(Double.class, (byte) 10);
assertEncodedType(Double.class, (short) 1234);
assertEncodedType(Double.class, 123.4f);
assertEncodedType(Double.class, 1234.0);
assertEncodedType(Double.class, 1234);
// longs, big nums become strings
assertEncodedType(String.class, 1234L);
assertEncodedType(String.class, new BigDecimal(1));
assertEncodedType(String.class, new BigInteger("1"));
assertEncodedType(String.class, new Date());
assertEncodedType(Double.class, Foo.BAR);
assertEncodedType(Boolean.class, true);
assertEncodedType(Boolean.class, false);
// nulls becomes JSON Null. Needed because JSONObject stringify treats 'null'
// as a reason to not emit the key in the stringified object
assertEquals(JSONObject.NULL, requestProcessor.encodePropertyValue(null));
assertEquals(new Double(1.0), requestProcessor.encodePropertyValue(new Integer(1)));
}
public void testEndToEnd() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
// modify fields and sync
foo.put("intId", 45);
foo.put("userName", "JSC");
foo.put("longField", "" + 9L);
foo.put("enumField", SimpleEnum.BAR.ordinal());
foo.put("boolField", false);
Date now = new Date();
foo.put("created", "" + now.getTime());
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
JSONArray updateArray = result.getJSONObject("sideEffects").getJSONArray(
"UPDATE");
assertEquals(1, updateArray.length());
assertEquals(2, updateArray.getJSONObject(0).length());
assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_ID_PROPERTY));
assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_VERSION_PROPERTY));
assertFalse(updateArray.getJSONObject(0).has("violations"));
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
assertEquals(now, fooResult.getCreated());
assertEquals(9L, (long) fooResult.getLongField());
assertEquals(com.google.gwt.requestfactory.shared.SimpleEnum.BAR,
fooResult.getEnumField());
assertEquals(false, (boolean) fooResult.getBoolField());
}
private String createNoChangeRequestAndGetServerVersion(JSONObject foo) throws Exception {
// change the value on the server behind the back
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
String savedVersion = requestProcessor.encodePropertyValue(fooResult.getVersion() + 1).toString();
fooResult.setVersion(fooResult.getVersion() + 1);
fooResult.isChanged = false;
// modify fields and sync -- there should be no change on the server.
foo.put("intId", 45);
foo.put("userName", "JSC");
return savedVersion;
}
public void testEndToEndSmartDiff_NoChange() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
String savedVersion = createNoChangeRequestAndGetServerVersion(foo);
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
JSONArray updateArray = result.getJSONObject("sideEffects").getJSONArray(
"UPDATE");
// verify that the version number is unchanged.
assertEquals(1, updateArray.length());
assertEquals(2, updateArray.getJSONObject(0).length());
assertTrue(updateArray.getJSONObject(0).has(Constants.ENCODED_ID_PROPERTY));
assertTrue(updateArray.getJSONObject(0).has(
Constants.ENCODED_VERSION_PROPERTY));
assertEquals(savedVersion,
updateArray.getJSONObject(0).getString(
Constants.ENCODED_VERSION_PROPERTY));
// verify that the server values are unchanged.
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
assertEquals(savedVersion,
requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
}
/*
* This test differs from testEndToEndSmartDiff_NoChange in that the version
* numbers are not sent. As a result, the server does not send an UPDATE
* sideEffect in its response.
*/
public void testEndToEndSmartDiff_NoChange_NoVersion() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
String savedVersion = createNoChangeRequestAndGetServerVersion(foo);
// remove version number from the request.
foo.remove(Constants.ENCODED_VERSION_PROPERTY);
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
assertFalse(result.getJSONObject("sideEffects").has("UPDATE"));
// verify that the server values are unchanged.
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
assertEquals(savedVersion,
requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
}
/*
* This test differs from testEndToEndSmartDiff_NoChange in that the property
* that is changed here does not cause a version increment. As a result, no
* UPDATE is sent back.
*/
public void testEndToEndSmartDiff_NoVersionChange() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
// change the value on the server behind the back
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setLongField(45L);
String savedVersion = requestProcessor.encodePropertyValue(fooResult.getVersion()).toString();
// modify fields and sync -- there should be no change on the server.
foo.put("longField", 45L);
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
assertFalse(result.getJSONObject("sideEffects").has("UPDATE"));
// verify that the server values are unchanged.
fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45L, (long) fooResult.getLongField());
assertEquals(savedVersion,
requestProcessor.encodePropertyValue(fooResult.getVersion()).toString());
}
public void testEndToEndSmartDiff_SomeChangeWithNull() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
// change some fields but don't change other fields.
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
fooResult.setNullField(null);
fooResult.setBarField(SimpleBar.getSingleton());
fooResult.setBarNullField(null);
foo.put("userName", JSONObject.NULL);
foo.put("intId", 45);
foo.put("nullField", "test");
foo.put("barNullField",
JsonRequestProcessor.base64Encode(SimpleBar.getSingleton().getId())
+ "@NO@" + SimpleBarProxy.class.getName());
foo.put("barField", JSONObject.NULL);
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertNull(fooResult.getUserName());
assertEquals("test", fooResult.getNullField());
assertEquals(SimpleBar.getSingleton(), fooResult.getBarNullField());
assertNull(fooResult.getBarField());
}
public void testEndToEndSmartDiff_SomeChange() throws Exception {
com.google.gwt.requestfactory.server.SimpleFoo.reset();
// fetch object
JSONObject foo = fetchVerifyAndGetInitialObject();
// change some fields but don't change other fields.
SimpleFoo fooResult = SimpleFoo.findSimpleFooById(999L);
fooResult.setUserName("JSC");
fooResult.setIntId(45);
foo.put("userName", "JSC");
foo.put("intId", 45);
Date now = new Date();
long newTime = now.getTime() + 10000;
foo.put("created", "" + newTime);
JSONObject result = getResultFromServer(foo);
// check modified fields and no violations
assertTrue(result.getJSONObject("sideEffects").has("UPDATE"));
fooResult = SimpleFoo.findSimpleFooById(999L);
assertEquals(45, (int) fooResult.getIntId());
assertEquals("JSC", fooResult.getUserName());
assertEquals(newTime, fooResult.getCreated().getTime());
}
public void testEndToEndNumberList()
throws ClassNotFoundException, InvocationTargetException,
NoSuchMethodException, JSONException, InstantiationException,
IllegalAccessException {
fetchVerifyAndGetNumberList();
}
private void assertEncodedType(Class<?> expected, Object value) {
assertEquals(expected,
requestProcessor.encodePropertyValue(value).getClass());
}
private <T> void assertTypeAndValueEquals(Class<T> expectedType,
T expectedValue, String paramValue) throws SecurityException,
JSONException, IllegalAccessException, InvocationTargetException,
NoSuchMethodException, InstantiationException {
Object val = requestProcessor.decodeParameterValue(expectedType, paramValue);
if (val != null) {
assertEquals(expectedType, val.getClass());
}
assertEquals(expectedValue, val);
}
@SuppressWarnings("unchecked")
private JSONObject fetchVerifyAndGetInitialObject() throws JSONException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, SecurityException, InstantiationException {
JSONObject results = requestProcessor.processJsonRequest("{ \""
+ Constants.OPERATION_TOKEN
+ "\": \""
+ com.google.gwt.requestfactory.shared.SimpleFooRequest.class.getName()
+ ReflectionBasedOperationRegistry.SCOPE_SEPARATOR
+ "findSimpleFooById\", "
+ "\""
+ Constants.PARAM_TOKEN
+ "0\": \"999\", \"" + Constants.PROPERTY_REF_TOKEN + "\": "
+ "\"oneToManyField,oneToManySetField,selfOneToManyField\""
+ "}");
JSONObject foo = results.getJSONObject("result");
assertEquals(foo.getLong("id"), 999L);
assertEquals(foo.getInt("intId"), 42);
assertEquals(foo.getString("userName"), "GWT");
assertEquals(foo.getLong("longField"), 8L);
assertEquals(foo.getInt("enumField"), 0);
assertEquals(foo.getInt(Constants.ENCODED_VERSION_PROPERTY), 1);
assertEquals(foo.getBoolean("boolField"), true);
assertNotNull(foo.getString("!id"));
assertTrue(foo.has("created"));
List<Double> numList = (List<Double>) foo.get("numberListField");
assertEquals(2, numList.size());
assertEquals(42.0, numList.get(0));
assertEquals(99.0, numList.get(1));
List<String> oneToMany = (List<String>) foo.get("oneToManyField");
assertEquals(2, oneToMany.size());
assertEquals(JsonRequestProcessor.base64Encode("1L") + "@NO@com.google.gwt.requestfactory.shared.SimpleBarProxy", oneToMany.get(0));
assertEquals(JsonRequestProcessor.base64Encode("1L") + "@NO@com.google.gwt.requestfactory.shared.SimpleBarProxy", oneToMany.get(1));
List<String> selfOneToMany = (List<String>) foo.get("selfOneToManyField");
assertEquals(1, selfOneToMany.size());
assertEquals("999@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy", selfOneToMany.get(0));
Set<String> oneToManySet = (Set<String>) foo.get("oneToManySetField");
assertEquals(1, oneToManySet.size());
assertEquals(JsonRequestProcessor.base64Encode("1L") + "@NO@com.google.gwt.requestfactory.shared.SimpleBarProxy", oneToManySet.iterator().next());
return foo;
}
private JSONArray fetchVerifyAndGetNumberList() throws JSONException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, SecurityException, InstantiationException {
JSONObject results = requestProcessor.processJsonRequest("{ \""
+ Constants.OPERATION_TOKEN
+ "\": \""
+ com.google.gwt.requestfactory.shared.SimpleFooRequest.class.getName()
+ ReflectionBasedOperationRegistry.SCOPE_SEPARATOR
+ "getNumberList\" }");
JSONArray foo = results.getJSONArray("result");
assertEquals(foo.length(), 3);
assertEquals(foo.getInt(0), 1);
assertEquals(foo.getInt(1), 2);
assertEquals(foo.getInt(2), 3);
return foo;
}
public void testPrimitiveListAsParameter() throws JSONException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, SecurityException, InstantiationException {
JSONObject results = requestProcessor.processJsonRequest("{ \""
+ Constants.OPERATION_TOKEN
+ "\": \""
+ com.google.gwt.requestfactory.shared.SimpleFooRequest.class.getName()
+ ReflectionBasedOperationRegistry.SCOPE_SEPARATOR
+ "sum\", "
+ "\"" + Constants.PARAM_TOKEN + "0\":"
+ "\"1@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy\","
+ "\""
+ Constants.PARAM_TOKEN
+ "1\": [1, 2, 3] }");
assertEquals(6, results.getInt("result"));
}
public void testProxyListAsParameter() throws JSONException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, SecurityException, InstantiationException {
SimpleFoo.reset();
JSONObject results = requestProcessor.processJsonRequest("{ \""
+ Constants.OPERATION_TOKEN
+ "\": \""
+ com.google.gwt.requestfactory.shared.SimpleFooRequest.class.getName()
+ ReflectionBasedOperationRegistry.SCOPE_SEPARATOR
+ "processList\", "
+ "\"" + Constants.PARAM_TOKEN + "0\":"
+ "\"1@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy\","
+ "\""
+ Constants.PARAM_TOKEN
+ "1\": [\"1@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy\", \"1@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy\", \"1@NO@com.google.gwt.requestfactory.shared.SimpleFooProxy\"] }");
assertEquals("GWTGWTGWT", results.getString("result"));
}
private JSONObject getResultFromServer(JSONObject foo) throws JSONException,
NoSuchMethodException, IllegalAccessException, InvocationTargetException,
ClassNotFoundException, SecurityException, InstantiationException {
JSONObject proxyWithSchema = new JSONObject();
proxyWithSchema.put(SimpleFooProxy.class.getName(), foo);
JSONArray arr = new JSONArray();
arr.put(proxyWithSchema);
JSONObject operation = new JSONObject();
operation.put(WriteOperation.UPDATE.toString(), arr);
JSONObject sync = new JSONObject();
sync.put(Constants.OPERATION_TOKEN,
"com.google.gwt.requestfactory.shared.SimpleFooRequest::persist");
sync.put(Constants.CONTENT_TOKEN, operation.toString());
sync.put(Constants.PARAM_TOKEN + "0", foo.getString("id") + "@NO" + "@"
+ SimpleFooProxy.class.getName());
return requestProcessor.processJsonRequest(sync.toString());
}
}