/*******************************************************************************
 * Copyright (c) 2005, 2009 SAP. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     SAP - initial API and implementation
 ******************************************************************************/

package org.eclipse.persistence.testing.tests.wdf.jpa1.entitymanager;

import java.sql.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;

import org.eclipse.persistence.testing.framework.wdf.Bugzilla;
import org.eclipse.persistence.testing.framework.wdf.JPAEnvironment;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Cubicle;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Department;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Employee;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Project;
import org.eclipse.persistence.testing.models.wdf.jpa1.employee.Review;
import org.eclipse.persistence.testing.models.wdf.jpa1.node.Node;
import org.eclipse.persistence.testing.tests.wdf.jpa1.JPA1Base;
import org.junit.Test;

public class TestFlush extends JPA1Base {

    /*
     * For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade
     * element value cascade=PERSIST or cascade=ALL: <p> If Y is new or removed, an IllegalStateException will be thrown by the
     * flush operation (and the transaction rolled back) or the transaction commit will fail.
     */
    @Test
    public void testRelationshipToNew() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            // case 1: direct relationship Employee -> Cubicle (new) - 1:1
            Department dep = new Department(1, "dep");
            Employee emp1 = new Employee(2, "first", "last", dep);
            Cubicle cub1 = new Cubicle(new Integer(3), new Integer(3), "color", emp1);
            emp1.setCubicle(cub1);
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            boolean flushFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushFailed, "flush succeeded although there is a relation to an unmanaged entity");
            // case 2: direct relationship Employee -> Project (new) - n:m
            dep = new Department(4, "dep");
            emp1 = new Employee(5, "first", "last", dep);
            Project proj = new Project("project");
            Set<Project> emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            Set<Employee> projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            flushFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushFailed, "flush succeeded although there is a relation to an unmanaged entity");
            // case 3: indirect relationship Employee -> Project -> Employee (new)
            dep = new Department(7, "dep");
            emp1 = new Employee(8, "first1", "last1", dep);
            Employee emp2 = new Employee(9, "first2", "last2", dep);
            proj = new Project("project");
            emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            Set<Project> emp2Projects = new HashSet<Project>();
            emp2Projects.add(proj);
            emp2.setProjects(emp2Projects);
            projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            projEmployees.add(emp2);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            em.persist(proj);
            flushFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushFailed, "flush succeeded although there is a relation to an unmanaged entity");
        } finally {
            closeEntityManager(em);
        }
    }

    /*
     * For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade
     * element value cascade=PERSIST or cascade=ALL: <p> If Y is new or removed, an IllegalStateException will be thrown by the
     * flush operation (and the transaction rolled back) or the transaction commit will fail.
     */
    @SuppressWarnings("unchecked")
    @Test
    @Bugzilla(bugid=317760)
    public void testRelationshipToRemoved() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            // case 1: direct relationship Employee -> Cubicle (FOR_DELETE) - 1:1
            Department dep = new Department(101, "dep");
            Employee emp1 = new Employee(102, "first", "last", dep);
            Cubicle cub1 = new Cubicle(new Integer(103), new Integer(103), "color", emp1);
            emp1.setCubicle(cub1);
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            em.persist(cub1);
            env.commitTransactionAndClear(em);
            
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            cub1 = em.find(Cubicle.class, cub1.getId());
            cub1.setEmployee(null); // added as suggested by Tom
            em.remove(cub1);
            boolean flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to a removed entity");
            em.clear();
            // case 2: direct relationship Employee -> Project (FOR_DELETE) - n:m
            dep = new Department(104, "dep");
            emp1 = new Employee(105, "first", "last", dep);
            Project proj = new Project("project");
            Set<Project> emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            Set<Employee> projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(proj);
            em.persist(dep);
            em.persist(emp1);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            proj = em.find(Project.class, proj.getId());
            emp1.getProjects().size();
            em.remove(proj);
            flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to an unmanaged entity");
            em.clear();
            // case 3: indirect relationship Employee -> Project -> Employee (FOR_DELETE)
            dep = new Department(107, "dep");
            emp1 = new Employee(108, "first1", "last1", dep);
            Employee emp2 = new Employee(109, "first2", "last2", dep);
            proj = new Project("project");
            emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            Set<Project> emp2Projects = new HashSet<Project>();
            emp2Projects.add(proj);
            emp2.setProjects(emp2Projects);
            projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            projEmployees.add(emp2);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(proj);
            em.persist(dep);
            em.persist(emp1);
            em.persist(emp2);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            emp2 = em.find(Employee.class, new Integer(emp2.getId()));
            proj = em.find(Project.class, proj.getId());
            emp1.getProjects().size();
            proj.getEmployees().size();
            em.remove(emp2);
            flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to an unmanaged entity");
            em.clear();
            // case 1b: direct relationship Employee -> Cubicle (DELETE_EXECUTED) - 1:1
            dep = new Department(111, "dep");
            emp1 = new Employee(112, "first", "last", dep);
            cub1 = new Cubicle(new Integer(113), new Integer(112), "color", emp1);
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            em.persist(cub1);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            cub1 = em.find(Cubicle.class, cub1.getId());
            em.remove(cub1);
            em.flush();
            emp1.setCubicle(cub1);
            flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to an unmanaged entity");
            em.clear();
            // case 2b: direct relationship Employee -> Project (DELETE_EXECUTED) - n:m
            dep = new Department(114, "dep");
            emp1 = new Employee(115, "first", "last", dep);
            proj = new Project("project");
            env.beginTransaction(em);
            em.persist(dep);
            em.persist(emp1);
            em.persist(proj);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            proj = em.find(Project.class, proj.getId());
            em.remove(proj);
            em.flush();
            emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to an unmanaged entity");
            em.clear();
            // case 3b: indirect relationship Employee -> Project -> Employee (DELETE_EXECUTED)
            dep = new Department(117, "dep");
            emp1 = new Employee(118, "first1", "last1", dep);
            emp2 = new Employee(119, "first2", "last2", dep);
            proj = new Project("project");
            emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(proj);
            em.persist(dep);
            em.persist(emp1);
            em.persist(emp2);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            emp2 = em.find(Employee.class, new Integer(emp2.getId()));
            proj = em.find(Project.class, proj.getId());
            emp1.getProjects().size();
            projEmployees = proj.getEmployees();
            projEmployees.size();
            em.remove(emp2);
            em.flush();
            emp2Projects = new HashSet<Project>();
            emp2Projects.add(proj);
            emp2.setProjects(emp2Projects);
            projEmployees.add(emp2);
            flushOrCommmitFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushOrCommmitFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushOrCommmitFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushOrCommmitFailed, "flush succeeded although there is a relation to an unmanaged entity");
            em.clear();
        } finally {
            closeEntityManager(em);
        }
    }

    /**
     * This test checks a special case that can occur with lazily loaded relationships:
     * <ul>
     * <li>Read Project proj1 and remove it.</li>
     * <li>Read Employee emp1 with relationship to proj1 (lazy loading).</li>
     * <li>Assign the set of emp1's projects to a new employee emp2 (forces implicit loading on flush).</li>
     * <li>Flush -> IllegalStateException expected because of relation emp2 -> proj1 (removed).</li>
     * </ul>
     */
    @Test
    @Bugzilla(bugid=317760)
    public void testRelationshipToRemovedLazy() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            // case 1: explicit flush
            Department dep = new Department(201, "dep");
            Employee emp1 = new Employee(202, "first", "last", dep);
            Project proj = new Project("project");
            Set<Project> emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            Set<Employee> projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(proj);
            em.persist(dep);
            em.persist(emp1);
            env.commitTransactionAndClear(em);
            
            env.beginTransaction(em);
            dep = em.find(Department.class, new Integer(dep.getId()));
            proj = em.find(Project.class, proj.getId());
            em.remove(proj);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            // copy all projects from emp1 to emp2 with out actually touching them
            Employee emp2 = new Employee(203, "aaa", "bbb", dep);
            proj.addEmployee(emp2); // added as suggested by Tom
            emp2.setProjects(emp1.getProjects());
            em.persist(emp2);
            boolean flushFailed = false;
            try {
                em.flush();
            } catch (IllegalStateException e) {
                // $JL-EXC$ this is expected behavior
                flushFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
                env.rollbackTransactionAndClear(em);
            }
            try {
                if (env.isTransactionActive(em)) {
                    env.commitTransactionAndClear(em);
                }
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushFailed, "flush succeeded although there is a relation to a removed entity");
            em.clear();
            // case 2: implicit flush during commit
            dep = new Department(204, "dep");
            emp1 = new Employee(205, "first", "last", dep);
            proj = new Project("project");
            emp1Projects = new HashSet<Project>();
            emp1Projects.add(proj);
            emp1.setProjects(emp1Projects);
            projEmployees = new HashSet<Employee>();
            projEmployees.add(emp1);
            proj.setEmployees(projEmployees);
            env.beginTransaction(em);
            em.persist(proj);
            em.persist(dep);
            em.persist(emp1);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            dep = em.find(Department.class, new Integer(dep.getId()));
            proj = em.find(Project.class, proj.getId());
            em.remove(proj);
            emp1 = em.find(Employee.class, new Integer(emp1.getId()));
            // copy all projects from emp1 to emp2 with out actually touching them
            emp2 = new Employee(206, "aaa", "bbb", dep);
            emp2.setProjects(emp1.getProjects());
            em.persist(emp2);
            flushFailed = false;
            try {
                env.commitTransactionAndClear(em);
            } catch (RuntimeException e) {
                if (!checkForIllegalStateException(e)) {
                    throw e;
                }
                flushFailed = true;
            }
            verify(!env.isTransactionActive(em), "Transaction still active");
            verify(flushFailed, "flush succeeded although there is a relation to a removed entity");
            em.clear();
        } finally {
            closeEntityManager(em);
        }
    }

    /**
     * Force an exception during flush and check whether the current transaction is rolled back.
     */
    @Test
    public void testWithException() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            Node node = new Node(301, true); // PostPersist method will throw a Node.MyRuntimeException
            env.beginTransaction(em);
            em.persist(node);
            boolean flushFailed = false;
            try {
                em.flush();
            } catch (Node.MyRuntimeException e) {
                // $JL-EXC$ this is expected behavior
                flushFailed = true;
                verify(env.isTransactionMarkedForRollback(em),
                        "IllegalStateException during flush did not mark transaction for rollback");
            }
            verify(flushFailed, "callback method did not throw exception as expected");
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testRestoreFieldAfterFlush() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            final String initial = "initial";
            final int id = 301;
            Department department = new Department(id, initial);
            env.beginTransaction(em);
            em.persist(department);
            department.setName("changed");
            em.flush();
            // undo the change between flush and commit (on a new entity)
            department.setName(initial);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            department = em.find(Department.class, Integer.valueOf(id));
            verify(initial.equals(department.getName()), "wrong name: " + department.getName());
            department.setName("changed");
            em.flush();
            // lets try the same with a managed field
            department.setName(initial);
            env.commitTransactionAndClear(em);
            department = em.find(Department.class, Integer.valueOf(id));
            verify(initial.equals(department.getName()), "wrong name: " + department.getName());
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testRestoreRelationAfterFlush() {
        JPAEnvironment env = getEnvironment();
        EntityManager em = env.getEntityManager();
        try {
            final int id = 302;
            Employee frank = new Employee(id, "Frank", "Schuster", null);
            env.beginTransaction(em);
            Review r1 = new Review(101, Date.valueOf("2006-10-19"), "Performance");
            frank.addReview(r1);
            Review r2 = new Review(102, Date.valueOf("2006-10-19"), "Passion");
            frank.addReview(r2);
            Review r3 = new Review(103, Date.valueOf("2006-10-19"), "Six-Sigma");
            frank.addReview(r3);
            em.persist(frank);
            em.persist(r1);
            em.persist(r2);
            em.persist(r3);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            frank = em.find(Employee.class, Integer.valueOf(id));
            Set<Review> reviewsFound = frank.getReviews();
            int foundSize = reviewsFound.size();
            // lets remove a department the same with a managed field
            Set<Review> set = new HashSet<Review>();
            set.add(r1);
            set.add(r2);
            frank.setReviews(set);
            em.flush();
            // undo the change
            frank.setReviews(reviewsFound);
            env.commitTransactionAndClear(em);
            env.beginTransaction(em);
            frank = em.find(Employee.class, Integer.valueOf(id));
            verify(frank.getReviews().size() == foundSize, "wrong number of reviews: " + frank.getReviews().size());
            env.rollbackTransactionAndClear(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    public void testNoTransaction() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        try {
            em.flush();
            flop("exception not thrown as expected");
        } catch (TransactionRequiredException e) {
            // $JL-EXC$ expected behavior
        } finally {
            closeEntityManager(em);
        }
    }

    @SuppressWarnings("unchecked")
    @Test
    public void testTransactionMarkedForRollback() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        Department dep = new Department(401, "dep401");
        try {
            env.beginTransaction(em);
            em.persist(dep);
            env.markTransactionForRollback(em);
            em.flush();
            // verify that entity is inserted
            Query query = em.createQuery("select d from Department d where d.id = ?1");
            query.setParameter(1, Integer.valueOf(dep.getId()));
            List<Department> result = query.getResultList();
            verify(result.size() == 1, "query returned " + result.size() + " entities");
            env.rollbackTransaction(em);
        } finally {
            closeEntityManager(em);
        }
    }

    @Test
    @Bugzilla(bugid=309681)
    public void testChangedEntityIgnoredByFlush() {
        final JPAEnvironment env = getEnvironment();
        final EntityManager em = env.getEntityManager();
        Employee emp = new Employee(911, "Robi", "Tobi", null);
        try {
            env.beginTransaction(em);
            em.persist(emp);
            env.commitTransactionAndClear(em);

            env.beginTransaction(em);
            Employee found = em.find(Employee.class, 911);
            found.clearPostUpdate();
            found.setLastName("lesbar");
            em.createQuery("select i from Island i").getResultList();
            verify(!found.postUpdateWasCalled(), "post update was called");
            env.rollbackTransactionAndClear(em);

        } finally {
            closeEntityManager(em);
        }
    }

}
