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

[35/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/DataContextExtrasTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextExtrasTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextExtrasTest.java
deleted file mode 100644
index 81d5f61..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextExtrasTest.java
+++ /dev/null
@@ -1,421 +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.Date;
-import java.util.List;
-
-import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.dba.JdbcAdapter;
-import org.apache.cayenne.dba.JdbcPkGenerator;
-import org.apache.cayenne.dba.PkGenerator;
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.log.JdbcEventLogger;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.query.SQLTemplate;
-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.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;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextExtrasTest extends ServerCase {
-
-    @Inject
-    protected DataContext context;
-
-    @Inject
-    protected DBHelper dbHelper;
-
-    @Inject
-    protected JdbcEventLogger logger;
-
-    @Inject
-    protected AdhocObjectFactory objectFactory;
-
-    protected TableHelper tArtist;
-    protected TableHelper tPainting;
-
-    @Override
-    protected void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("PAINTING_INFO");
-        dbHelper.deleteAll("PAINTING");
-        dbHelper.deleteAll("PAINTING1");
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("ARTIST_GROUP");
-        dbHelper.deleteAll("ARTIST");
-
-        tArtist = new TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
-
-        tPainting = new TableHelper(dbHelper, "PAINTING");
-        tPainting.setColumns(
-                "PAINTING_ID",
-                "ARTIST_ID",
-                "PAINTING_TITLE",
-                "ESTIMATED_PRICE").setColumnTypes(
-                Types.INTEGER,
-                Types.BIGINT,
-                Types.VARCHAR,
-                Types.DECIMAL);
-    }
-
-    protected void createPhantomModificationDataSet() throws Exception {
-        tArtist.insert(33001, "artist1");
-        tArtist.insert(33002, "artist2");
-    }
-
-    protected void createPhantomModificationsValidateToOneDataSet() throws Exception {
-        tArtist.insert(33001, "artist1");
-        tPainting.insert(33001, 33001, "P1", 3000);
-    }
-
-    protected void createValidateOnToManyChangeDataSet() throws Exception {
-        tArtist.insert(33001, "artist1");
-    }
-
-    protected void createPhantomRelationshipModificationCommitDataSet() throws Exception {
-        tArtist.insert(33001, "artist1");
-        tArtist.insert(33002, "artist2");
-        tPainting.insert(33001, 33001, "P1", 3000);
-    }
-
-    public void testManualIdProcessingOnCommit() throws Exception {
-
-        Artist object = context.newObject(Artist.class);
-        object.setArtistName("ABC");
-        assertEquals(PersistenceState.NEW, object.getPersistenceState());
-
-        // do a manual ID substitution
-        ObjectId manualId = new ObjectId("Artist", Artist.ARTIST_ID_PK_COLUMN, 77777);
-        object.setObjectId(manualId);
-
-        context.commitChanges();
-
-        assertEquals(PersistenceState.COMMITTED, object.getPersistenceState());
-        assertSame(object, context.getGraphManager().getNode(manualId));
-        assertEquals(manualId, object.getObjectId());
-    }
-
-    public void testResolveFault() {
-
-        Artist o1 = context.newObject(Artist.class);
-        o1.setArtistName("a");
-        context.commitChanges();
-
-        context.invalidateObjects(o1);
-        assertEquals(PersistenceState.HOLLOW, o1.getPersistenceState());
-        assertNull(o1.readPropertyDirectly("artistName"));
-
-        context.prepareForAccess(o1, null, false);
-        assertEquals(PersistenceState.COMMITTED, o1.getPersistenceState());
-        assertEquals("a", o1.readPropertyDirectly("artistName"));
-    }
-
-    public void testResolveFaultFailure() {
-
-        Persistent o1 = context.findOrCreateObject(new ObjectId(
-                "Artist",
-                Artist.ARTIST_ID_PK_COLUMN,
-                234));
-
-        try {
-            context.prepareForAccess(o1, null, false);
-            fail("Must blow on non-existing fault.");
-        }
-        catch (CayenneRuntimeException ex) {
-
-        }
-    }
-
-    public void testUserProperties() {
-
-        assertNull(context.getUserProperty("ABC"));
-        Object object = new Object();
-
-        context.setUserProperty("ABC", object);
-        assertSame(object, context.getUserProperty("ABC"));
-    }
-
-    public void testHasChangesNew() {
-
-        assertTrue("No changes expected in context", !context.hasChanges());
-        context.newObject("Artist");
-        assertTrue(
-                "Object added to context, expected to report changes",
-                context.hasChanges());
-    }
-
-    public void testNewObject() {
-
-        Artist a1 = (Artist) context.newObject("Artist");
-        assertTrue(context.getGraphManager().registeredNodes().contains(a1));
-        assertTrue(context.newObjects().contains(a1));
-    }
-
-    public void testNewObjectWithClass() {
-
-        Artist a1 = context.newObject(Artist.class);
-        assertTrue(context.getGraphManager().registeredNodes().contains(a1));
-        assertTrue(context.newObjects().contains(a1));
-    }
-
-    public void testIdObjectFromDataRow() {
-
-        DataRow row = new DataRow(10);
-        row.put("ARTIST_ID", new Integer(100000));
-        DataObject obj = context.objectFromDataRow(Artist.class, row);
-        assertNotNull(obj);
-        assertTrue(context.getGraphManager().registeredNodes().contains(obj));
-        assertEquals(PersistenceState.HOLLOW, obj.getPersistenceState());
-
-        assertNull(context.getObjectStore().getCachedSnapshot(obj.getObjectId()));
-    }
-
-    public void testPartialObjectFromDataRow() {
-
-        DataRow row = new DataRow(10);
-        row.put("ARTIST_ID", new Integer(100001));
-        row.put("ARTIST_NAME", "ArtistXYZ");
-        DataObject obj = context.objectFromDataRow(Artist.class, row);
-        assertNotNull(obj);
-        assertTrue(context.getGraphManager().registeredNodes().contains(obj));
-        assertEquals(PersistenceState.HOLLOW, obj.getPersistenceState());
-        assertNull(context.getObjectStore().getCachedSnapshot(obj.getObjectId()));
-    }
-
-    public void testFullObjectFromDataRow() {
-
-        DataRow row = new DataRow(10);
-        row.put("ARTIST_ID", new Integer(123456));
-        row.put("ARTIST_NAME", "ArtistXYZ");
-        row.put("DATE_OF_BIRTH", new Date());
-        Artist obj = context.objectFromDataRow(Artist.class, row);
-
-        assertTrue(context.getGraphManager().registeredNodes().contains(obj));
-        assertEquals(PersistenceState.COMMITTED, obj.getPersistenceState());
-        assertNotNull(context.getObjectStore().getCachedSnapshot(obj.getObjectId()));
-        assertEquals("ArtistXYZ", obj.getArtistName());
-    }
-
-    public void testCommitChangesError() {
-
-        DataDomain domain = context.getParentDataDomain();
-
-        // setup mockup PK generator that will blow on PK request
-        // to emulate an exception
-        JdbcAdapter jdbcAdapter = objectFactory.newInstance(
-                JdbcAdapter.class,
-                JdbcAdapter.class.getName());
-        PkGenerator newGenerator = new JdbcPkGenerator(jdbcAdapter) {
-
-            @Override
-            public Object generatePk(DataNode node, DbAttribute pk) throws Exception {
-                throw new CayenneRuntimeException("Intentional");
-            }
-        };
-
-        PkGenerator oldGenerator = domain
-                .getDataNodes()
-                .iterator()
-                .next()
-                .getAdapter()
-                .getPkGenerator();
-        JdbcAdapter adapter = (JdbcAdapter) domain
-                .getDataNodes()
-                .iterator()
-                .next()
-                .getAdapter();
-
-        adapter.setPkGenerator(newGenerator);
-        try {
-            Artist newArtist = context.newObject(Artist.class);
-            newArtist.setArtistName("aaa");
-            context.commitChanges();
-            fail("Exception expected but not thrown due to missing PK generation routine.");
-        }
-        catch (CayenneRuntimeException ex) {
-            // exception expected
-        }
-        finally {
-            adapter.setPkGenerator(oldGenerator);
-        }
-    }
-
-    /**
-     * Testing behavior of Cayenne when a database exception is thrown in SELECT query.
-     */
-    public void testSelectException() {
-
-        SQLTemplate q = new SQLTemplate(Artist.class, "SELECT * FROM NON_EXISTENT_TABLE");
-
-        try {
-            context.performGenericQuery(q);
-            fail("Query was invalid and was supposed to fail.");
-        }
-        catch (RuntimeException ex) {
-            // exception expected
-        }
-
-    }
-
-    public void testEntityResolver() {
-        assertNotNull(context.getEntityResolver());
-    }
-
-    public void testPhantomModificationsValidate() throws Exception {
-
-        createPhantomModificationDataSet();
-
-        List<?> objects = context.performQuery(new SelectQuery(Artist.class));
-        Artist a1 = (Artist) objects.get(0);
-        Artist a2 = (Artist) objects.get(1);
-
-        a1.setArtistName(a1.getArtistName());
-        a1.resetValidationFlags();
-        a2.resetValidationFlags();
-        context.commitChanges();
-
-        assertFalse(a1.isValidateForSaveCalled());
-        assertFalse(a2.isValidateForSaveCalled());
-
-        // "phantom" modification - the property is really unchanged
-        a1.setArtistName(a1.getArtistName());
-
-        // some other unrelated object modification caused phantom modification to be
-        // committed as well...
-        // (see CAY-355)
-        a2.setArtistName(a2.getArtistName() + "_x");
-
-        a1.resetValidationFlags();
-        a2.resetValidationFlags();
-        context.commitChanges();
-
-        assertTrue(a2.isValidateForSaveCalled());
-        assertFalse(a1.isValidateForSaveCalled());
-    }
-
-    public void testPhantomModificationsValidateToOne() throws Exception {
-
-        createPhantomModificationsValidateToOneDataSet();
-
-        List<?> objects = context.performQuery(new SelectQuery(Painting.class));
-        Painting p1 = (Painting) objects.get(0);
-
-        p1.setPaintingTitle(p1.getPaintingTitle());
-        p1.resetValidationFlags();
-        context.commitChanges();
-
-        assertFalse(
-                "To-one relationship presence caused incorrect validation call.",
-                p1.isValidateForSaveCalled());
-    }
-
-    public void testValidateOnToManyChange() throws Exception {
-
-        createValidateOnToManyChangeDataSet();
-
-        List<?> objects = context.performQuery(new SelectQuery(Artist.class));
-        Artist a1 = (Artist) objects.get(0);
-
-        Painting p1 = context.newObject(Painting.class);
-        p1.setPaintingTitle("XXX");
-        a1.addToPaintingArray(p1);
-        a1.resetValidationFlags();
-        context.commitChanges();
-
-        assertFalse(a1.isValidateForSaveCalled());
-    }
-
-    public void testPhantomAttributeModificationCommit() throws Exception {
-
-        createPhantomModificationDataSet();
-
-        List<?> objects = context.performQuery(new SelectQuery(Artist.class));
-        Artist a1 = (Artist) objects.get(0);
-
-        String oldName = a1.getArtistName();
-
-        a1.setArtistName(oldName + ".mod");
-        a1.setArtistName(oldName);
-
-        context.commitChanges();
-        assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
-    }
-
-    public void testPhantomRelationshipModificationCommit() throws Exception {
-
-        createPhantomRelationshipModificationCommitDataSet();
-
-        SelectQuery query = new SelectQuery(Painting.class);
-        List<?> objects = context.performQuery(query);
-        assertEquals(1, objects.size());
-
-        Painting p1 = (Painting) objects.get(0);
-
-        Artist oldArtist = p1.getToArtist();
-        Artist newArtist = Cayenne.objectForPK(context, Artist.class, 33002);
-
-        assertNotSame(oldArtist, newArtist);
-
-        p1.setToArtist(newArtist);
-        p1.setToArtist(oldArtist);
-
-        context.commitChanges();
-
-        assertEquals(PersistenceState.COMMITTED, p1.getPersistenceState());
-        assertEquals(PersistenceState.COMMITTED, oldArtist.getPersistenceState());
-        assertEquals(PersistenceState.COMMITTED, newArtist.getPersistenceState());
-    }
-
-    public void testPhantomRelationshipModificationValidate() throws Exception {
-
-        createPhantomRelationshipModificationCommitDataSet();
-
-        SelectQuery query = new SelectQuery(Painting.class);
-        List<?> objects = context.performQuery(query);
-        assertEquals(1, objects.size());
-
-        Painting p1 = (Painting) objects.get(0);
-
-        Artist oldArtist = p1.getToArtist();
-        Artist newArtist = Cayenne.objectForPK(context, Artist.class, 33002);
-
-        assertNotSame(oldArtist, newArtist);
-
-        p1.setToArtist(newArtist);
-        p1.setToArtist(oldArtist);
-
-        p1.resetValidationFlags();
-        context.commitChanges();
-        assertFalse(p1.isValidateForSaveCalled());
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesIT.java
new file mode 100644
index 0000000..6cb1ec4
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesIT.java
@@ -0,0 +1,385 @@
+/*****************************************************************
+ *   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.PersistenceState;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.EJBQLQuery;
+import org.apache.cayenne.query.SelectQuery;
+import org.apache.cayenne.reflect.PersistentDescriptor;
+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.testdo.testmap.CompoundPainting;
+import org.apache.cayenne.testdo.testmap.CompoundPaintingLongNames;
+import org.apache.cayenne.testdo.testmap.Gallery;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.math.BigDecimal;
+import java.sql.Types;
+import java.util.Iterator;
+import java.util.List;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextFlattenedAttributesIT 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("PAINTING1");
+        dbHelper.deleteAll("ARTIST_EXHIBIT");
+        dbHelper.deleteAll("ARTIST_GROUP");
+        dbHelper.deleteAll("ARTIST");
+        dbHelper.deleteAll("GALLERY");
+    }
+
+    private void createTestDataSet() throws Exception {
+        TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
+
+        TableHelper tPainting = new TableHelper(dbHelper, "PAINTING");
+        tPainting.setColumns(
+                "PAINTING_ID",
+                "PAINTING_TITLE",
+                "ARTIST_ID",
+                "ESTIMATED_PRICE",
+                "GALLERY_ID").setColumnTypes(
+                Types.INTEGER,
+                Types.VARCHAR,
+                Types.BIGINT,
+                Types.DECIMAL,
+                Types.INTEGER);
+
+        TableHelper tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
+        tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
+
+        TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
+        tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+
+        long dateBase = System.currentTimeMillis();
+        for (int i = 1; i <= 4; i++) {
+            tArtist.insert(i + 1, "artist" + i, new java.sql.Date(dateBase
+                    + 1000
+                    * 60
+                    * 60
+                    * 24
+                    * i));
+        }
+
+        for (int i = 1; i <= 2; i++) {
+            tGallery.insert(i + 2, "gallery" + i);
+        }
+
+        for (int i = 1; i <= 8; i++) {
+
+            Integer galleryId = (i == 3) ? null : (i - 1) % 2 + 3;
+            tPainting.insert(
+                    i,
+                    "painting" + i,
+                    (i - 1) % 4 + 2,
+                    new BigDecimal(1000d),
+                    galleryId);
+
+            tPaintingInfo.insert(i, "painting review" + i);
+        }
+
+    }
+
+    public void testSelectCompound1() throws Exception {
+        createTestDataSet();
+        SelectQuery query = new SelectQuery(CompoundPainting.class);
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(8, objects.size());
+        assertTrue(
+                "CompoundPainting expected, got " + objects.get(0).getClass(),
+                objects.get(0) instanceof CompoundPainting);
+
+        for (Iterator<?> i = objects.iterator(); i.hasNext();) {
+            CompoundPainting painting = (CompoundPainting) i.next();
+            Number id = (Number) painting
+                    .getObjectId()
+                    .getIdSnapshot()
+                    .get("PAINTING_ID");
+            assertEquals(
+                    "CompoundPainting.getPaintingTitle(): " + painting.getPaintingTitle(),
+                    "painting" + id,
+                    painting.getPaintingTitle());
+            if (painting.getToPaintingInfo() == null) {
+                assertNull(painting.getTextReview());
+            }
+            else {
+                assertEquals(
+                        "CompoundPainting.getTextReview(): " + painting.getTextReview(),
+                        "painting review" + id,
+                        painting.getTextReview());
+            }
+            assertEquals(
+                    "CompoundPainting.getArtistName(): " + painting.getArtistName(),
+                    painting.getToArtist().getArtistName(),
+                    painting.getArtistName());
+            if (painting.getToGallery() == null) {
+                assertNull(painting.getGalleryName());
+            }
+            else {
+                assertEquals(
+                        "CompoundPainting.getGalleryName(): " + painting.getGalleryName(),
+                        painting.getToGallery().getGalleryName(),
+                        painting.getGalleryName());
+            }
+        }
+    }
+
+    // TODO: andrus 1/5/2007 - CAY-952: SelectQuery uses INNER JOIN for flattened
+    // attributes, while
+    // EJBQLQuery does an OUTER JOIN... which seems like a better idea...
+    // 14/01/2010 now it uses LEFT JOIN
+    public void testSelectCompound2() throws Exception {
+        createTestDataSet();
+        SelectQuery query = new SelectQuery(
+                CompoundPainting.class,
+                ExpressionFactory.matchExp("artistName", "artist2"));
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(2, objects.size());
+        assertTrue(
+                "CompoundPainting expected, got " + objects.get(0).getClass(),
+                objects.get(0) instanceof CompoundPainting);
+
+        for (Iterator<?> i = objects.iterator(); i.hasNext();) {
+            CompoundPainting painting = (CompoundPainting) i.next();
+            assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
+
+            assertEquals(
+                    "CompoundPainting.getArtistName(): " + painting.getArtistName(),
+                    "artist2",
+                    painting.getArtistName());
+            assertEquals(
+                    "CompoundPainting.getArtistName(): " + painting.getGalleryName(),
+                    painting.getToGallery().getGalleryName(),
+                    painting.getGalleryName());
+        }
+    }
+
+    /**
+     * Emulates the situation when flattened attribute has unusual(long) name, that puts
+     * this attribute property to the top of PersistentDescriptor.declaredProperties map,
+     * {@link PersistentDescriptor}[105] That forced an error during the building of the
+     * SelectQuery statement, CAY-1484
+     */
+    public void testSelectCompoundLongNames() throws Exception {
+        createTestDataSet();
+        SelectQuery query = new SelectQuery(CompoundPaintingLongNames.class);
+        // the error was thrown on query execution
+        List<?> objects = context.performQuery(query);
+        assertNotNull(objects);
+    }
+
+    public void testSelectEJQBQL() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT a FROM CompoundPainting a WHERE a.artistName = 'artist2'");
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(2, objects.size());
+        assertTrue(
+                "CompoundPainting expected, got " + objects.get(0).getClass(),
+                objects.get(0) instanceof CompoundPainting);
+        Iterator<?> i = objects.iterator();
+        while (i.hasNext()) {
+            CompoundPainting painting = (CompoundPainting) i.next();
+            assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
+        }
+    }
+
+    public void testSelectEJQBQLCollectionTheta() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT DISTINCT a FROM CompoundPainting cp, Artist a "
+                        + "WHERE a.artistName=cp.artistName ORDER BY a.artistName");
+
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(4, objects.size());
+        Iterator<?> i = objects.iterator();
+        int index = 1;
+        while (i.hasNext()) {
+            Artist artist = (Artist) i.next();
+            assertEquals("artist" + index, artist.getArtistName());
+            index++;
+        }
+    }
+
+    public void testSelectEJQBQLLike() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT a FROM CompoundPainting a WHERE a.artistName LIKE 'artist%' "
+                        + "ORDER BY a.paintingTitle");
+
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(8, objects.size());
+        Iterator<?> i = objects.iterator();
+        int index = 1;
+        while (i.hasNext()) {
+            CompoundPainting painting = (CompoundPainting) i.next();
+            assertEquals("painting" + index, painting.getPaintingTitle());
+            index++;
+        }
+    }
+
+    public void testSelectEJQBQLBetween() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery("SELECT a FROM CompoundPainting a "
+                + "WHERE a.artistName BETWEEN 'artist1' AND 'artist4' "
+                + "ORDER BY a.paintingTitle");
+
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(8, objects.size());
+        Iterator<?> i = objects.iterator();
+        int index = 1;
+        while (i.hasNext()) {
+            CompoundPainting painting = (CompoundPainting) i.next();
+            assertEquals("painting" + index, painting.getPaintingTitle());
+            index++;
+        }
+    }
+
+    public void testSelectEJQBQLSubquery() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT g FROM Gallery g WHERE "
+                        + "(SELECT COUNT(cp) FROM CompoundPainting cp WHERE g.galleryName=cp.galleryName) = 4");
+
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(1, objects.size());
+        Gallery gallery = (Gallery) objects.get(0);
+        assertEquals("gallery2", gallery.getGalleryName());
+
+    }
+
+    public void testSelectEJQBQLHaving() throws Exception {
+        createTestDataSet();
+        EJBQLQuery query = new EJBQLQuery(
+                "SELECT cp.galleryName, COUNT(a) from  Artist a, CompoundPainting cp "
+                        + "WHERE cp.artistName = a.artistName "
+                        + "GROUP BY cp.galleryName "
+                        + "HAVING cp.galleryName LIKE 'gallery1'");
+
+        List<Object[]> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(1, objects.size());
+        Object[] galleryItem = objects.get(0);
+        assertEquals("gallery1", galleryItem[0]);
+        assertEquals(3L, galleryItem[1]);
+    }
+
+    public void testInsert() {
+        CompoundPainting o1 = context.newObject(CompoundPainting.class);
+        o1.setArtistName("A1");
+        o1.setEstimatedPrice(new BigDecimal(1.0d));
+        o1.setGalleryName("G1");
+        o1.setPaintingTitle("P1");
+        o1.setTextReview("T1");
+
+        context.commitChanges();
+
+        Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Artist a"));
+        assertEquals(1, artistCount.intValue());
+        Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Painting a"));
+        assertEquals(1, paintingCount.intValue());
+
+        Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Gallery a"));
+        assertEquals(1, galleryCount.intValue());
+    }
+
+    public void testDelete() throws Exception {
+        // throw in a bit of random overlapping data, to make sure FK/PK correspondence is
+        // not purely coincidental
+        Artist a = context.newObject(Artist.class);
+        a.setArtistName("AX");
+        context.commitChanges();
+
+        CompoundPainting o1 = context.newObject(CompoundPainting.class);
+        o1.setArtistName("A1");
+        o1.setEstimatedPrice(new BigDecimal(1.0d));
+        o1.setGalleryName("G1");
+        o1.setPaintingTitle("P1");
+        o1.setTextReview("T1");
+
+        context.commitChanges();
+
+        context.deleteObjects(o1);
+        context.commitChanges();
+
+        Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Artist a"));
+        assertEquals(1, artistCount.intValue());
+        Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Painting a"));
+        assertEquals(0, paintingCount.intValue());
+
+        Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
+                "select count(a) from Gallery a"));
+        assertEquals(0, galleryCount.intValue());
+    }
+
+    public void testUpdate() {
+        CompoundPainting o1 = context.newObject(CompoundPainting.class);
+        o1.setArtistName("A1");
+        o1.setEstimatedPrice(new BigDecimal(1d));
+        o1.setGalleryName("G1");
+        o1.setPaintingTitle("P1");
+        o1.setTextReview("T1");
+
+        context.commitChanges();
+
+        o1.setArtistName("X1");
+        o1.setEstimatedPrice(new BigDecimal(2d));
+        o1.setGalleryName("X1");
+        o1.setPaintingTitle("X1");
+        o1.setTextReview("X1");
+
+        context.commitChanges();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java
deleted file mode 100644
index 58d72fb..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextFlattenedAttributesTest.java
+++ /dev/null
@@ -1,385 +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.math.BigDecimal;
-import java.sql.Types;
-import java.util.Iterator;
-import java.util.List;
-
-import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.PersistenceState;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.query.EJBQLQuery;
-import org.apache.cayenne.query.SelectQuery;
-import org.apache.cayenne.reflect.PersistentDescriptor;
-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.testdo.testmap.CompoundPainting;
-import org.apache.cayenne.testdo.testmap.CompoundPaintingLongNames;
-import org.apache.cayenne.testdo.testmap.Gallery;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextFlattenedAttributesTest 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("PAINTING1");
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("ARTIST_GROUP");
-        dbHelper.deleteAll("ARTIST");
-        dbHelper.deleteAll("GALLERY");
-    }
-
-    private void createTestDataSet() throws Exception {
-        TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
-
-        TableHelper tPainting = new TableHelper(dbHelper, "PAINTING");
-        tPainting.setColumns(
-                "PAINTING_ID",
-                "PAINTING_TITLE",
-                "ARTIST_ID",
-                "ESTIMATED_PRICE",
-                "GALLERY_ID").setColumnTypes(
-                Types.INTEGER,
-                Types.VARCHAR,
-                Types.BIGINT,
-                Types.DECIMAL,
-                Types.INTEGER);
-
-        TableHelper tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
-        tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
-
-        TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
-        tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
-
-        long dateBase = System.currentTimeMillis();
-        for (int i = 1; i <= 4; i++) {
-            tArtist.insert(i + 1, "artist" + i, new java.sql.Date(dateBase
-                    + 1000
-                    * 60
-                    * 60
-                    * 24
-                    * i));
-        }
-
-        for (int i = 1; i <= 2; i++) {
-            tGallery.insert(i + 2, "gallery" + i);
-        }
-
-        for (int i = 1; i <= 8; i++) {
-
-            Integer galleryId = (i == 3) ? null : (i - 1) % 2 + 3;
-            tPainting.insert(
-                    i,
-                    "painting" + i,
-                    (i - 1) % 4 + 2,
-                    new BigDecimal(1000d),
-                    galleryId);
-
-            tPaintingInfo.insert(i, "painting review" + i);
-        }
-
-    }
-
-    public void testSelectCompound1() throws Exception {
-        createTestDataSet();
-        SelectQuery query = new SelectQuery(CompoundPainting.class);
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(8, objects.size());
-        assertTrue(
-                "CompoundPainting expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof CompoundPainting);
-
-        for (Iterator<?> i = objects.iterator(); i.hasNext();) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            Number id = (Number) painting
-                    .getObjectId()
-                    .getIdSnapshot()
-                    .get("PAINTING_ID");
-            assertEquals(
-                    "CompoundPainting.getPaintingTitle(): " + painting.getPaintingTitle(),
-                    "painting" + id,
-                    painting.getPaintingTitle());
-            if (painting.getToPaintingInfo() == null) {
-                assertNull(painting.getTextReview());
-            }
-            else {
-                assertEquals(
-                        "CompoundPainting.getTextReview(): " + painting.getTextReview(),
-                        "painting review" + id,
-                        painting.getTextReview());
-            }
-            assertEquals(
-                    "CompoundPainting.getArtistName(): " + painting.getArtistName(),
-                    painting.getToArtist().getArtistName(),
-                    painting.getArtistName());
-            if (painting.getToGallery() == null) {
-                assertNull(painting.getGalleryName());
-            }
-            else {
-                assertEquals(
-                        "CompoundPainting.getGalleryName(): " + painting.getGalleryName(),
-                        painting.getToGallery().getGalleryName(),
-                        painting.getGalleryName());
-            }
-        }
-    }
-
-    // TODO: andrus 1/5/2007 - CAY-952: SelectQuery uses INNER JOIN for flattened
-    // attributes, while
-    // EJBQLQuery does an OUTER JOIN... which seems like a better idea...
-    // 14/01/2010 now it uses LEFT JOIN
-    public void testSelectCompound2() throws Exception {
-        createTestDataSet();
-        SelectQuery query = new SelectQuery(
-                CompoundPainting.class,
-                ExpressionFactory.matchExp("artistName", "artist2"));
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(2, objects.size());
-        assertTrue(
-                "CompoundPainting expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof CompoundPainting);
-
-        for (Iterator<?> i = objects.iterator(); i.hasNext();) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
-
-            assertEquals(
-                    "CompoundPainting.getArtistName(): " + painting.getArtistName(),
-                    "artist2",
-                    painting.getArtistName());
-            assertEquals(
-                    "CompoundPainting.getArtistName(): " + painting.getGalleryName(),
-                    painting.getToGallery().getGalleryName(),
-                    painting.getGalleryName());
-        }
-    }
-
-    /**
-     * Emulates the situation when flattened attribute has unusual(long) name, that puts
-     * this attribute property to the top of PersistentDescriptor.declaredProperties map,
-     * {@link PersistentDescriptor}[105] That forced an error during the building of the
-     * SelectQuery statement, CAY-1484
-     */
-    public void testSelectCompoundLongNames() throws Exception {
-        createTestDataSet();
-        SelectQuery query = new SelectQuery(CompoundPaintingLongNames.class);
-        // the error was thrown on query execution
-        List<?> objects = context.performQuery(query);
-        assertNotNull(objects);
-    }
-
-    public void testSelectEJQBQL() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT a FROM CompoundPainting a WHERE a.artistName = 'artist2'");
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(2, objects.size());
-        assertTrue(
-                "CompoundPainting expected, got " + objects.get(0).getClass(),
-                objects.get(0) instanceof CompoundPainting);
-        Iterator<?> i = objects.iterator();
-        while (i.hasNext()) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
-        }
-    }
-
-    public void testSelectEJQBQLCollectionTheta() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT DISTINCT a FROM CompoundPainting cp, Artist a "
-                        + "WHERE a.artistName=cp.artistName ORDER BY a.artistName");
-
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(4, objects.size());
-        Iterator<?> i = objects.iterator();
-        int index = 1;
-        while (i.hasNext()) {
-            Artist artist = (Artist) i.next();
-            assertEquals("artist" + index, artist.getArtistName());
-            index++;
-        }
-    }
-
-    public void testSelectEJQBQLLike() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT a FROM CompoundPainting a WHERE a.artistName LIKE 'artist%' "
-                        + "ORDER BY a.paintingTitle");
-
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(8, objects.size());
-        Iterator<?> i = objects.iterator();
-        int index = 1;
-        while (i.hasNext()) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            assertEquals("painting" + index, painting.getPaintingTitle());
-            index++;
-        }
-    }
-
-    public void testSelectEJQBQLBetween() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery("SELECT a FROM CompoundPainting a "
-                + "WHERE a.artistName BETWEEN 'artist1' AND 'artist4' "
-                + "ORDER BY a.paintingTitle");
-
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(8, objects.size());
-        Iterator<?> i = objects.iterator();
-        int index = 1;
-        while (i.hasNext()) {
-            CompoundPainting painting = (CompoundPainting) i.next();
-            assertEquals("painting" + index, painting.getPaintingTitle());
-            index++;
-        }
-    }
-
-    public void testSelectEJQBQLSubquery() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT g FROM Gallery g WHERE "
-                        + "(SELECT COUNT(cp) FROM CompoundPainting cp WHERE g.galleryName=cp.galleryName) = 4");
-
-        List<?> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(1, objects.size());
-        Gallery gallery = (Gallery) objects.get(0);
-        assertEquals("gallery2", gallery.getGalleryName());
-
-    }
-
-    public void testSelectEJQBQLHaving() throws Exception {
-        createTestDataSet();
-        EJBQLQuery query = new EJBQLQuery(
-                "SELECT cp.galleryName, COUNT(a) from  Artist a, CompoundPainting cp "
-                        + "WHERE cp.artistName = a.artistName "
-                        + "GROUP BY cp.galleryName "
-                        + "HAVING cp.galleryName LIKE 'gallery1'");
-
-        List<Object[]> objects = context.performQuery(query);
-
-        assertNotNull(objects);
-        assertEquals(1, objects.size());
-        Object[] galleryItem = objects.get(0);
-        assertEquals("gallery1", galleryItem[0]);
-        assertEquals(3L, galleryItem[1]);
-    }
-
-    public void testInsert() {
-        CompoundPainting o1 = context.newObject(CompoundPainting.class);
-        o1.setArtistName("A1");
-        o1.setEstimatedPrice(new BigDecimal(1.0d));
-        o1.setGalleryName("G1");
-        o1.setPaintingTitle("P1");
-        o1.setTextReview("T1");
-
-        context.commitChanges();
-
-        Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Artist a"));
-        assertEquals(1, artistCount.intValue());
-        Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Painting a"));
-        assertEquals(1, paintingCount.intValue());
-
-        Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Gallery a"));
-        assertEquals(1, galleryCount.intValue());
-    }
-
-    public void testDelete() throws Exception {
-        // throw in a bit of random overlapping data, to make sure FK/PK correspondence is
-        // not purely coincidental
-        Artist a = context.newObject(Artist.class);
-        a.setArtistName("AX");
-        context.commitChanges();
-
-        CompoundPainting o1 = context.newObject(CompoundPainting.class);
-        o1.setArtistName("A1");
-        o1.setEstimatedPrice(new BigDecimal(1.0d));
-        o1.setGalleryName("G1");
-        o1.setPaintingTitle("P1");
-        o1.setTextReview("T1");
-
-        context.commitChanges();
-
-        context.deleteObjects(o1);
-        context.commitChanges();
-
-        Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Artist a"));
-        assertEquals(1, artistCount.intValue());
-        Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Painting a"));
-        assertEquals(0, paintingCount.intValue());
-
-        Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
-                "select count(a) from Gallery a"));
-        assertEquals(0, galleryCount.intValue());
-    }
-
-    public void testUpdate() {
-        CompoundPainting o1 = context.newObject(CompoundPainting.class);
-        o1.setArtistName("A1");
-        o1.setEstimatedPrice(new BigDecimal(1d));
-        o1.setGalleryName("G1");
-        o1.setPaintingTitle("P1");
-        o1.setTextReview("T1");
-
-        context.commitChanges();
-
-        o1.setArtistName("X1");
-        o1.setEstimatedPrice(new BigDecimal(2d));
-        o1.setGalleryName("X1");
-        o1.setPaintingTitle("X1");
-        o1.setTextReview("X1");
-
-        context.commitChanges();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIT.java
new file mode 100644
index 0000000..ca4f923
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextIT.java
@@ -0,0 +1,804 @@
+/*****************************************************************
+ *   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.DataObject;
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.Fault;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.PersistenceState;
+import org.apache.cayenne.ResultIterator;
+import org.apache.cayenne.ResultIteratorCallback;
+import org.apache.cayenne.conn.PoolManager;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.map.EntityResolver;
+import org.apache.cayenne.query.EJBQLQuery;
+import org.apache.cayenne.query.ObjectIdQuery;
+import org.apache.cayenne.query.Ordering;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.QueryMetadata;
+import org.apache.cayenne.query.QueryRouter;
+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.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.Exhibit;
+import org.apache.cayenne.testdo.testmap.NullTestEntity;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.apache.cayenne.testdo.testmap.ROArtist;
+import org.apache.cayenne.unit.UnitDbAdapter;
+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.ServerCaseDataSourceFactory;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextIT extends ServerCase {
+
+    @Inject
+    protected DataContext context;
+
+    @Inject
+    protected DBHelper dbHelper;
+
+    @Inject
+    protected UnitDbAdapter accessStackAdapter;
+
+    @Inject
+    protected DataChannelInterceptor queryInterceptor;
+
+    @Inject
+    protected ServerCaseDataSourceFactory dataSourceFactory;
+
+    protected TableHelper tArtist;
+    protected TableHelper tExhibit;
+    protected TableHelper tGallery;
+    protected TableHelper tPainting;
+
+    @Override
+    protected void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("PAINTING_INFO");
+        dbHelper.deleteAll("PAINTING");
+        dbHelper.deleteAll("ARTIST_EXHIBIT");
+        dbHelper.deleteAll("ARTIST_GROUP");
+        dbHelper.deleteAll("ARTIST");
+        dbHelper.deleteAll("EXHIBIT");
+        dbHelper.deleteAll("GALLERY");
+
+        tArtist = new TableHelper(dbHelper, "ARTIST");
+        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+
+        tExhibit = new TableHelper(dbHelper, "EXHIBIT");
+        tExhibit.setColumns("EXHIBIT_ID", "GALLERY_ID", "OPENING_DATE", "CLOSING_DATE");
+
+        tGallery = new TableHelper(dbHelper, "GALLERY");
+        tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+
+        tPainting = new TableHelper(dbHelper, "PAINTING");
+        tPainting.setColumns("PAINTING_ID", "PAINTING_TITLE", "ARTIST_ID", "ESTIMATED_PRICE");
+    }
+
+    protected void createSingleArtistDataSet() throws Exception {
+        tArtist.insert(33001, "artist1");
+    }
+
+    protected void createFiveArtistDataSet_MixedCaseName() throws Exception {
+        tArtist.insert(33001, "artist1");
+        tArtist.insert(33002, "Artist3");
+        tArtist.insert(33003, "aRtist5");
+        tArtist.insert(33004, "arTist2");
+        tArtist.insert(33005, "artISt4");
+    }
+
+    protected void createGalleriesAndExhibitsDataSet() throws Exception {
+
+        tGallery.insert(33001, "gallery1");
+        tGallery.insert(33002, "gallery2");
+        tGallery.insert(33003, "gallery3");
+        tGallery.insert(33004, "gallery4");
+
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+
+        tExhibit.insert(1, 33001, now, now);
+        tExhibit.insert(2, 33002, now, now);
+    }
+
+    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, "artist11");
+        tArtist.insert(33007, "artist21");
+    }
+
+    protected void createArtistsAndPaintingsDataSet() throws Exception {
+        createArtistsDataSet();
+
+        tPainting.insert(33001, "P_artist1", 33001, 1000);
+        tPainting.insert(33002, "P_artist2", 33002, 2000);
+        tPainting.insert(33003, "P_artist3", 33003, 3000);
+        tPainting.insert(33004, "P_artist4", 33004, 4000);
+        tPainting.insert(33005, "P_artist5", 33005, 5000);
+        tPainting.insert(33006, "P_artist11", 33006, 11000);
+        tPainting.insert(33007, "P_artist21", 33007, 21000);
+    }
+
+    public void testCurrentSnapshot1() throws Exception {
+        createSingleArtistDataSet();
+
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        Artist artist = (Artist) context.performQuery(query).get(0);
+
+        DataRow snapshot = context.currentSnapshot(artist);
+        assertEquals(artist.getArtistName(), snapshot.get("ARTIST_NAME"));
+        assertEquals(artist.getDateOfBirth(), snapshot.get("DATE_OF_BIRTH"));
+    }
+
+    public void testCurrentSnapshot2() throws Exception {
+        createSingleArtistDataSet();
+
+        // test null values
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        Artist artist = (Artist) context.performQuery(query).get(0);
+
+        artist.setArtistName(null);
+        artist.setDateOfBirth(null);
+
+        DataRow snapshot = context.currentSnapshot(artist);
+        assertTrue(snapshot.containsKey("ARTIST_NAME"));
+        assertNull(snapshot.get("ARTIST_NAME"));
+
+        assertTrue(snapshot.containsKey("DATE_OF_BIRTH"));
+        assertNull(snapshot.get("DATE_OF_BIRTH"));
+    }
+
+    public void testCurrentSnapshot3() throws Exception {
+        createSingleArtistDataSet();
+
+        // test null values
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        Artist artist = (Artist) context.performQuery(query).get(0);
+
+        // test FK relationship snapshotting
+        Painting p1 = new Painting();
+        context.registerNewObject(p1);
+        p1.setToArtist(artist);
+
+        DataRow s1 = context.currentSnapshot(p1);
+        Map<String, Object> idMap = artist.getObjectId().getIdSnapshot();
+        assertEquals(idMap.get("ARTIST_ID"), s1.get("ARTIST_ID"));
+    }
+
+    /**
+     * Testing snapshot with to-one fault. This was a bug CAY-96.
+     */
+    public void testCurrentSnapshotWithToOneFault() throws Exception {
+
+        createGalleriesAndExhibitsDataSet();
+
+        // Exhibit with Gallery as Fault must still include Gallery
+        // Artist and Exhibit (Exhibit has unresolved to-one to gallery as in
+        // the
+        // CAY-96 bug report)
+
+        ObjectId eId = new ObjectId("Exhibit", Exhibit.EXHIBIT_ID_PK_COLUMN, 2);
+        Exhibit e = (Exhibit) context.performQuery(new ObjectIdQuery(eId)).get(0);
+
+        assertTrue(e.readPropertyDirectly(Exhibit.TO_GALLERY_PROPERTY) instanceof Fault);
+
+        DataRow snapshot = context.currentSnapshot(e);
+
+        // assert that after taking a snapshot, we have FK in, but the
+        // relationship
+        // is still a Fault
+        assertTrue(e.readPropertyDirectly(Exhibit.TO_GALLERY_PROPERTY) instanceof Fault);
+        assertEquals(new Integer(33002), snapshot.get("GALLERY_ID"));
+    }
+
+    /**
+     * Tests how CHAR field is handled during fetch. Some databases (Oracle...)
+     * would pad a CHAR column with extra spaces, returned to the client.
+     * Cayenne should trim it.
+     */
+    public void testCharFetch() throws Exception {
+        createSingleArtistDataSet();
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        Artist a = (Artist) context.performQuery(query).get(0);
+        assertEquals(a.getArtistName().trim(), a.getArtistName());
+    }
+
+    /**
+     * Tests how CHAR field is handled during fetch in the WHERE clause. Some
+     * databases (Oracle...) would pad a CHAR column with extra spaces, returned
+     * to the client. Cayenne should trim it.
+     */
+    public void testCharInQualifier() throws Exception {
+        createArtistsDataSet();
+
+        Expression e = ExpressionFactory.matchExp("artistName", "artist1");
+        SelectQuery q = new SelectQuery(Artist.class, e);
+        List<Artist> artists = context.performQuery(q);
+        assertEquals(1, artists.size());
+    }
+
+    /**
+     * Test fetching query with multiple relationship paths between the same 2
+     * entities used in qualifier.
+     */
+    public void testMultiObjRelFetch() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        SelectQuery q = new SelectQuery(Painting.class);
+        q.andQualifier(ExpressionFactory.matchExp("toArtist.artistName", "artist2"));
+        q.orQualifier(ExpressionFactory.matchExp("toArtist.artistName", "artist4"));
+        List<Painting> results = context.performQuery(q);
+
+        assertEquals(2, results.size());
+    }
+
+    /**
+     * Test fetching query with multiple relationship paths between the same 2
+     * entities used in qualifier.
+     */
+    public void testMultiDbRelFetch() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        SelectQuery q = new SelectQuery("Painting");
+        q.andQualifier(ExpressionFactory.matchDbExp("toArtist.ARTIST_NAME", "artist2"));
+        q.orQualifier(ExpressionFactory.matchDbExp("toArtist.ARTIST_NAME", "artist4"));
+        List<?> results = context.performQuery(q);
+
+        assertEquals(2, results.size());
+    }
+
+    public void testSelectDate() throws Exception {
+        createGalleriesAndExhibitsDataSet();
+
+        List<Exhibit> objects = context.performQuery(new SelectQuery(Exhibit.class));
+        assertFalse(objects.isEmpty());
+
+        Exhibit e1 = objects.get(0);
+        assertEquals(java.util.Date.class, e1.getClosingDate().getClass());
+    }
+
+    public void testCaseInsensitiveOrdering() throws Exception {
+        if (!accessStackAdapter.supportsCaseInsensitiveOrder()) {
+            return;
+        }
+
+        createFiveArtistDataSet_MixedCaseName();
+
+        // case insensitive ordering appends extra columns
+        // to the query when query is using DISTINCT...
+        // verify that the result is not messed up
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        Ordering ordering = new Ordering(Artist.ARTIST_NAME_PROPERTY, SortOrder.ASCENDING_INSENSITIVE);
+        query.addOrdering(ordering);
+        query.setDistinct(true);
+
+        List<Artist> objects = context.performQuery(query);
+        assertEquals(5, objects.size());
+
+        Artist artist = objects.get(0);
+        DataRow snapshot = context.getObjectStore().getSnapshot(artist.getObjectId());
+        assertEquals(3, snapshot.size());
+
+        // assert the ordering
+        assertEquals("artist1", objects.get(0).getArtistName());
+        assertEquals("arTist2", objects.get(1).getArtistName());
+        assertEquals("Artist3", objects.get(2).getArtistName());
+        assertEquals("artISt4", objects.get(3).getArtistName());
+        assertEquals("aRtist5", objects.get(4).getArtistName());
+    }
+
+    public void testSelect_DataRows() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        SelectQuery<DataRow> query = SelectQuery.dataRowQuery(Artist.class, null);
+        List<DataRow> objects = context.select(query);
+
+        assertNotNull(objects);
+        assertEquals(7, objects.size());
+        assertTrue("DataRow expected, got " + objects.get(0).getClass(), objects.get(0) instanceof DataRow);
+    }
+
+    public void testPerformSelectQuery1() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(7, objects.size());
+        assertTrue("Artist expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Artist);
+    }
+
+    public void testPerformSelectQuery2() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        // do a query with complex qualifier
+        List<Expression> expressions = new ArrayList<Expression>();
+        expressions.add(ExpressionFactory.matchExp("artistName", "artist3"));
+        expressions.add(ExpressionFactory.matchExp("artistName", "artist5"));
+        expressions.add(ExpressionFactory.matchExp("artistName", "artist21"));
+
+        SelectQuery query = new SelectQuery(Artist.class, ExpressionFactory.joinExp(Expression.OR, expressions));
+
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(3, objects.size());
+        assertTrue("Artist expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Artist);
+    }
+
+    public void testPerformQuery_Routing() {
+        Query query = mock(Query.class);
+        QueryMetadata md = mock(QueryMetadata.class);
+        when(query.getMetaData(any(EntityResolver.class))).thenReturn(md);
+        context.performGenericQuery(query);
+        verify(query).route(any(QueryRouter.class), eq(context.getEntityResolver()), (Query) isNull());
+    }
+
+    public void testPerformNonSelectingQuery() throws Exception {
+
+        createSingleArtistDataSet();
+
+        SelectQuery select = new SelectQuery(Painting.class, Expression.fromString("db:PAINTING_ID = 1"));
+
+        assertEquals(0, context.performQuery(select).size());
+
+        SQLTemplate query = new SQLTemplate(Painting.class,
+                "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
+                        + "VALUES (1, 'PX', 33001, 1)");
+        context.performNonSelectingQuery(query);
+        assertEquals(1, context.performQuery(select).size());
+    }
+
+    public void testPerformNonSelectingQueryCounts1() throws Exception {
+        createArtistsDataSet();
+
+        SQLTemplate query = new SQLTemplate(Painting.class,
+                "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
+                        + "VALUES ($pid, '$pt', $aid, $price)");
+
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("pid", new Integer(1));
+        map.put("pt", "P1");
+        map.put("aid", new Integer(33002));
+        map.put("price", new Double(1.1));
+
+        // single batch of parameters
+        query.setParameters(map);
+
+        int[] counts = context.performNonSelectingQuery(query);
+        assertNotNull(counts);
+        assertEquals(1, counts.length);
+        assertEquals(1, counts[0]);
+    }
+
+    public void testPerformNonSelectingQueryCounts2() throws Exception {
+
+        createArtistsDataSet();
+
+        SQLTemplate query = new SQLTemplate(Painting.class,
+                "INSERT INTO PAINTING (PAINTING_ID, PAINTING_TITLE, ARTIST_ID, ESTIMATED_PRICE) "
+                        + "VALUES ($pid, '$pt', $aid, #bind($price 'DECIMAL' 2))");
+
+        Map<String, Object>[] maps = new Map[3];
+        for (int i = 0; i < maps.length; i++) {
+            maps[i] = new HashMap<String, Object>();
+            maps[i].put("pid", new Integer(1 + i));
+            maps[i].put("pt", "P-" + i);
+            maps[i].put("aid", new Integer(33002));
+            maps[i].put("price", new BigDecimal("1." + i));
+        }
+
+        // single batch of parameters
+        query.setParameters(maps);
+
+        int[] counts = context.performNonSelectingQuery(query);
+        assertNotNull(counts);
+        assertEquals(maps.length, counts.length);
+        for (int i = 0; i < maps.length; i++) {
+            assertEquals(1, counts[i]);
+        }
+
+        SQLTemplate delete = new SQLTemplate(Painting.class, "delete from PAINTING");
+        counts = context.performNonSelectingQuery(delete);
+        assertNotNull(counts);
+        assertEquals(1, counts.length);
+        assertEquals(3, counts[0]);
+    }
+
+    public void testPerformPaginatedQuery() throws Exception {
+        createArtistsDataSet();
+
+        SelectQuery<Artist> query = SelectQuery.query(Artist.class);
+        query.setPageSize(5);
+        List<Artist> objects = context.select(query);
+        assertNotNull(objects);
+        assertTrue(objects instanceof IncrementalFaultList<?>);
+        assertTrue(((IncrementalFaultList<Artist>) objects).elements.get(0) instanceof Long);
+        assertTrue(((IncrementalFaultList<Artist>) objects).elements.get(6) instanceof Long);
+
+        assertTrue(objects.get(0) instanceof Artist);
+    }
+
+    public void testPerformPaginatedQuery1() throws Exception {
+        createArtistsDataSet();
+
+        EJBQLQuery query = new EJBQLQuery("select a FROM Artist a");
+        query.setPageSize(5);
+        List<?> objects = context.performQuery(query);
+        assertNotNull(objects);
+        assertTrue(objects instanceof IncrementalFaultList<?>);
+        assertTrue(((IncrementalFaultList<?>) objects).elements.get(0) instanceof Long);
+        assertTrue(((IncrementalFaultList<?>) objects).elements.get(6) instanceof Long);
+
+        assertTrue(objects.get(0) instanceof Artist);
+    }
+
+    public void testPerformPaginatedQueryBigPage() throws Exception {
+        createArtistsDataSet();
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        query.setPageSize(5);
+        final List<?> objects = context.performQuery(query);
+        assertNotNull(objects);
+        assertTrue(objects instanceof IncrementalFaultList<?>);
+
+        queryInterceptor.runWithQueriesBlocked(new UnitTestClosure() {
+
+            public void execute() {
+                assertEquals(7, objects.size());
+            }
+        });
+    }
+
+    public void testPerformDataRowQuery() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery query = new SelectQuery(Artist.class);
+        query.setFetchingDataRows(true);
+        List<?> objects = context.performQuery(query);
+
+        assertNotNull(objects);
+        assertEquals(7, objects.size());
+        assertTrue("Map expected, got " + objects.get(0).getClass(), objects.get(0) instanceof Map<?, ?>);
+    }
+
+    public void testCommitChangesRO1() throws Exception {
+
+        ROArtist a1 = (ROArtist) context.newObject("ROArtist");
+        a1.writePropertyDirectly("artistName", "abc");
+        a1.setPersistenceState(PersistenceState.MODIFIED);
+
+        try {
+            context.commitChanges();
+            fail("Inserting a 'read-only' object must fail.");
+        } catch (Exception ex) {
+            // exception is expected,
+            // must blow on saving new "read-only" object.
+        }
+    }
+
+    public void testCommitChangesRO2() throws Exception {
+        createArtistsDataSet();
+
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
+        a1.writeProperty(ROArtist.ARTIST_NAME_PROPERTY, "abc");
+
+        try {
+            context.commitChanges();
+            fail("Updating a 'read-only' object must fail.");
+        } catch (Exception ex) {
+            // exception is expected,
+            // must blow on saving new "read-only" object.
+        }
+    }
+
+    public void testCommitChangesRO3() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
+        context.deleteObjects(a1);
+
+        try {
+            context.commitChanges();
+            fail("Deleting a 'read-only' object must fail.");
+        } catch (Exception ex) {
+            // exception is expected,
+            // must blow on saving new "read-only" object.
+        }
+    }
+
+    public void testCommitChangesRO4() throws Exception {
+        createArtistsDataSet();
+
+        SelectQuery query = new SelectQuery(ROArtist.class, ExpressionFactory.matchExp(Artist.ARTIST_NAME_PROPERTY,
+                "artist1"));
+        ROArtist a1 = (ROArtist) context.performQuery(query).get(0);
+
+        Painting painting = context.newObject(Painting.class);
+        painting.setPaintingTitle("paint");
+        a1.addToPaintingArray(painting);
+
+        assertEquals(PersistenceState.MODIFIED, a1.getPersistenceState());
+        try {
+            context.commitChanges();
+        } catch (Exception ex) {
+            fail("Updating 'read-only' object's to-many must succeed, instead an exception was thrown: " + ex);
+        }
+
+        assertEquals(PersistenceState.COMMITTED, a1.getPersistenceState());
+    }
+
+	public void testIterate() throws Exception {
+
+		createArtistsDataSet();
+
+		SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class);
+		
+		final int[] count = new int[1];
+		
+		context.iterate(q1, new ResultIteratorCallback<Artist>() {
+
+			@Override
+			public void next(Artist object) {
+				assertNotNull(object.getArtistName());
+				count[0]++;
+			}
+		});
+		
+		 assertEquals(7, count[0]);
+	}
+
+    public void testIterateDataRows() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery<DataRow> q1 = SelectQuery.dataRowQuery(Artist.class, null);
+        final int[] count = new int[1];
+        
+        context.iterate(q1, new ResultIteratorCallback<DataRow>() {
+        	
+        	@Override
+        	public void next(DataRow object) {
+        		 assertNotNull(object.get("ARTIST_ID"));
+                 count[0]++;
+        	}
+        });
+        
+        assertEquals(7, count[0]);
+    }
+
+    public void testIterator() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class);
+
+        ResultIterator<Artist> it = context.iterator(q1);
+        try {
+            int count = 0;
+
+            for (Artist a : it) {
+                count++;
+            }
+
+            assertEquals(7, count);
+        } finally {
+            it.close();
+        }
+    }
+
+    public void testPerformIteratedQuery1() throws Exception {
+
+        createArtistsDataSet();
+
+        SelectQuery<Artist> q1 = new SelectQuery<Artist>(Artist.class);
+        ResultIterator<?> it = context.performIteratedQuery(q1);
+
+        try {
+            int count = 0;
+            while (it.hasNextRow()) {
+                it.nextRow();
+                count++;
+            }
+
+            assertEquals(7, count);
+        } finally {
+            it.close();
+        }
+    }
+
+    public void testPerformIteratedQuery2() throws Exception {
+        createArtistsAndPaintingsDataSet();
+
+        ResultIterator it = context.performIteratedQuery(new SelectQuery(Artist.class));
+
+        // just for this test increase pool size
+        changeMaxConnections(1);
+
+        try {
+            while (it.hasNextRow()) {
+                DataRow row = (DataRow) it.nextRow();
+
+                // try instantiating an object and fetching its relationships
+                Artist artist = context.objectFromDataRow(Artist.class, row);
+                List<?> paintings = artist.getPaintingArray();
+                assertNotNull(paintings);
+                assertEquals("Expected one painting for artist: " + artist, 1, paintings.size());
+            }
+        } finally {
+            // change allowed connections back
+            changeMaxConnections(-1);
+            it.close();
+        }
+    }
+
+    /**
+     * Tests that hasChanges performs correctly when an object is "modified" and
+     * the property is simply set to the same value (an unreal modification)
+     */
+    public void testHasChangesPhantom() {
+
+        String artistName = "ArtistName";
+        Artist artist = (Artist) context.newObject("Artist");
+        artist.setArtistName(artistName);
+        context.commitChanges();
+
+        // Set again to *exactly* the same value
+        artist.setArtistName(artistName);
+
+        // note that since 1.2 the polciy is for hasChanges to return true for
+        // phantom
+        // modifications, as there is no way to detect some more subtle
+        // modifications like
+        // a change of the master related object, until we actually create the
+        // PKs
+        assertTrue(context.hasChanges());
+    }
+
+    /**
+     * Tests that hasChanges performs correctly when an object is "modified" and
+     * the property is simply set to the same value (an unreal modification)
+     */
+    public void testHasChangesRealModify() {
+        Artist artist = (Artist) context.newObject("Artist");
+        artist.setArtistName("ArtistName");
+        context.commitChanges();
+
+        artist.setArtistName("Something different");
+        assertTrue(context.hasChanges());
+    }
+
+    public void testInvalidateObjects_Vararg() throws Exception {
+
+        DataRow row = new DataRow(10);
+        row.put("ARTIST_ID", new Integer(1));
+        row.put("ARTIST_NAME", "ArtistXYZ");
+        row.put("DATE_OF_BIRTH", new Date());
+        DataObject object = context.objectFromDataRow(Artist.class, row);
+        ObjectId oid = object.getObjectId();
+
+        // insert object into the ObjectStore
+        context.getObjectStore().registerNode(oid, object);
+
+        assertSame(object, context.getObjectStore().getNode(oid));
+        assertNotNull(context.getObjectStore().getCachedSnapshot(oid));
+
+        context.invalidateObjects(object);
+
+        assertSame(oid, object.getObjectId());
+        assertNull(context.getObjectStore().getCachedSnapshot(oid));
+        assertSame(object, context.getObjectStore().getNode(oid));
+    }
+
+    public void testInvalidateObjects() throws Exception {
+
+        DataRow row = new DataRow(10);
+        row.put("ARTIST_ID", new Integer(1));
+        row.put("ARTIST_NAME", "ArtistXYZ");
+        row.put("DATE_OF_BIRTH", new Date());
+        DataObject object = context.objectFromDataRow(Artist.class, row);
+        ObjectId oid = object.getObjectId();
+
+        // insert object into the ObjectStore
+        context.getObjectStore().registerNode(oid, object);
+
+        assertSame(object, context.getObjectStore().getNode(oid));
+        assertNotNull(context.getObjectStore().getCachedSnapshot(oid));
+
+        context.invalidateObjects(Collections.singleton(object));
+
+        assertSame(oid, object.getObjectId());
+        assertNull(context.getObjectStore().getCachedSnapshot(oid));
+        assertSame(object, context.getObjectStore().getNode(oid));
+    }
+
+    public void testBeforeHollowDeleteShouldChangeStateToCommited() throws Exception {
+        createSingleArtistDataSet();
+
+        Artist hollow = Cayenne.objectForPK(context, Artist.class, 33001);
+        context.invalidateObjects(hollow);
+        assertEquals(PersistenceState.HOLLOW, hollow.getPersistenceState());
+
+        // testing this...
+        context.deleteObjects(hollow);
+        assertSame(hollow, context.getGraphManager().getNode(new ObjectId("Artist", "ARTIST_ID", 33001)));
+        assertEquals("artist1", hollow.getArtistName());
+
+        assertEquals(PersistenceState.DELETED, hollow.getPersistenceState());
+    }
+
+    public void testCommitUnchangedInsert() throws Exception {
+
+        // see CAY-1444 - reproducible on DB's that support auto incremented PK
+
+        NullTestEntity newObject = context.newObject(NullTestEntity.class);
+
+        assertTrue(context.hasChanges());
+        context.commitChanges();
+        assertFalse(context.hasChanges());
+
+        assertEquals(PersistenceState.COMMITTED, newObject.getPersistenceState());
+    }
+
+    private void changeMaxConnections(int delta) {
+        PoolManager manager = (PoolManager) dataSourceFactory.getSharedDataSource();
+        manager.setMaxConnections(manager.getMaxConnections() + delta);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesIT.java
new file mode 100644
index 0000000..b6ba8ee
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesIT.java
@@ -0,0 +1,115 @@
+/*****************************************************************
+ *   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.ObjectContext;
+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.testmap.Artist;
+import org.apache.cayenne.testdo.testmap.Gallery;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+
+import java.sql.Timestamp;
+import java.util.List;
+
+@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
+public class DataContextJoinAliasesIT extends ServerCase {
+    
+    @Inject
+    ObjectContext context;
+    
+    @Inject
+    DBHelper dbHelper;
+    
+    protected TableHelper tArtist;
+    protected TableHelper tExhibit;
+    protected TableHelper tGallery;
+    protected TableHelper tArtistExhibit;
+
+    @Override
+    public void setUpAfterInjection() throws Exception {
+        dbHelper.deleteAll("ARTIST_EXHIBIT");
+        dbHelper.deleteAll("EXHIBIT");
+        dbHelper.deleteAll("GALLERY");
+        dbHelper.deleteAll("ARTIST");
+        
+        tArtist = new TableHelper(dbHelper, "ARTIST");
+        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+        
+        tExhibit = new TableHelper(dbHelper, "EXHIBIT");
+        tExhibit.setColumns("EXHIBIT_ID", "GALLERY_ID", "OPENING_DATE", "CLOSING_DATE");
+        
+        tGallery = new TableHelper(dbHelper, "GALLERY");
+        tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
+        
+        tArtistExhibit = new TableHelper(dbHelper, "ARTIST_EXHIBIT");
+        tArtistExhibit.setColumns("EXHIBIT_ID", "ARTIST_ID");
+    }
+    
+    protected void createMatchAllDataSet() throws Exception {
+        tArtist.insert(1, "Picasso");
+        tArtist.insert(2, "Dali");
+        tArtist.insert(3, "X");
+        tArtist.insert(4, "Y");
+        tGallery.insert(1, "G1");
+        tGallery.insert(2, "G2");
+        tGallery.insert(3, "G3");
+        
+        Timestamp now = new Timestamp(System.currentTimeMillis());
+        
+        tExhibit.insert(1, 2, now, now);
+        tExhibit.insert(2, 2, now, now);
+        tExhibit.insert(3, 1, now, now);
+        tExhibit.insert(4, 1, now, now);
+        tExhibit.insert(5, 3, now, now);
+        
+        tArtistExhibit.insert(1, 1);
+        tArtistExhibit.insert(1, 3);
+        tArtistExhibit.insert(3, 1);
+        tArtistExhibit.insert(4, 2);
+        tArtistExhibit.insert(4, 4);
+        tArtistExhibit.insert(5, 2);
+    }
+
+    public void testMatchAll() throws Exception {
+        // select all galleries that have exhibits by both Picasso and Dali...
+
+        createMatchAllDataSet();
+
+        Artist picasso = Cayenne.objectForPK(context, Artist.class, 1);
+        Artist dali = Cayenne.objectForPK(context, Artist.class, 2);
+
+        SelectQuery query = new SelectQuery(Gallery.class);
+        query.andQualifier(ExpressionFactory.matchAllExp(
+                "|exhibitArray.artistExhibitArray.toArtist",
+                picasso,
+                dali));
+
+        List<Gallery> galleries = context.performQuery(query);
+
+        assertEquals(1, galleries.size());
+        assertEquals("G1", galleries.get(0).getGalleryName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e42c376c/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesTest.java b/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesTest.java
deleted file mode 100644
index a65427a..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/DataContextJoinAliasesTest.java
+++ /dev/null
@@ -1,115 +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.Timestamp;
-import java.util.List;
-
-import org.apache.cayenne.Cayenne;
-import org.apache.cayenne.ObjectContext;
-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.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Gallery;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-
-@UseServerRuntime(ServerCase.TESTMAP_PROJECT)
-public class DataContextJoinAliasesTest extends ServerCase {
-    
-    @Inject
-    ObjectContext context;
-    
-    @Inject
-    DBHelper dbHelper;
-    
-    protected TableHelper tArtist;
-    protected TableHelper tExhibit;
-    protected TableHelper tGallery;
-    protected TableHelper tArtistExhibit;
-
-    @Override
-    public void setUpAfterInjection() throws Exception {
-        dbHelper.deleteAll("ARTIST_EXHIBIT");
-        dbHelper.deleteAll("EXHIBIT");
-        dbHelper.deleteAll("GALLERY");
-        dbHelper.deleteAll("ARTIST");
-        
-        tArtist = new TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
-        
-        tExhibit = new TableHelper(dbHelper, "EXHIBIT");
-        tExhibit.setColumns("EXHIBIT_ID", "GALLERY_ID", "OPENING_DATE", "CLOSING_DATE");
-        
-        tGallery = new TableHelper(dbHelper, "GALLERY");
-        tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
-        
-        tArtistExhibit = new TableHelper(dbHelper, "ARTIST_EXHIBIT");
-        tArtistExhibit.setColumns("EXHIBIT_ID", "ARTIST_ID");
-    }
-    
-    protected void createMatchAllDataSet() throws Exception {
-        tArtist.insert(1, "Picasso");
-        tArtist.insert(2, "Dali");
-        tArtist.insert(3, "X");
-        tArtist.insert(4, "Y");
-        tGallery.insert(1, "G1");
-        tGallery.insert(2, "G2");
-        tGallery.insert(3, "G3");
-        
-        Timestamp now = new Timestamp(System.currentTimeMillis());
-        
-        tExhibit.insert(1, 2, now, now);
-        tExhibit.insert(2, 2, now, now);
-        tExhibit.insert(3, 1, now, now);
-        tExhibit.insert(4, 1, now, now);
-        tExhibit.insert(5, 3, now, now);
-        
-        tArtistExhibit.insert(1, 1);
-        tArtistExhibit.insert(1, 3);
-        tArtistExhibit.insert(3, 1);
-        tArtistExhibit.insert(4, 2);
-        tArtistExhibit.insert(4, 4);
-        tArtistExhibit.insert(5, 2);
-    }
-
-    public void testMatchAll() throws Exception {
-        // select all galleries that have exhibits by both Picasso and Dali...
-
-        createMatchAllDataSet();
-
-        Artist picasso = Cayenne.objectForPK(context, Artist.class, 1);
-        Artist dali = Cayenne.objectForPK(context, Artist.class, 2);
-
-        SelectQuery query = new SelectQuery(Gallery.class);
-        query.andQualifier(ExpressionFactory.matchAllExp(
-                "|exhibitArray.artistExhibitArray.toArtist",
-                picasso,
-                dali));
-
-        List<Gallery> galleries = context.performQuery(query);
-
-        assertEquals(1, galleries.size());
-        assertEquals("G1", galleries.get(0).getGalleryName());
-    }
-
-}