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:10:05 UTC

[17/48] Installing Maven Failsafe Plugin

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/SimpleIdIncrementalFaultListTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/SimpleIdIncrementalFaultListTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/SimpleIdIncrementalFaultListTest.java
deleted file mode 100644
index f622f11..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/SimpleIdIncrementalFaultListTest.java
+++ /dev/null
@@ -1,292 +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.access;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.Ordering;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class SimpleIdIncrementalFaultListTest extends ServerCase {
-
-    @Inject
-    private DataContext context;
-
-    @Inject
-    private DBHelper dbHelper;
-
-    private TableHelper tArtist;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("PAINTING_INFO");
-        dbHelper.deleteAll("PAINTING");
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("ARTIST_GROUP");
-        dbHelper.deleteAll("ARTIST");
-
-        tArtist = new TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
-    }
-
-    protected void createArtistsDataSet() throws Exception {
-        tArtist.insert(33001, "artist1");
-        tArtist.insert(33002, "artist2");
-        tArtist.insert(33003, "artist3");
-        tArtist.insert(33004, "artist4");
-        tArtist.insert(33005, "artist5");
-        tArtist.insert(33006, "artist6");
-        tArtist.insert(33007, "artist7");
-        tArtist.insert(33008, "artist8");
-        tArtist.insert(33009, "artist9");
-        tArtist.insert(33010, "artist10");
-        tArtist.insert(33011, "artist11");
-        tArtist.insert(33012, "artist12");
-        tArtist.insert(33013, "artist13");
-        tArtist.insert(33014, "artist14");
-        tArtist.insert(33015, "artist15");
-        tArtist.insert(33016, "artist16");
-        tArtist.insert(33017, "artist17");
-        tArtist.insert(33018, "artist18");
-        tArtist.insert(33019, "artist19");
-        tArtist.insert(33020, "artist20");
-        tArtist.insert(33021, "artist21");
-        tArtist.insert(33022, "artist22");
-        tArtist.insert(33023, "artist23");
-        tArtist.insert(33024, "artist24");
-        tArtist.insert(33025, "artist25");
-    }
-
-    public void testRemoveDeleted() throws Exception {
-        createArtistsDataSet();
-
-        // DataContext context = createDataContext();
-
-        SelectQuery query = new SelectQuery(Artist.class);
-        query.setPageSize(10);
-        SimpleIdIncrementalFaultList<Artist> list = new SimpleIdIncrementalFaultList<Artist>(
-                context,
-                query, 10000);
-
-        assertEquals(25, list.size());
-
-        Artist a1 = list.get(0);
-        context.deleteObjects(a1);
-        context.commitChanges();
-
-        list.remove(0);
-        assertEquals(24, list.size());
-    }
-
-    private SimpleIdIncrementalFaultList<?> prepareList(int pageSize) throws Exception {
-        createArtistsDataSet();
-
-        SelectQuery query = new SelectQuery(Artist.class);
-
-        // make sure total number of objects is not divisable
-        // by the page size, to test the last smaller page
-        query.setPageSize(pageSize);
-        query.addOrdering("db:ARTIST_ID", SortOrder.ASCENDING);
-        return new SimpleIdIncrementalFaultList<Object>(context, query, 10000);
-    }
-
-    public void testSize() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        assertEquals(25, list.size());
-    }
-
-    public void testSmallList() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(49);
-        assertEquals(25, list.size());
-    }
-
-    public void testOnePageList() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(25);
-        assertEquals(25, list.size());
-    }
-
-    public void testIterator() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        Iterator<?> it = list.iterator();
-        int counter = 0;
-        while (it.hasNext()) {
-            Object obj = it.next();
-            assertNotNull(obj);
-            assertTrue(obj instanceof DataObject);
-
-            // iterator must be resolved page by page
-            int expectedResolved = list.pageIndex(counter)
-                    * list.getPageSize()
-                    + list.getPageSize();
-            if (expectedResolved > list.size()) {
-                expectedResolved = list.size();
-            }
-
-            assertEquals(list.size() - expectedResolved, list.getUnfetchedObjects());
-
-            counter++;
-        }
-    }
-
-    public void testNewObject() throws Exception {
-
-        createArtistsDataSet();
-
-        Artist newArtist = context.newObject(Artist.class);
-        newArtist.setArtistName("x");
-        context.commitChanges();
-
-        SelectQuery<Artist> q = new SelectQuery<Artist>(Artist.class);
-        q.setPageSize(6);
-        q.addOrdering(Artist.ARTIST_NAME.asc());
-
-        SimpleIdIncrementalFaultList<?> list = new SimpleIdIncrementalFaultList<Object>(
-                context,
-                q, 10000);
-
-        assertSame(newArtist, list.get(25));
-    }
-
-    public void testListIterator() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        ListIterator<?> it = list.listIterator();
-        int counter = 0;
-        while (it.hasNext()) {
-            Object obj = it.next();
-            assertNotNull(obj);
-            assertTrue(obj instanceof DataObject);
-
-            // iterator must be resolved page by page
-            int expectedResolved = list.pageIndex(counter)
-                    * list.getPageSize()
-                    + list.getPageSize();
-            if (expectedResolved > list.size()) {
-                expectedResolved = list.size();
-            }
-
-            assertEquals(list.size() - expectedResolved, list.getUnfetchedObjects());
-
-            counter++;
-        }
-    }
-
-    public void testSort() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-
-        new Ordering(Artist.ARTIST_NAME_PROPERTY, SortOrder.DESCENDING).orderList(list);
-
-        Iterator<?> it = list.iterator();
-        Artist previousArtist = null;
-        while (it.hasNext()) {
-            Artist artist = (Artist) it.next();
-            if (previousArtist != null) {
-                assertTrue(previousArtist.getArtistName().compareTo(
-                        artist.getArtistName()) > 0);
-            }
-        }
-    }
-
-    public void testUnfetchedObjects() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        assertEquals(25, list.getUnfetchedObjects());
-        list.get(7);
-        assertEquals(25 - 6, list.getUnfetchedObjects());
-        list.resolveAll();
-        assertEquals(0, list.getUnfetchedObjects());
-    }
-
-    public void testPageIndex() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        assertEquals(0, list.pageIndex(0));
-        assertEquals(0, list.pageIndex(1));
-        assertEquals(1, list.pageIndex(6));
-
-        try {
-            assertEquals(13, list.pageIndex(82));
-            fail("Element index beyound array size must throw an IndexOutOfBoundsException.");
-        }
-        catch (IndexOutOfBoundsException ex) {
-            // exception expercted
-        }
-    }
-
-    public void testPagesRead1() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        assertTrue(list.elements.get(0) instanceof Long);
-        assertTrue(list.elements.get(8) instanceof Long);
-
-        list.resolveInterval(5, 10);
-        assertTrue(list.elements.get(7) instanceof Artist);
-
-        list.resolveAll();
-        assertTrue((list.elements.get(list.size() - 1)) instanceof Artist);
-    }
-
-    public void testGet1() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        assertTrue(list.elements.get(0) instanceof Long);
-        assertTrue(list.elements.get(8) instanceof Long);
-
-        Object a = list.get(8);
-
-        assertNotNull(a);
-        assertTrue(a instanceof Artist);
-        assertTrue(list.elements.get(8) instanceof Artist);
-    }
-
-    public void testIndexOf() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        Expression qual = ExpressionFactory.matchExp("artistName", "artist20");
-        SelectQuery query = new SelectQuery(Artist.class, qual);
-        List<?> artists = list.dataContext.performQuery(query);
-
-        assertEquals(1, artists.size());
-
-        Artist row = (Artist) artists.get(0);
-        assertEquals(19, list.indexOf(row));
-        assertEquals(-1, list.indexOf(list.dataContext.newObject("Artist")));
-    }
-
-    public void testLastIndexOf() throws Exception {
-        SimpleIdIncrementalFaultList<?> list = prepareList(6);
-        Expression qual = ExpressionFactory.matchExp("artistName", "artist20");
-        SelectQuery query = new SelectQuery(Artist.class, qual);
-        List<?> artists = list.dataContext.performQuery(query);
-
-        assertEquals(1, artists.size());
-
-        Artist row = (Artist) artists.get(0);
-        assertEquals(19, list.lastIndexOf(row));
-        assertEquals(-1, list.lastIndexOf(list.dataContext.newObject("Artist")));
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1IT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1IT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1IT.java
new file mode 100644
index 0000000..32220f0
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1IT.java
@@ -0,0 +1,102 @@
+/*****************************************************************
+ *   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.ObjectContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.inheritance_flat.Group;
+import org.apache.cayenne.testdo.inheritance_flat.Role;
+import org.apache.cayenne.testdo.inheritance_flat.User;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+/**
+ * Special test cases per CAY-1378, CAY-1379.
+ */
+@UseServerRuntime(ServerCase.INHERTITANCE_SINGLE_TABLE1_PROJECT)
+public class SingleTableInheritance1IT extends ServerCase {
+
+    @Inject
+    private ObjectContext context;
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+
+        dbHelper.deleteAll("GROUP_MEMBERS");
+        dbHelper.deleteAll("USER_PROPERTIES");
+        dbHelper.deleteAll("GROUP_PROPERTIES");
+        dbHelper.deleteAll("ROLES");
+    }
+
+    public void testGroupActions() throws Exception {
+
+        User user = context.newObject(User.class);
+        user.setName("test_user");
+
+        Group group1 = context.newObject(Group.class);
+        group1.setName("test_group1");
+
+        Group group2 = context.newObject(Group.class);
+        group2.setName("test_group2");
+
+        group1.addToGroupMembers(user);
+        group2.addToGroupMembers(group1);
+
+        group2.getObjectContext().commitChanges();
+
+        // Per CAY-1379 removing user and then refetching resulted in a FFE downstream
+        group1.removeFromGroupMembers(user);
+        Expression exp = ExpressionFactory.matchExp(Role.ROLE_GROUPS_PROPERTY, group2);
+        SelectQuery query = new SelectQuery(Group.class, exp);
+        context.performQuery(query);
+        context.commitChanges();
+
+        context.deleteObjects(group1);
+        context.deleteObjects(group2);
+        context.deleteObjects(user);
+        context.commitChanges();
+    }
+
+    public void testFlattenedNullifyNullifyDeleteRules() throws Exception {
+
+        User user = context.newObject(User.class);
+        user.setName("test_user");
+        Group group = context.newObject(Group.class);
+        group.setName("test_group");
+        group.addToGroupMembers(user);
+        context.commitChanges();
+
+        context.deleteObjects(user);
+        assertTrue(group.getGroupMembers().isEmpty());
+
+        context.commitChanges();
+
+        // here Cayenne would throw per CAY-1378 on an attempt to delete a previously
+        // related transient object
+        context.deleteObjects(group);
+        context.commitChanges();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1Test.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1Test.java b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1Test.java
deleted file mode 100644
index 6b71456..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritance1Test.java
+++ /dev/null
@@ -1,102 +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.access;
-
-import org.apache.cayenne.ObjectContext;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.testdo.inheritance_flat.Group;
-import org.apache.cayenne.testdo.inheritance_flat.Role;
-import org.apache.cayenne.testdo.inheritance_flat.User;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-/**
- * Special test cases per CAY-1378, CAY-1379.
- */
-@UseServerRuntime(ServerCase.INHERTITANCE_SINGLE_TABLE1_PROJECT)
-public class SingleTableInheritance1Test extends ServerCase {
-
-    @Inject
-    private ObjectContext context;
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-
-        dbHelper.deleteAll("GROUP_MEMBERS");
-        dbHelper.deleteAll("USER_PROPERTIES");
-        dbHelper.deleteAll("GROUP_PROPERTIES");
-        dbHelper.deleteAll("ROLES");
-    }
-
-    public void testGroupActions() throws Exception {
-
-        User user = context.newObject(User.class);
-        user.setName("test_user");
-
-        Group group1 = context.newObject(Group.class);
-        group1.setName("test_group1");
-
-        Group group2 = context.newObject(Group.class);
-        group2.setName("test_group2");
-
-        group1.addToGroupMembers(user);
-        group2.addToGroupMembers(group1);
-
-        group2.getObjectContext().commitChanges();
-
-        // Per CAY-1379 removing user and then refetching resulted in a FFE downstream
-        group1.removeFromGroupMembers(user);
-        Expression exp = ExpressionFactory.matchExp(Role.ROLE_GROUPS_PROPERTY, group2);
-        SelectQuery query = new SelectQuery(Group.class, exp);
-        context.performQuery(query);
-        context.commitChanges();
-
-        context.deleteObjects(group1);
-        context.deleteObjects(group2);
-        context.deleteObjects(user);
-        context.commitChanges();
-    }
-
-    public void testFlattenedNullifyNullifyDeleteRules() throws Exception {
-
-        User user = context.newObject(User.class);
-        user.setName("test_user");
-        Group group = context.newObject(Group.class);
-        group.setName("test_group");
-        group.addToGroupMembers(user);
-        context.commitChanges();
-
-        context.deleteObjects(user);
-        assertTrue(group.getGroupMembers().isEmpty());
-
-        context.commitChanges();
-
-        // here Cayenne would throw per CAY-1378 on an attempt to delete a previously
-        // related transient object
-        context.deleteObjects(group);
-        context.commitChanges();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceIT.java
new file mode 100644
index 0000000..ea76fa7
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceIT.java
@@ -0,0 +1,533 @@
+/*****************************************************************
+ *   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.Cayenne;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.PrefetchTreeNode;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.testdo.inherit.AbstractPerson;
+import org.apache.cayenne.testdo.inherit.Address;
+import org.apache.cayenne.testdo.inherit.BaseEntity;
+import org.apache.cayenne.testdo.inherit.ClientCompany;
+import org.apache.cayenne.testdo.inherit.CustomerRepresentative;
+import org.apache.cayenne.testdo.inherit.Department;
+import org.apache.cayenne.testdo.inherit.Employee;
+import org.apache.cayenne.testdo.inherit.Manager;
+import org.apache.cayenne.testdo.inherit.PersonNotes;
+import org.apache.cayenne.testdo.inherit.RelatedEntity;
+import org.apache.cayenne.testdo.inherit.SubEntity;
+import org.apache.cayenne.unit.di.DataChannelInterceptor;
+import org.apache.cayenne.unit.di.UnitTestClosure;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Types;
+import java.util.Arrays;
+import java.util.List;
+
+@UseServerRuntime(ServerCase.PEOPLE_PROJECT)
+public class SingleTableInheritanceIT extends ServerCase {
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private DataContext context;
+
+    @Inject
+    private DataContext context2;
+
+    @Inject
+    private DataChannelInterceptor queryBlocker;
+
+    private TableHelper tPerson;
+    private TableHelper tAddress;
+    private TableHelper tClientCompany;
+    private TableHelper tDepartment;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        tPerson = new TableHelper(dbHelper, "PERSON");
+        tPerson.setColumns(
+                "PERSON_ID",
+                "NAME",
+                "PERSON_TYPE",
+                "SALARY",
+                "CLIENT_COMPANY_ID",
+                "DEPARTMENT_ID").setColumnTypes(
+                Types.INTEGER,
+                Types.VARCHAR,
+                Types.CHAR,
+                Types.FLOAT,
+                Types.INTEGER,
+                Types.INTEGER);
+
+        tAddress = new TableHelper(dbHelper, "ADDRESS");
+        tAddress.setColumns("ADDRESS_ID", "CITY", "PERSON_ID");
+
+        tClientCompany = new TableHelper(dbHelper, "CLIENT_COMPANY");
+        tClientCompany.setColumns("CLIENT_COMPANY_ID", "NAME");
+
+        tDepartment = new TableHelper(dbHelper, "DEPARTMENT");
+        tDepartment.setColumns("DEPARTMENT_ID", "NAME");
+
+        // manually break circular deps
+        tPerson.update().set("DEPARTMENT_ID", null, Types.INTEGER).execute();
+
+        dbHelper.deleteAll("ADDRESS");
+        dbHelper.deleteAll("DEPARTMENT");
+        dbHelper.deleteAll("PERSON_NOTES");
+        dbHelper.deleteAll("PERSON");
+        dbHelper.deleteAll("CLIENT_COMPANY");
+    }
+
+    private void create2PersonDataSet() throws Exception {
+        tPerson.insert(1, "E1", "EE", null, null, null);
+        tPerson.insert(2, "E2", "EM", null, null, null);
+    }
+
+    private void create5PersonDataSet() throws Exception {
+        tPerson.insert(1, "E1", "EE", null, null, null);
+        tPerson.insert(2, "E2", "EM", null, null, null);
+        tPerson.insert(3, "E3", "EE", null, null, null);
+        tPerson.insert(4, "E4", "EM", null, null, null);
+        tPerson.insert(5, "E5", "EE", null, null, null);
+    }
+
+    private void createSelectDataSet() throws Exception {
+        tPerson.insert(1, "e1", "EE", 20000, null, null);
+        tPerson.insert(2, "e2", "EE", 25000, null, null);
+        tPerson.insert(3, "e3", "EE", 28000, null, null);
+        tPerson.insert(4, "m1", "EM", 30000, null, null);
+        tPerson.insert(5, "m2", "EM", 40000, null, null);
+
+        tClientCompany.insert(1, "Citibank");
+        tPerson.insert(6, "c1", "C", null, 1, null);
+    }
+
+    private void createEmployeeAddressDataSet() throws Exception {
+        tPerson.insert(1, "e1", "EE", 20000, null, null);
+        tAddress.insert(1, "New York", 1);
+    }
+
+    private void createManagerAddressDataSet() throws Exception {
+        tPerson.insert(4, "m1", "EM", 30000, null, null);
+        tAddress.insert(1, "New York", 4);
+    }
+
+    private void createRepCompanyDataSet() throws Exception {
+        tClientCompany.insert(1, "Citibank");
+        tPerson.insert(6, "c1", "C", null, 1, null);
+    }
+
+    private void createDepartmentEmployeesDataSet() throws Exception {
+        tDepartment.insert(1, "Accounting");
+
+        tPerson.insert(7, "John", "EE", 25000, null, 1);
+        tPerson.insert(8, "Susan", "EE", 50000, null, 1);
+        tPerson.insert(9, "Kelly", "EM", 100000, null, 1);
+    }
+
+    public void testMatchingOnSuperAttributes() throws Exception {
+        create2PersonDataSet();
+
+        // fetch on leaf, but match on a super attribute
+        SelectQuery select = new SelectQuery(Manager.class);
+        select.andQualifier(ExpressionFactory
+                .matchExp(AbstractPerson.NAME_PROPERTY, "E2"));
+
+        List<Manager> results = context.performQuery(select);
+        assertEquals(1, results.size());
+        assertEquals("E2", results.get(0).getName());
+    }
+
+    public void testMatchingOnSuperAttributesWithPrefetch() throws Exception {
+        create2PersonDataSet();
+
+        // fetch on leaf, but match on a super attribute
+        SelectQuery select = new SelectQuery(Employee.class);
+        select.addPrefetch(Employee.TO_DEPARTMENT_PROPERTY);
+        select.andQualifier(ExpressionFactory
+                .matchExp(AbstractPerson.NAME_PROPERTY, "E2"));
+
+        List<Manager> results = context.performQuery(select);
+        assertEquals(1, results.size());
+        assertEquals("E2", results.get(0).getName());
+    }
+
+    public void testPaginatedQueries() throws Exception {
+
+        create5PersonDataSet();
+
+        SelectQuery select = new SelectQuery(AbstractPerson.class);
+        select.addOrdering(
+                "db:" + AbstractPerson.PERSON_ID_PK_COLUMN,
+                SortOrder.ASCENDING);
+        select.setPageSize(3);
+
+        List<AbstractPerson> results = context.performQuery(select);
+        assertEquals(5, results.size());
+
+        assertTrue(results.get(0) instanceof Employee);
+
+        // this is where things would blow up per CAY-1142
+        assertTrue(results.get(1) instanceof Manager);
+
+        assertTrue(results.get(3) instanceof Manager);
+        assertTrue(results.get(4) instanceof Employee);
+    }
+
+    public void testRelationshipToAbstractSuper() {
+        context
+                .performGenericQuery(new SQLTemplate(
+                        AbstractPerson.class,
+                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (1, 'AA', 'EE')"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (1, 'AA', 1)"));
+
+        PersonNotes note = Cayenne.objectForPK(context, PersonNotes.class, 1);
+        assertNotNull(note);
+        assertNotNull(note.getPerson());
+        assertTrue(note.getPerson() instanceof Employee);
+    }
+
+    public void testRelationshipAbstractFromSuperPrefetchingJoint() {
+        context
+                .performGenericQuery(new SQLTemplate(
+                        AbstractPerson.class,
+                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (4, 'BB', 3)"));
+
+        SelectQuery query = new SelectQuery(AbstractPerson.class);
+        query.addPrefetch(AbstractPerson.NOTES_PROPERTY).setSemantics(
+                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+
+        final AbstractPerson person = (AbstractPerson) Cayenne.objectForQuery(
+                context,
+                query);
+
+        assertTrue(person instanceof Employee);
+
+        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals(2, person.getNotes().size());
+
+                String[] names = new String[2];
+                names[0] = person.getNotes().get(0).getNotes();
+                names[1] = person.getNotes().get(1).getNotes();
+                List<String> nameSet = Arrays.asList(names);
+
+                assertTrue(nameSet.contains("AA"));
+                assertTrue(nameSet.contains("BB"));
+            }
+        });
+    }
+
+    public void testRelationshipAbstractFromSuperPrefetchingDisjoint() {
+        context
+                .performGenericQuery(new SQLTemplate(
+                        AbstractPerson.class,
+                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (4, 'BB', 3)"));
+
+        SelectQuery query = new SelectQuery(AbstractPerson.class);
+        query.addPrefetch(AbstractPerson.NOTES_PROPERTY);
+
+        final AbstractPerson person = (AbstractPerson) Cayenne.objectForQuery(
+                context,
+                query);
+        assertTrue(person instanceof Employee);
+
+        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals(2, person.getNotes().size());
+
+                String[] names = new String[2];
+                names[0] = person.getNotes().get(0).getNotes();
+                names[1] = person.getNotes().get(1).getNotes();
+                List<String> nameSet = Arrays.asList(names);
+
+                assertTrue(nameSet.contains("AA"));
+                assertTrue(nameSet.contains("BB"));
+            }
+        });
+    }
+
+    public void testRelationshipAbstractToSuperPrefetchingDisjoint() {
+        context
+                .performGenericQuery(new SQLTemplate(
+                        AbstractPerson.class,
+                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (2, 'AA', 'EE')"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (2, 'AA', 2)"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'BB', 2)"));
+
+        SelectQuery query = new SelectQuery(PersonNotes.class);
+        query.addPrefetch(PersonNotes.PERSON_PROPERTY);
+        query.addOrdering(PersonNotes.NOTES_PROPERTY, SortOrder.ASCENDING);
+
+        List<PersonNotes> notes = context.performQuery(query);
+        assertEquals(2, notes.size());
+        final PersonNotes note = notes.get(0);
+
+        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals("AA", note.getPerson().getName());
+            }
+        });
+    }
+
+    public void testRelationshipAbstractToSuperPrefetchingJoint() {
+        context
+                .performGenericQuery(new SQLTemplate(
+                        AbstractPerson.class,
+                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
+
+        context.performGenericQuery(new SQLTemplate(
+                PersonNotes.class,
+                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
+
+        SelectQuery query = new SelectQuery(PersonNotes.class);
+        query.addPrefetch(PersonNotes.PERSON_PROPERTY).setSemantics(
+                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
+
+        final PersonNotes note = (PersonNotes) Cayenne.objectForQuery(context, query);
+
+        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals("AA", note.getPerson().getName());
+            }
+        });
+
+    }
+
+    public void testSave() throws Exception {
+        ClientCompany company = context.newObject(ClientCompany.class);
+        company.setName("Boeing");
+
+        CustomerRepresentative rep = context.newObject(CustomerRepresentative.class);
+        rep.setName("Joe Schmoe");
+        rep.setToClientCompany(company);
+        rep.setPersonType("C");
+
+        Employee employee = context.newObject(Employee.class);
+        employee.setName("Our Joe Schmoe");
+        employee.setPersonType("E");
+
+        context.commitChanges();
+        context.invalidateObjects(company, rep, employee);
+
+        SelectQuery query = new SelectQuery(CustomerRepresentative.class);
+        List<?> reps = context2.performQuery(query);
+
+        assertEquals(1, reps.size());
+        assertEquals(1, countObjectOfClass(reps, CustomerRepresentative.class));
+    }
+
+    /**
+     * Tests that to-one relationship produces correct subclass.
+     */
+    public void testEmployeeAddress() throws Exception {
+        createEmployeeAddressDataSet();
+
+        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
+
+        assertEquals(1, addresses.size());
+        Address address = (Address) addresses.get(0);
+        assertSame(Employee.class, address.getToEmployee().getClass());
+    }
+
+    /**
+     * Tests that to-one relationship produces correct subclass.
+     */
+    public void testManagerAddress() throws Exception {
+        createManagerAddressDataSet();
+
+        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
+
+        assertEquals(1, addresses.size());
+        Address address = (Address) addresses.get(0);
+        Employee e = address.getToEmployee();
+
+        assertSame(Manager.class, e.getClass());
+    }
+
+    public void testCAY592() throws Exception {
+        createManagerAddressDataSet();
+
+        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
+
+        assertEquals(1, addresses.size());
+        Address address = (Address) addresses.get(0);
+        Employee e = address.getToEmployee();
+
+        // CAY-592 - make sure modification of the address in a parallel context
+        // doesn't mess up the Manager
+
+        e = (Employee) Cayenne.objectForPK(context2, e.getObjectId());
+        address = e.getAddresses().get(0);
+
+        assertSame(e, address.getToEmployee());
+        address.setCity("XYZ");
+        assertSame(e, address.getToEmployee());
+    }
+
+    /**
+     * Tests that to-one relationship produces correct subclass.
+     */
+    public void testRepCompany() throws Exception {
+        createRepCompanyDataSet();
+
+        List<?> companies = context.performQuery(new SelectQuery(ClientCompany.class));
+
+        assertEquals(1, companies.size());
+        ClientCompany company = (ClientCompany) companies.get(0);
+        List<?> reps = company.getRepresentatives();
+        assertEquals(1, reps.size());
+        assertSame(CustomerRepresentative.class, reps.get(0).getClass());
+    }
+
+    /**
+     * Tests that to-many relationship produces correct subclasses.
+     */
+    public void testDepartmentEmployees() throws Exception {
+        createDepartmentEmployeesDataSet();
+
+        List<?> departments = context.performQuery(new SelectQuery(Department.class));
+
+        assertEquals(1, departments.size());
+        Department dept = (Department) departments.get(0);
+        List<?> employees = dept.getEmployees();
+        assertEquals(3, employees.size());
+        assertEquals(3, countObjectOfClass(employees, Employee.class));
+        assertEquals(1, countObjectOfClass(employees, Manager.class));
+    }
+
+    public void testSelectInheritanceResolving() throws Exception {
+        createSelectDataSet();
+
+        SelectQuery query = new SelectQuery(AbstractPerson.class);
+        List<?> abstractPpl = context.performQuery(query);
+        assertEquals(6, abstractPpl.size());
+
+        assertEquals(1, countObjectOfClass(abstractPpl, CustomerRepresentative.class));
+        assertEquals(5, countObjectOfClass(abstractPpl, Employee.class));
+        assertEquals(2, countObjectOfClass(abstractPpl, Manager.class));
+    }
+
+    /**
+     * Test for CAY-1008: Reverse relationships may not be correctly set if inheritance is
+     * used.
+     */
+    public void testCAY1008() {
+        RelatedEntity related = context.newObject(RelatedEntity.class);
+
+        BaseEntity base = context.newObject(BaseEntity.class);
+        base.setToRelatedEntity(related);
+
+        assertEquals(1, related.getBaseEntities().size());
+        assertEquals(0, related.getSubEntities().size());
+
+        SubEntity sub = context.newObject(SubEntity.class);
+        sub.setToRelatedEntity(related);
+
+        assertEquals(2, related.getBaseEntities().size());
+
+        // TODO: andrus 2008/03/28 - this fails...
+        // assertEquals(1, related.getSubEntities().size());
+    }
+
+    /**
+     * Test for CAY-1009: Bogus runtime relationships can mess up commit.
+     */
+    public void testCAY1009() {
+
+        // We should have only one relationship. DirectToSubEntity -> SubEntity.
+
+        // this fails as a result of 'EntityResolver().applyObjectLayerDefaults()'
+        // creating incorrect relationships
+        // assertEquals(1, context
+        // .getEntityResolver()
+        // .getObjEntity("DirectToSubEntity")
+        // .getRelationships()
+        // .size());
+
+        // We should still just have the one mapped relationship, but we in fact now have
+        // two:
+        // DirectToSubEntity -> BaseEntity and DirectToSubEntity -> SubEntity.
+
+        // TODO: andrus 2008/03/28 - this fails...
+        // assertEquals(1, context.getEntityResolver().getObjEntity("DirectToSubEntity")
+        // .getRelationships().size());
+        //
+        // DirectToSubEntity direct = context.newObject(DirectToSubEntity.class);
+        //
+        // SubEntity sub = context.newObject(SubEntity.class);
+        // sub.setToDirectToSubEntity(direct);
+        //
+        // assertEquals(1, direct.getSubEntities().size());
+        //
+        // context.deleteObject(sub);
+        // assertEquals(0, direct.getSubEntities().size());
+    }
+
+    /**
+     * Returns a number of objects of a particular class and subclasses in the list.
+     */
+    private int countObjectOfClass(List<?> objects, Class<?> aClass) {
+        int i = 0;
+
+        for (Object next : objects) {
+            if (aClass.isAssignableFrom(next.getClass())) {
+                i++;
+            }
+        }
+        return i;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceTest.java
deleted file mode 100644
index 3bc5f68..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/SingleTableInheritanceTest.java
+++ /dev/null
@@ -1,533 +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.access;
-
-import java.sql.Types;
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.PrefetchTreeNode;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.testdo.inherit.AbstractPerson;
-import org.apache.cayenne.testdo.inherit.Address;
-import org.apache.cayenne.testdo.inherit.BaseEntity;
-import org.apache.cayenne.testdo.inherit.ClientCompany;
-import org.apache.cayenne.testdo.inherit.CustomerRepresentative;
-import org.apache.cayenne.testdo.inherit.Department;
-import org.apache.cayenne.testdo.inherit.Employee;
-import org.apache.cayenne.testdo.inherit.Manager;
-import org.apache.cayenne.testdo.inherit.PersonNotes;
-import org.apache.cayenne.testdo.inherit.RelatedEntity;
-import org.apache.cayenne.testdo.inherit.SubEntity;
-import org.apache.cayenne.unit.di.DataChannelInterceptor;
-import org.apache.cayenne.unit.di.UnitTestClosure;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ServerCase.PEOPLE_PROJECT)
-public class SingleTableInheritanceTest extends ServerCase {
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private DataContext context;
-
-    @Inject
-    private DataContext context2;
-
-    @Inject
-    private DataChannelInterceptor queryBlocker;
-
-    private TableHelper tPerson;
-    private TableHelper tAddress;
-    private TableHelper tClientCompany;
-    private TableHelper tDepartment;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        tPerson = new TableHelper(dbHelper, "PERSON");
-        tPerson.setColumns(
-                "PERSON_ID",
-                "NAME",
-                "PERSON_TYPE",
-                "SALARY",
-                "CLIENT_COMPANY_ID",
-                "DEPARTMENT_ID").setColumnTypes(
-                Types.INTEGER,
-                Types.VARCHAR,
-                Types.CHAR,
-                Types.FLOAT,
-                Types.INTEGER,
-                Types.INTEGER);
-
-        tAddress = new TableHelper(dbHelper, "ADDRESS");
-        tAddress.setColumns("ADDRESS_ID", "CITY", "PERSON_ID");
-
-        tClientCompany = new TableHelper(dbHelper, "CLIENT_COMPANY");
-        tClientCompany.setColumns("CLIENT_COMPANY_ID", "NAME");
-
-        tDepartment = new TableHelper(dbHelper, "DEPARTMENT");
-        tDepartment.setColumns("DEPARTMENT_ID", "NAME");
-
-        // manually break circular deps
-        tPerson.update().set("DEPARTMENT_ID", null, Types.INTEGER).execute();
-
-        dbHelper.deleteAll("ADDRESS");
-        dbHelper.deleteAll("DEPARTMENT");
-        dbHelper.deleteAll("PERSON_NOTES");
-        dbHelper.deleteAll("PERSON");
-        dbHelper.deleteAll("CLIENT_COMPANY");
-    }
-
-    private void create2PersonDataSet() throws Exception {
-        tPerson.insert(1, "E1", "EE", null, null, null);
-        tPerson.insert(2, "E2", "EM", null, null, null);
-    }
-
-    private void create5PersonDataSet() throws Exception {
-        tPerson.insert(1, "E1", "EE", null, null, null);
-        tPerson.insert(2, "E2", "EM", null, null, null);
-        tPerson.insert(3, "E3", "EE", null, null, null);
-        tPerson.insert(4, "E4", "EM", null, null, null);
-        tPerson.insert(5, "E5", "EE", null, null, null);
-    }
-
-    private void createSelectDataSet() throws Exception {
-        tPerson.insert(1, "e1", "EE", 20000, null, null);
-        tPerson.insert(2, "e2", "EE", 25000, null, null);
-        tPerson.insert(3, "e3", "EE", 28000, null, null);
-        tPerson.insert(4, "m1", "EM", 30000, null, null);
-        tPerson.insert(5, "m2", "EM", 40000, null, null);
-
-        tClientCompany.insert(1, "Citibank");
-        tPerson.insert(6, "c1", "C", null, 1, null);
-    }
-
-    private void createEmployeeAddressDataSet() throws Exception {
-        tPerson.insert(1, "e1", "EE", 20000, null, null);
-        tAddress.insert(1, "New York", 1);
-    }
-
-    private void createManagerAddressDataSet() throws Exception {
-        tPerson.insert(4, "m1", "EM", 30000, null, null);
-        tAddress.insert(1, "New York", 4);
-    }
-
-    private void createRepCompanyDataSet() throws Exception {
-        tClientCompany.insert(1, "Citibank");
-        tPerson.insert(6, "c1", "C", null, 1, null);
-    }
-
-    private void createDepartmentEmployeesDataSet() throws Exception {
-        tDepartment.insert(1, "Accounting");
-
-        tPerson.insert(7, "John", "EE", 25000, null, 1);
-        tPerson.insert(8, "Susan", "EE", 50000, null, 1);
-        tPerson.insert(9, "Kelly", "EM", 100000, null, 1);
-    }
-
-    public void testMatchingOnSuperAttributes() throws Exception {
-        create2PersonDataSet();
-
-        // fetch on leaf, but match on a super attribute
-        SelectQuery select = new SelectQuery(Manager.class);
-        select.andQualifier(ExpressionFactory
-                .matchExp(AbstractPerson.NAME_PROPERTY, "E2"));
-
-        List<Manager> results = context.performQuery(select);
-        assertEquals(1, results.size());
-        assertEquals("E2", results.get(0).getName());
-    }
-
-    public void testMatchingOnSuperAttributesWithPrefetch() throws Exception {
-        create2PersonDataSet();
-
-        // fetch on leaf, but match on a super attribute
-        SelectQuery select = new SelectQuery(Employee.class);
-        select.addPrefetch(Employee.TO_DEPARTMENT_PROPERTY);
-        select.andQualifier(ExpressionFactory
-                .matchExp(AbstractPerson.NAME_PROPERTY, "E2"));
-
-        List<Manager> results = context.performQuery(select);
-        assertEquals(1, results.size());
-        assertEquals("E2", results.get(0).getName());
-    }
-
-    public void testPaginatedQueries() throws Exception {
-
-        create5PersonDataSet();
-
-        SelectQuery select = new SelectQuery(AbstractPerson.class);
-        select.addOrdering(
-                "db:" + AbstractPerson.PERSON_ID_PK_COLUMN,
-                SortOrder.ASCENDING);
-        select.setPageSize(3);
-
-        List<AbstractPerson> results = context.performQuery(select);
-        assertEquals(5, results.size());
-
-        assertTrue(results.get(0) instanceof Employee);
-
-        // this is where things would blow up per CAY-1142
-        assertTrue(results.get(1) instanceof Manager);
-
-        assertTrue(results.get(3) instanceof Manager);
-        assertTrue(results.get(4) instanceof Employee);
-    }
-
-    public void testRelationshipToAbstractSuper() {
-        context
-                .performGenericQuery(new SQLTemplate(
-                        AbstractPerson.class,
-                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (1, 'AA', 'EE')"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (1, 'AA', 1)"));
-
-        PersonNotes note = Cayenne.objectForPK(context, PersonNotes.class, 1);
-        assertNotNull(note);
-        assertNotNull(note.getPerson());
-        assertTrue(note.getPerson() instanceof Employee);
-    }
-
-    public void testRelationshipAbstractFromSuperPrefetchingJoint() {
-        context
-                .performGenericQuery(new SQLTemplate(
-                        AbstractPerson.class,
-                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (4, 'BB', 3)"));
-
-        SelectQuery query = new SelectQuery(AbstractPerson.class);
-        query.addPrefetch(AbstractPerson.NOTES_PROPERTY).setSemantics(
-                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
-
-        final AbstractPerson person = (AbstractPerson) Cayenne.objectForQuery(
-                context,
-                query);
-
-        assertTrue(person instanceof Employee);
-
-        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                assertEquals(2, person.getNotes().size());
-
-                String[] names = new String[2];
-                names[0] = person.getNotes().get(0).getNotes();
-                names[1] = person.getNotes().get(1).getNotes();
-                List<String> nameSet = Arrays.asList(names);
-
-                assertTrue(nameSet.contains("AA"));
-                assertTrue(nameSet.contains("BB"));
-            }
-        });
-    }
-
-    public void testRelationshipAbstractFromSuperPrefetchingDisjoint() {
-        context
-                .performGenericQuery(new SQLTemplate(
-                        AbstractPerson.class,
-                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (4, 'BB', 3)"));
-
-        SelectQuery query = new SelectQuery(AbstractPerson.class);
-        query.addPrefetch(AbstractPerson.NOTES_PROPERTY);
-
-        final AbstractPerson person = (AbstractPerson) Cayenne.objectForQuery(
-                context,
-                query);
-        assertTrue(person instanceof Employee);
-
-        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                assertEquals(2, person.getNotes().size());
-
-                String[] names = new String[2];
-                names[0] = person.getNotes().get(0).getNotes();
-                names[1] = person.getNotes().get(1).getNotes();
-                List<String> nameSet = Arrays.asList(names);
-
-                assertTrue(nameSet.contains("AA"));
-                assertTrue(nameSet.contains("BB"));
-            }
-        });
-    }
-
-    public void testRelationshipAbstractToSuperPrefetchingDisjoint() {
-        context
-                .performGenericQuery(new SQLTemplate(
-                        AbstractPerson.class,
-                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (2, 'AA', 'EE')"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (2, 'AA', 2)"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'BB', 2)"));
-
-        SelectQuery query = new SelectQuery(PersonNotes.class);
-        query.addPrefetch(PersonNotes.PERSON_PROPERTY);
-        query.addOrdering(PersonNotes.NOTES_PROPERTY, SortOrder.ASCENDING);
-
-        List<PersonNotes> notes = context.performQuery(query);
-        assertEquals(2, notes.size());
-        final PersonNotes note = notes.get(0);
-
-        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                assertEquals("AA", note.getPerson().getName());
-            }
-        });
-    }
-
-    public void testRelationshipAbstractToSuperPrefetchingJoint() {
-        context
-                .performGenericQuery(new SQLTemplate(
-                        AbstractPerson.class,
-                        "INSERT INTO PERSON (PERSON_ID, NAME, PERSON_TYPE) VALUES (3, 'AA', 'EE')"));
-
-        context.performGenericQuery(new SQLTemplate(
-                PersonNotes.class,
-                "INSERT INTO PERSON_NOTES (ID, NOTES, PERSON_ID) VALUES (3, 'AA', 3)"));
-
-        SelectQuery query = new SelectQuery(PersonNotes.class);
-        query.addPrefetch(PersonNotes.PERSON_PROPERTY).setSemantics(
-                PrefetchTreeNode.JOINT_PREFETCH_SEMANTICS);
-
-        final PersonNotes note = (PersonNotes) Cayenne.objectForQuery(context, query);
-
-        queryBlocker.runWithQueriesBlocked(new UnitTestClosure() {
-
-            public void execute() {
-                assertEquals("AA", note.getPerson().getName());
-            }
-        });
-
-    }
-
-    public void testSave() throws Exception {
-        ClientCompany company = context.newObject(ClientCompany.class);
-        company.setName("Boeing");
-
-        CustomerRepresentative rep = context.newObject(CustomerRepresentative.class);
-        rep.setName("Joe Schmoe");
-        rep.setToClientCompany(company);
-        rep.setPersonType("C");
-
-        Employee employee = context.newObject(Employee.class);
-        employee.setName("Our Joe Schmoe");
-        employee.setPersonType("E");
-
-        context.commitChanges();
-        context.invalidateObjects(company, rep, employee);
-
-        SelectQuery query = new SelectQuery(CustomerRepresentative.class);
-        List<?> reps = context2.performQuery(query);
-
-        assertEquals(1, reps.size());
-        assertEquals(1, countObjectOfClass(reps, CustomerRepresentative.class));
-    }
-
-    /**
-     * Tests that to-one relationship produces correct subclass.
-     */
-    public void testEmployeeAddress() throws Exception {
-        createEmployeeAddressDataSet();
-
-        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
-
-        assertEquals(1, addresses.size());
-        Address address = (Address) addresses.get(0);
-        assertSame(Employee.class, address.getToEmployee().getClass());
-    }
-
-    /**
-     * Tests that to-one relationship produces correct subclass.
-     */
-    public void testManagerAddress() throws Exception {
-        createManagerAddressDataSet();
-
-        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
-
-        assertEquals(1, addresses.size());
-        Address address = (Address) addresses.get(0);
-        Employee e = address.getToEmployee();
-
-        assertSame(Manager.class, e.getClass());
-    }
-
-    public void testCAY592() throws Exception {
-        createManagerAddressDataSet();
-
-        List<?> addresses = context.performQuery(new SelectQuery(Address.class));
-
-        assertEquals(1, addresses.size());
-        Address address = (Address) addresses.get(0);
-        Employee e = address.getToEmployee();
-
-        // CAY-592 - make sure modification of the address in a parallel context
-        // doesn't mess up the Manager
-
-        e = (Employee) Cayenne.objectForPK(context2, e.getObjectId());
-        address = e.getAddresses().get(0);
-
-        assertSame(e, address.getToEmployee());
-        address.setCity("XYZ");
-        assertSame(e, address.getToEmployee());
-    }
-
-    /**
-     * Tests that to-one relationship produces correct subclass.
-     */
-    public void testRepCompany() throws Exception {
-        createRepCompanyDataSet();
-
-        List<?> companies = context.performQuery(new SelectQuery(ClientCompany.class));
-
-        assertEquals(1, companies.size());
-        ClientCompany company = (ClientCompany) companies.get(0);
-        List<?> reps = company.getRepresentatives();
-        assertEquals(1, reps.size());
-        assertSame(CustomerRepresentative.class, reps.get(0).getClass());
-    }
-
-    /**
-     * Tests that to-many relationship produces correct subclasses.
-     */
-    public void testDepartmentEmployees() throws Exception {
-        createDepartmentEmployeesDataSet();
-
-        List<?> departments = context.performQuery(new SelectQuery(Department.class));
-
-        assertEquals(1, departments.size());
-        Department dept = (Department) departments.get(0);
-        List<?> employees = dept.getEmployees();
-        assertEquals(3, employees.size());
-        assertEquals(3, countObjectOfClass(employees, Employee.class));
-        assertEquals(1, countObjectOfClass(employees, Manager.class));
-    }
-
-    public void testSelectInheritanceResolving() throws Exception {
-        createSelectDataSet();
-
-        SelectQuery query = new SelectQuery(AbstractPerson.class);
-        List<?> abstractPpl = context.performQuery(query);
-        assertEquals(6, abstractPpl.size());
-
-        assertEquals(1, countObjectOfClass(abstractPpl, CustomerRepresentative.class));
-        assertEquals(5, countObjectOfClass(abstractPpl, Employee.class));
-        assertEquals(2, countObjectOfClass(abstractPpl, Manager.class));
-    }
-
-    /**
-     * Test for CAY-1008: Reverse relationships may not be correctly set if inheritance is
-     * used.
-     */
-    public void testCAY1008() {
-        RelatedEntity related = context.newObject(RelatedEntity.class);
-
-        BaseEntity base = context.newObject(BaseEntity.class);
-        base.setToRelatedEntity(related);
-
-        assertEquals(1, related.getBaseEntities().size());
-        assertEquals(0, related.getSubEntities().size());
-
-        SubEntity sub = context.newObject(SubEntity.class);
-        sub.setToRelatedEntity(related);
-
-        assertEquals(2, related.getBaseEntities().size());
-
-        // TODO: andrus 2008/03/28 - this fails...
-        // assertEquals(1, related.getSubEntities().size());
-    }
-
-    /**
-     * Test for CAY-1009: Bogus runtime relationships can mess up commit.
-     */
-    public void testCAY1009() {
-
-        // We should have only one relationship. DirectToSubEntity -> SubEntity.
-
-        // this fails as a result of 'EntityResolver().applyObjectLayerDefaults()'
-        // creating incorrect relationships
-        // assertEquals(1, context
-        // .getEntityResolver()
-        // .getObjEntity("DirectToSubEntity")
-        // .getRelationships()
-        // .size());
-
-        // We should still just have the one mapped relationship, but we in fact now have
-        // two:
-        // DirectToSubEntity -> BaseEntity and DirectToSubEntity -> SubEntity.
-
-        // TODO: andrus 2008/03/28 - this fails...
-        // assertEquals(1, context.getEntityResolver().getObjEntity("DirectToSubEntity")
-        // .getRelationships().size());
-        //
-        // DirectToSubEntity direct = context.newObject(DirectToSubEntity.class);
-        //
-        // SubEntity sub = context.newObject(SubEntity.class);
-        // sub.setToDirectToSubEntity(direct);
-        //
-        // assertEquals(1, direct.getSubEntities().size());
-        //
-        // context.deleteObject(sub);
-        // assertEquals(0, direct.getSubEntities().size());
-    }
-
-    /**
-     * Returns a number of objects of a particular class and subclasses in the list.
-     */
-    private int countObjectOfClass(List<?> objects, Class<?> aClass) {
-        int i = 0;
-
-        for (Object next : objects) {
-            if (aClass.isAssignableFrom(next.getClass())) {
-                i++;
-            }
-        }
-        return i;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListIT.java
new file mode 100644
index 0000000..54a555c
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListIT.java
@@ -0,0 +1,263 @@
+/*****************************************************************
+ *   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.PersistenceState;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.apache.cayenne.util.PersistentObjectList;
+
+import java.lang.reflect.Field;
+import java.util.LinkedList;
+import java.util.List;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class ToManyListIT extends ServerCase {
+
+    @Inject
+    private DataContext context;
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("PAINTING_INFO");
+        dbHelper.deleteAll("PAINTING");
+        dbHelper.deleteAll("ARTIST_EXHIBIT");
+        dbHelper.deleteAll("ARTIST_GROUP");
+        dbHelper.deleteAll("ARTIST");
+    }
+
+    private ToManyList createForNewArtist() {
+        Artist artist = context.newObject(Artist.class);
+        return new ToManyList(artist, Artist.PAINTING_ARRAY_PROPERTY);
+    }
+
+    private ToManyList createForExistingArtist() {
+        Artist artist = context.newObject(Artist.class);
+        artist.setArtistName("aa");
+        context.commitChanges();
+        return new ToManyList(artist, Artist.PAINTING_ARRAY_PROPERTY);
+    }
+
+    public void testNewAddRemove() throws Exception {
+        ToManyList list = createForNewArtist();
+        assertFalse("Expected resolved list when created with a new object", list
+                .isFault());
+        assertEquals(0, list.size());
+
+        Painting p1 = context.newObject(Painting.class);
+        list.add(p1);
+        assertEquals(1, list.size());
+
+        Painting p2 = context.newObject(Painting.class);
+        list.add(p2);
+        assertEquals(2, list.size());
+
+        list.remove(p1);
+        assertEquals(1, list.size());
+    }
+
+    public void testSavedUnresolvedAddRemove() throws Exception {
+        ToManyList list = createForExistingArtist();
+
+        // immediately tag Artist as MODIFIED, since we are messing up with relationship
+        // bypassing normal CayenneDataObject methods
+        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
+
+        assertTrue("List must be unresolved for an existing object", list.isFault());
+
+        Painting p1 = context.newObject(Painting.class);
+        list.add(p1);
+        assertTrue("List must be unresolved when adding an object...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p1));
+
+        Painting p2 = context.newObject(Painting.class);
+        list.add(p2);
+        assertTrue("List must be unresolved when adding an object...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p2));
+
+        list.remove(p1);
+        assertTrue("List must be unresolved when removing an object...", list.isFault());
+        assertFalse(addedToUnresolved(list).contains(p1));
+
+        // now resolve
+        int size = list.size();
+        assertFalse("List must be resolved after checking a size...", list.isFault());
+        assertEquals(1, size);
+        assertTrue(getValue(list).contains(p2));
+    }
+
+    public void testSavedUnresolvedMerge() throws Exception {
+        ToManyList list = createForExistingArtist();
+
+        Painting p1 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+
+        // list being tested is a separate copy from
+        // the relationship list that Artist has, so adding a painting
+        // here will not add the painting to the array being tested
+        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p1);
+        context.commitChanges();
+
+        // immediately tag Artist as MODIFIED, since we are messing up with relationship
+        // bypassing normal CayenneDataObject methods
+        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
+
+        assertTrue("List must be unresolved...", list.isFault());
+        list.add(p1);
+        assertTrue("List must be unresolved when adding an object...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p1));
+
+        Painting p2 = context.newObject(Painting.class);
+        list.add(p2);
+        assertTrue("List must be unresolved when adding an object...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p2));
+
+        // now resolve the list and see how merge worked
+        int size = list.size();
+        assertFalse("List must be resolved after checking a size...", list.isFault());
+        assertEquals(2, size);
+        assertTrue(getValue(list).contains(p2));
+        assertTrue(getValue(list).contains(p1));
+    }
+
+    public void testThrowOutDeleted() throws Exception {
+        ToManyList list = createForExistingArtist();
+
+        Painting p1 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+        Painting p2 = context.newObject(Painting.class);
+        p2.setPaintingTitle("p2");
+
+        // list being tested is a separate copy from
+        // the relationship list that Artist has, so adding a painting
+        // here will not add the painting to the array being tested
+        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p1);
+        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p2);
+        context.commitChanges();
+
+        // immediately tag Artist as MODIFIED, since we are messing up with relationship
+        // bypassing normal CayenneDataObject methods
+        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
+
+        assertTrue("List must be unresolved...", list.isFault());
+        list.add(p1);
+        list.add(p2);
+        assertTrue("List must be unresolved when adding an object...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p2));
+        assertTrue(addedToUnresolved(list).contains(p1));
+
+        // now delete p2 and resolve list
+        ((Artist) list.getRelationshipOwner()).removeFromPaintingArray(p2);
+        context.deleteObjects(p2);
+        context.commitChanges();
+
+        assertTrue("List must be unresolved...", list.isFault());
+        assertTrue(
+                "List must be unresolved when an object was deleted externally...",
+                list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p2));
+        assertTrue(addedToUnresolved(list).contains(p1));
+
+        // now resolve the list and see how merge worked
+        int size = list.size();
+        assertFalse("List must be resolved after checking a size...", list.isFault());
+        assertEquals("Deleted object must have been purged...", 1, size);
+        assertTrue(getValue(list).contains(p1));
+        assertFalse("Deleted object must have been purged...", getValue(list)
+                .contains(p2));
+    }
+
+    public void testRealRelationship() throws Exception {
+        Artist artist = context.newObject(Artist.class);
+        artist.setArtistName("aaa");
+
+        Painting p1 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+
+        context.commitChanges();
+        context.invalidateObjects(artist);
+
+        ToManyList list = (ToManyList) artist.getPaintingArray();
+        assertTrue("List must be unresolved...", list.isFault());
+
+        Painting p2 = context.newObject(Painting.class);
+        p2.setPaintingTitle("p2");
+
+        artist.addToPaintingArray(p1);
+        artist.addToPaintingArray(p2);
+        assertTrue("List must be unresolved...", list.isFault());
+
+        context.commitChanges();
+
+        assertTrue("List must be unresolved...", list.isFault());
+
+        int size = list.size();
+        assertFalse("List must be resolved...", list.isFault());
+        assertTrue(list.contains(p1));
+        assertTrue(list.contains(p2));
+        assertEquals(2, size);
+    }
+
+    public void testRealRelationshipRollback() throws Exception {
+        Artist artist = context.newObject(Artist.class);
+        artist.setArtistName("aaa");
+
+        Painting p1 = context.newObject(Painting.class);
+        p1.setPaintingTitle("p1");
+        artist.addToPaintingArray(p1);
+        context.commitChanges();
+        context.invalidateObjects(artist);
+
+        ToManyList list = (ToManyList) artist.getPaintingArray();
+        assertTrue("List must be unresolved...", list.isFault());
+
+        Painting p2 = context.newObject(Painting.class);
+
+        artist.addToPaintingArray(p2);
+        assertTrue("List must be unresolved...", list.isFault());
+        assertTrue(addedToUnresolved(list).contains(p2));
+
+        context.rollbackChanges();
+
+        assertTrue("List must be unresolved...", list.isFault());
+
+        // call to "contains" must trigger list resolution
+        assertTrue(list.contains(p1));
+        assertFalse(list.contains(p2));
+        assertFalse("List must be resolved...", list.isFault());
+    }
+
+    private List<?> getValue(ToManyList list) {
+        return (List<?>) list.getValueDirectly();
+    }
+
+    private LinkedList<?> addedToUnresolved(ToManyList list) throws Exception {
+        Field f = PersistentObjectList.class.getDeclaredField("addedToUnresolved");
+        f.setAccessible(true);
+        return (LinkedList<?>) f.get(list);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListTest.java
deleted file mode 100644
index 1cc84e1..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/ToManyListTest.java
+++ /dev/null
@@ -1,263 +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.access;
-
-import java.lang.reflect.Field;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Painting;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.apache.cayenne.util.PersistentObjectList;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class ToManyListTest extends ServerCase {
-
-    @Inject
-    private DataContext context;
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("PAINTING_INFO");
-        dbHelper.deleteAll("PAINTING");
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("ARTIST_GROUP");
-        dbHelper.deleteAll("ARTIST");
-    }
-
-    private ToManyList createForNewArtist() {
-        Artist artist = context.newObject(Artist.class);
-        return new ToManyList(artist, Artist.PAINTING_ARRAY_PROPERTY);
-    }
-
-    private ToManyList createForExistingArtist() {
-        Artist artist = context.newObject(Artist.class);
-        artist.setArtistName("aa");
-        context.commitChanges();
-        return new ToManyList(artist, Artist.PAINTING_ARRAY_PROPERTY);
-    }
-
-    public void testNewAddRemove() throws Exception {
-        ToManyList list = createForNewArtist();
-        assertFalse("Expected resolved list when created with a new object", list
-                .isFault());
-        assertEquals(0, list.size());
-
-        Painting p1 = context.newObject(Painting.class);
-        list.add(p1);
-        assertEquals(1, list.size());
-
-        Painting p2 = context.newObject(Painting.class);
-        list.add(p2);
-        assertEquals(2, list.size());
-
-        list.remove(p1);
-        assertEquals(1, list.size());
-    }
-
-    public void testSavedUnresolvedAddRemove() throws Exception {
-        ToManyList list = createForExistingArtist();
-
-        // immediately tag Artist as MODIFIED, since we are messing up with relationship
-        // bypassing normal CayenneDataObject methods
-        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
-
-        assertTrue("List must be unresolved for an existing object", list.isFault());
-
-        Painting p1 = context.newObject(Painting.class);
-        list.add(p1);
-        assertTrue("List must be unresolved when adding an object...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p1));
-
-        Painting p2 = context.newObject(Painting.class);
-        list.add(p2);
-        assertTrue("List must be unresolved when adding an object...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p2));
-
-        list.remove(p1);
-        assertTrue("List must be unresolved when removing an object...", list.isFault());
-        assertFalse(addedToUnresolved(list).contains(p1));
-
-        // now resolve
-        int size = list.size();
-        assertFalse("List must be resolved after checking a size...", list.isFault());
-        assertEquals(1, size);
-        assertTrue(getValue(list).contains(p2));
-    }
-
-    public void testSavedUnresolvedMerge() throws Exception {
-        ToManyList list = createForExistingArtist();
-
-        Painting p1 = context.newObject(Painting.class);
-        p1.setPaintingTitle("p1");
-
-        // list being tested is a separate copy from
-        // the relationship list that Artist has, so adding a painting
-        // here will not add the painting to the array being tested
-        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p1);
-        context.commitChanges();
-
-        // immediately tag Artist as MODIFIED, since we are messing up with relationship
-        // bypassing normal CayenneDataObject methods
-        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
-
-        assertTrue("List must be unresolved...", list.isFault());
-        list.add(p1);
-        assertTrue("List must be unresolved when adding an object...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p1));
-
-        Painting p2 = context.newObject(Painting.class);
-        list.add(p2);
-        assertTrue("List must be unresolved when adding an object...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p2));
-
-        // now resolve the list and see how merge worked
-        int size = list.size();
-        assertFalse("List must be resolved after checking a size...", list.isFault());
-        assertEquals(2, size);
-        assertTrue(getValue(list).contains(p2));
-        assertTrue(getValue(list).contains(p1));
-    }
-
-    public void testThrowOutDeleted() throws Exception {
-        ToManyList list = createForExistingArtist();
-
-        Painting p1 = context.newObject(Painting.class);
-        p1.setPaintingTitle("p1");
-        Painting p2 = context.newObject(Painting.class);
-        p2.setPaintingTitle("p2");
-
-        // list being tested is a separate copy from
-        // the relationship list that Artist has, so adding a painting
-        // here will not add the painting to the array being tested
-        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p1);
-        ((Artist) list.getRelationshipOwner()).addToPaintingArray(p2);
-        context.commitChanges();
-
-        // immediately tag Artist as MODIFIED, since we are messing up with relationship
-        // bypassing normal CayenneDataObject methods
-        list.getRelationshipOwner().setPersistenceState(PersistenceState.MODIFIED);
-
-        assertTrue("List must be unresolved...", list.isFault());
-        list.add(p1);
-        list.add(p2);
-        assertTrue("List must be unresolved when adding an object...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p2));
-        assertTrue(addedToUnresolved(list).contains(p1));
-
-        // now delete p2 and resolve list
-        ((Artist) list.getRelationshipOwner()).removeFromPaintingArray(p2);
-        context.deleteObjects(p2);
-        context.commitChanges();
-
-        assertTrue("List must be unresolved...", list.isFault());
-        assertTrue(
-                "List must be unresolved when an object was deleted externally...",
-                list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p2));
-        assertTrue(addedToUnresolved(list).contains(p1));
-
-        // now resolve the list and see how merge worked
-        int size = list.size();
-        assertFalse("List must be resolved after checking a size...", list.isFault());
-        assertEquals("Deleted object must have been purged...", 1, size);
-        assertTrue(getValue(list).contains(p1));
-        assertFalse("Deleted object must have been purged...", getValue(list)
-                .contains(p2));
-    }
-
-    public void testRealRelationship() throws Exception {
-        Artist artist = context.newObject(Artist.class);
-        artist.setArtistName("aaa");
-
-        Painting p1 = context.newObject(Painting.class);
-        p1.setPaintingTitle("p1");
-
-        context.commitChanges();
-        context.invalidateObjects(artist);
-
-        ToManyList list = (ToManyList) artist.getPaintingArray();
-        assertTrue("List must be unresolved...", list.isFault());
-
-        Painting p2 = context.newObject(Painting.class);
-        p2.setPaintingTitle("p2");
-
-        artist.addToPaintingArray(p1);
-        artist.addToPaintingArray(p2);
-        assertTrue("List must be unresolved...", list.isFault());
-
-        context.commitChanges();
-
-        assertTrue("List must be unresolved...", list.isFault());
-
-        int size = list.size();
-        assertFalse("List must be resolved...", list.isFault());
-        assertTrue(list.contains(p1));
-        assertTrue(list.contains(p2));
-        assertEquals(2, size);
-    }
-
-    public void testRealRelationshipRollback() throws Exception {
-        Artist artist = context.newObject(Artist.class);
-        artist.setArtistName("aaa");
-
-        Painting p1 = context.newObject(Painting.class);
-        p1.setPaintingTitle("p1");
-        artist.addToPaintingArray(p1);
-        context.commitChanges();
-        context.invalidateObjects(artist);
-
-        ToManyList list = (ToManyList) artist.getPaintingArray();
-        assertTrue("List must be unresolved...", list.isFault());
-
-        Painting p2 = context.newObject(Painting.class);
-
-        artist.addToPaintingArray(p2);
-        assertTrue("List must be unresolved...", list.isFault());
-        assertTrue(addedToUnresolved(list).contains(p2));
-
-        context.rollbackChanges();
-
-        assertTrue("List must be unresolved...", list.isFault());
-
-        // call to "contains" must trigger list resolution
-        assertTrue(list.contains(p1));
-        assertFalse(list.contains(p2));
-        assertFalse("List must be resolved...", list.isFault());
-    }
-
-    private List<?> getValue(ToManyList list) {
-        return (List<?>) list.getValueDirectly();
-    }
-
-    private LinkedList<?> addedToUnresolved(ToManyList list) throws Exception {
-        Field f = PersistentObjectList.class.getDeclaredField("addedToUnresolved");
-        f.setAccessible(true);
-        return (LinkedList<?>) f.get(list);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
new file mode 100644
index 0000000..eb290fd
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/TransactionThreadIT.java
@@ -0,0 +1,118 @@
+/*****************************************************************
+ *   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 java.sql.Connection;
+
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.testmap.Artist;
+import org.apache.cayenne.tx.BaseTransaction;
+import org.apache.cayenne.tx.CayenneTransaction;
+import org.apache.cayenne.tx.Transaction;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class TransactionThreadIT extends ServerCase {
+
+    @Inject
+    private DataContext context;
+
+    @Inject
+    protected DBHelper dbHelper;
+
+    @Inject
+    private JdbcEventLogger logger;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("PAINTING_INFO");
+        dbHelper.deleteAll("PAINTING");
+        dbHelper.deleteAll("ARTIST_EXHIBIT");
+        dbHelper.deleteAll("ARTIST_GROUP");
+        dbHelper.deleteAll("ARTIST");
+    }
+
+    public void testThreadConnectionReuseOnSelect() throws Exception {
+
+        ConnectionCounterTx t = new ConnectionCounterTx(new CayenneTransaction(logger));
+        BaseTransaction.bindThreadTransaction(t);
+
+        try {
+
+            SelectQuery q1 = new SelectQuery(Artist.class);
+            context.performQuery(q1);
+            assertEquals(1, t.connectionCount);
+
+            // delegate will fail if the second query opens a new connection
+            SelectQuery q2 = new SelectQuery(Artist.class);
+            context.performQuery(q2);
+
+        } finally {
+            BaseTransaction.bindThreadTransaction(null);
+            t.commit();
+        }
+    }
+
+    class ConnectionCounterTx implements Transaction {
+
+        private Transaction delegate;
+        int connectionCount;
+
+        ConnectionCounterTx(Transaction delegate) {
+            this.delegate = delegate;
+        }
+
+        public void begin() {
+            delegate.begin();
+        }
+
+        public void commit() {
+            delegate.commit();
+        }
+
+        public void rollback() {
+            delegate.rollback();
+        }
+
+        public void setRollbackOnly() {
+            delegate.setRollbackOnly();
+        }
+
+        public boolean isRollbackOnly() {
+            return delegate.isRollbackOnly();
+        }
+
+        public Connection getConnection(String name) {
+            return delegate.getConnection(name);
+        }
+
+        public void addConnection(String name, Connection connection) {
+            if (connectionCount++ > 0) {
+                fail("Invalid attempt to add connection");
+            }
+
+            delegate.addConnection(name, connection);
+        }
+    }
+}