You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2014/11/02 08:39:00 UTC

[4/8] Rename Integration Tests in cayenne-client (*IT.java instead of *Test.java)

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
new file mode 100644
index 0000000..937f39c
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextIT.java
@@ -0,0 +1,864 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.cayenne;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cayenne.configuration.rop.client.ClientRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.graph.GraphChangeHandler;
+import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.remote.RemoteCayenneCase;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.testdo.mt.ClientMtTooneDep;
+import org.apache.cayenne.testdo.mt.ClientMtTooneMaster;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+/**
+ * Tests nested object contexts
+ */
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class NestedCayenneContextIT extends RemoteCayenneCase {
+
+    @Inject
+    private ClientRuntime runtime;
+    
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private DataChannelInterceptor queryInterceptor;
+
+    @Override
+    public void setUpAfterInjection() throws Exception {
+        super.setUpAfterInjection();
+
+        dbHelper.deleteAll("MT_TABLE2");
+        dbHelper.deleteAll("MT_TABLE1");
+    }
+
+    public void testChannels() {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        assertNotNull(child);
+        assertSame(clientContext, child.getChannel());
+
+        // second level of nesting
+        ObjectContext grandchild = runtime.newContext((DataChannel) child);
+
+        assertNotNull(grandchild);
+        assertSame(child, grandchild.getChannel());
+    }
+
+    public void testSelect() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable1 committed = clientContext.newObject(ClientMtTable1.class);
+        ClientMtTable1 deleted = clientContext.newObject(ClientMtTable1.class);
+        ClientMtTable1 modified = clientContext.newObject(ClientMtTable1.class);
+
+        clientContext.commitChanges();
+        int modifiedid = Cayenne.intPKForObject(modified);
+
+        // test how different object states appear in the child on select
+
+        clientContext.deleteObjects(deleted);
+        modified.setGlobalAttribute1("a");
+
+        ClientMtTable1 _new = clientContext.newObject(ClientMtTable1.class);
+
+        assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
+        assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
+        assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
+        assertEquals(PersistenceState.NEW, _new.getPersistenceState());
+
+        List<?> objects = child.performQuery(new SelectQuery(ClientMtTable1.class));
+        assertEquals("All but NEW object must have been included", 3, objects.size());
+
+        Iterator<?> it = objects.iterator();
+        while (it.hasNext()) {
+            ClientMtTable1 next = (ClientMtTable1) it.next();
+            assertEquals(PersistenceState.COMMITTED, next.getPersistenceState());
+
+            int id = Cayenne.intPKForObject(next);
+            if (id == modifiedid) {
+                assertEquals("a", next.getGlobalAttribute1());
+            }
+        }
+    }
+
+    public void testPrefetchingToOne() throws Exception {
+        final ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        ClientMtTable2 mt21 = clientContext.newObject(ClientMtTable2.class);
+        ClientMtTable2 mt22 = clientContext.newObject(ClientMtTable2.class);
+
+        mt21.setTable1(mt11);
+        mt22.setTable1(mt11);
+
+        clientContext.commitChanges();
+
+        final ObjectContext child = runtime.newContext(clientContext);
+
+        SelectQuery q = new SelectQuery(ClientMtTable2.class);
+        q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
+
+        final List<?> results = child.performQuery(q);
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals(2, results.size());
+                Iterator<?> it = results.iterator();
+                while (it.hasNext()) {
+                    ClientMtTable2 o = (ClientMtTable2) it.next();
+                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+                    assertSame(child, o.getObjectContext());
+
+                    ClientMtTable1 o1 = o.getTable1();
+                    assertNotNull(o1);
+                    assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+                    assertSame(child, o1.getObjectContext());
+                    assertEquals(mt11.getObjectId(), o1.getObjectId());
+                }
+            }
+        });
+    }
+
+    public void testPrefetchingToMany() throws Exception {
+        ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
+        mt11.setGlobalAttribute1("1");
+
+        ClientMtTable1 mt12 = clientContext.newObject(ClientMtTable1.class);
+        mt12.setGlobalAttribute1("2");
+
+        ClientMtTable2 mt21 = clientContext.newObject(ClientMtTable2.class);
+        ClientMtTable2 mt22 = clientContext.newObject(ClientMtTable2.class);
+
+        mt21.setTable1(mt11);
+        mt22.setTable1(mt11);
+
+        clientContext.commitChanges();
+
+        final ObjectContext child = runtime.newContext(clientContext);
+
+        SelectQuery q = new SelectQuery(ClientMtTable1.class);
+        q.addOrdering("globalAttribute1", SortOrder.ASCENDING);
+        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+
+        final List<?> results = child.performQuery(q);
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
+                assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
+                assertSame(child, o1.getObjectContext());
+
+                List<ClientMtTable2> children1 = o1.getTable2Array();
+
+                assertEquals(2, children1.size());
+                Iterator<ClientMtTable2> it = children1.iterator();
+                while (it.hasNext()) {
+                    ClientMtTable2 o = it.next();
+                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
+                    assertSame(child, o.getObjectContext());
+
+                    assertEquals(o1, o.getTable1());
+                }
+
+                ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
+                assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+                assertSame(child, o2.getObjectContext());
+
+                List<?> children2 = o2.getTable2Array();
+
+                assertEquals(0, children2.size());
+            }
+        });
+    }
+
+    public void testDeleteNew() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
+        clientContext.commitChanges();
+
+        ClientMtTable2 p = child.newObject(ClientMtTable2.class);
+        ClientMtTable1 aChild = (ClientMtTable1) Cayenne.objectForPK(
+                child,
+                a.getObjectId());
+        p.setGlobalAttribute("X");
+        aChild.addToTable2Array(p);
+
+        child.commitChangesToParent();
+
+        child.deleteObjects(p);
+        aChild.removeFromTable2Array(p);
+
+        child.commitChangesToParent();
+    }
+
+    /**
+     * A test case for CAY-698 bug.
+     */
+    public void testNullifyToOne() throws Exception {
+        ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
+        ClientMtTable2 b = clientContext.newObject(ClientMtTable2.class);
+        a.addToTable2Array(b);
+
+        clientContext.commitChanges();
+
+        final ObjectContext child = runtime.newContext(clientContext);
+        ObjectContext childPeer = runtime.newContext(clientContext);
+
+        final ClientMtTable2 childP1 = (ClientMtTable2) Cayenne.objectForPK(
+                child,
+                b.getObjectId());
+
+        // trigger object creation in the peer nested DC
+        Cayenne.objectForPK(childPeer, b.getObjectId());
+        childP1.setTable1(null);
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                child.commitChangesToParent();
+                assertEquals(PersistenceState.COMMITTED, childP1.getPersistenceState());
+
+                ClientMtTable2 parentP1 = (ClientMtTable2) clientContext
+                        .getGraphManager()
+                        .getNode(childP1.getObjectId());
+
+                assertNotNull(parentP1);
+                assertEquals(PersistenceState.MODIFIED, parentP1.getPersistenceState());
+                assertNull(parentP1.getTable1());
+
+                // check that arc changes got recorded in the parent context
+                GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
+                final int[] arcDiffs = new int[1];
+
+                diffs.apply(new GraphChangeHandler() {
+
+                    public void arcCreated(
+                            Object nodeId,
+                            Object targetNodeId,
+                            Object arcId) {
+                        arcDiffs[0]++;
+                    }
+
+                    public void arcDeleted(
+                            Object nodeId,
+                            Object targetNodeId,
+                            Object arcId) {
+                        arcDiffs[0]--;
+                    }
+
+                    public void nodeCreated(Object nodeId) {
+
+                    }
+
+                    public void nodeIdChanged(Object nodeId, Object newId) {
+                    }
+
+                    public void nodePropertyChanged(
+                            Object nodeId,
+                            String property,
+                            Object oldValue,
+                            Object newValue) {
+                    }
+
+                    public void nodeRemoved(Object nodeId) {
+
+                    }
+                });
+
+                assertEquals(-2, arcDiffs[0]);
+            }
+        });
+    }
+
+    public void testCommitChangesToParent() throws Exception {
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.commitChanges();
+
+        final ObjectContext child = runtime.newContext(clientContext);
+
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        List<?> objects = child.performQuery(query);
+
+        assertEquals(4, objects.size());
+
+        final ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
+        childNew.setGlobalAttribute1("NNN");
+
+        final ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
+        childModified.setGlobalAttribute1("MMM");
+
+        final ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
+
+        final ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
+        child.invalidateObjects(childHollow);
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                child.commitChangesToParent();
+
+                // * all modified child objects must be in committed state now
+                // * all modifications should be propagated to the parent
+                // * no actual commit should occur.
+
+                assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
+                assertEquals(
+                        PersistenceState.COMMITTED,
+                        childModified.getPersistenceState());
+                assertEquals(
+                        PersistenceState.COMMITTED,
+                        childCommitted.getPersistenceState());
+                assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
+
+                ClientMtTable1 parentNew = (ClientMtTable1) clientContext
+                        .getGraphManager()
+                        .getNode(childNew.getObjectId());
+                final ClientMtTable1 parentModified = (ClientMtTable1) clientContext
+                        .getGraphManager()
+                        .getNode(childModified.getObjectId());
+                ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
+                        .getGraphManager()
+                        .getNode(childCommitted.getObjectId());
+                ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
+                        .getGraphManager()
+                        .getNode(childHollow.getObjectId());
+
+                assertNotNull(parentNew);
+                assertEquals(PersistenceState.NEW, parentNew.getPersistenceState());
+                assertEquals("NNN", parentNew.getGlobalAttribute1());
+
+                assertNotNull(parentModified);
+                assertEquals(
+                        PersistenceState.MODIFIED,
+                        parentModified.getPersistenceState());
+                assertEquals("MMM", parentModified.getGlobalAttribute1());
+
+                assertNotNull(parentCommitted);
+                assertEquals(
+                        PersistenceState.COMMITTED,
+                        parentCommitted.getPersistenceState());
+
+                assertNotNull(parentHollow);
+
+                // check that arc changes got recorded in the parent context
+                GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
+
+                final int[] modifiedProperties = new int[1];
+
+                diffs.apply(new GraphChangeHandler() {
+
+                    public void arcCreated(
+                            Object nodeId,
+                            Object targetNodeId,
+                            Object arcId) {
+
+                    }
+
+                    public void arcDeleted(
+                            Object nodeId,
+                            Object targetNodeId,
+                            Object arcId) {
+
+                    }
+
+                    public void nodeCreated(Object nodeId) {
+
+                    }
+
+                    public void nodeIdChanged(Object nodeId, Object newId) {
+                    }
+
+                    public void nodePropertyChanged(
+                            Object nodeId,
+                            String property,
+                            Object oldValue,
+                            Object newValue) {
+
+                        if (nodeId.equals(parentModified.getObjectId())) {
+                            modifiedProperties[0]++;
+                        }
+                    }
+
+                    public void nodeRemoved(Object nodeId) {
+
+                    }
+                });
+
+                assertEquals(1, modifiedProperties[0]);
+            }
+        });
+    }
+
+    public void testCommitChangesToParentDeleted() throws Exception {
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.commitChanges();
+
+        ObjectContext child = runtime.newContext(clientContext);
+
+        // make sure we fetch in predictable order
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        List<?> objects = child.performQuery(query);
+
+        assertEquals(4, objects.size());
+
+        // delete AND modify
+        ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
+        child.deleteObjects(childDeleted);
+        childDeleted.setGlobalAttribute1("DDD");
+
+        // don't block queries - on delete Cayenne may need to resolve delete rules via
+        // fetch
+        child.commitChangesToParent();
+
+        // * all modified child objects must be in committed state now
+        // * all modifications should be propagated to the parent
+        // * no actual commit should occur.
+
+        assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
+
+        ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childDeleted.getObjectId());
+
+        assertNotNull(parentDeleted);
+        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
+        assertEquals("DDD", parentDeleted.getGlobalAttribute1());
+    }
+
+    /*
+     * was added for CAY-1636
+     */
+    public void testCAY1636() throws Exception {
+
+        ClientMtTooneMaster A = clientContext.newObject(ClientMtTooneMaster.class);
+        clientContext.commitChanges();
+
+        ClientMtTooneDep B = clientContext.newObject(ClientMtTooneDep.class);
+        A.setToDependent(B);
+        clientContext.commitChanges();
+
+        ObjectContext child = runtime.newContext(clientContext);
+
+        SelectQuery query = new SelectQuery(ClientMtTooneMaster.class);
+        List<?> objects = child.performQuery(query);
+
+        assertEquals(1, objects.size());
+
+        ClientMtTooneMaster childDeleted = (ClientMtTooneMaster) objects.get(0);
+
+        child.deleteObjects(childDeleted);
+
+        child.commitChangesToParent();
+
+        ClientMtTooneMaster parentDeleted = (ClientMtTooneMaster) clientContext
+                .getGraphManager()
+                .getNode(childDeleted.getObjectId());
+
+        assertNotNull(parentDeleted);
+        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
+
+        clientContext.commitChanges();
+
+        SelectQuery query2 = new SelectQuery(ClientMtTooneMaster.class);
+        List<?> objects2 = child.performQuery(query2);
+
+        assertEquals(0, objects2.size());
+
+    }
+
+    public void testCAY1636_2() throws Exception {
+
+        ClientMtTooneMaster A = clientContext.newObject(ClientMtTooneMaster.class);
+        clientContext.commitChanges();
+
+        ClientMtTooneDep B = clientContext.newObject(ClientMtTooneDep.class);
+        A.setToDependent(B);
+        clientContext.commitChanges();
+
+        ObjectContext child = runtime.newContext(clientContext);
+
+        SelectQuery queryB = new SelectQuery(ClientMtTooneDep.class);
+        List<?> objectsB = child.performQuery(queryB);
+
+        assertEquals(1, objectsB.size());
+
+        ClientMtTooneDep childBDeleted = (ClientMtTooneDep) objectsB.get(0);
+        child.deleteObjects(childBDeleted);
+
+        SelectQuery query = new SelectQuery(ClientMtTooneMaster.class);
+        List<?> objects = child.performQuery(query);
+
+        assertEquals(1, objects.size());
+
+        ClientMtTooneMaster childDeleted = (ClientMtTooneMaster) objects.get(0);
+
+        child.deleteObjects(childDeleted);
+
+        child.commitChangesToParent();
+
+        ClientMtTooneMaster parentDeleted = (ClientMtTooneMaster) clientContext
+                .getGraphManager()
+                .getNode(childDeleted.getObjectId());
+
+        assertNotNull(parentDeleted);
+        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
+
+        clientContext.commitChanges();
+
+        SelectQuery query2 = new SelectQuery(ClientMtTooneMaster.class);
+        List<?> objects2 = child.performQuery(query2);
+
+        assertEquals(0, objects2.size());
+
+    }
+
+    public void testCommitChanges() throws Exception {
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.newObject(ClientMtTable1.class);
+        clientContext.commitChanges();
+
+        ObjectContext child = runtime.newContext(clientContext);
+
+        // make sure we fetch in predictable order
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        List<?> objects = child.performQuery(query);
+
+        assertEquals(4, objects.size());
+
+        ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
+        childNew.setGlobalAttribute1("NNN");
+
+        ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
+        childModified.setGlobalAttribute1("MMM");
+
+        ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
+
+        // delete AND modify
+        ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
+        child.deleteObjects(childDeleted);
+        childDeleted.setGlobalAttribute1("DDD");
+
+        ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
+        child.invalidateObjects(childHollow);
+
+        child.commitChanges();
+
+        assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
+        assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
+        assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
+        assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
+        assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
+
+        ClientMtTable1 parentNew = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childNew.getObjectId());
+        ClientMtTable1 parentModified = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childModified.getObjectId());
+        ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childCommitted.getObjectId());
+        ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childDeleted.getObjectId());
+        ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(childHollow.getObjectId());
+
+        assertNotNull(parentNew);
+        assertEquals(PersistenceState.COMMITTED, parentNew.getPersistenceState());
+        assertEquals("NNN", parentNew.getGlobalAttribute1());
+
+        assertNotNull(parentModified);
+        assertEquals(PersistenceState.COMMITTED, parentModified.getPersistenceState());
+        assertEquals("MMM", parentModified.getGlobalAttribute1());
+
+        assertNull("Deleted object should not be registered.", parentDeleted);
+
+        assertNotNull(parentCommitted);
+        assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
+
+        assertNotNull(parentHollow);
+    }
+
+    public void testAddRemove() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable1 a = child.newObject(ClientMtTable1.class);
+        a.setGlobalAttribute1("X");
+        child.commitChanges();
+
+        ClientMtTable2 p1 = child.newObject(ClientMtTable2.class);
+        p1.setGlobalAttribute("P1");
+        a.addToTable2Array(p1);
+
+        ClientMtTable2 p2 = child.newObject(ClientMtTable2.class);
+        p2.setGlobalAttribute("P2");
+        a.addToTable2Array(p2);
+
+        a.removeFromTable2Array(p2);
+
+        // this causes an error on commit
+        child.deleteObjects(p2);
+
+        child.commitChangesToParent();
+
+    }
+
+    public void testChangeRel() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable1 a = child.newObject(ClientMtTable1.class);
+        ClientMtTable2 b = child.newObject(ClientMtTable2.class);
+        child.commitChanges();
+
+        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+
+        a.addToTable2Array(b);
+        assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
+
+        child.commitChangesToParent();
+        ClientMtTable1 parentA = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(a.getObjectId());
+        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+        assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
+        assertEquals(1, parentA.getTable2Array().size());
+
+        clientContext.commitChanges();
+        assertEquals(PersistenceState.COMMITTED, parentA.getPersistenceState());
+
+        a.removeFromTable2Array(b);
+        assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
+
+        child.commitChangesToParent();
+        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
+        assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
+        assertEquals(0, parentA.getTable2Array().size());
+    }
+
+    public void testCAY1183() throws Exception {
+        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
+        clientContext.commitChanges();
+
+        ObjectContext child = runtime.newContext(clientContext);
+        ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(
+                child,
+                parentMt.getObjectId());
+        childMt.setGlobalAttribute1("1183");
+        ClientMtTable2 childMt2 = child.newObject(ClientMtTable2.class);
+        childMt2.setGlobalAttribute("1183");
+        childMt2.setTable1(childMt);
+
+        child.commitChangesToParent();
+
+        // fetching other relationship... this fails per CAY-1183
+        childMt2.getTable3();
+    }
+    
+    /**
+     * CAY1714
+     */
+    public void testQueriesOnTemporaryObject() throws Exception {
+        ObjectContext clientContext = runtime.newContext((DataChannel) this.clientContext);
+        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
+
+        ObjectContext childContext = runtime.newContext((DataChannel) clientContext);
+        ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(childContext, parentMt.getObjectId());
+        childMt.setGlobalAttribute1("1183");
+        ClientMtTable2 childMt2 = childContext.newObject(ClientMtTable2.class);
+        childMt2.setGlobalAttribute("1183");
+        childMt2.setTable1(childMt);
+
+        childContext.commitChangesToParent();
+
+        assertNull(childMt2.getTable3());
+    }
+
+    public void testCAY1194() throws Exception {
+        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable2 childMt2 = child.newObject(ClientMtTable2.class);
+        childMt2.setGlobalAttribute("222");
+
+        ClientMtTable1 localParentMt = child.localObject(parentMt);
+        assertEquals(0, parentMt.getTable2Array().size());
+        assertEquals(0, localParentMt.getTable2Array().size());
+
+        childMt2.setTable1(localParentMt);
+
+        assertEquals(0, parentMt.getTable2Array().size());
+        assertEquals(1, localParentMt.getTable2Array().size());
+
+        assertEquals(localParentMt.getTable2Array().get(0).getObjectContext(), child);
+
+        child.commitChangesToParent();
+        assertEquals(1, parentMt.getTable2Array().size());
+        assertEquals(parentMt.getTable2Array().get(0).getObjectContext(), clientContext);
+    }
+
+    public void testCommitChangesToParentOneToMany() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTable1 master = child.newObject(ClientMtTable1.class);
+        ClientMtTable2 dep = child.newObject(ClientMtTable2.class);
+        master.addToTable2Array(dep);
+
+        child.commitChangesToParent();
+
+        ClientMtTable1 masterParent = (ClientMtTable1) clientContext
+                .getGraphManager()
+                .getNode(master.getObjectId());
+        ClientMtTable2 depParent = (ClientMtTable2) clientContext
+                .getGraphManager()
+                .getNode(dep.getObjectId());
+
+        assertNotNull(masterParent);
+        assertNotNull(depParent);
+
+        assertSame(masterParent, depParent.getTable1());
+        assertTrue(masterParent.getTable2Array().contains(depParent));
+
+        // check that arc changes got recorded in the parent context
+        GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
+
+        final int[] arcDiffs = new int[1];
+        final int[] newNodes = new int[1];
+
+        diffs.apply(new GraphChangeHandler() {
+
+            public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+                arcDiffs[0]++;
+            }
+
+            public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+                arcDiffs[0]--;
+            }
+
+            public void nodeCreated(Object nodeId) {
+                newNodes[0]++;
+            }
+
+            public void nodeIdChanged(Object nodeId, Object newId) {
+            }
+
+            public void nodePropertyChanged(
+                    Object nodeId,
+                    String property,
+                    Object oldValue,
+                    Object newValue) {
+            }
+
+            public void nodeRemoved(Object nodeId) {
+                newNodes[0]--;
+            }
+        });
+
+        assertEquals(2, newNodes[0]);
+        assertEquals(2, arcDiffs[0]);
+    }
+
+    public void testCommitChangesToParentOneToOne() throws Exception {
+        ObjectContext child = runtime.newContext(clientContext);
+
+        ClientMtTooneMaster master = child.newObject(ClientMtTooneMaster.class);
+        ClientMtTooneDep dep = child.newObject(ClientMtTooneDep.class);
+        master.setToDependent(dep);
+
+        child.commitChangesToParent();
+
+        ClientMtTooneMaster masterParent = (ClientMtTooneMaster) clientContext
+                .getGraphManager()
+                .getNode(master.getObjectId());
+        ClientMtTooneDep depParent = (ClientMtTooneDep) clientContext
+                .getGraphManager()
+                .getNode(dep.getObjectId());
+
+        assertNotNull(masterParent);
+        assertNotNull(depParent);
+
+        assertSame(masterParent, depParent.getToMaster());
+        assertSame(depParent, masterParent.getToDependent());
+
+        // check that arc changes got recorded in the parent context
+        GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
+
+        final int[] arcDiffs = new int[1];
+        final int[] newNodes = new int[1];
+
+        diffs.apply(new GraphChangeHandler() {
+
+            public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
+                arcDiffs[0]++;
+            }
+
+            public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
+                arcDiffs[0]--;
+            }
+
+            public void nodeCreated(Object nodeId) {
+                newNodes[0]++;
+            }
+
+            public void nodeIdChanged(Object nodeId, Object newId) {
+            }
+
+            public void nodePropertyChanged(
+                    Object nodeId,
+                    String property,
+                    Object oldValue,
+                    Object newValue) {
+            }
+
+            public void nodeRemoved(Object nodeId) {
+                newNodes[0]--;
+            }
+        });
+
+        assertEquals(2, newNodes[0]);
+        assertEquals(2, arcDiffs[0]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextTest.java b/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextTest.java
deleted file mode 100644
index aec2547..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/NestedCayenneContextTest.java
+++ /dev/null
@@ -1,864 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.cayenne;
-
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.cayenne.configuration.rop.client.ClientRuntime;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.graph.GraphChangeHandler;
-import org.apache.cayenne.graph.GraphDiff;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.remote.RemoteCayenneCase;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.testdo.mt.ClientMtTable1;
-import org.apache.cayenne.testdo.mt.ClientMtTable2;
-import org.apache.cayenne.testdo.mt.ClientMtTooneDep;
-import org.apache.cayenne.testdo.mt.ClientMtTooneMaster;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Painting;
-import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-/**
- * Tests nested object contexts
- */
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class NestedCayenneContextTest extends RemoteCayenneCase {
-
-    @Inject
-    private ClientRuntime runtime;
-    
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private DataChannelInterceptor queryInterceptor;
-
-    @Override
-    public void setUpAfterInjection() throws Exception {
-        super.setUpAfterInjection();
-
-        dbHelper.deleteAll("MT_TABLE2");
-        dbHelper.deleteAll("MT_TABLE1");
-    }
-
-    public void testChannels() {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        assertNotNull(child);
-        assertSame(clientContext, child.getChannel());
-
-        // second level of nesting
-        ObjectContext grandchild = runtime.newContext((DataChannel) child);
-
-        assertNotNull(grandchild);
-        assertSame(child, grandchild.getChannel());
-    }
-
-    public void testSelect() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable1 committed = clientContext.newObject(ClientMtTable1.class);
-        ClientMtTable1 deleted = clientContext.newObject(ClientMtTable1.class);
-        ClientMtTable1 modified = clientContext.newObject(ClientMtTable1.class);
-
-        clientContext.commitChanges();
-        int modifiedid = Cayenne.intPKForObject(modified);
-
-        // test how different object states appear in the child on select
-
-        clientContext.deleteObjects(deleted);
-        modified.setGlobalAttribute1("a");
-
-        ClientMtTable1 _new = clientContext.newObject(ClientMtTable1.class);
-
-        assertEquals(PersistenceState.COMMITTED, committed.getPersistenceState());
-        assertEquals(PersistenceState.MODIFIED, modified.getPersistenceState());
-        assertEquals(PersistenceState.DELETED, deleted.getPersistenceState());
-        assertEquals(PersistenceState.NEW, _new.getPersistenceState());
-
-        List<?> objects = child.performQuery(new SelectQuery(ClientMtTable1.class));
-        assertEquals("All but NEW object must have been included", 3, objects.size());
-
-        Iterator<?> it = objects.iterator();
-        while (it.hasNext()) {
-            ClientMtTable1 next = (ClientMtTable1) it.next();
-            assertEquals(PersistenceState.COMMITTED, next.getPersistenceState());
-
-            int id = Cayenne.intPKForObject(next);
-            if (id == modifiedid) {
-                assertEquals("a", next.getGlobalAttribute1());
-            }
-        }
-    }
-
-    public void testPrefetchingToOne() throws Exception {
-        final ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        ClientMtTable2 mt21 = clientContext.newObject(ClientMtTable2.class);
-        ClientMtTable2 mt22 = clientContext.newObject(ClientMtTable2.class);
-
-        mt21.setTable1(mt11);
-        mt22.setTable1(mt11);
-
-        clientContext.commitChanges();
-
-        final ObjectContext child = runtime.newContext(clientContext);
-
-        SelectQuery q = new SelectQuery(ClientMtTable2.class);
-        q.addPrefetch(ClientMtTable2.TABLE1_PROPERTY);
-
-        final List<?> results = child.performQuery(q);
-
-        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                assertEquals(2, results.size());
-                Iterator<?> it = results.iterator();
-                while (it.hasNext()) {
-                    ClientMtTable2 o = (ClientMtTable2) it.next();
-                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
-                    assertSame(child, o.getObjectContext());
-
-                    ClientMtTable1 o1 = o.getTable1();
-                    assertNotNull(o1);
-                    assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
-                    assertSame(child, o1.getObjectContext());
-                    assertEquals(mt11.getObjectId(), o1.getObjectId());
-                }
-            }
-        });
-    }
-
-    public void testPrefetchingToMany() throws Exception {
-        ClientMtTable1 mt11 = clientContext.newObject(ClientMtTable1.class);
-        mt11.setGlobalAttribute1("1");
-
-        ClientMtTable1 mt12 = clientContext.newObject(ClientMtTable1.class);
-        mt12.setGlobalAttribute1("2");
-
-        ClientMtTable2 mt21 = clientContext.newObject(ClientMtTable2.class);
-        ClientMtTable2 mt22 = clientContext.newObject(ClientMtTable2.class);
-
-        mt21.setTable1(mt11);
-        mt22.setTable1(mt11);
-
-        clientContext.commitChanges();
-
-        final ObjectContext child = runtime.newContext(clientContext);
-
-        SelectQuery q = new SelectQuery(ClientMtTable1.class);
-        q.addOrdering("globalAttribute1", SortOrder.ASCENDING);
-        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
-
-        final List<?> results = child.performQuery(q);
-
-        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
-                assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
-                assertSame(child, o1.getObjectContext());
-
-                List<ClientMtTable2> children1 = o1.getTable2Array();
-
-                assertEquals(2, children1.size());
-                Iterator<ClientMtTable2> it = children1.iterator();
-                while (it.hasNext()) {
-                    ClientMtTable2 o = it.next();
-                    assertEquals(PersistenceState.COMMITTED, o.getPersistenceState());
-                    assertSame(child, o.getObjectContext());
-
-                    assertEquals(o1, o.getTable1());
-                }
-
-                ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
-                assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
-                assertSame(child, o2.getObjectContext());
-
-                List<?> children2 = o2.getTable2Array();
-
-                assertEquals(0, children2.size());
-            }
-        });
-    }
-
-    public void testDeleteNew() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
-        clientContext.commitChanges();
-
-        ClientMtTable2 p = child.newObject(ClientMtTable2.class);
-        ClientMtTable1 aChild = (ClientMtTable1) Cayenne.objectForPK(
-                child,
-                a.getObjectId());
-        p.setGlobalAttribute("X");
-        aChild.addToTable2Array(p);
-
-        child.commitChangesToParent();
-
-        child.deleteObjects(p);
-        aChild.removeFromTable2Array(p);
-
-        child.commitChangesToParent();
-    }
-
-    /**
-     * A test case for CAY-698 bug.
-     */
-    public void testNullifyToOne() throws Exception {
-        ClientMtTable1 a = clientContext.newObject(ClientMtTable1.class);
-        ClientMtTable2 b = clientContext.newObject(ClientMtTable2.class);
-        a.addToTable2Array(b);
-
-        clientContext.commitChanges();
-
-        final ObjectContext child = runtime.newContext(clientContext);
-        ObjectContext childPeer = runtime.newContext(clientContext);
-
-        final ClientMtTable2 childP1 = (ClientMtTable2) Cayenne.objectForPK(
-                child,
-                b.getObjectId());
-
-        // trigger object creation in the peer nested DC
-        Cayenne.objectForPK(childPeer, b.getObjectId());
-        childP1.setTable1(null);
-
-        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                child.commitChangesToParent();
-                assertEquals(PersistenceState.COMMITTED, childP1.getPersistenceState());
-
-                ClientMtTable2 parentP1 = (ClientMtTable2) clientContext
-                        .getGraphManager()
-                        .getNode(childP1.getObjectId());
-
-                assertNotNull(parentP1);
-                assertEquals(PersistenceState.MODIFIED, parentP1.getPersistenceState());
-                assertNull(parentP1.getTable1());
-
-                // check that arc changes got recorded in the parent context
-                GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
-                final int[] arcDiffs = new int[1];
-
-                diffs.apply(new GraphChangeHandler() {
-
-                    public void arcCreated(
-                            Object nodeId,
-                            Object targetNodeId,
-                            Object arcId) {
-                        arcDiffs[0]++;
-                    }
-
-                    public void arcDeleted(
-                            Object nodeId,
-                            Object targetNodeId,
-                            Object arcId) {
-                        arcDiffs[0]--;
-                    }
-
-                    public void nodeCreated(Object nodeId) {
-
-                    }
-
-                    public void nodeIdChanged(Object nodeId, Object newId) {
-                    }
-
-                    public void nodePropertyChanged(
-                            Object nodeId,
-                            String property,
-                            Object oldValue,
-                            Object newValue) {
-                    }
-
-                    public void nodeRemoved(Object nodeId) {
-
-                    }
-                });
-
-                assertEquals(-2, arcDiffs[0]);
-            }
-        });
-    }
-
-    public void testCommitChangesToParent() throws Exception {
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.commitChanges();
-
-        final ObjectContext child = runtime.newContext(clientContext);
-
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        List<?> objects = child.performQuery(query);
-
-        assertEquals(4, objects.size());
-
-        final ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
-        childNew.setGlobalAttribute1("NNN");
-
-        final ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
-        childModified.setGlobalAttribute1("MMM");
-
-        final ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
-
-        final ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
-        child.invalidateObjects(childHollow);
-
-        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                child.commitChangesToParent();
-
-                // * all modified child objects must be in committed state now
-                // * all modifications should be propagated to the parent
-                // * no actual commit should occur.
-
-                assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
-                assertEquals(
-                        PersistenceState.COMMITTED,
-                        childModified.getPersistenceState());
-                assertEquals(
-                        PersistenceState.COMMITTED,
-                        childCommitted.getPersistenceState());
-                assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
-
-                ClientMtTable1 parentNew = (ClientMtTable1) clientContext
-                        .getGraphManager()
-                        .getNode(childNew.getObjectId());
-                final ClientMtTable1 parentModified = (ClientMtTable1) clientContext
-                        .getGraphManager()
-                        .getNode(childModified.getObjectId());
-                ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
-                        .getGraphManager()
-                        .getNode(childCommitted.getObjectId());
-                ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
-                        .getGraphManager()
-                        .getNode(childHollow.getObjectId());
-
-                assertNotNull(parentNew);
-                assertEquals(PersistenceState.NEW, parentNew.getPersistenceState());
-                assertEquals("NNN", parentNew.getGlobalAttribute1());
-
-                assertNotNull(parentModified);
-                assertEquals(
-                        PersistenceState.MODIFIED,
-                        parentModified.getPersistenceState());
-                assertEquals("MMM", parentModified.getGlobalAttribute1());
-
-                assertNotNull(parentCommitted);
-                assertEquals(
-                        PersistenceState.COMMITTED,
-                        parentCommitted.getPersistenceState());
-
-                assertNotNull(parentHollow);
-
-                // check that arc changes got recorded in the parent context
-                GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
-
-                final int[] modifiedProperties = new int[1];
-
-                diffs.apply(new GraphChangeHandler() {
-
-                    public void arcCreated(
-                            Object nodeId,
-                            Object targetNodeId,
-                            Object arcId) {
-
-                    }
-
-                    public void arcDeleted(
-                            Object nodeId,
-                            Object targetNodeId,
-                            Object arcId) {
-
-                    }
-
-                    public void nodeCreated(Object nodeId) {
-
-                    }
-
-                    public void nodeIdChanged(Object nodeId, Object newId) {
-                    }
-
-                    public void nodePropertyChanged(
-                            Object nodeId,
-                            String property,
-                            Object oldValue,
-                            Object newValue) {
-
-                        if (nodeId.equals(parentModified.getObjectId())) {
-                            modifiedProperties[0]++;
-                        }
-                    }
-
-                    public void nodeRemoved(Object nodeId) {
-
-                    }
-                });
-
-                assertEquals(1, modifiedProperties[0]);
-            }
-        });
-    }
-
-    public void testCommitChangesToParentDeleted() throws Exception {
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.commitChanges();
-
-        ObjectContext child = runtime.newContext(clientContext);
-
-        // make sure we fetch in predictable order
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        List<?> objects = child.performQuery(query);
-
-        assertEquals(4, objects.size());
-
-        // delete AND modify
-        ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
-        child.deleteObjects(childDeleted);
-        childDeleted.setGlobalAttribute1("DDD");
-
-        // don't block queries - on delete Cayenne may need to resolve delete rules via
-        // fetch
-        child.commitChangesToParent();
-
-        // * all modified child objects must be in committed state now
-        // * all modifications should be propagated to the parent
-        // * no actual commit should occur.
-
-        assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
-
-        ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childDeleted.getObjectId());
-
-        assertNotNull(parentDeleted);
-        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
-        assertEquals("DDD", parentDeleted.getGlobalAttribute1());
-    }
-
-    /*
-     * was added for CAY-1636
-     */
-    public void testCAY1636() throws Exception {
-
-        ClientMtTooneMaster A = clientContext.newObject(ClientMtTooneMaster.class);
-        clientContext.commitChanges();
-
-        ClientMtTooneDep B = clientContext.newObject(ClientMtTooneDep.class);
-        A.setToDependent(B);
-        clientContext.commitChanges();
-
-        ObjectContext child = runtime.newContext(clientContext);
-
-        SelectQuery query = new SelectQuery(ClientMtTooneMaster.class);
-        List<?> objects = child.performQuery(query);
-
-        assertEquals(1, objects.size());
-
-        ClientMtTooneMaster childDeleted = (ClientMtTooneMaster) objects.get(0);
-
-        child.deleteObjects(childDeleted);
-
-        child.commitChangesToParent();
-
-        ClientMtTooneMaster parentDeleted = (ClientMtTooneMaster) clientContext
-                .getGraphManager()
-                .getNode(childDeleted.getObjectId());
-
-        assertNotNull(parentDeleted);
-        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
-
-        clientContext.commitChanges();
-
-        SelectQuery query2 = new SelectQuery(ClientMtTooneMaster.class);
-        List<?> objects2 = child.performQuery(query2);
-
-        assertEquals(0, objects2.size());
-
-    }
-
-    public void testCAY1636_2() throws Exception {
-
-        ClientMtTooneMaster A = clientContext.newObject(ClientMtTooneMaster.class);
-        clientContext.commitChanges();
-
-        ClientMtTooneDep B = clientContext.newObject(ClientMtTooneDep.class);
-        A.setToDependent(B);
-        clientContext.commitChanges();
-
-        ObjectContext child = runtime.newContext(clientContext);
-
-        SelectQuery queryB = new SelectQuery(ClientMtTooneDep.class);
-        List<?> objectsB = child.performQuery(queryB);
-
-        assertEquals(1, objectsB.size());
-
-        ClientMtTooneDep childBDeleted = (ClientMtTooneDep) objectsB.get(0);
-        child.deleteObjects(childBDeleted);
-
-        SelectQuery query = new SelectQuery(ClientMtTooneMaster.class);
-        List<?> objects = child.performQuery(query);
-
-        assertEquals(1, objects.size());
-
-        ClientMtTooneMaster childDeleted = (ClientMtTooneMaster) objects.get(0);
-
-        child.deleteObjects(childDeleted);
-
-        child.commitChangesToParent();
-
-        ClientMtTooneMaster parentDeleted = (ClientMtTooneMaster) clientContext
-                .getGraphManager()
-                .getNode(childDeleted.getObjectId());
-
-        assertNotNull(parentDeleted);
-        assertEquals(PersistenceState.DELETED, parentDeleted.getPersistenceState());
-
-        clientContext.commitChanges();
-
-        SelectQuery query2 = new SelectQuery(ClientMtTooneMaster.class);
-        List<?> objects2 = child.performQuery(query2);
-
-        assertEquals(0, objects2.size());
-
-    }
-
-    public void testCommitChanges() throws Exception {
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.newObject(ClientMtTable1.class);
-        clientContext.commitChanges();
-
-        ObjectContext child = runtime.newContext(clientContext);
-
-        // make sure we fetch in predictable order
-        SelectQuery query = new SelectQuery(ClientMtTable1.class);
-        List<?> objects = child.performQuery(query);
-
-        assertEquals(4, objects.size());
-
-        ClientMtTable1 childNew = child.newObject(ClientMtTable1.class);
-        childNew.setGlobalAttribute1("NNN");
-
-        ClientMtTable1 childModified = (ClientMtTable1) objects.get(0);
-        childModified.setGlobalAttribute1("MMM");
-
-        ClientMtTable1 childCommitted = (ClientMtTable1) objects.get(1);
-
-        // delete AND modify
-        ClientMtTable1 childDeleted = (ClientMtTable1) objects.get(2);
-        child.deleteObjects(childDeleted);
-        childDeleted.setGlobalAttribute1("DDD");
-
-        ClientMtTable1 childHollow = (ClientMtTable1) objects.get(3);
-        child.invalidateObjects(childHollow);
-
-        child.commitChanges();
-
-        assertEquals(PersistenceState.COMMITTED, childNew.getPersistenceState());
-        assertEquals(PersistenceState.COMMITTED, childModified.getPersistenceState());
-        assertEquals(PersistenceState.COMMITTED, childCommitted.getPersistenceState());
-        assertEquals(PersistenceState.TRANSIENT, childDeleted.getPersistenceState());
-        assertEquals(PersistenceState.HOLLOW, childHollow.getPersistenceState());
-
-        ClientMtTable1 parentNew = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childNew.getObjectId());
-        ClientMtTable1 parentModified = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childModified.getObjectId());
-        ClientMtTable1 parentCommitted = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childCommitted.getObjectId());
-        ClientMtTable1 parentDeleted = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childDeleted.getObjectId());
-        ClientMtTable1 parentHollow = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(childHollow.getObjectId());
-
-        assertNotNull(parentNew);
-        assertEquals(PersistenceState.COMMITTED, parentNew.getPersistenceState());
-        assertEquals("NNN", parentNew.getGlobalAttribute1());
-
-        assertNotNull(parentModified);
-        assertEquals(PersistenceState.COMMITTED, parentModified.getPersistenceState());
-        assertEquals("MMM", parentModified.getGlobalAttribute1());
-
-        assertNull("Deleted object should not be registered.", parentDeleted);
-
-        assertNotNull(parentCommitted);
-        assertEquals(PersistenceState.COMMITTED, parentCommitted.getPersistenceState());
-
-        assertNotNull(parentHollow);
-    }
-
-    public void testAddRemove() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable1 a = child.newObject(ClientMtTable1.class);
-        a.setGlobalAttribute1("X");
-        child.commitChanges();
-
-        ClientMtTable2 p1 = child.newObject(ClientMtTable2.class);
-        p1.setGlobalAttribute("P1");
-        a.addToTable2Array(p1);
-
-        ClientMtTable2 p2 = child.newObject(ClientMtTable2.class);
-        p2.setGlobalAttribute("P2");
-        a.addToTable2Array(p2);
-
-        a.removeFromTable2Array(p2);
-
-        // this causes an error on commit
-        child.deleteObjects(p2);
-
-        child.commitChangesToParent();
-
-    }
-
-    public void testChangeRel() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable1 a = child.newObject(ClientMtTable1.class);
-        ClientMtTable2 b = child.newObject(ClientMtTable2.class);
-        child.commitChanges();
-
-        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
-
-        a.addToTable2Array(b);
-        assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
-
-        child.commitChangesToParent();
-        ClientMtTable1 parentA = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(a.getObjectId());
-        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
-        assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
-        assertEquals(1, parentA.getTable2Array().size());
-
-        clientContext.commitChanges();
-        assertEquals(PersistenceState.COMMITTED, parentA.getPersistenceState());
-
-        a.removeFromTable2Array(b);
-        assertEquals(PersistenceState.MODIFIED, a.getPersistenceState());
-
-        child.commitChangesToParent();
-        assertEquals(PersistenceState.COMMITTED, a.getPersistenceState());
-        assertEquals(PersistenceState.MODIFIED, parentA.getPersistenceState());
-        assertEquals(0, parentA.getTable2Array().size());
-    }
-
-    public void testCAY1183() throws Exception {
-        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
-        clientContext.commitChanges();
-
-        ObjectContext child = runtime.newContext(clientContext);
-        ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(
-                child,
-                parentMt.getObjectId());
-        childMt.setGlobalAttribute1("1183");
-        ClientMtTable2 childMt2 = child.newObject(ClientMtTable2.class);
-        childMt2.setGlobalAttribute("1183");
-        childMt2.setTable1(childMt);
-
-        child.commitChangesToParent();
-
-        // fetching other relationship... this fails per CAY-1183
-        childMt2.getTable3();
-    }
-    
-    /**
-     * CAY1714
-     */
-    public void testQueriesOnTemporaryObject() throws Exception {
-        ObjectContext clientContext = runtime.newContext((DataChannel) this.clientContext);
-        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
-
-        ObjectContext childContext = runtime.newContext((DataChannel) clientContext);
-        ClientMtTable1 childMt = (ClientMtTable1) Cayenne.objectForPK(childContext, parentMt.getObjectId());
-        childMt.setGlobalAttribute1("1183");
-        ClientMtTable2 childMt2 = childContext.newObject(ClientMtTable2.class);
-        childMt2.setGlobalAttribute("1183");
-        childMt2.setTable1(childMt);
-
-        childContext.commitChangesToParent();
-
-        assertNull(childMt2.getTable3());
-    }
-
-    public void testCAY1194() throws Exception {
-        ClientMtTable1 parentMt = clientContext.newObject(ClientMtTable1.class);
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable2 childMt2 = child.newObject(ClientMtTable2.class);
-        childMt2.setGlobalAttribute("222");
-
-        ClientMtTable1 localParentMt = child.localObject(parentMt);
-        assertEquals(0, parentMt.getTable2Array().size());
-        assertEquals(0, localParentMt.getTable2Array().size());
-
-        childMt2.setTable1(localParentMt);
-
-        assertEquals(0, parentMt.getTable2Array().size());
-        assertEquals(1, localParentMt.getTable2Array().size());
-
-        assertEquals(localParentMt.getTable2Array().get(0).getObjectContext(), child);
-
-        child.commitChangesToParent();
-        assertEquals(1, parentMt.getTable2Array().size());
-        assertEquals(parentMt.getTable2Array().get(0).getObjectContext(), clientContext);
-    }
-
-    public void testCommitChangesToParentOneToMany() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTable1 master = child.newObject(ClientMtTable1.class);
-        ClientMtTable2 dep = child.newObject(ClientMtTable2.class);
-        master.addToTable2Array(dep);
-
-        child.commitChangesToParent();
-
-        ClientMtTable1 masterParent = (ClientMtTable1) clientContext
-                .getGraphManager()
-                .getNode(master.getObjectId());
-        ClientMtTable2 depParent = (ClientMtTable2) clientContext
-                .getGraphManager()
-                .getNode(dep.getObjectId());
-
-        assertNotNull(masterParent);
-        assertNotNull(depParent);
-
-        assertSame(masterParent, depParent.getTable1());
-        assertTrue(masterParent.getTable2Array().contains(depParent));
-
-        // check that arc changes got recorded in the parent context
-        GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
-
-        final int[] arcDiffs = new int[1];
-        final int[] newNodes = new int[1];
-
-        diffs.apply(new GraphChangeHandler() {
-
-            public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
-                arcDiffs[0]++;
-            }
-
-            public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
-                arcDiffs[0]--;
-            }
-
-            public void nodeCreated(Object nodeId) {
-                newNodes[0]++;
-            }
-
-            public void nodeIdChanged(Object nodeId, Object newId) {
-            }
-
-            public void nodePropertyChanged(
-                    Object nodeId,
-                    String property,
-                    Object oldValue,
-                    Object newValue) {
-            }
-
-            public void nodeRemoved(Object nodeId) {
-                newNodes[0]--;
-            }
-        });
-
-        assertEquals(2, newNodes[0]);
-        assertEquals(2, arcDiffs[0]);
-    }
-
-    public void testCommitChangesToParentOneToOne() throws Exception {
-        ObjectContext child = runtime.newContext(clientContext);
-
-        ClientMtTooneMaster master = child.newObject(ClientMtTooneMaster.class);
-        ClientMtTooneDep dep = child.newObject(ClientMtTooneDep.class);
-        master.setToDependent(dep);
-
-        child.commitChangesToParent();
-
-        ClientMtTooneMaster masterParent = (ClientMtTooneMaster) clientContext
-                .getGraphManager()
-                .getNode(master.getObjectId());
-        ClientMtTooneDep depParent = (ClientMtTooneDep) clientContext
-                .getGraphManager()
-                .getNode(dep.getObjectId());
-
-        assertNotNull(masterParent);
-        assertNotNull(depParent);
-
-        assertSame(masterParent, depParent.getToMaster());
-        assertSame(depParent, masterParent.getToDependent());
-
-        // check that arc changes got recorded in the parent context
-        GraphDiff diffs = clientContext.internalGraphManager().getDiffs();
-
-        final int[] arcDiffs = new int[1];
-        final int[] newNodes = new int[1];
-
-        diffs.apply(new GraphChangeHandler() {
-
-            public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) {
-                arcDiffs[0]++;
-            }
-
-            public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) {
-                arcDiffs[0]--;
-            }
-
-            public void nodeCreated(Object nodeId) {
-                newNodes[0]++;
-            }
-
-            public void nodeIdChanged(Object nodeId, Object newId) {
-            }
-
-            public void nodePropertyChanged(
-                    Object nodeId,
-                    String property,
-                    Object oldValue,
-                    Object newValue) {
-            }
-
-            public void nodeRemoved(Object nodeId) {
-                newNodes[0]--;
-            }
-        });
-
-        assertEquals(2, newNodes[0]);
-        assertEquals(2, arcDiffs[0]);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextIT.java
new file mode 100644
index 0000000..f9775a4
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextIT.java
@@ -0,0 +1,142 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.cayenne;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectIdQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.testdo.mt.MtTable1;
+import org.apache.cayenne.testdo.mt.MtTable2;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.util.PersistentObjectHolder;
+
+import java.util.List;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class PersistentObjectInContextIT extends ClientCase {
+
+    @Inject
+    private CayenneContext context;
+
+    @Inject
+    private DBHelper dbHelper;
+
+    private TableHelper tMtTable1;
+    private TableHelper tMtTable2;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("MT_TABLE2");
+        dbHelper.deleteAll("MT_TABLE1");
+
+        tMtTable1 = new TableHelper(dbHelper, "MT_TABLE1");
+        tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
+
+        tMtTable2 = new TableHelper(dbHelper, "MT_TABLE2");
+        tMtTable2.setColumns("TABLE2_ID", "TABLE1_ID", "GLOBAL_ATTRIBUTE");
+    }
+
+    private void createTwoMtTable1sAnd2sDataSet() throws Exception {
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable1.insert(2, "g2", "s2");
+
+        tMtTable2.insert(1, 1, "g1");
+        tMtTable2.insert(2, 1, "g2");
+    }
+
+    public void testResolveToManyReverseResolved() throws Exception {
+        createTwoMtTable1sAnd2sDataSet();
+
+        ObjectId gid = new ObjectId(
+                "MtTable1",
+                MtTable1.TABLE1_ID_PK_COLUMN,
+                new Integer(1));
+        ClientMtTable1 t1 = (ClientMtTable1) Cayenne.objectForQuery(
+                context,
+                new ObjectIdQuery(gid));
+
+        assertNotNull(t1);
+
+        List<ClientMtTable2> t2s = t1.getTable2Array();
+        assertEquals(2, t2s.size());
+
+        for (ClientMtTable2 t2 : t2s) {
+
+            PersistentObjectHolder holder = (PersistentObjectHolder) t2.getTable1Direct();
+            assertFalse(holder.isFault());
+            assertSame(t1, holder.getValue());
+        }
+    }
+
+    public void testToOneRelationship() throws Exception {
+        createTwoMtTable1sAnd2sDataSet();
+
+        ObjectId gid = new ObjectId(
+                "MtTable2",
+                MtTable2.TABLE2_ID_PK_COLUMN,
+                new Integer(1));
+        ClientMtTable2 mtTable21 = (ClientMtTable2) Cayenne.objectForQuery(
+                context,
+                new ObjectIdQuery(gid));
+
+        assertNotNull(mtTable21);
+
+        ClientMtTable1 mtTable1 = mtTable21.getTable1();
+        assertNotNull("To one relationship incorrectly resolved to null", mtTable1);
+        assertEquals("g1", mtTable1.getGlobalAttribute1());
+    }
+
+    public void testResolveToOneReverseResolved() throws Exception {
+        createTwoMtTable1sAnd2sDataSet();
+
+        ObjectId gid = new ObjectId(
+                "MtTable2",
+                MtTable2.TABLE2_ID_PK_COLUMN,
+                new Integer(1));
+        ClientMtTable2 mtTable21 = (ClientMtTable2) Cayenne.objectForQuery(
+                context,
+                new ObjectIdQuery(gid));
+
+        assertNotNull(mtTable21);
+
+        ClientMtTable1 mtTable1 = mtTable21.getTable1();
+        assertNotNull("To one relationship incorrectly resolved to null", mtTable1);
+
+        List<ClientMtTable2> list = mtTable1.getTable2Array();
+        assertNotNull(list);
+        assertTrue(list instanceof ValueHolder);
+
+        assertTrue(((ValueHolder) list).isFault());
+
+        // resolve it here...
+        assertEquals(2, list.size());
+        for (ClientMtTable2 t2 : list) {
+            PersistentObjectHolder holder = (PersistentObjectHolder) t2.getTable1Direct();
+            assertFalse(holder.isFault());
+            assertSame(mtTable1, holder.getValue());
+        }
+
+        assertEquals("g1", mtTable1.getGlobalAttribute1());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextTest.java b/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextTest.java
deleted file mode 100644
index 57c9843..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/PersistentObjectInContextTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you 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 org.apache.cayenne;
-
-import java.util.List;
-
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.ObjectIdQuery;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.mt.ClientMtTable1;
-import org.apache.cayenne.testdo.mt.ClientMtTable2;
-import org.apache.cayenne.testdo.mt.MtTable1;
-import org.apache.cayenne.testdo.mt.MtTable2;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.apache.cayenne.util.PersistentObjectHolder;
-
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class PersistentObjectInContextTest extends ClientCase {
-
-    @Inject
-    private CayenneContext context;
-
-    @Inject
-    private DBHelper dbHelper;
-
-    private TableHelper tMtTable1;
-    private TableHelper tMtTable2;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("MT_TABLE2");
-        dbHelper.deleteAll("MT_TABLE1");
-
-        tMtTable1 = new TableHelper(dbHelper, "MT_TABLE1");
-        tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
-
-        tMtTable2 = new TableHelper(dbHelper, "MT_TABLE2");
-        tMtTable2.setColumns("TABLE2_ID", "TABLE1_ID", "GLOBAL_ATTRIBUTE");
-    }
-
-    private void createTwoMtTable1sAnd2sDataSet() throws Exception {
-        tMtTable1.insert(1, "g1", "s1");
-        tMtTable1.insert(2, "g2", "s2");
-
-        tMtTable2.insert(1, 1, "g1");
-        tMtTable2.insert(2, 1, "g2");
-    }
-
-    public void testResolveToManyReverseResolved() throws Exception {
-        createTwoMtTable1sAnd2sDataSet();
-
-        ObjectId gid = new ObjectId(
-                "MtTable1",
-                MtTable1.TABLE1_ID_PK_COLUMN,
-                new Integer(1));
-        ClientMtTable1 t1 = (ClientMtTable1) Cayenne.objectForQuery(
-                context,
-                new ObjectIdQuery(gid));
-
-        assertNotNull(t1);
-
-        List<ClientMtTable2> t2s = t1.getTable2Array();
-        assertEquals(2, t2s.size());
-
-        for (ClientMtTable2 t2 : t2s) {
-
-            PersistentObjectHolder holder = (PersistentObjectHolder) t2.getTable1Direct();
-            assertFalse(holder.isFault());
-            assertSame(t1, holder.getValue());
-        }
-    }
-
-    public void testToOneRelationship() throws Exception {
-        createTwoMtTable1sAnd2sDataSet();
-
-        ObjectId gid = new ObjectId(
-                "MtTable2",
-                MtTable2.TABLE2_ID_PK_COLUMN,
-                new Integer(1));
-        ClientMtTable2 mtTable21 = (ClientMtTable2) Cayenne.objectForQuery(
-                context,
-                new ObjectIdQuery(gid));
-
-        assertNotNull(mtTable21);
-
-        ClientMtTable1 mtTable1 = mtTable21.getTable1();
-        assertNotNull("To one relationship incorrectly resolved to null", mtTable1);
-        assertEquals("g1", mtTable1.getGlobalAttribute1());
-    }
-
-    public void testResolveToOneReverseResolved() throws Exception {
-        createTwoMtTable1sAnd2sDataSet();
-
-        ObjectId gid = new ObjectId(
-                "MtTable2",
-                MtTable2.TABLE2_ID_PK_COLUMN,
-                new Integer(1));
-        ClientMtTable2 mtTable21 = (ClientMtTable2) Cayenne.objectForQuery(
-                context,
-                new ObjectIdQuery(gid));
-
-        assertNotNull(mtTable21);
-
-        ClientMtTable1 mtTable1 = mtTable21.getTable1();
-        assertNotNull("To one relationship incorrectly resolved to null", mtTable1);
-
-        List<ClientMtTable2> list = mtTable1.getTable2Array();
-        assertNotNull(list);
-        assertTrue(list instanceof ValueHolder);
-
-        assertTrue(((ValueHolder) list).isFault());
-
-        // resolve it here...
-        assertEquals(2, list.size());
-        for (ClientMtTable2 t2 : list) {
-            PersistentObjectHolder holder = (PersistentObjectHolder) t2.getTable1Direct();
-            assertFalse(holder.isFault());
-            assertSame(mtTable1, holder.getValue());
-        }
-
-        assertEquals("g1", mtTable1.getGlobalAttribute1());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
new file mode 100644
index 0000000..f5cd8f1
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/access/ClientServerChannelIT.java
@@ -0,0 +1,260 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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 org.apache.cayenne.access;
+
+import org.apache.cayenne.DataChannel;
+import org.apache.cayenne.MockDataChannel;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.QueryResponse;
+import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.configuration.server.ServerRuntime;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.graph.MockGraphDiff;
+import org.apache.cayenne.graph.NodeCreateOperation;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.MockQuery;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.remote.QueryMessage;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable1Subclass1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.testdo.mt.ClientMtTable3;
+import org.apache.cayenne.testdo.mt.MtTable1;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.util.EqualsBuilder;
+
+import java.util.List;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class ClientServerChannelIT extends ClientCase {
+
+    @Inject
+    protected DataContext serverContext;
+
+    @Inject
+    protected ClientServerChannel clientServerChannel;
+
+    @Inject
+    protected DBHelper dbHelper;
+
+    @Inject
+    protected DataChannelInterceptor queryInterceptor;
+
+    @Inject
+    protected JdbcEventLogger logger;
+
+    @Inject
+    private ServerRuntime runtime;
+
+    private TableHelper tMtTable1;
+    private TableHelper tMtTable2;
+    private TableHelper tMtTable3;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("MT_TABLE2");
+        dbHelper.deleteAll("MT_TABLE1");
+        dbHelper.deleteAll("MT_TABLE3");
+
+        tMtTable1 = new TableHelper(dbHelper, "MT_TABLE1");
+        tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
+
+        tMtTable2 = new TableHelper(dbHelper, "MT_TABLE2");
+        tMtTable2.setColumns("TABLE2_ID", "TABLE1_ID", "GLOBAL_ATTRIBUTE");
+
+        tMtTable3 = new TableHelper(dbHelper, "MT_TABLE3");
+        tMtTable3.setColumns("TABLE3_ID", "BINARY_COLUMN", "CHAR_COLUMN", "INT_COLUMN");
+    }
+
+    protected void createTwoMtTable1sAnd2sDataSet() throws Exception {
+
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable1.insert(2, "g2", "s2");
+
+        tMtTable2.insert(1, 1, "g1");
+        tMtTable2.insert(2, 1, "g2");
+    }
+
+    public void testGetEntityResolver() throws Exception {
+        EntityResolver resolver = clientServerChannel.getEntityResolver();
+        assertNotNull(resolver);
+        assertNull(resolver.getObjEntity(ClientMtTable1.class));
+        assertNotNull(resolver.getClientEntityResolver().getObjEntity(ClientMtTable1.class));
+    }
+
+    public void testSynchronizeCommit() throws Exception {
+
+        SelectQuery query = new SelectQuery(MtTable1.class);
+
+        // no changes...
+        clientServerChannel.onSync(serverContext, new MockGraphDiff(), DataChannel.FLUSH_CASCADE_SYNC);
+
+        assertEquals(0, serverContext.performQuery(query).size());
+
+        // introduce changes
+        clientServerChannel.onSync(serverContext, new NodeCreateOperation(new ObjectId("MtTable1")),
+                DataChannel.FLUSH_CASCADE_SYNC);
+
+        assertEquals(1, serverContext.performQuery(query).size());
+    }
+
+    public void testPerformQueryObjectIDInjection() throws Exception {
+        tMtTable1.insert(55, "g1", "s1");
+
+        Query query = new SelectQuery("MtTable1");
+        QueryResponse response = clientServerChannel.onQuery(null, query);
+
+        assertNotNull(response);
+
+        List<?> results = response.firstList();
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+
+        Object result = results.get(0);
+        assertTrue(result instanceof ClientMtTable1);
+        ClientMtTable1 clientObject = (ClientMtTable1) result;
+        assertNotNull(clientObject.getObjectId());
+
+        assertEquals(new ObjectId("MtTable1", MtTable1.TABLE1_ID_PK_COLUMN, 55), clientObject.getObjectId());
+    }
+
+    public void testPerformQueryValuePropagation() throws Exception {
+
+        byte[] bytes = new byte[] { 1, 2, 3 };
+
+        tMtTable3.insert(1, bytes, "abc", 4);
+
+        Query query = new SelectQuery("MtTable3");
+        QueryResponse response = clientServerChannel.onQuery(null, query);
+
+        assertNotNull(response);
+
+        List<?> results = response.firstList();
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+
+        Object result = results.get(0);
+        assertTrue("Result is of wrong type: " + result, result instanceof ClientMtTable3);
+        ClientMtTable3 clientObject = (ClientMtTable3) result;
+
+        assertEquals("abc", clientObject.getCharColumn());
+        assertEquals(new Integer(4), clientObject.getIntColumn());
+        assertTrue(new EqualsBuilder().append(clientObject.getBinaryColumn(), bytes).isEquals());
+    }
+
+    public void testPerformQueryPropagationInheritance() throws Exception {
+
+        tMtTable1.insert(65, "sub1", "xyz");
+
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        QueryResponse response = clientServerChannel.onQuery(null, query);
+
+        assertNotNull(response);
+
+        List<?> results = response.firstList();
+
+        assertNotNull(results);
+        assertEquals(1, results.size());
+
+        Object result = results.get(0);
+        assertTrue("Result is of wrong type: " + result, result instanceof ClientMtTable1Subclass1);
+        ClientMtTable1Subclass1 clientObject = (ClientMtTable1Subclass1) result;
+
+        assertEquals("sub1", clientObject.getGlobalAttribute1());
+    }
+
+    public void testOnQuery() {
+
+        final boolean[] genericDone = new boolean[1];
+        MockDataChannel parent = new MockDataChannel(new EntityResolver()) {
+
+            @Override
+            public QueryResponse onQuery(ObjectContext context, Query query) {
+                genericDone[0] = true;
+                return super.onQuery(context, query);
+            }
+        };
+        DataContext context = (DataContext) runtime.newContext(parent);
+
+        QueryMessage message = new QueryMessage(new MockQuery());
+        new ClientServerChannel(context).onQuery(null, message.getQuery());
+        assertTrue(genericDone[0]);
+    }
+
+    public void testOnQueryPrefetchingToMany() throws Exception {
+        createTwoMtTable1sAnd2sDataSet();
+
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        query.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
+        query.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+
+        final List<?> results = clientServerChannel.onQuery(null, query).firstList();
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                ClientMtTable1 o1 = (ClientMtTable1) results.get(0);
+                assertNull(o1.getObjectContext());
+
+                List<ClientMtTable2> children1 = o1.getTable2Array();
+
+                assertEquals(2, children1.size());
+                for (ClientMtTable2 o : children1) {
+                    assertNull(o.getObjectContext());
+                }
+            }
+        });
+    }
+
+    public void testOnQueryPrefetchingToManyEmpty() throws Exception {
+        createTwoMtTable1sAnd2sDataSet();
+
+        SelectQuery q = new SelectQuery(ClientMtTable1.class);
+        q.addOrdering(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, SortOrder.ASCENDING);
+        q.addPrefetch(ClientMtTable1.TABLE2ARRAY_PROPERTY);
+
+        final List<?> results = clientServerChannel.onQuery(null, q).firstList();
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+
+                ClientMtTable1 o2 = (ClientMtTable1) results.get(1);
+                assertNull(o2.getObjectContext());
+
+                List<?> children2 = o2.getTable2Array();
+                assertNotNull(children2);
+                assertFalse(((ValueHolder) children2).isFault());
+                assertEquals(0, children2.size());
+            }
+        });
+    }
+}