/*
Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
this software, see the FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this
program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
Floor, Boston, MA 02110-1301 USA
*/
package testsuite.regression;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameParser;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
import testsuite.BaseTestCase;
import testsuite.simple.DataSourceTest;
import com.mysql.jdbc.ConnectionProperties;
import com.mysql.jdbc.NonRegisteringDriver;
import com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSourceFactory;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
/**
* Tests fixes for bugs related to datasources.
*
* @author Mark Matthews
*
* @version $Id: DataSourceRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38
* mmatthews Exp $
*/
public class DataSourceRegressionTest extends BaseTestCase {
public final static String DS_DATABASE_PROP_NAME = "com.mysql.jdbc.test.ds.db";
public final static String DS_HOST_PROP_NAME = "com.mysql.jdbc.test.ds.host";
public final static String DS_PASSWORD_PROP_NAME = "com.mysql.jdbc.test.ds.password";
public final static String DS_PORT_PROP_NAME = "com.mysql.jdbc.test.ds.port";
public final static String DS_USER_PROP_NAME = "com.mysql.jdbc.test.ds.user";
private Context ctx;
private File tempDir;
/**
* Creates a new DataSourceRegressionTest suite for the given test name
*
* @param name
* the name of the testcase to run.
*/
public DataSourceRegressionTest(String name) {
super(name);
}
/**
* Runs all test cases in this test suite
*
* @param args
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(DataSourceTest.class);
}
/**
* Sets up this test, calling registerDataSource() to bind a DataSource into
* JNDI, using the FSContext JNDI provider from Sun
*
* @throws Exception
* if an error occurs.
*/
public void setUp() throws Exception {
super.setUp();
createJNDIContext();
}
/**
* Un-binds the DataSource, and cleans up the filesystem
*
* @throws Exception
* if an error occurs
*/
public void tearDown() throws Exception {
this.ctx.unbind(this.tempDir.getAbsolutePath() + "/test");
this.ctx.unbind(this.tempDir.getAbsolutePath() + "/testNoUrl");
this.ctx.close();
this.tempDir.delete();
super.tearDown();
}
/**
* Tests fix for BUG#4808- Calling .close() twice on a PooledConnection
* causes NPE.
*
* @throws Exception
* if an error occurs.
*/
public void testBug4808() throws Exception {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setURL(BaseTestCase.dbUrl);
PooledConnection closeMeTwice = ds.getPooledConnection();
closeMeTwice.close();
closeMeTwice.close();
}
/**
* Tests fix for Bug#3848, port # alone parsed incorrectly
*
* @throws Exception
* ...
*/
public void testBug3848() throws Exception {
String jndiName = "/testBug3848";
String databaseName = System.getProperty(DS_DATABASE_PROP_NAME);
String userName = System.getProperty(DS_USER_PROP_NAME);
String password = System.getProperty(DS_PASSWORD_PROP_NAME);
String port = System.getProperty(DS_PORT_PROP_NAME);
// Only run this test if at least one of the above are set
if ((databaseName != null) || (userName != null) || (password != null)
|| (port != null)) {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
if (databaseName != null) {
ds.setDatabaseName(databaseName);
}
if (userName != null) {
ds.setUser(userName);
}
if (password != null) {
ds.setPassword(password);
}
if (port != null) {
ds.setPortNumber(Integer.parseInt(port));
}
bindDataSource(jndiName, ds);
ConnectionPoolDataSource boundDs = null;
try {
boundDs = (ConnectionPoolDataSource) lookupDatasourceInJNDI(jndiName);
assertTrue("Datasource not bound", boundDs != null);
Connection dsConn = null;
try {
dsConn = boundDs.getPooledConnection().getConnection();
} finally {
if (dsConn != null) {
dsConn.close();
}
}
} finally {
if (boundDs != null) {
this.ctx.unbind(jndiName);
}
}
}
}
/**
* Tests that we can get a connection from the DataSource bound in JNDI
* during test setup
*
* @throws Exception
* if an error occurs
*/
public void testBug3920() throws Exception {
String jndiName = "/testBug3920";
String databaseName = System.getProperty(DS_DATABASE_PROP_NAME);
String userName = System.getProperty(DS_USER_PROP_NAME);
String password = System.getProperty(DS_PASSWORD_PROP_NAME);
String port = System.getProperty(DS_PORT_PROP_NAME);
String serverName = System.getProperty(DS_HOST_PROP_NAME);
// Only run this test if at least one of the above are set
if ((databaseName != null) || (serverName != null)
|| (userName != null) || (password != null) || (port != null)) {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
if (databaseName != null) {
ds.setDatabaseName(databaseName);
}
if (userName != null) {
ds.setUser(userName);
}
if (password != null) {
ds.setPassword(password);
}
if (port != null) {
ds.setPortNumber(Integer.parseInt(port));
}
if (serverName != null) {
ds.setServerName(serverName);
}
bindDataSource(jndiName, ds);
ConnectionPoolDataSource boundDs = null;
try {
boundDs = (ConnectionPoolDataSource) lookupDatasourceInJNDI(jndiName);
assertTrue("Datasource not bound", boundDs != null);
Connection dsCon = null;
Statement dsStmt = null;
try {
dsCon = boundDs.getPooledConnection().getConnection();
dsStmt = dsCon.createStatement();
dsStmt.executeUpdate("DROP TABLE IF EXISTS testBug3920");
dsStmt
.executeUpdate("CREATE TABLE testBug3920 (field1 varchar(32))");
assertTrue(
"Connection can not be obtained from data source",
dsCon != null);
} finally {
dsStmt.executeUpdate("DROP TABLE IF EXISTS testBug3920");
dsStmt.close();
dsCon.close();
}
} finally {
if (boundDs != null) {
this.ctx.unbind(jndiName);
}
}
}
}
/**
* Tests fix for BUG#19169 - ConnectionProperties (and thus some
* subclasses) are not serializable, even though some J2EE containers
* expect them to be.
*
* @throws Exception if the test fails.
*/
public void testBug19169() throws Exception {
MysqlDataSource toSerialize = new MysqlDataSource();
toSerialize.setZeroDateTimeBehavior("convertToNull");
boolean testBooleanFlag = !toSerialize.getAllowLoadLocalInfile();
toSerialize.setAllowLoadLocalInfile(testBooleanFlag);
int testIntFlag = toSerialize.getBlobSendChunkSize() + 1;
toSerialize.setBlobSendChunkSize(String.valueOf(testIntFlag));
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream(bOut);
objOut.writeObject(toSerialize);
objOut.flush();
ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray()));
MysqlDataSource thawedDs = (MysqlDataSource)objIn.readObject();
assertEquals("convertToNull", thawedDs.getZeroDateTimeBehavior());
assertEquals(testBooleanFlag, thawedDs.getAllowLoadLocalInfile());
assertEquals(testIntFlag, thawedDs.getBlobSendChunkSize());
}
/**
* Tests fix for BUG#20242 - MysqlValidConnectionChecker for JBoss doesn't
* work with MySQLXADataSources.
*
* @throws Exception if the test fails.
*/
public void testBug20242() throws Exception {
if (versionMeetsMinimum(5, 0)) {
try {
Class.forName("org.jboss.resource.adapter.jdbc.ValidConnectionChecker");
} catch (Exception ex) {
return; // class not available for testing
}
MysqlXADataSource xaDs = new MysqlXADataSource();
xaDs.setUrl(dbUrl);
MysqlValidConnectionChecker checker = new MysqlValidConnectionChecker();
assertNull(checker.isValidConnection(xaDs.getXAConnection().getConnection()));
}
}
private void bindDataSource(String name, DataSource ds) throws Exception {
this.ctx.bind(this.tempDir.getAbsolutePath() + name, ds);
}
/**
* This method is separated from the rest of the example since you normally
* would NOT register a JDBC driver in your code. It would likely be
* configered into your naming and directory service using some GUI.
*
* @throws Exception
* if an error occurs
*/
private void createJNDIContext() throws Exception {
this.tempDir = File.createTempFile("jnditest", null);
this.tempDir.delete();
this.tempDir.mkdir();
this.tempDir.deleteOnExit();
MysqlConnectionPoolDataSource ds;
Hashtable<String, String> env = new Hashtable<String, String>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
this.ctx = new InitialContext(env);
assertTrue("Naming Context not created", this.ctx != null);
ds = new MysqlConnectionPoolDataSource();
ds.setUrl(dbUrl); // from BaseTestCase
ds.setDatabaseName("test");
this.ctx.bind(this.tempDir.getAbsolutePath() + "/test", ds);
}
private DataSource lookupDatasourceInJNDI(String jndiName) throws Exception {
NameParser nameParser = this.ctx.getNameParser("");
Name datasourceName = nameParser.parse(this.tempDir.getAbsolutePath()
+ jndiName);
Object obj = this.ctx.lookup(datasourceName);
DataSource boundDs = null;
if (obj instanceof DataSource) {
boundDs = (DataSource) obj;
} else if (obj instanceof Reference) {
//
// For some reason, this comes back as a Reference
// instance under CruiseControl !?
//
Reference objAsRef = (Reference) obj;
ObjectFactory factory = (ObjectFactory) Class.forName(
objAsRef.getFactoryClassName()).newInstance();
boundDs = (DataSource) factory.getObjectInstance(objAsRef,
datasourceName, this.ctx, new Hashtable<Object, Object>());
}
return boundDs;
}
public void testCSC4616() throws Exception {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setURL(BaseTestCase.dbUrl);
PooledConnection pooledConn = ds.getPooledConnection();
Connection physConn = pooledConn.getConnection();
Statement physStatement = physConn.createStatement();
Method enableStreamingResultsMethodStmt = Class.forName(
"com.mysql.jdbc.jdbc2.optional.StatementWrapper").getMethod(
"enableStreamingResults", new Class[0]);
enableStreamingResultsMethodStmt.invoke(physStatement, (Object[])null);
this.rs = physStatement.executeQuery("SELECT 1");
try {
physConn.createStatement().executeQuery("SELECT 2");
fail("Should have caught a streaming exception here");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage() != null
&& sqlEx.getMessage().indexOf("Streaming") != -1);
} finally {
if (this.rs != null) {
this.rs.close();
this.rs = null;
}
}
PreparedStatement physPrepStmt = physConn.prepareStatement("SELECT 1");
Method enableStreamingResultsMethodPstmt = Class.forName(
"com.mysql.jdbc.jdbc2.optional.PreparedStatementWrapper")
.getMethod("enableStreamingResults", (Class[])null);
enableStreamingResultsMethodPstmt.invoke(physPrepStmt, (Object[])null);
this.rs = physPrepStmt.executeQuery();
try {
physConn.createStatement().executeQuery("SELECT 2");
fail("Should have caught a streaming exception here");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage() != null
&& sqlEx.getMessage().indexOf("Streaming") != -1);
} finally {
if (this.rs != null) {
this.rs.close();
this.rs = null;
}
}
}
/**
* Tests fix for BUG#16791 - NullPointerException in MysqlDataSourceFactory
* due to Reference containing RefAddrs with null content.
*
* @throws Exception if the test fails
*/
public void testBug16791() throws Exception {
MysqlDataSource myDs = new MysqlDataSource();
myDs.setUrl(dbUrl);
Reference asRef = myDs.getReference();
System.out.println(asRef);
removeFromRef(asRef, "port");
removeFromRef(asRef, NonRegisteringDriver.USER_PROPERTY_KEY);
removeFromRef(asRef, NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
removeFromRef(asRef, "serverName");
removeFromRef(asRef, "databaseName");
//MysqlDataSource newDs = (MysqlDataSource)
new MysqlDataSourceFactory().getObjectInstance(asRef, null, null, null);
}
private void removeFromRef(Reference ref, String key) {
int size = ref.size();
for (int i = 0; i < size; i++) {
RefAddr refAddr = ref.get(i);
if (refAddr.getType().equals(key)) {
ref.remove(i);
break;
}
}
}
/**
* Tests fix for BUG#32101 - When using a connection from our ConnectionPoolDataSource,
* some Connection.prepareStatement() methods would return null instead of
* a prepared statement.
*
* @throws Exception
*/
public void testBug32101() throws Exception {
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setURL(BaseTestCase.dbUrl);
PooledConnection pc = ds.getPooledConnection();
assertNotNull(pc.getConnection().prepareStatement("SELECT 1"));
assertNotNull(pc.getConnection().prepareStatement("SELECT 1", Statement.RETURN_GENERATED_KEYS));
assertNotNull(pc.getConnection().prepareStatement("SELECT 1", new int[0]));
assertNotNull(pc.getConnection().prepareStatement("SELECT 1", new String[0]));
assertNotNull(pc.getConnection().prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY));
assertNotNull(pc.getConnection().prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT));
}
public void testBug35810() throws Exception {
int defaultConnectTimeout = ((ConnectionProperties) this.conn).getConnectTimeout();
int nonDefaultConnectTimeout = defaultConnectTimeout + 1000 * 2;
MysqlConnectionPoolDataSource cpds = new MysqlConnectionPoolDataSource();
String dsUrl = BaseTestCase.dbUrl;
if (dsUrl.indexOf("?") == -1) {
dsUrl += "?";
} else {
dsUrl += "&";
}
dsUrl += "connectTimeout=" + nonDefaultConnectTimeout;
cpds.setUrl(dsUrl);
Connection dsConn = cpds.getPooledConnection().getConnection();
int configuredConnectTimeout = ((ConnectionProperties) dsConn).getConnectTimeout();
assertEquals("Connect timeout spec'd by URL didn't take", nonDefaultConnectTimeout, configuredConnectTimeout);
assertFalse("Connect timeout spec'd by URL didn't take", defaultConnectTimeout == configuredConnectTimeout);
}
}