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:03 UTC

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

Rename Integration Tests in cayenne-client (*IT.java instead of *Test.java)


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/fcb1d536
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/fcb1d536
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/fcb1d536

Branch: refs/heads/master
Commit: fcb1d5364154294525f1c2087f280cc5d38879f3
Parents: ec5c3cf
Author: Savva Kolbechev <s....@gmail.com>
Authored: Wed Oct 29 16:53:38 2014 +0300
Committer: Savva Kolbechev <s....@gmail.com>
Committed: Thu Oct 30 16:41:59 2014 +0300

----------------------------------------------------------------------
 .../apache/cayenne/CayenneContextCayenneIT.java |  55 ++
 .../cayenne/CayenneContextCayenneTest.java      |  55 --
 .../CayenneContextClientChannelEventsIT.java    | 345 ++++++++
 .../CayenneContextClientChannelEventsTest.java  | 345 --------
 .../cayenne/CayenneContextDeleteRulesIT.java    | 111 +++
 .../cayenne/CayenneContextDeleteRulesTest.java  | 111 ---
 .../apache/cayenne/CayenneContextEJBQLIT.java   |  87 ++
 .../apache/cayenne/CayenneContextEJBQLTest.java |  87 --
 .../CayenneContextGraphDiffCompressorIT.java    |  96 +++
 .../CayenneContextGraphDiffCompressorTest.java  |  96 ---
 .../org/apache/cayenne/CayenneContextIT.java    | 351 ++++++++
 .../cayenne/CayenneContextInheritanceIT.java    | 151 ++++
 .../cayenne/CayenneContextInheritanceTest.java  | 151 ----
 .../CayenneContextMapRelationshipIT.java        | 112 +++
 .../CayenneContextMapRelationshipTest.java      | 112 ---
 .../cayenne/CayenneContextMergeHandlerIT.java   |  90 ++
 .../cayenne/CayenneContextMergeHandlerTest.java |  90 --
 .../CayenneContextNamedQueryCachingIT.java      | 133 +++
 .../CayenneContextNamedQueryCachingTest.java    | 133 ---
 .../CayenneContextPaginatedListCachingIT.java   |  75 ++
 .../CayenneContextPaginatedListCachingTest.java |  75 --
 .../cayenne/CayenneContextPrimitiveIT.java      | 100 +++
 .../cayenne/CayenneContextPrimitiveTest.java    | 100 ---
 .../cayenne/CayenneContextRefreshQueryIT.java   |  76 ++
 .../cayenne/CayenneContextRefreshQueryTest.java |  76 --
 .../cayenne/CayenneContextRelationshipsIT.java  | 100 +++
 .../CayenneContextRelationshipsTest.java        | 100 ---
 .../cayenne/CayenneContextSQLTemplateIT.java    |  54 ++
 .../cayenne/CayenneContextSQLTemplateTest.java  |  54 --
 .../cayenne/CayenneContextServerDiffsIT.java    | 153 ++++
 .../cayenne/CayenneContextServerDiffsTest.java  | 153 ----
 .../org/apache/cayenne/CayenneContextTest.java  | 351 --------
 .../cayenne/CayenneContextValidationIT.java     |  89 ++
 .../cayenne/CayenneContextValidationTest.java   |  89 --
 .../CayenneContextWithDataContextIT.java        | 570 ++++++++++++
 .../CayenneContextWithDataContextTest.java      | 570 ------------
 .../apache/cayenne/NestedCayenneContextIT.java  | 864 +++++++++++++++++++
 .../cayenne/NestedCayenneContextTest.java       | 864 -------------------
 .../cayenne/PersistentObjectInContextIT.java    | 142 +++
 .../cayenne/PersistentObjectInContextTest.java  | 142 ---
 .../cayenne/access/ClientServerChannelIT.java   | 260 ++++++
 .../access/ClientServerChannelQueryIT.java      | 239 +++++
 .../access/ClientServerChannelQueryTest.java    | 239 -----
 .../cayenne/access/ClientServerChannelTest.java | 260 ------
 .../cayenne/map/ClientEntityResolverIT.java     |  62 ++
 .../cayenne/map/ClientEntityResolverTest.java   |  62 --
 .../cayenne/query/ClientExpressionIT.java       | 319 +++++++
 .../cayenne/query/ClientExpressionTest.java     | 319 -------
 .../query/ClientSelectQueryExpressionIT.java    |  71 ++
 .../query/ClientSelectQueryExpressionTest.java  |  71 --
 .../remote/CayenneContextDeletionIT.java        |  38 +
 .../remote/CayenneContextDeletionTest.java      |  38 -
 .../remote/ClientChannelServerDiffsIT.java      | 263 ++++++
 .../remote/ClientChannelServerDiffsTest.java    | 263 ------
 .../cayenne/remote/LightSuperClassIT.java       |  95 ++
 .../cayenne/remote/LightSuperClassTest.java     |  95 --
 .../remote/NestedObjectContextLocalIT.java      |  58 ++
 .../remote/NestedObjectContextLocalTest.java    |  58 --
 .../NestedObjectContextParentEventsIT.java      |  64 ++
 .../NestedObjectContextParentEventsTest.java    |  64 --
 .../remote/NestedObjectContextPeerEventsIT.java | 149 ++++
 .../NestedObjectContextPeerEventsTest.java      | 149 ----
 .../remote/NestedObjectContextRollbackIT.java   |  71 ++
 .../remote/NestedObjectContextRollbackTest.java |  71 --
 .../cayenne/remote/ROPPrefetchToManyMapIT.java  |  70 ++
 .../remote/ROPPrefetchToManyMapTest.java        |  70 --
 .../cayenne/remote/RelationshipChangeIT.java    |  60 ++
 .../cayenne/remote/RelationshipChangeTest.java  |  60 --
 .../cayenne/remote/RemoteCallbacksIT.java       | 118 +++
 .../cayenne/remote/RemoteCallbacksTest.java     | 118 ---
 .../remote/RemoteIncrementalFaultListIT.java    | 266 ++++++
 .../remote/RemoteIncrementalFaultListTest.java  | 266 ------
 .../apache/cayenne/remote/RemoteRollbackIT.java | 147 ++++
 .../cayenne/remote/RemoteRollbackTest.java      | 147 ----
 .../apache/cayenne/remote/ValueInjectorIT.java  |  73 ++
 .../cayenne/remote/ValueInjectorTest.java       |  73 --
 .../unit/di/client/ClientCaseSelfIT.java        |  46 +
 .../unit/di/client/ClientCaseSelfTest.java      |  46 -
 .../cayenne/util/ObjectDetachOperationIT.java   | 112 +++
 .../cayenne/util/ObjectDetachOperationTest.java | 112 ---
 .../util/ShallowMergeOperation_ClientIT.java    | 210 +++++
 .../util/ShallowMergeOperation_ClientTest.java  | 210 -----
 82 files changed, 6545 insertions(+), 6545 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneIT.java
