package org.springframework.social.evernote.api.impl; import org.apache.thrift.protocol.TJSONProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TMemoryBuffer; import org.apache.thrift.transport.TTransport; import org.junit.Test; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.AopUtils; import org.springframework.social.evernote.api.impl.entity.Bar; import org.springframework.social.evernote.api.impl.entity.Baz; import org.springframework.social.evernote.api.impl.entity.Foo; import java.util.*; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.springframework.social.evernote.api.impl.ThriftWrapper.makeNullSafe; /** * @author Tadaya Tsuyukubo */ public class ThriftWrapperTest { @Test public void testWrap() throws Exception { Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); Bar bar = new Bar(); Baz baz = new Baz(); bar.setName("bar"); baz.setName("baz"); bar.setBaz(baz); foo.setBar(bar); // initially all options are null assertThat(foo.getName(), is("foo")); assertThat(foo.getRequiredList(), is(emptyCollectionOf(String.class))); assertThat(foo.getRequiredSet(), is(emptyCollectionOf(String.class))); assertThat(foo.getRequiredMap(), is(notNullValue())); assertThat(foo.getRequiredMap().size(), is(0)); assertThat(foo.getOptionalList(), is(nullValue())); assertThat(foo.getOptionalSet(), is(nullValue())); assertThat(foo.getOptionalMap(), is(nullValue())); assertThat(bar.getName(), is("bar")); assertThat(bar.getBarList(), is(nullValue())); assertThat(bar.getBarSet(), is(nullValue())); assertThat(bar.getBarMap(), is(nullValue())); assertThat(baz.getName(), is("baz")); assertThat(baz.getBazList(), is(nullValue())); assertThat(baz.getBazSet(), is(nullValue())); assertThat(baz.getBazMap(), is(nullValue())); Foo wrapped = makeNullSafe(foo); // wrap assertThat(wrapped.getName(), is("foo")); assertThat(wrapped.getRequiredList(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getRequiredSet(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getRequiredMap(), is(notNullValue())); assertThat(wrapped.getRequiredMap().size(), is(0)); assertThat(wrapped.getOptionalList(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getOptionalSet(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getOptionalMap(), is(notNullValue())); assertThat(wrapped.getOptionalMap().size(), is(0)); assertThat(wrapped.getBar().getName(), is("bar")); assertThat(wrapped.getBar().getBarList(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getBar().getBarSet(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getBar().getBarMap(), is(notNullValue())); assertThat(wrapped.getBar().getBarMap().size(), is(0)); assertThat(wrapped.getBar().getBaz().getName(), is("baz")); assertThat(wrapped.getBar().getBaz().getBazList(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getBar().getBaz().getBazSet(), is(emptyCollectionOf(String.class))); assertThat(wrapped.getBar().getBaz().getBazMap(), is(notNullValue())); assertThat(wrapped.getBar().getBaz().getBazMap().size(), is(0)); } @Test public void testWrite() throws Exception { TTransport tTransport = new TMemoryBuffer(100); TProtocol tProtocol = new TJSONProtocol(tTransport); Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); Bar bar = new Bar(); Baz baz = new Baz(); bar.setName("bar"); baz.setName("baz"); foo.setBar(bar); bar.setBaz(baz); // optional fields are all null, so should not be transmitted Foo wrapped = makeNullSafe(foo); wrapped.write(tProtocol); List<String> list = new ArrayList<String>(Arrays.asList(new String[]{"LIST-VALUE"})); Set<String> set = new HashSet<String>(Arrays.asList(new String[]{"SET-VALUE"})); Map<String, String> map = new HashMap<String, String>(); map.put("MAP-KEY", "MAP-VALUE"); // construct new object graph with some values in collections Foo newFoo = new Foo("FOO", list, set, map); newFoo.setOptionalList(list); newFoo.setOptionalSet(set); newFoo.setOptionalMap(map); Bar newBar = new Bar(); newBar.setName("BAR"); newBar.setBarList(list); newBar.setBarSet(set); newBar.setBarMap(map); newFoo.setBar(newBar); // read from message newFoo.read(tProtocol); assertThat(newFoo.getName(), is("foo")); assertThat(newFoo.getRequiredList(), is(emptyCollectionOf(String.class))); assertThat(newFoo.getRequiredSet(), is(emptyCollectionOf(String.class))); assertThat(newFoo.getRequiredMap(), is(notNullValue())); assertThat(newFoo.getRequiredMap().size(), is(0)); // optional fields should not be overridden because they were not sent in thrift message assertThat(newFoo.getOptionalList(), hasItem("LIST-VALUE")); assertThat(newFoo.getOptionalSet(), hasItem("SET-VALUE")); assertThat(newFoo.getOptionalMap(), hasEntry("MAP-KEY", "MAP-VALUE")); assertThat(newFoo.getBar(), is(not(sameInstance(bar)))); // thrift creates new instance assertThat(newFoo.getBar().getName(), is("bar")); assertThat(newFoo.getBar().getBarList(), is(nullValue())); // default for optional container is null assertThat(newFoo.getBar().getBarSet(), is(nullValue())); assertThat(newFoo.getBar().getBarMap(), is(nullValue())); assertThat(newFoo.getBar().getBaz(), is(not(sameInstance(baz)))); assertThat(newFoo.getBar().getBaz().getName(), is("baz")); assertThat(newFoo.getBar().getBaz().getBazList(), is(nullValue())); assertThat(newFoo.getBar().getBaz().getBazSet(), is(nullValue())); assertThat(newFoo.getBar().getBaz().getBazMap(), is(nullValue())); } @Test public void testSetValue() throws Exception { Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); Foo wrapped = makeNullSafe(foo); wrapped.getOptionalList().add("FOO-LIST"); wrapped.getOptionalSet().add("FOO-SET"); wrapped.getOptionalMap().put("FOO-MAP-KEY", "FOO-MAP-VALUE"); assertThat(foo.getOptionalList(), hasItem("FOO-LIST")); assertThat(foo.getOptionalSet(), hasItem("FOO-SET")); assertThat(foo.getOptionalMap(), hasEntry("FOO-MAP-KEY", "FOO-MAP-VALUE")); assertThat(wrapped.getOptionalList(), hasItem("FOO-LIST")); assertThat(wrapped.getOptionalSet(), hasItem("FOO-SET")); assertThat(wrapped.getOptionalMap(), hasEntry("FOO-MAP-KEY", "FOO-MAP-VALUE")); } @Test public void testWriteWithValue() throws Exception { TTransport tTransport = new TMemoryBuffer(100); TProtocol tProtocol = new TJSONProtocol(tTransport); Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); foo.addToOptionalList("FOO-LIST"); foo.addToOptionalSet("FOO-SET"); foo.putToOptionalMap("FOO-MAP-KEY", "FOO-MAP-VALUE"); Bar bar = new Bar(); bar.setName("bar"); bar.addToBarList("BAR-LIST"); bar.addToBarSet("BAR-SET"); bar.putToBarMap("BAR-MAP-KEY", "BAR-MAP-VALUE"); foo.setBar(bar); Foo wrapped = makeNullSafe(foo); wrapped.write(tProtocol); Foo newFoo = new Foo("new-foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); // read from message newFoo.read(tProtocol); assertThat(newFoo.getOptionalList(), hasItem("FOO-LIST")); assertThat(newFoo.getOptionalSet(), hasItem("FOO-SET")); assertThat(newFoo.getOptionalMap(), hasEntry("FOO-MAP-KEY", "FOO-MAP-VALUE")); assertThat(newFoo.getBar(), is(notNullValue())); assertThat(newFoo.getBar().getName(), is("bar")); assertThat(newFoo.getBar().getBarList(), hasItem("BAR-LIST")); assertThat(newFoo.getBar().getBarSet(), hasItem("BAR-SET")); assertThat(newFoo.getBar().getBarMap(), hasEntry("BAR-MAP-KEY", "BAR-MAP-VALUE")); assertThat(newFoo.getBar().getBaz(), is(nullValue())); } @Test public void testWriteSetCollectionsToEmpty() throws Exception { TTransport tTransport = new TMemoryBuffer(100); TProtocol tProtocol = new TJSONProtocol(tTransport); // original object has values in collections Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); foo.addToOptionalList("FOO-LIST"); foo.addToOptionalSet("FOO-SET"); foo.putToOptionalMap("FOO-MAP-KEY", "FOO-MAP-VALUE"); // wrap it Foo wrapped = makeNullSafe(foo); // make collections empty wrapped.getOptionalList().clear(); wrapped.getOptionalSet().clear(); wrapped.getOptionalMap().clear(); // write wrapped.write(tProtocol); Foo newFoo = new Foo("new-foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); // read from message newFoo.read(tProtocol); // now new object should have empty collections assertThat(newFoo.getName(), is("foo")); assertThat(newFoo.getOptionalList(), is(emptyCollectionOf(String.class))); assertThat(newFoo.getOptionalSet(), is(emptyCollectionOf(String.class))); assertThat(newFoo.getOptionalMap(), is(notNullValue())); assertThat(newFoo.getOptionalMap().size(), is(0)); } @Test public void testNull() { Object result = makeNullSafe(null); assertThat(result, is(nullValue())); } @Test public void testThriftWrapperProxyMarker() { Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); Bar bar = new Bar(); Baz baz = new Baz(); bar.setName("bar"); baz.setName("baz"); bar.setBaz(baz); foo.setBar(bar); Foo wrapped = makeNullSafe(foo); // wrap assertThat(AopUtils.isAopProxy(wrapped), is(true)); assertThat(wrapped, is(instanceOf(ThriftWrapper.ThriftWrapperProxyMarker.class))); assertThat(AopUtils.isAopProxy(wrapped.getBar()), is(true)); assertThat(wrapped.getBar(), is(instanceOf(ThriftWrapper.ThriftWrapperProxyMarker.class))); assertThat(AopUtils.isAopProxy(wrapped.getBar().getBaz()), is(true)); assertThat(wrapped.getBar().getBaz(), is(instanceOf(ThriftWrapper.ThriftWrapperProxyMarker.class))); } @Test public void testIsNullSafeProxy() { Foo foo = new Foo("foo", new ArrayList<String>(), new HashSet<String>(), new HashMap<String, String>()); assertThat(ThriftWrapper.isNullSafeProxy(foo), is(false)); Foo wrapped = makeNullSafe(foo); // wrap assertThat(ThriftWrapper.isNullSafeProxy(wrapped), is(true)); // proxy but not by ThriftWrapper ProxyFactory proxyFactory = new ProxyFactory(foo); proxyFactory.setProxyTargetClass(true); // force cglib Foo proxy = (Foo) proxyFactory.getProxy(); assertThat(ThriftWrapper.isNullSafeProxy(proxy), is(false)); } }