blob: 33ebe560614c1465ae6baa423fb2e4ced76dcb2e [file] [log] [blame]
/*
* 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.openjpa.persistence.exception;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.OptimisticLockException;
import javax.persistence.TransactionRequiredException;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.SQLErrorCodeReader;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
* Tests proper JPA exceptions are raised by the implementation.
* Actual runtime type of the raised exception is a subclass of JPA-defined
* exception.
* The raised exception may nest the expected exception.
*
* @author Pinaki Poddar
*/
public class TestException extends SingleEMFTestCase {
private static long ID_COUNTER = System.currentTimeMillis();
public void setUp() {
super.setUp(PObject.class, CLEAR_TABLES);
}
/**
* Tests that when Optimistic transaction consistency is violated, the
* exception thrown is an instance of javax.persistence.OptimisticException.
*/
public void testThrowsOptimisticException() {
EntityManager em1 = emf.createEntityManager();
EntityManager em2 = emf.createEntityManager();
assertNotEquals(em1, em2);
em1.getTransaction().begin();
PObject pc = new PObject();
long id = ++ID_COUNTER;
pc.setId(id);
em1.persist(pc);
em1.getTransaction().commit();
em1.clear();
em1.getTransaction().begin();
em2.getTransaction().begin();
PObject pc1 = em1.find(PObject.class, id);
PObject pc2 = em2.find(PObject.class, id);
assertTrue(pc1 != pc2);
pc1.setName("Modified in TXN1");
em1.flush();
try {
pc2.setName("Modified in TXN2");
em2.flush();
fail("Expected " + OptimisticLockException.class);
} catch (Throwable t) {
assertException(t, OptimisticLockException.class);
}
em1.getTransaction().commit();
try {
em2.getTransaction().commit();
fail("Expected " + OptimisticLockException.class);
} catch (Throwable t) {
assertException(t, OptimisticLockException.class);
}
}
public void testThrowsEntityExistsException() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
PObject pc = new PObject();
long id = ++ID_COUNTER;
pc.setId(id);
em.persist(pc);
em.getTransaction().commit();
em.clear();
em.getTransaction().begin();
PObject pc2 = new PObject();
pc2.setId(id);
em.persist(pc2);
try {
em.getTransaction().commit();
fail("Expected " + EntityExistsException.class);
} catch (Throwable t) {
assertException(t, EntityExistsException.class);
}
}
public void testThrowsEntityNotFoundException() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
PObject pc = new PObject();
long id = ++ID_COUNTER;
pc.setId(id);
em.persist(pc);
em.getTransaction().commit();
EntityManager em2 = emf.createEntityManager();
em2.getTransaction().begin();
PObject pc2 = em2.find(PObject.class, id);
assertNotNull(pc2);
em2.remove(pc2);
em2.getTransaction().commit();
try {
em.refresh(pc);
fail("Expected " + EntityNotFoundException.class);
} catch (Throwable t) {
assertException(t, EntityNotFoundException.class);
}
}
public void testErrorCodeConfigurationHasAllKnownDictionaries() {
SQLErrorCodeReader reader = new SQLErrorCodeReader();
InputStream in = DBDictionary.class.getResourceAsStream
("sql-error-state-codes.xml");
assertNotNull(in);
List<String> names = reader.getDictionaries(in);
assertTrue(names.size()>=18);
for (String name:names) {
try {
Class.forName(name, false, Thread.currentThread()
.getContextClassLoader());
} catch (Throwable t) {
fail("DB dictionary " + name + " can not be loaded");
t.printStackTrace();
}
}
}
/**
* Asserts that the given expected type of the exception is equal to or a
* subclass of the given throwable or any of its nested exception.
* Otherwise fails assertion and prints the given throwable and its nested
* exception on the console.
*/
void assertException(Throwable t, Class expectedType) {
if (!isExpectedException(t, expectedType)) {
t.printStackTrace();
print(t, 0);
fail(t + " or its cause is not instanceof " + expectedType);
}
}
/**
* Affirms if the given expected type of the exception is equal to or a
* subclass of the given throwable or any of its nested exception.
*/
boolean isExpectedException(Throwable t, Class expectedType) {
if (t == null)
return false;
if (expectedType.isAssignableFrom(t.getClass()))
return true;
return isExpectedException(t.getCause(), expectedType);
}
void print(Throwable t, int tab) {
if (t == null) return;
for (int i=0; i<tab*4;i++) System.out.print(" ");
String sqlState = (t instanceof SQLException) ?
"(SQLState=" + ((SQLException)t).getSQLState() + ":"
+ t.getMessage() + ")" : "";
System.out.println(t.getClass().getName() + sqlState);
if (t.getCause() == t)
return;
print(t.getCause(), tab+1);
}
}