/* | |
* 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.conf; | |
import java.util.Properties; | |
import javax.persistence.EntityManager; | |
import javax.persistence.EntityManagerFactory; | |
import javax.persistence.Persistence; | |
import javax.persistence.PersistenceException; | |
import junit.framework.AssertionFailedError; | |
import junit.framework.TestCase; | |
import org.apache.openjpa.persistence.OpenJPAPersistence; | |
import org.apache.openjpa.util.UserException; | |
/** | |
* Verifies appropriate exception is thrown when an incorrect protocol or | |
* sub-protocol is specified in the JDBC URL. Per the JDBC specification, the | |
* Driver should return a null connection upon getConnection() when a bad driver | |
* is specified on the URL. OpenJPA must be able to handle this condition and | |
* return an appropriate message. | |
* | |
* OpenJPA JIRA: {@link http://issues.apache.org/jira/browse/OPENJPA-656} | |
* | |
* @author Jeremy Bauer | |
* @author Pinaki Poddar | |
* | |
*/ | |
public class TestBadJdbcUrl extends TestCase { | |
public static final String GOOD_URL = "jdbc:derby:target/database/openjpa-derby-database;create=true"; | |
public static final String GOOD_DRIVER = "org.apache.derby.jdbc.EmbeddedDriver"; | |
public static final String GOOD_DATASOURCE = "org.apache.commons.dbcp.BasicDataSource"; | |
public static final String BAD_DRIVER = "bad.driver"; | |
public static final String BAD_URL_PROTOCOL = "bad.url.protocol"; | |
public static final String BAD_URL_SUBPROTOCOL = "bad.url.sub.protocol"; | |
public static final String BAD_CONN_PROPS = "connectionUrl=bad,connectionDriver=bad"; | |
/* | |
* Test specifying URL with bad protocol but a valid Driver. | |
*/ | |
public void testBadUrlProtocolValueWithValidDriverClass() { | |
Properties p = new Properties(); | |
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER); | |
p.put("openjpa.ConnectionURL", BAD_URL_PROTOCOL); | |
verifyConnectException(p, PersistenceException.class, | |
UserException.class, GOOD_DRIVER, BAD_URL_PROTOCOL); | |
} | |
/* | |
* Test specifying URL with bad protocol but a valid DataSource. | |
*/ | |
public void testBadUrlProtocolValueWithValidDataSource() { | |
Properties p = new Properties(); | |
p.put("openjpa.ConnectionDriverName", GOOD_DATASOURCE); | |
p.put("openjpa.ConnectionURL", BAD_URL_PROTOCOL); | |
p.put("openjpa.ConnectionProperties", BAD_CONN_PROPS); | |
verifyConnectException(p, PersistenceException.class, | |
null, (String[])null); | |
} | |
/* | |
* Test specifying URL with bad sub-protocol but a valid Driver. | |
*/ | |
public void testBadUrlSubprotocolValueWithValidDriverClass() { | |
Properties p = new Properties(); | |
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER); | |
p.put("openjpa.ConnectionURL", BAD_URL_SUBPROTOCOL); | |
verifyConnectException(p, PersistenceException.class, | |
UserException.class, GOOD_DRIVER, BAD_URL_SUBPROTOCOL); | |
} | |
/* | |
* Test specifying URL with bad sub-protocol but a valid Driver. | |
*/ | |
public void testBadUrlSubprotocolValueWithValidDataSource() { | |
Properties p = new Properties(); | |
p.put("openjpa.ConnectionDriverName", GOOD_DRIVER); | |
p.put("openjpa.ConnectionURL", BAD_URL_SUBPROTOCOL); | |
verifyConnectException(p, PersistenceException.class, | |
UserException.class, GOOD_DRIVER, BAD_URL_SUBPROTOCOL); | |
} | |
/* | |
* Test specifying Valid URL with an invalid Driver. | |
*/ | |
public void testValidUrlWithInvalidDriver() { | |
Properties p = new Properties(); | |
p.put("openjpa.ConnectionDriverName", BAD_DRIVER); | |
p.put("openjpa.ConnectionURL", GOOD_URL); | |
verifyConnectException(p, PersistenceException.class, | |
UserException.class, GOOD_URL, BAD_DRIVER); | |
} | |
/** | |
* Attempts to connect with given properties and analyze exception for the | |
* existence of given target exception and error message strings. | |
* | |
* @param props | |
* the properties to initialize the persistence unit | |
* @param target | |
* the type expected exception to be raised. | |
* @param nested | |
* the type expected nested exception. null implies not to look | |
* for any. | |
* @param keys | |
* the strings that must occur in the exception message. | |
*/ | |
private void verifyConnectException(Properties props, Class targetType, | |
Class nestedType, String... keys) { | |
EntityManagerFactory emf = null; | |
EntityManager em = null; | |
try { | |
emf = Persistence.createEntityManagerFactory("test", props); | |
em = emf.createEntityManager(); | |
OpenJPAPersistence.cast(em).getConnection(); | |
fail("Should have caught a " + targetType.getName()); | |
} catch (Throwable t) { | |
assertException(t, targetType, nestedType); | |
assertMessage(t, keys); | |
} finally { | |
if (em != null) | |
em.close(); | |
if (emf != null) | |
emf.close(); | |
} | |
} | |
/** | |
* Asserts that the given targetType is assignable from actual. Asserts that | |
* the nestedType is a nested within the given actual Throwable | |
* | |
* @param actual | |
* @param targetType | |
* @param nestedType | |
*/ | |
void assertException(final Throwable actual, Class targetType, | |
Class nestedTargetType) { | |
if (targetType == null) | |
return; | |
assertNotNull(actual); | |
Class actualType = actual.getClass(); | |
if (!targetType.isAssignableFrom(actualType)) { | |
actual.printStackTrace(); | |
fail(targetType.getName() + " is not assignable from " | |
+ actualType.getName()); | |
} | |
if (nestedTargetType != null) { | |
Throwable nested = actual.getCause(); | |
Class nestedType = (nested == null) ? null : nested.getClass(); | |
while (nestedType != null) { | |
if (nestedType.isAssignableFrom(nestedTargetType)) { | |
return; | |
} else { | |
Throwable next = nested.getCause(); | |
if (next == null || next == nested) | |
break; | |
nestedType = next.getClass(); | |
nested = next; | |
} | |
} | |
actual.printStackTrace(); | |
fail("No nested type " + nestedTargetType + " in " + actual); | |
} | |
} | |
/** | |
* Assert that each of given keys are present in the message of the given | |
* Throwable. | |
*/ | |
void assertMessage(Throwable actual, String... keys) { | |
if (actual == null || keys == null) | |
return; | |
String message = actual.getMessage(); | |
for (String key : keys) { | |
assertTrue(key + " is not in " + message, message.contains(key)); | |
} | |
} | |
} |