001: /*
002: Copyright (C) 2002-2006 MySQL AB
003:
004: This program is free software; you can redistribute it and/or modify
005: it under the terms of version 2 of the GNU General Public License as
006: published by the Free Software Foundation.
007:
008: There are special exceptions to the terms and conditions of the GPL
009: as it is applied to this software. View the full text of the
010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
011: software distribution.
012:
013: This program is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: GNU General Public License for more details.
017:
018: You should have received a copy of the GNU General Public License
019: along with this program; if not, write to the Free Software
020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022:
023:
024: */
025: package testsuite.regression;
026:
027: import java.io.ByteArrayInputStream;
028: import java.io.ByteArrayOutputStream;
029: import java.io.File;
030: import java.io.ObjectInputStream;
031: import java.io.ObjectOutputStream;
032: import java.lang.reflect.Method;
033: import java.sql.Connection;
034: import java.sql.PreparedStatement;
035: import java.sql.SQLException;
036: import java.sql.Statement;
037: import java.util.Hashtable;
038:
039: import javax.naming.Context;
040: import javax.naming.InitialContext;
041: import javax.naming.Name;
042: import javax.naming.NameParser;
043: import javax.naming.RefAddr;
044: import javax.naming.Reference;
045: import javax.naming.spi.ObjectFactory;
046: import javax.sql.ConnectionPoolDataSource;
047: import javax.sql.DataSource;
048: import javax.sql.PooledConnection;
049:
050: import testsuite.BaseTestCase;
051: import testsuite.simple.DataSourceTest;
052:
053: import com.mysql.jdbc.NonRegisteringDriver;
054: import com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker;
055: import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
056: import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
057: import com.mysql.jdbc.jdbc2.optional.MysqlDataSourceFactory;
058: import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
059:
060: /**
061: * Tests fixes for bugs related to datasources.
062: *
063: * @author Mark Matthews
064: *
065: * @version $Id: DataSourceRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38
066: * mmatthews Exp $
067: */
068: public class DataSourceRegressionTest extends BaseTestCase {
069:
070: public final static String DS_DATABASE_PROP_NAME = "com.mysql.jdbc.test.ds.db";
071:
072: public final static String DS_HOST_PROP_NAME = "com.mysql.jdbc.test.ds.host";
073:
074: public final static String DS_PASSWORD_PROP_NAME = "com.mysql.jdbc.test.ds.password";
075:
076: public final static String DS_PORT_PROP_NAME = "com.mysql.jdbc.test.ds.port";
077:
078: public final static String DS_USER_PROP_NAME = "com.mysql.jdbc.test.ds.user";
079:
080: private Context ctx;
081:
082: private File tempDir;
083:
084: /**
085: * Creates a new DataSourceRegressionTest suite for the given test name
086: *
087: * @param name
088: * the name of the testcase to run.
089: */
090: public DataSourceRegressionTest(String name) {
091: super (name);
092:
093: // TODO Auto-generated constructor stub
094: }
095:
096: /**
097: * Runs all test cases in this test suite
098: *
099: * @param args
100: */
101: public static void main(String[] args) {
102: junit.textui.TestRunner.run(DataSourceTest.class);
103: }
104:
105: /**
106: * Sets up this test, calling registerDataSource() to bind a DataSource into
107: * JNDI, using the FSContext JNDI provider from Sun
108: *
109: * @throws Exception
110: * if an error occurs.
111: */
112: public void setUp() throws Exception {
113: super .setUp();
114: createJNDIContext();
115: }
116:
117: /**
118: * Un-binds the DataSource, and cleans up the filesystem
119: *
120: * @throws Exception
121: * if an error occurs
122: */
123: public void tearDown() throws Exception {
124: this .ctx.unbind(this .tempDir.getAbsolutePath() + "/test");
125: this .ctx.unbind(this .tempDir.getAbsolutePath() + "/testNoUrl");
126: this .ctx.close();
127: this .tempDir.delete();
128:
129: super .tearDown();
130: }
131:
132: /**
133: * Tests fix for BUG#4808- Calling .close() twice on a PooledConnection
134: * causes NPE.
135: *
136: * @throws Exception
137: * if an error occurs.
138: */
139: public void testBug4808() throws Exception {
140: MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
141: ds.setURL(BaseTestCase.dbUrl);
142: PooledConnection closeMeTwice = ds.getPooledConnection();
143: closeMeTwice.close();
144: closeMeTwice.close();
145:
146: }
147:
148: /**
149: * Tests fix for Bug#3848, port # alone parsed incorrectly
150: *
151: * @throws Exception
152: * ...
153: */
154: public void testBug3848() throws Exception {
155: String jndiName = "/testBug3848";
156:
157: String databaseName = System.getProperty(DS_DATABASE_PROP_NAME);
158: String userName = System.getProperty(DS_USER_PROP_NAME);
159: String password = System.getProperty(DS_PASSWORD_PROP_NAME);
160: String port = System.getProperty(DS_PORT_PROP_NAME);
161:
162: // Only run this test if at least one of the above are set
163: if ((databaseName != null) || (userName != null)
164: || (password != null) || (port != null)) {
165: MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
166:
167: if (databaseName != null) {
168: ds.setDatabaseName(databaseName);
169: }
170:
171: if (userName != null) {
172: ds.setUser(userName);
173: }
174:
175: if (password != null) {
176: ds.setPassword(password);
177: }
178:
179: if (port != null) {
180: ds.setPortNumber(Integer.parseInt(port));
181: }
182:
183: bindDataSource(jndiName, ds);
184:
185: ConnectionPoolDataSource boundDs = null;
186:
187: try {
188: boundDs = (ConnectionPoolDataSource) lookupDatasourceInJNDI(jndiName);
189:
190: assertTrue("Datasource not bound", boundDs != null);
191:
192: Connection dsConn = null;
193:
194: try {
195: dsConn = boundDs.getPooledConnection()
196: .getConnection();
197: } finally {
198: if (dsConn != null) {
199: dsConn.close();
200: }
201: }
202: } finally {
203: if (boundDs != null) {
204: this .ctx.unbind(jndiName);
205: }
206: }
207: }
208: }
209:
210: /**
211: * Tests that we can get a connection from the DataSource bound in JNDI
212: * during test setup
213: *
214: * @throws Exception
215: * if an error occurs
216: */
217: public void testBug3920() throws Exception {
218: String jndiName = "/testBug3920";
219:
220: String databaseName = System.getProperty(DS_DATABASE_PROP_NAME);
221: String userName = System.getProperty(DS_USER_PROP_NAME);
222: String password = System.getProperty(DS_PASSWORD_PROP_NAME);
223: String port = System.getProperty(DS_PORT_PROP_NAME);
224: String serverName = System.getProperty(DS_HOST_PROP_NAME);
225:
226: // Only run this test if at least one of the above are set
227: if ((databaseName != null) || (serverName != null)
228: || (userName != null) || (password != null)
229: || (port != null)) {
230: MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
231:
232: if (databaseName != null) {
233: ds.setDatabaseName(databaseName);
234: }
235:
236: if (userName != null) {
237: ds.setUser(userName);
238: }
239:
240: if (password != null) {
241: ds.setPassword(password);
242: }
243:
244: if (port != null) {
245: ds.setPortNumber(Integer.parseInt(port));
246: }
247:
248: if (serverName != null) {
249: ds.setServerName(serverName);
250: }
251:
252: bindDataSource(jndiName, ds);
253:
254: ConnectionPoolDataSource boundDs = null;
255:
256: try {
257: boundDs = (ConnectionPoolDataSource) lookupDatasourceInJNDI(jndiName);
258:
259: assertTrue("Datasource not bound", boundDs != null);
260:
261: Connection dsCon = null;
262: Statement dsStmt = null;
263:
264: try {
265: dsCon = boundDs.getPooledConnection()
266: .getConnection();
267: dsStmt = dsCon.createStatement();
268: dsStmt
269: .executeUpdate("DROP TABLE IF EXISTS testBug3920");
270: dsStmt
271: .executeUpdate("CREATE TABLE testBug3920 (field1 varchar(32))");
272:
273: assertTrue(
274: "Connection can not be obtained from data source",
275: dsCon != null);
276: } finally {
277: dsStmt
278: .executeUpdate("DROP TABLE IF EXISTS testBug3920");
279:
280: dsStmt.close();
281: dsCon.close();
282: }
283: } finally {
284: if (boundDs != null) {
285: this .ctx.unbind(jndiName);
286: }
287: }
288: }
289: }
290:
291: /**
292: * Tests fix for BUG#19169 - ConnectionProperties (and thus some
293: * subclasses) are not serializable, even though some J2EE containers
294: * expect them to be.
295: *
296: * @throws Exception if the test fails.
297: */
298: public void testBug19169() throws Exception {
299: MysqlDataSource toSerialize = new MysqlDataSource();
300: toSerialize.setZeroDateTimeBehavior("convertToNull");
301:
302: boolean testBooleanFlag = !toSerialize
303: .getAllowLoadLocalInfile();
304: toSerialize.setAllowLoadLocalInfile(testBooleanFlag);
305:
306: int testIntFlag = toSerialize.getBlobSendChunkSize() + 1;
307: toSerialize.setBlobSendChunkSize(String.valueOf(testIntFlag));
308:
309: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
310: ObjectOutputStream objOut = new ObjectOutputStream(bOut);
311: objOut.writeObject(toSerialize);
312: objOut.flush();
313:
314: ObjectInputStream objIn = new ObjectInputStream(
315: new ByteArrayInputStream(bOut.toByteArray()));
316:
317: MysqlDataSource thawedDs = (MysqlDataSource) objIn.readObject();
318:
319: assertEquals("convertToNull", thawedDs
320: .getZeroDateTimeBehavior());
321: assertEquals(testBooleanFlag, thawedDs
322: .getAllowLoadLocalInfile());
323: assertEquals(testIntFlag, thawedDs.getBlobSendChunkSize());
324: }
325:
326: /**
327: * Tests fix for BUG#20242 - MysqlValidConnectionChecker for JBoss doesn't
328: * work with MySQLXADataSources.
329: *
330: * @throws Exception if the test fails.
331: */
332: public void testBug20242() throws Exception {
333: if (versionMeetsMinimum(5, 0)) {
334: try {
335: Class
336: .forName("org.jboss.resource.adapter.jdbc.ValidConnectionChecker");
337: } catch (Exception ex) {
338: return; // class not available for testing
339: }
340:
341: MysqlXADataSource xaDs = new MysqlXADataSource();
342: xaDs.setUrl(dbUrl);
343:
344: MysqlValidConnectionChecker checker = new MysqlValidConnectionChecker();
345: assertNull(checker.isValidConnection(xaDs.getXAConnection()
346: .getConnection()));
347: }
348: }
349:
350: private void bindDataSource(String name, DataSource ds)
351: throws Exception {
352: this .ctx.bind(this .tempDir.getAbsolutePath() + name, ds);
353: }
354:
355: /**
356: * This method is separated from the rest of the example since you normally
357: * would NOT register a JDBC driver in your code. It would likely be
358: * configered into your naming and directory service using some GUI.
359: *
360: * @throws Exception
361: * if an error occurs
362: */
363: private void createJNDIContext() throws Exception {
364: this .tempDir = File.createTempFile("jnditest", null);
365: this .tempDir.delete();
366: this .tempDir.mkdir();
367: this .tempDir.deleteOnExit();
368:
369: MysqlConnectionPoolDataSource ds;
370: Hashtable env = new Hashtable();
371: env.put(Context.INITIAL_CONTEXT_FACTORY,
372: "com.sun.jndi.fscontext.RefFSContextFactory");
373: this .ctx = new InitialContext(env);
374: assertTrue("Naming Context not created", this .ctx != null);
375: ds = new MysqlConnectionPoolDataSource();
376: ds.setUrl(dbUrl); // from BaseTestCase
377: ds.setDatabaseName("test");
378: this .ctx.bind(this .tempDir.getAbsolutePath() + "/test", ds);
379: }
380:
381: private DataSource lookupDatasourceInJNDI(String jndiName)
382: throws Exception {
383: NameParser nameParser = this .ctx.getNameParser("");
384: Name datasourceName = nameParser.parse(this .tempDir
385: .getAbsolutePath()
386: + jndiName);
387: Object obj = this .ctx.lookup(datasourceName);
388: DataSource boundDs = null;
389:
390: if (obj instanceof DataSource) {
391: boundDs = (DataSource) obj;
392: } else if (obj instanceof Reference) {
393: //
394: // For some reason, this comes back as a Reference
395: // instance under CruiseControl !?
396: //
397: Reference objAsRef = (Reference) obj;
398: ObjectFactory factory = (ObjectFactory) Class.forName(
399: objAsRef.getFactoryClassName()).newInstance();
400: boundDs = (DataSource) factory.getObjectInstance(objAsRef,
401: datasourceName, this .ctx, new Hashtable());
402: }
403:
404: return boundDs;
405: }
406:
407: public void testCSC4616() throws Exception {
408: MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
409: ds.setURL(BaseTestCase.dbUrl);
410: PooledConnection pooledConn = ds.getPooledConnection();
411: Connection physConn = pooledConn.getConnection();
412: Statement physStatement = physConn.createStatement();
413:
414: Method enableStreamingResultsMethodStmt = Class.forName(
415: "com.mysql.jdbc.jdbc2.optional.StatementWrapper")
416: .getMethod("enableStreamingResults", new Class[0]);
417: enableStreamingResultsMethodStmt.invoke(physStatement,
418: new Class[0]);
419: this .rs = physStatement.executeQuery("SELECT 1");
420:
421: try {
422: physConn.createStatement().executeQuery("SELECT 2");
423: fail("Should have caught a streaming exception here");
424: } catch (SQLException sqlEx) {
425: assertTrue(sqlEx.getMessage() != null
426: && sqlEx.getMessage().indexOf("Streaming") != -1);
427: } finally {
428: if (this .rs != null) {
429: this .rs.close();
430: this .rs = null;
431: }
432: }
433:
434: PreparedStatement physPrepStmt = physConn
435: .prepareStatement("SELECT 1");
436: Method enableStreamingResultsMethodPstmt = Class
437: .forName(
438: "com.mysql.jdbc.jdbc2.optional.PreparedStatementWrapper")
439: .getMethod("enableStreamingResults", new Class[0]);
440: enableStreamingResultsMethodPstmt.invoke(physPrepStmt,
441: new Class[0]);
442:
443: this .rs = physPrepStmt.executeQuery();
444:
445: try {
446: physConn.createStatement().executeQuery("SELECT 2");
447: fail("Should have caught a streaming exception here");
448: } catch (SQLException sqlEx) {
449: assertTrue(sqlEx.getMessage() != null
450: && sqlEx.getMessage().indexOf("Streaming") != -1);
451: } finally {
452: if (this .rs != null) {
453: this .rs.close();
454: this .rs = null;
455: }
456: }
457: }
458:
459: /**
460: * Tests fix for BUG#16791 - NullPointerException in MysqlDataSourceFactory
461: * due to Reference containing RefAddrs with null content.
462: *
463: * @throws Exception if the test fails
464: */
465: public void testBug16791() throws Exception {
466: MysqlDataSource myDs = new MysqlDataSource();
467: myDs.setUrl(dbUrl);
468: Reference asRef = myDs.getReference();
469: System.out.println(asRef);
470:
471: removeFromRef(asRef, "port");
472: removeFromRef(asRef, NonRegisteringDriver.USER_PROPERTY_KEY);
473: removeFromRef(asRef, NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
474: removeFromRef(asRef, "serverName");
475: removeFromRef(asRef, "databaseName");
476:
477: MysqlDataSource newDs = (MysqlDataSource) new MysqlDataSourceFactory()
478: .getObjectInstance(asRef, null, null, null);
479: }
480:
481: private void removeFromRef(Reference ref, String key) {
482: int size = ref.size();
483:
484: for (int i = 0; i < size; i++) {
485: RefAddr refAddr = ref.get(i);
486: if (refAddr.getType().equals(key)) {
487: ref.remove(i);
488: break;
489: }
490: }
491: }
492: }
|