new file mode 100644
index 0000000..31c9d97
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneIT.java
@@ -0,0 +1,55 @@
+/*****************************************************************
+ *   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.SQLTemplate;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextCayenneIT extends ClientCase {
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private CayenneContext context;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("MT_TABLE2");
+        dbHelper.deleteAll("MT_TABLE1");
+    }
+
+    public void testObjectForPK() throws Exception {
+
+        context.performGenericQuery(new SQLTemplate(
+                ClientMtTable1.class,
+                "insert into MT_TABLE1 "
+                        + "(TABLE1_ID, GLOBAL_ATTRIBUTE1, SERVER_ATTRIBUTE1) "
+                        + "values (1, 'g1', 's1')"));
+
+        ClientMtTable1 o = Cayenne.objectForPK(context, ClientMtTable1.class, 1);
+        assertNotNull(o);
+        assertEquals("g1", o.getGlobalAttribute1());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneTest.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneTest.java
deleted file mode 100644
index b3d8c89..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextCayenneTest.java
+++ /dev/null
@@ -1,55 +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 org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.testdo.mt.ClientMtTable1;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class CayenneContextCayenneTest extends ClientCase {
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private CayenneContext context;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("MT_TABLE2");
-        dbHelper.deleteAll("MT_TABLE1");
-    }
-
-    public void testObjectForPK() throws Exception {
-
-        context.performGenericQuery(new SQLTemplate(
-                ClientMtTable1.class,
-                "insert into MT_TABLE1 "
-                        + "(TABLE1_ID, GLOBAL_ATTRIBUTE1, SERVER_ATTRIBUTE1) "
-                        + "values (1, 'g1', 's1')"));
-
-        ClientMtTable1 o = Cayenne.objectForPK(context, ClientMtTable1.class, 1);
-        assertNotNull(o);
-        assertEquals("g1", o.getGlobalAttribute1());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsIT.java
new file mode 100644
index 0000000..c4af230
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsIT.java
@@ -0,0 +1,345 @@
+/*****************************************************************
+ *   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.configuration.Constants;
+import org.apache.cayenne.configuration.rop.client.ClientRuntime;
+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.ClientMtTable4;
+import org.apache.cayenne.testdo.mt.ClientMtTable5;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.client.ClientRuntimeProperty;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+/**
+ * Tests peer context synchronization via ClientChannel events.
+ */
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+@ClientRuntimeProperty({
+        Constants.ROP_CHANNEL_EVENTS_PROPERTY, "true"
+})
+public class CayenneContextClientChannelEventsIT extends ClientCase {
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private ClientRuntime runtime;
+
+    private TableHelper tMtTable1;
+    private TableHelper tMtTable2;
+    private TableHelper tMtTable4;
+    private TableHelper tMtTable5;
+    private TableHelper tMtJoin45;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("MT_TABLE2");
+        dbHelper.deleteAll("MT_TABLE1");
+        dbHelper.deleteAll("MT_JOIN45");
+        dbHelper.deleteAll("MT_TABLE4");
+        dbHelper.deleteAll("MT_TABLE5");
+
+        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");
+
+        tMtTable4 = new TableHelper(dbHelper, "MT_TABLE4");
+        tMtTable4.setColumns("ID");
+
+        tMtTable5 = new TableHelper(dbHelper, "MT_TABLE5");
+        tMtTable5.setColumns("ID");
+
+        tMtJoin45 = new TableHelper(dbHelper, "MT_JOIN45");
+        tMtJoin45.setColumns("TABLE4_ID", "TABLE5_ID");
+    }
+
+    public void testSyncNewObject() throws Exception {
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+        assertNotSame(c1, c2);
+
+        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("X");
+        c1.commitChanges();
+
+        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
+                o1.getObjectId());
+
+        assertNull(o2);
+        // now fetch it fresh
+
+        o2 = (ClientMtTable1) c2.performQuery(new ObjectIdQuery(o1.getObjectId())).get(0);
+        assertNotNull(o2);
+
+        assertEquals("X", o2.getGlobalAttribute1());
+        assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncNewDeletedObject() throws Exception {
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+        assertNotSame(c1, c2);
+
+        // insert, then delete - this shouldn't propagate via an event.
+        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("X");
+        c1.deleteObjects(o1);
+
+        // introduce some other change so that commit can go ahead...
+        ClientMtTable1 o1x = c1.newObject(ClientMtTable1.class);
+        o1x.setGlobalAttribute1("Y");
+        c1.commitChanges();
+
+        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
+                o1.getObjectId());
+
+        assertNull(o2);
+
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncNewObjectIntoDirtyContext() throws Exception {
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+        assertNotSame(c1, c2);
+
+        // make sure c2 has uncommitted changes
+        c2.newObject(ClientMtTable1.class);
+
+        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("X");
+        c1.commitChanges();
+
+        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
+                o1.getObjectId());
+        assertNull(o2);
+
+        // now fetch it fresh
+
+        o2 = (ClientMtTable1) c2.performQuery(new ObjectIdQuery(o1.getObjectId())).get(0);
+        assertNotNull(o2);
+        assertEquals("X", o2.getGlobalAttribute1());
+        assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertTrue(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncSimpleProperty() throws Exception {
+
+        tMtTable1.insert(1, "g1", "s1");
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+        assertNotSame(c1, c2);
+
+        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+
+        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
+                c2,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+
+        assertEquals("g1", o1.getGlobalAttribute1());
+        assertEquals("g1", o2.getGlobalAttribute1());
+
+        o1.setGlobalAttribute1("X");
+        c1.commitChanges();
+        
+        // let the events propagate to peers
+        Thread.sleep(500);
+
+        assertEquals("X", o2.getGlobalAttribute1());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncToOneRelationship() throws Exception {
+
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable1.insert(2, "g2", "s2");
+        tMtTable2.insert(1, 1, "g1");
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+
+        ClientMtTable2 o1 = (ClientMtTable2) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable2", "TABLE2_ID", 1)));
+
+        ClientMtTable2 o2 = (ClientMtTable2) Cayenne.objectForQuery(
+                c2,
+                new ObjectIdQuery(new ObjectId("MtTable2", "TABLE2_ID", 1)));
+
+        assertEquals("g1", o1.getTable1().getGlobalAttribute1());
+        assertEquals("g1", o2.getTable1().getGlobalAttribute1());
+
+        ClientMtTable1 o1r = (ClientMtTable1) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 2)));
+        o1.setTable1(o1r);
+        c1.commitChanges();
+        
+        // let the events propagate to peers
+        Thread.sleep(500);
+
+        assertEquals("g2", o2.getTable1().getGlobalAttribute1());
+        assertEquals(o1r.getObjectId(), o2.getTable1().getObjectId());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncToManyRelationship() throws Exception {
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable2.insert(1, 1, "g1");
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+
+        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+
+        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
+                c2,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+
+        assertEquals(1, o1.getTable2Array().size());
+        assertEquals(1, o2.getTable2Array().size());
+
+        ClientMtTable2 o1r = c1.newObject(ClientMtTable2.class);
+        o1r.setGlobalAttribute("X");
+        o1.addToTable2Array(o1r);
+
+        c1.commitChanges();
+        
+        // let the events propagate to peers
+        Thread.sleep(500);
+
+        assertEquals(2, o1.getTable2Array().size());
+        assertEquals(2, o2.getTable2Array().size());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncToManyRelationship1() throws Exception {
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable2.insert(1, 1, "g1");
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+
+        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+
+        // do not resolve objects in question in the second context and see if the merge
+        // causes any issues...
+
+        assertEquals(1, o1.getTable2Array().size());
+
+        ClientMtTable2 o1r = c1.newObject(ClientMtTable2.class);
+        o1r.setGlobalAttribute("X");
+        o1.addToTable2Array(o1r);
+
+        c1.commitChanges();
+
+        assertEquals(2, o1.getTable2Array().size());
+
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+
+        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
+                c2,
+                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
+        assertEquals(2, o2.getTable2Array().size());
+    }
+
+    public void testSyncManyToManyRelationship() throws Exception {
+        tMtTable4.insert(1);
+        tMtTable5.insert(1);
+        tMtTable5.insert(2);
+        tMtJoin45.insert(1, 1);
+        tMtJoin45.insert(1, 2);
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+
+        ClientMtTable4 o1 = (ClientMtTable4) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable4", "ID", 1)));
+
+        ClientMtTable4 o2 = (ClientMtTable4) Cayenne.objectForQuery(
+                c2,
+                new ObjectIdQuery(new ObjectId("MtTable4", "ID", 1)));
+
+        assertEquals(2, o1.getTable5s().size());
+        assertEquals(2, o2.getTable5s().size());
+
+        ClientMtTable5 o1r = (ClientMtTable5) Cayenne.objectForQuery(
+                c1,
+                new ObjectIdQuery(new ObjectId("MtTable5", "ID", 1)));
+        o1.removeFromTable5s(o1r);
+
+        c1.commitChanges();
+        // let the events propagate to peers
+        Thread.sleep(500);
+
+        assertEquals(1, o1.getTable5s().size());
+        assertEquals(1, o2.getTable5s().size());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+
+    public void testSyncManyToManyRelationship1() throws Exception {
+
+        CayenneContext c1 = (CayenneContext) runtime.newContext();
+        CayenneContext c2 = (CayenneContext) runtime.newContext();
+
+        ClientMtTable4 o1 = c1.newObject(ClientMtTable4.class);
+        ClientMtTable5 o1r = c1.newObject(ClientMtTable5.class);
+        c1.commitChanges();
+
+        ClientMtTable4 o2 = c2.localObject(o1);
+        ClientMtTable5 o2r = c2.localObject(o1r);
+
+        o2.addToTable5s(o2r);
+        c2.commitChanges();
+
+        assertEquals(1, o1.getTable5s().size());
+        assertEquals(1, o2.getTable5s().size());
+        assertFalse(c1.internalGraphManager().hasChanges());
+        assertFalse(c2.internalGraphManager().hasChanges());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsTest.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsTest.java
deleted file mode 100644
index 6b4238e..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextClientChannelEventsTest.java
+++ /dev/null
@@ -1,345 +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 org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.rop.client.ClientRuntime;
-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.ClientMtTable4;
-import org.apache.cayenne.testdo.mt.ClientMtTable5;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.client.ClientRuntimeProperty;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-/**
- * Tests peer context synchronization via ClientChannel events.
- */
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-@ClientRuntimeProperty({
-        Constants.ROP_CHANNEL_EVENTS_PROPERTY, "true"
-})
-public class CayenneContextClientChannelEventsTest extends ClientCase {
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private ClientRuntime runtime;
-
-    private TableHelper tMtTable1;
-    private TableHelper tMtTable2;
-    private TableHelper tMtTable4;
-    private TableHelper tMtTable5;
-    private TableHelper tMtJoin45;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("MT_TABLE2");
-        dbHelper.deleteAll("MT_TABLE1");
-        dbHelper.deleteAll("MT_JOIN45");
-        dbHelper.deleteAll("MT_TABLE4");
-        dbHelper.deleteAll("MT_TABLE5");
-
-        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");
-
-        tMtTable4 = new TableHelper(dbHelper, "MT_TABLE4");
-        tMtTable4.setColumns("ID");
-
-        tMtTable5 = new TableHelper(dbHelper, "MT_TABLE5");
-        tMtTable5.setColumns("ID");
-
-        tMtJoin45 = new TableHelper(dbHelper, "MT_JOIN45");
-        tMtJoin45.setColumns("TABLE4_ID", "TABLE5_ID");
-    }
-
-    public void testSyncNewObject() throws Exception {
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-        assertNotSame(c1, c2);
-
-        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
-        o1.setGlobalAttribute1("X");
-        c1.commitChanges();
-
-        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
-                o1.getObjectId());
-
-        assertNull(o2);
-        // now fetch it fresh
-
-        o2 = (ClientMtTable1) c2.performQuery(new ObjectIdQuery(o1.getObjectId())).get(0);
-        assertNotNull(o2);
-
-        assertEquals("X", o2.getGlobalAttribute1());
-        assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncNewDeletedObject() throws Exception {
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-        assertNotSame(c1, c2);
-
-        // insert, then delete - this shouldn't propagate via an event.
-        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
-        o1.setGlobalAttribute1("X");
-        c1.deleteObjects(o1);
-
-        // introduce some other change so that commit can go ahead...
-        ClientMtTable1 o1x = c1.newObject(ClientMtTable1.class);
-        o1x.setGlobalAttribute1("Y");
-        c1.commitChanges();
-
-        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
-                o1.getObjectId());
-
-        assertNull(o2);
-
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncNewObjectIntoDirtyContext() throws Exception {
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-        assertNotSame(c1, c2);
-
-        // make sure c2 has uncommitted changes
-        c2.newObject(ClientMtTable1.class);
-
-        ClientMtTable1 o1 = c1.newObject(ClientMtTable1.class);
-        o1.setGlobalAttribute1("X");
-        c1.commitChanges();
-
-        ClientMtTable1 o2 = (ClientMtTable1) c2.getGraphManager().getNode(
-                o1.getObjectId());
-        assertNull(o2);
-
-        // now fetch it fresh
-
-        o2 = (ClientMtTable1) c2.performQuery(new ObjectIdQuery(o1.getObjectId())).get(0);
-        assertNotNull(o2);
-        assertEquals("X", o2.getGlobalAttribute1());
-        assertEquals(PersistenceState.COMMITTED, o2.getPersistenceState());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertTrue(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncSimpleProperty() throws Exception {
-
-        tMtTable1.insert(1, "g1", "s1");
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-        assertNotSame(c1, c2);
-
-        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-
-        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
-                c2,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-
-        assertEquals("g1", o1.getGlobalAttribute1());
-        assertEquals("g1", o2.getGlobalAttribute1());
-
-        o1.setGlobalAttribute1("X");
-        c1.commitChanges();
-        
-        // let the events propagate to peers
-        Thread.sleep(500);
-
-        assertEquals("X", o2.getGlobalAttribute1());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncToOneRelationship() throws Exception {
-
-        tMtTable1.insert(1, "g1", "s1");
-        tMtTable1.insert(2, "g2", "s2");
-        tMtTable2.insert(1, 1, "g1");
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-
-        ClientMtTable2 o1 = (ClientMtTable2) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable2", "TABLE2_ID", 1)));
-
-        ClientMtTable2 o2 = (ClientMtTable2) Cayenne.objectForQuery(
-                c2,
-                new ObjectIdQuery(new ObjectId("MtTable2", "TABLE2_ID", 1)));
-
-        assertEquals("g1", o1.getTable1().getGlobalAttribute1());
-        assertEquals("g1", o2.getTable1().getGlobalAttribute1());
-
-        ClientMtTable1 o1r = (ClientMtTable1) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 2)));
-        o1.setTable1(o1r);
-        c1.commitChanges();
-        
-        // let the events propagate to peers
-        Thread.sleep(500);
-
-        assertEquals("g2", o2.getTable1().getGlobalAttribute1());
-        assertEquals(o1r.getObjectId(), o2.getTable1().getObjectId());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncToManyRelationship() throws Exception {
-        tMtTable1.insert(1, "g1", "s1");
-        tMtTable2.insert(1, 1, "g1");
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-
-        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-
-        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
-                c2,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-
-        assertEquals(1, o1.getTable2Array().size());
-        assertEquals(1, o2.getTable2Array().size());
-
-        ClientMtTable2 o1r = c1.newObject(ClientMtTable2.class);
-        o1r.setGlobalAttribute("X");
-        o1.addToTable2Array(o1r);
-
-        c1.commitChanges();
-        
-        // let the events propagate to peers
-        Thread.sleep(500);
-
-        assertEquals(2, o1.getTable2Array().size());
-        assertEquals(2, o2.getTable2Array().size());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncToManyRelationship1() throws Exception {
-        tMtTable1.insert(1, "g1", "s1");
-        tMtTable2.insert(1, 1, "g1");
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-
-        ClientMtTable1 o1 = (ClientMtTable1) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-
-        // do not resolve objects in question in the second context and see if the merge
-        // causes any issues...
-
-        assertEquals(1, o1.getTable2Array().size());
-
-        ClientMtTable2 o1r = c1.newObject(ClientMtTable2.class);
-        o1r.setGlobalAttribute("X");
-        o1.addToTable2Array(o1r);
-
-        c1.commitChanges();
-
-        assertEquals(2, o1.getTable2Array().size());
-
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-
-        ClientMtTable1 o2 = (ClientMtTable1) Cayenne.objectForQuery(
-                c2,
-                new ObjectIdQuery(new ObjectId("MtTable1", "TABLE1_ID", 1)));
-        assertEquals(2, o2.getTable2Array().size());
-    }
-
-    public void testSyncManyToManyRelationship() throws Exception {
-        tMtTable4.insert(1);
-        tMtTable5.insert(1);
-        tMtTable5.insert(2);
-        tMtJoin45.insert(1, 1);
-        tMtJoin45.insert(1, 2);
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-
-        ClientMtTable4 o1 = (ClientMtTable4) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable4", "ID", 1)));
-
-        ClientMtTable4 o2 = (ClientMtTable4) Cayenne.objectForQuery(
-                c2,
-                new ObjectIdQuery(new ObjectId("MtTable4", "ID", 1)));
-
-        assertEquals(2, o1.getTable5s().size());
-        assertEquals(2, o2.getTable5s().size());
-
-        ClientMtTable5 o1r = (ClientMtTable5) Cayenne.objectForQuery(
-                c1,
-                new ObjectIdQuery(new ObjectId("MtTable5", "ID", 1)));
-        o1.removeFromTable5s(o1r);
-
-        c1.commitChanges();
-        // let the events propagate to peers
-        Thread.sleep(500);
-
-        assertEquals(1, o1.getTable5s().size());
-        assertEquals(1, o2.getTable5s().size());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-
-    public void testSyncManyToManyRelationship1() throws Exception {
-
-        CayenneContext c1 = (CayenneContext) runtime.newContext();
-        CayenneContext c2 = (CayenneContext) runtime.newContext();
-
-        ClientMtTable4 o1 = c1.newObject(ClientMtTable4.class);
-        ClientMtTable5 o1r = c1.newObject(ClientMtTable5.class);
-        c1.commitChanges();
-
-        ClientMtTable4 o2 = c2.localObject(o1);
-        ClientMtTable5 o2r = c2.localObject(o1r);
-
-        o2.addToTable5s(o2r);
-        c2.commitChanges();
-
-        assertEquals(1, o1.getTable5s().size());
-        assertEquals(1, o2.getTable5s().size());
-        assertFalse(c1.internalGraphManager().hasChanges());
-        assertFalse(c2.internalGraphManager().hasChanges());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesIT.java
new file mode 100644
index 0000000..f9af40f
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesIT.java
@@ -0,0 +1,111 @@
+/*****************************************************************
+ *   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.testdo.mt.ClientMtDeleteCascade;
+import org.apache.cayenne.testdo.mt.ClientMtDeleteDeny;
+import org.apache.cayenne.testdo.mt.ClientMtDeleteNullify;
+import org.apache.cayenne.testdo.mt.ClientMtDeleteRule;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextDeleteRulesIT extends ClientCase {
+
+    @Inject
+    private CayenneContext context;
+
+    public void testNullifyToOne() {
+
+        ClientMtDeleteNullify object = context.newObject(ClientMtDeleteNullify.class);
+        object.setName("object");
+
+        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
+        object.setName("related");
+
+        object.setNullify(related);
+        context.commitChanges();
+
+        context.deleteObjects(object);
+        assertFalse(related.getFromNullify().contains(object));
+        assertNull(object.getNullify());
+
+        // And be sure that the commit works afterwards, just for sanity
+        context.commitChanges();
+    }
+
+    public void testDenyToOne() {
+
+        ClientMtDeleteDeny object = context.newObject(ClientMtDeleteDeny.class);
+        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
+        object.setDeny(related);
+        context.commitChanges();
+
+        try {
+            context.deleteObjects(object);
+            fail("Should have thrown an exception");
+        }
+        catch (DeleteDenyException e) {
+            // expected
+        }
+
+        object.setDeny(null);
+        context.deleteObjects(object);
+        context.commitChanges();
+    }
+
+    public void testCascadeToOne() {
+
+        ClientMtDeleteCascade object = context.newObject(ClientMtDeleteCascade.class);
+        object.setName("object");
+
+        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
+        object.setName("related");
+
+        object.setCascade(related);
+        context.commitChanges();
+
+        context.deleteObjects(object);
+        assertEquals(PersistenceState.DELETED, related.getPersistenceState());
+        assertTrue(context.deletedObjects().contains(related));
+
+        // And be sure that the commit works afterwards, just for sanity
+        context.commitChanges();
+    }
+
+    public void testCascadeToOneNewObject() {
+
+        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
+        context.commitChanges();
+
+        ClientMtDeleteCascade object = context.newObject(ClientMtDeleteCascade.class);
+        object.setName("object");
+        object.setCascade(related);
+
+        context.deleteObjects(object);
+        assertEquals(PersistenceState.TRANSIENT, object.getPersistenceState());
+        assertEquals(PersistenceState.DELETED, related.getPersistenceState());
+        assertFalse(context.deletedObjects().contains(object));
+        assertTrue(context.deletedObjects().contains(related));
+
+        context.commitChanges();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesTest.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesTest.java
deleted file mode 100644
index 6d9cf99..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextDeleteRulesTest.java
+++ /dev/null
@@ -1,111 +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 org.apache.cayenne.di.Inject;
-import org.apache.cayenne.testdo.mt.ClientMtDeleteCascade;
-import org.apache.cayenne.testdo.mt.ClientMtDeleteDeny;
-import org.apache.cayenne.testdo.mt.ClientMtDeleteNullify;
-import org.apache.cayenne.testdo.mt.ClientMtDeleteRule;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class CayenneContextDeleteRulesTest extends ClientCase {
-
-    @Inject
-    private CayenneContext context;
-
-    public void testNullifyToOne() {
-
-        ClientMtDeleteNullify object = context.newObject(ClientMtDeleteNullify.class);
-        object.setName("object");
-
-        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
-        object.setName("related");
-
-        object.setNullify(related);
-        context.commitChanges();
-
-        context.deleteObjects(object);
-        assertFalse(related.getFromNullify().contains(object));
-        assertNull(object.getNullify());
-
-        // And be sure that the commit works afterwards, just for sanity
-        context.commitChanges();
-    }
-
-    public void testDenyToOne() {
-
-        ClientMtDeleteDeny object = context.newObject(ClientMtDeleteDeny.class);
-        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
-        object.setDeny(related);
-        context.commitChanges();
-
-        try {
-            context.deleteObjects(object);
-            fail("Should have thrown an exception");
-        }
-        catch (DeleteDenyException e) {
-            // expected
-        }
-
-        object.setDeny(null);
-        context.deleteObjects(object);
-        context.commitChanges();
-    }
-
-    public void testCascadeToOne() {
-
-        ClientMtDeleteCascade object = context.newObject(ClientMtDeleteCascade.class);
-        object.setName("object");
-
-        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
-        object.setName("related");
-
-        object.setCascade(related);
-        context.commitChanges();
-
-        context.deleteObjects(object);
-        assertEquals(PersistenceState.DELETED, related.getPersistenceState());
-        assertTrue(context.deletedObjects().contains(related));
-
-        // And be sure that the commit works afterwards, just for sanity
-        context.commitChanges();
-    }
-
-    public void testCascadeToOneNewObject() {
-
-        ClientMtDeleteRule related = context.newObject(ClientMtDeleteRule.class);
-        context.commitChanges();
-
-        ClientMtDeleteCascade object = context.newObject(ClientMtDeleteCascade.class);
-        object.setName("object");
-        object.setCascade(related);
-
-        context.deleteObjects(object);
-        assertEquals(PersistenceState.TRANSIENT, object.getPersistenceState());
-        assertEquals(PersistenceState.DELETED, related.getPersistenceState());
-        assertFalse(context.deletedObjects().contains(object));
-        assertTrue(context.deletedObjects().contains(related));
-
-        context.commitChanges();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLIT.java
new file mode 100644
index 0000000..f9805fa
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLIT.java
@@ -0,0 +1,87 @@
+/*****************************************************************
+ *   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.EJBQLQuery;
+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.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.util.List;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextEJBQLIT extends ClientCase {
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private CayenneContext context;
+
+    private TableHelper tMtTable1;
+
+    @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");
+    }
+
+    private void createTwoRecords() throws Exception {
+        tMtTable1.insert(1, "g1", "s1");
+        tMtTable1.insert(2, "g2", "s2");
+    }
+
+    public void testEJBQLSelect() throws Exception {
+        createTwoRecords();
+
+        EJBQLQuery query = new EJBQLQuery("SELECT a FROM MtTable1 a");
+        List<ClientMtTable1> results = context.performQuery(query);
+
+        assertEquals(2, results.size());
+    }
+
+    public void testEJBQLSelectScalar() throws Exception {
+        createTwoRecords();
+
+        EJBQLQuery query = new EJBQLQuery("SELECT COUNT(a) FROM MtTable1 a");
+
+        List<Long> results = context.performQuery(query);
+        assertEquals(Long.valueOf(2), results.get(0));
+    }
+
+    public void testEJBQLSelectMixed() throws Exception {
+        createTwoRecords();
+
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT COUNT(a), a, a.serverAttribute1 FROM MtTable1 a Group By a ORDER BY a.serverAttribute1");
+
+        List<Object[]> results = context.performQuery(query);
+
+        assertEquals(2, results.size());
+        assertEquals(Long.valueOf(1), results.get(0)[0]);
+        assertTrue(results.get(0)[1] instanceof ClientMtTable1);
+        assertEquals("s1", results.get(0)[2]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
deleted file mode 100644
index f9226b8..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextEJBQLTest.java
+++ /dev/null
@@ -1,87 +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.EJBQLQuery;
-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.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class CayenneContextEJBQLTest extends ClientCase {
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private CayenneContext context;
-
-    private TableHelper tMtTable1;
-
-    @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");
-    }
-
-    private void createTwoRecords() throws Exception {
-        tMtTable1.insert(1, "g1", "s1");
-        tMtTable1.insert(2, "g2", "s2");
-    }
-
-    public void testEJBQLSelect() throws Exception {
-        createTwoRecords();
-
-        EJBQLQuery query = new EJBQLQuery("SELECT a FROM MtTable1 a");
-        List<ClientMtTable1> results = context.performQuery(query);
-
-        assertEquals(2, results.size());
-    }
-
-    public void testEJBQLSelectScalar() throws Exception {
-        createTwoRecords();
-
-        EJBQLQuery query = new EJBQLQuery("SELECT COUNT(a) FROM MtTable1 a");
-
-        List<Long> results = context.performQuery(query);
-        assertEquals(Long.valueOf(2), results.get(0));
-    }
-
-    public void testEJBQLSelectMixed() throws Exception {
-        createTwoRecords();
-
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT COUNT(a), a, a.serverAttribute1 FROM MtTable1 a Group By a ORDER BY a.serverAttribute1");
-
-        List<Object[]> results = context.performQuery(query);
-
-        assertEquals(2, results.size());
-        assertEquals(Long.valueOf(1), results.get(0)[0]);
-        assertTrue(results.get(0)[1] instanceof ClientMtTable1);
-        assertEquals("s1", results.get(0)[2]);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorIT.java
new file mode 100644
index 0000000..1469c8b
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorIT.java
@@ -0,0 +1,96 @@
+/*****************************************************************
+ *   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.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.DataChannelSyncStats;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextGraphDiffCompressorIT extends ClientCase {
+
+    @Inject(ClientCase.ROP_CLIENT_KEY)
+    protected DataChannelInterceptor clientServerInterceptor;
+
+    @Inject
+    protected CayenneContext context;
+
+    public void testMultipleSimpleProperties() {
+
+        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("v1");
+        o1.setGlobalAttribute1("v2");
+
+        DataChannelSyncStats stats = clientServerInterceptor
+                .runWithSyncStatsCollection(new UnitTestClosure() {
+
+                    public void execute() {
+                        context.commitChanges();
+                    }
+                });
+
+        assertEquals(1, stats.nodePropertiesChanged);
+        assertEquals(1, stats.nodesCreated);
+    }
+
+    public void testComplimentaryArcs() {
+
+        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
+        ClientMtTable2 o2 = context.newObject(ClientMtTable2.class);
+        o2.setTable1(o1);
+        o2.setTable1(null);
+
+        DataChannelSyncStats stats = clientServerInterceptor
+                .runWithSyncStatsCollection(new UnitTestClosure() {
+
+                    public void execute() {
+                        context.commitChanges();
+                    }
+                });
+
+        assertEquals(0, stats.nodePropertiesChanged);
+        assertEquals(2, stats.nodesCreated);
+        assertEquals(0, stats.arcsCreated);
+        assertEquals(0, stats.arcsDeleted);
+    }
+
+    public void testDelete() {
+
+        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
+        o1.setGlobalAttribute1("v1");
+        context.deleteObjects(o1);
+
+        DataChannelSyncStats stats = clientServerInterceptor
+                .runWithSyncStatsCollection(new UnitTestClosure() {
+
+                    public void execute() {
+                        context.commitChanges();
+                    }
+                });
+        assertEquals(0, stats.nodePropertiesChanged);
+        assertEquals(0, stats.nodesCreated);
+        assertEquals(0, stats.nodesRemoved);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorTest.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorTest.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorTest.java
deleted file mode 100644
index b213e55..0000000
--- a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextGraphDiffCompressorTest.java
+++ /dev/null
@@ -1,96 +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 org.apache.cayenne.di.Inject;
-import org.apache.cayenne.testdo.mt.ClientMtTable1;
-import org.apache.cayenne.testdo.mt.ClientMtTable2;
-import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.DataChannelSyncStats;
-import org.apache.cayenne.unit.di.UnitTestClosure;
-import org.apache.cayenne.unit.di.client.ClientCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
-public class CayenneContextGraphDiffCompressorTest extends ClientCase {
-
-    @Inject(ClientCase.ROP_CLIENT_KEY)
-    protected DataChannelInterceptor clientServerInterceptor;
-
-    @Inject
-    protected CayenneContext context;
-
-    public void testMultipleSimpleProperties() {
-
-        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
-        o1.setGlobalAttribute1("v1");
-        o1.setGlobalAttribute1("v2");
-
-        DataChannelSyncStats stats = clientServerInterceptor
-                .runWithSyncStatsCollection(new UnitTestClosure() {
-
-                    public void execute() {
-                        context.commitChanges();
-                    }
-                });
-
-        assertEquals(1, stats.nodePropertiesChanged);
-        assertEquals(1, stats.nodesCreated);
-    }
-
-    public void testComplimentaryArcs() {
-
-        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
-        ClientMtTable2 o2 = context.newObject(ClientMtTable2.class);
-        o2.setTable1(o1);
-        o2.setTable1(null);
-
-        DataChannelSyncStats stats = clientServerInterceptor
-                .runWithSyncStatsCollection(new UnitTestClosure() {
-
-                    public void execute() {
-                        context.commitChanges();
-                    }
-                });
-
-        assertEquals(0, stats.nodePropertiesChanged);
-        assertEquals(2, stats.nodesCreated);
-        assertEquals(0, stats.arcsCreated);
-        assertEquals(0, stats.arcsDeleted);
-    }
-
-    public void testDelete() {
-
-        ClientMtTable1 o1 = context.newObject(ClientMtTable1.class);
-        o1.setGlobalAttribute1("v1");
-        context.deleteObjects(o1);
-
-        DataChannelSyncStats stats = clientServerInterceptor
-                .runWithSyncStatsCollection(new UnitTestClosure() {
-
-                    public void execute() {
-                        context.commitChanges();
-                    }
-                });
-        assertEquals(0, stats.nodePropertiesChanged);
-        assertEquals(0, stats.nodesCreated);
-        assertEquals(0, stats.nodesRemoved);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
new file mode 100644
index 0000000..588d56e
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextIT.java
@@ -0,0 +1,351 @@
+/*****************************************************************
+ *   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.event.DefaultEventManager;
+import org.apache.cayenne.event.EventManager;
+import org.apache.cayenne.event.MockEventManager;
+import org.apache.cayenne.graph.CompoundDiff;
+import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.graph.MockGraphDiff;
+import org.apache.cayenne.graph.NodeIdChangeOperation;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.remote.BootstrapMessage;
+import org.apache.cayenne.remote.ClientChannel;
+import org.apache.cayenne.remote.ClientConnection;
+import org.apache.cayenne.remote.ClientMessage;
+import org.apache.cayenne.testdo.mt.ClientMtTable1;
+import org.apache.cayenne.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.util.GenericResponse;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextIT extends ClientCase {
+
+    @Inject
+    private ObjectContext serverContext;
+
+    public void testConstructor() {
+
+        CayenneContext context = new CayenneContext();
+
+        // test default property parameters
+        assertNotNull(context.getGraphManager());
+        assertNull(context.channel);
+
+        MockDataChannel channel = new MockDataChannel();
+        context.setChannel(channel);
+        assertSame(channel, context.getChannel());
+    }
+
+    public void testChannel() {
+        MockDataChannel channel = new MockDataChannel();
+        CayenneContext context = new CayenneContext(channel);
+
+        assertSame(channel, context.getChannel());
+    }
+
+    public void testCommitUnchanged() {
+
+        MockDataChannel channel = new MockDataChannel();
+        CayenneContext context = new CayenneContext(channel);
+
+        // no context changes so no connector access is expected
+        context.commitChanges();
+        assertTrue(channel.getRequestObjects().isEmpty());
+    }
+
+    public void testCommitCommandExecuted() {
+
+        MockDataChannel channel = new MockDataChannel(new MockGraphDiff());
+        channel.setEntityResolver(serverContext
+                .getEntityResolver()
+                .getClientEntityResolver());
+        CayenneContext context = new CayenneContext(channel);
+
+        // test that a command is being sent via connector on commit...
+
+        context.internalGraphManager().nodePropertyChanged(
+                new ObjectId("MtTable1"),
+                "x",
+                "y",
+                "z");
+
+        context.commitChanges();
+        assertEquals(1, channel.getRequestObjects().size());
+
+        // expect a sync/commit chain
+        Object mainMessage = channel.getRequestObjects().iterator().next();
+        assertTrue(mainMessage instanceof GraphDiff);
+    }
+
+    public void testCommitChangesNew() {
+        final CompoundDiff diff = new CompoundDiff();
+        final Object newObjectId = new ObjectId("test", "key", "generated");
+        final EventManager eventManager = new DefaultEventManager(0);
+
+        // test that ids that are passed back are actually propagated to the right
+        // objects...
+
+        MockDataChannel channel = new MockDataChannel() {
+
+            @Override
+            public GraphDiff onSync(
+                    ObjectContext originatingContext,
+                    GraphDiff changes,
+                    int syncType) {
+
+                return diff;
+            }
+
+            // must provide a channel with working event manager
+            @Override
+            public EventManager getEventManager() {
+                return eventManager;
+            }
+        };
+
+        CayenneContext context = new CayenneContext(channel);
+        ObjEntity entity = new ObjEntity("test_entity");
+        entity.setClassName(MockPersistentObject.class.getName());
+
+        DataMap dataMap = new DataMap("test");
+        dataMap.addObjEntity(entity);
+        Collection<DataMap> entities = Collections.singleton(dataMap);
+        context.setEntityResolver(new EntityResolver(entities));
+        Persistent object = context.newObject(MockPersistentObject.class);
+
+        // record change here to make it available to the anonymous connector method..
+        diff.add(new NodeIdChangeOperation(object.getObjectId(), newObjectId));
+
+        // check that a generated object ID is assigned back to the object...
+        assertNotSame(newObjectId, object.getObjectId());
+        context.commitChanges();
+        assertSame(newObjectId, object.getObjectId());
+        assertSame(object, context.graphManager.getNode(newObjectId));
+    }
+
+    public void testNewObject() {
+
+        CayenneContext context = new CayenneContext(new MockDataChannel());
+
+        ObjEntity entity = new ObjEntity("test_entity");
+        entity.setClassName(MockPersistentObject.class.getName());
+
+        DataMap dataMap = new DataMap("test");
+        dataMap.addObjEntity(entity);
+        Collection<DataMap> entities = Collections.singleton(dataMap);
+        context.setEntityResolver(new EntityResolver(entities));
+
+        Persistent object = context.newObject(MockPersistentObject.class);
+        assertNotNull(object);
+        assertTrue(object instanceof MockPersistentObject);
+        assertEquals(PersistenceState.NEW, object.getPersistenceState());
+        assertSame(context, object.getObjectContext());
+        assertTrue(context
+                .internalGraphManager()
+                .dirtyNodes(PersistenceState.NEW)
+                .contains(object));
+        assertNotNull(object.getObjectId());
+        assertTrue(object.getObjectId().isTemporary());
+    }
+
+    public void testDeleteObject() {
+
+        CayenneContext context = new CayenneContext(new MockDataChannel());
+        ObjEntity entity = new ObjEntity("test_entity");
+        entity.setClassName(MockPersistentObject.class.getName());
+
+        DataMap dataMap = new DataMap("test");
+        dataMap.addObjEntity(entity);
+        Collection<DataMap> entities = Collections.singleton(dataMap);
+        context.setEntityResolver(new EntityResolver(entities));
+
+        // TRANSIENT ... should quietly ignore it
+        Persistent transientObject = new MockPersistentObject();
+        context.deleteObjects(transientObject);
+        assertEquals(PersistenceState.TRANSIENT, transientObject.getPersistenceState());
+
+        // NEW ... should make it TRANSIENT
+        // create via context to make sure that object store would register it
+        Persistent newObject = context.newObject(MockPersistentObject.class);
+        assertNotNull(newObject.getObjectContext());
+        context.deleteObjects(newObject);
+        assertNull(newObject.getObjectContext());
+        assertEquals(PersistenceState.TRANSIENT, newObject.getPersistenceState());
+        assertFalse(context
+                .internalGraphManager()
+                .dirtyNodes()
+                .contains(newObject.getObjectId()));
+
+        // see CAY-547 for details...
+        assertFalse(context.internalGraphManager().dirtyNodes().contains(null));
+
+        // COMMITTED
+        Persistent committed = new MockPersistentObject();
+        committed.setPersistenceState(PersistenceState.COMMITTED);
+        committed.setObjectId(new ObjectId("test_entity", "key", "value1"));
+        committed.setObjectContext(context);
+        context.deleteObjects(committed);
+        assertEquals(PersistenceState.DELETED, committed.getPersistenceState());
+
+        // MODIFIED
+        Persistent modified = new MockPersistentObject();
+        modified.setPersistenceState(PersistenceState.MODIFIED);
+        modified.setObjectId(new ObjectId("test_entity", "key", "value2"));
+        modified.setObjectContext(context);
+        context.deleteObjects(modified);
+        assertEquals(PersistenceState.DELETED, modified.getPersistenceState());
+
+        // DELETED
+        Persistent deleted = new MockPersistentObject();
+        deleted.setPersistenceState(PersistenceState.DELETED);
+        deleted.setObjectId(new ObjectId("test_entity", "key", "value3"));
+        deleted.setObjectContext(context);
+        context.deleteObjects(deleted);
+        assertEquals(PersistenceState.DELETED, committed.getPersistenceState());
+    }
+
+    public void testBeforePropertyReadShouldInflateHollow() {
+
+        ObjectId gid = new ObjectId("MtTable1", "a", "b");
+        final ClientMtTable1 inflated = new ClientMtTable1();
+        inflated.setPersistenceState(PersistenceState.COMMITTED);
+        inflated.setObjectId(gid);
+        inflated.setGlobalAttribute1("abc");
+
+        ClientConnection connection = mock(ClientConnection.class);
+        when(connection.sendMessage((ClientMessage) any())).thenAnswer(
+                new Answer<Object>() {
+
+                    public Object answer(InvocationOnMock invocation) {
+                        ClientMessage arg = (ClientMessage) invocation.getArguments()[0];
+
+                        if (arg instanceof BootstrapMessage) {
+                            return new EntityResolver();
+                        }
+                        else {
+                            return new GenericResponse(Arrays.asList(inflated));
+                        }
+                    }
+                });
+
+        ClientChannel channel = new ClientChannel(
+                connection,
+                false,
+                new MockEventManager(),
+                false);
+
+        // check that a HOLLOW object is infalted on "beforePropertyRead"
+        ClientMtTable1 hollow = new ClientMtTable1();
+        hollow.setPersistenceState(PersistenceState.HOLLOW);
+        hollow.setObjectId(gid);
+
+        final boolean[] selectExecuted = new boolean[1];
+        CayenneContext context = new CayenneContext(channel) {
+
+            @Override
+            public List<?> performQuery(Query query) {
+                selectExecuted[0] = true;
+                return super.performQuery(query);
+            }
+        };
+
+        context.setEntityResolver(serverContext
+                .getEntityResolver()
+                .getClientEntityResolver());
+
+        context.graphManager.registerNode(hollow.getObjectId(), hollow);
+
+        // testing this...
+        context
+                .prepareForAccess(
+                        hollow,
+                        ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY,
+                        false);
+        assertTrue(selectExecuted[0]);
+        assertSame(hollow, context.getGraphManager().getNode(gid));
+        assertEquals(
+                inflated.getGlobalAttribute1Direct(),
+                hollow.getGlobalAttribute1Direct());
+        assertEquals(PersistenceState.COMMITTED, hollow.getPersistenceState());
+    }
+
+    public void testBeforeHollowDeleteShouldChangeStateToCommited() {
+
+        ObjectId gid = new ObjectId("MtTable1", "a", "b");
+        final ClientMtTable1 inflated = new ClientMtTable1();
+        inflated.setPersistenceState(PersistenceState.COMMITTED);
+        inflated.setObjectId(gid);
+        inflated.setGlobalAttribute1("abc");
+
+        ClientConnection connection = mock(ClientConnection.class);
+        when(connection.sendMessage((ClientMessage) any())).thenAnswer(
+                new Answer<Object>() {
+
+                    public Object answer(InvocationOnMock invocation) {
+                        ClientMessage arg = (ClientMessage) invocation.getArguments()[0];
+
+                        if (arg instanceof BootstrapMessage) {
+                            return new EntityResolver();
+                        }
+                        else {
+                            return new GenericResponse(Arrays.asList(inflated));
+                        }
+                    }
+                });
+        ClientChannel channel = new ClientChannel(
+                connection,
+                false,
+                new MockEventManager(),
+                false);
+
+        CayenneContext context = new CayenneContext(channel);
+        context.setEntityResolver(serverContext
+                .getEntityResolver()
+                .getClientEntityResolver());
+        ClientMtTable1 hollow = context.localObject(inflated);
+        assertEquals(PersistenceState.HOLLOW, hollow.getPersistenceState());
+
+        // testing this...
+        context.deleteObjects(hollow);
+        assertSame(hollow, context.getGraphManager().getNode(gid));
+        assertEquals(
+                inflated.getGlobalAttribute1Direct(),
+                hollow.getGlobalAttribute1Direct());
+        assertEquals(PersistenceState.DELETED, hollow.getPersistenceState());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/fcb1d536/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
new file mode 100644
index 0000000..ec8c43a
--- /dev/null
+++ b/cayenne-client/src/test/java/org/apache/cayenne/CayenneContextInheritanceIT.java
@@ -0,0 +1,151 @@
+/*****************************************************************
+ *   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.exp.ExpressionFactory;
+import org.apache.cayenne.query.SelectQuery;
+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.unit.di.client.ClientCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Types;
+import java.util.List;
+
+@UseServerRuntime(ClientCase.MULTI_TIER_PROJECT)
+public class CayenneContextInheritanceIT extends ClientCase {
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private CayenneContext context;
+
+    private TableHelper tMtTable1;
+
+    @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",
+                "SUBCLASS_ATTRIBUTE1").setColumnTypes(
+                Types.INTEGER,
+                Types.VARCHAR,
+                Types.VARCHAR,
+                Types.VARCHAR);
+    }
+
+    public void testInsertSubclass() throws Exception {
+
+        ClientMtTable1Subclass1 object = context.newObject(ClientMtTable1Subclass1.class);
+        object.setGlobalAttribute1("sub1");
+        object.setServerAttribute1("sa1");
+        object.setSubclass1Attribute1("suba1");
+
+        context.commitChanges();
+
+        assertEquals(1, tMtTable1.getRowCount());
+        assertEquals("sub1", tMtTable1.getString("GLOBAL_ATTRIBUTE1"));
+        assertEquals("sa1", tMtTable1.getString("SERVER_ATTRIBUTE1"));
+        assertEquals("suba1", tMtTable1.getString("SUBCLASS_ATTRIBUTE1"));
+    }
+
+    public void testPerformQueryInheritanceLeaf() throws Exception {
+
+        tMtTable1.insert(1, "xxx", "yyy", null);
+        tMtTable1.insert(2, "sub1", "zzz", "sa1");
+        tMtTable1.insert(3, "1111", "aaa", null);
+
+        SelectQuery query = new SelectQuery(ClientMtTable1Subclass1.class);
+        List<ClientMtTable1Subclass1> objects = context.performQuery(query);
+
+        assertEquals(1, objects.size());
+        assertEquals("sa1", objects.get(0).getSubclass1Attribute1());
+    }
+
+    public void testPerformQueryInheritanceSuper() throws Exception {
+
+        tMtTable1.insert(1, "a", "yyy", null);
+        tMtTable1.insert(2, "sub1", "zzz", "sa1");
+        tMtTable1.insert(3, "z", "aaa", null);
+
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        List<ClientMtTable1> objects = context.performQuery(query);
+
+        assertEquals(3, objects.size());
+
+        int checkedFields = 0;
+        for (int i = 0; i < objects.size(); i++) {
+            Integer id = (Integer) objects.get(i).getObjectId().getIdSnapshot().get(
+                    "TABLE1_ID");
+            if (id == 1) {
+                assertEquals("a", objects.get(i).getGlobalAttribute1());
+                checkedFields++;
+            }
+            else if (id == 2) {
+                assertEquals("sa1", ((ClientMtTable1Subclass1) objects.get(i))
+                        .getSubclass1Attribute1());
+                checkedFields++;
+            }
+
+        }
+        assertEquals(2, checkedFields);
+    }
+
+    public void testPerformQueryWithQualifierInheritanceSuper() throws Exception {
+
+        tMtTable1.insert(1, "a", "XX", null);
+        tMtTable1.insert(2, "sub1", "XXA", "sa1");
+        tMtTable1.insert(3, "z", "MM", null);
+
+        SelectQuery query = new SelectQuery(ClientMtTable1.class);
+        query.andQualifier(ExpressionFactory.likeExp(
+                ClientMtTable1.SERVER_ATTRIBUTE1_PROPERTY,
+                "X%"));
+        List<ClientMtTable1> objects = context.performQuery(query);
+
+        assertEquals(2, objects.size());
+
+        int checkedFields = 0;
+        for (int i = 0; i < objects.size(); i++) {
+            Integer id = (Integer) objects.get(i).getObjectId().getIdSnapshot().get(
+                    "TABLE1_ID");
+            if (id == 1) {
+                assertEquals("a", objects.get(i).getGlobalAttribute1());
+                checkedFields++;
+            }
+            else if (id == 2) {
+                assertEquals("sa1", ((ClientMtTable1Subclass1) objects.get(i))
+                        .getSubclass1Attribute1());
+                checkedFields++;
+            }
+
+        }
+        assertEquals(2, checkedFields);
+    }
+
+}