| /* |
| * 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()); |
| } |
| } |