source: Ballon/out/artifacts/geisa_artifact/WEB-INF/lib/mysql-connector-java-5.1.21/src/testsuite/regression/PooledConnectionRegressionTest.java @ 766

Last change on this file since 766 was 766, checked in by npipsl, 11 years ago
File size: 13.1 KB
Line 
1/*
2 Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
3 
4
5  The MySQL Connector/J is licensed under the terms of the GPLv2
6  <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
7  There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
8  this software, see the FLOSS License Exception
9  <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
10
11  This program is free software; you can redistribute it and/or modify it under the terms
12  of the GNU General Public License as published by the Free Software Foundation; version 2
13  of the License.
14
15  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
16  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17  See the GNU General Public License for more details.
18
19  You should have received a copy of the GNU General Public License along with this
20  program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
21  Floor, Boston, MA 02110-1301  USA
22
23
24 
25 */
26package testsuite.regression;
27
28import java.io.BufferedInputStream;
29import java.io.FileInputStream;
30import java.sql.Connection;
31import java.sql.PreparedStatement;
32import java.sql.SQLException;
33
34import javax.sql.ConnectionEvent;
35import javax.sql.ConnectionEventListener;
36import javax.sql.ConnectionPoolDataSource;
37import javax.sql.PooledConnection;
38
39import junit.framework.Test;
40import junit.framework.TestSuite;
41import testsuite.BaseTestCase;
42
43import com.mysql.jdbc.PacketTooBigException;
44import com.mysql.jdbc.jdbc2.optional.ConnectionWrapper;
45import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
46import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
47
48/**
49 * Tests a PooledConnection implementation provided by a JDBC driver. Test case
50 * provided by Johnny Macchione from bug database record BUG#884. According to
51 * the JDBC 2.0 specification:
52 *
53 * <p>
54 * "Each call to PooledConnection.getConnection() must return a newly
55 * constructed Connection object that exhibits the default Connection behavior.
56 * Only the most recent Connection object produced from a particular
57 * PooledConnection is open. An existing Connection object is automatically
58 * closed, if the getConnection() method of its associated Pooled-Connection is
59 * called again, before it has been explicitly closed by the application. This
60 * gives the application server a way to ï¿œtake awayï¿œ a Connection from the
61 * application if it wishes, and give it out to someone else. This capability
62 * will not likely be used frequently in practice."
63 * </p>
64 *
65 * <p>
66 * "When the application calls Connection.close(), an event is triggered that
67 * tells the connection pool it can recycle the physical database connection. In
68 * other words, the event signals the connection pool that the PooledConnection
69 * object which originally produced the Connection object generating the event
70 * can be put back in the connection pool."
71 * </p>
72 *
73 * <p>
74 * "A Connection-EventListener will also be notified when a fatal error occurs,
75 * so that it can make a note not to put a bad PooledConnection object back in
76 * the cache when the application finishes using it. When an error occurs, the
77 * ConnectionEventListener is notified by the JDBC driver, just before the
78 * driver throws an SQLException to the application to notify it of the same
79 * error. Note that automatic closing of a Connection object as discussed in the
80 * previous section does not generate a connection close event."
81 * </p>
82 * The JDBC 3.0 specification states the same in other words:
83 *
84 * <p>
85 * "The Connection.close method closes the logical handle, but the physical
86 * connection is maintained. The connection pool manager is notified that the
87 * underlying PooledConnection object is now available for reuse. If the
88 * application attempts to reuse the logical handle, the Connection
89 * implementation throws an SQLException."
90 * </p>
91 *
92 * <p>
93 * "For a given PooledConnection object, only the most recently produced logical
94 * Connection object will be valid. Any previously existing Connection object is
95 * automatically closed when the associated PooledConnection.getConnection
96 * method is called. Listeners (connection pool managers) are not notified in
97 * this case. This gives the application server a way to take a connection away
98 * from a client. This is an unlikely scenario but may be useful if the
99 * application server is trying to force an orderly shutdown."
100 * </p>
101 *
102 * <p>
103 * "A connection pool manager shuts down a physical connection by calling the
104 * method PooledConnection.close. This method is typically called only in
105 * certain circumstances: when the application server is undergoing an orderly
106 * shutdown, when the connection cache is being reinitialized, or when the
107 * application server receives an event indicating that an unrecoverable error
108 * has occurred on the connection."
109 * </p>
110 * Even though the specification isn't clear about it, I think it is no use
111 * generating a close event when calling the method PooledConnection.close(),
112 * even if a logical Connection is open for this PooledConnection, bc the
113 * PooledConnection will obviously not be returned to the pool.
114 *
115 * @author fcr
116 */
117public final class PooledConnectionRegressionTest extends BaseTestCase {
118        private ConnectionPoolDataSource cpds;
119
120        // Count nb of closeEvent.
121        protected int closeEventCount;
122
123        // Count nb of connectionErrorEvent
124        protected int connectionErrorEventCount;
125
126        /**
127         * Creates a new instance of ProgressPooledConnectionTest
128         *
129         * @param testname
130         *            DOCUMENT ME!
131         */
132        public PooledConnectionRegressionTest(String testname) {
133                super(testname);
134        }
135
136        /**
137         * Set up test case before a test is run.
138         *
139         * @throws Exception
140         *             DOCUMENT ME!
141         */
142        public void setUp() throws Exception {
143                super.setUp();
144
145                // Reset event count.
146                this.closeEventCount = 0;
147                this.connectionErrorEventCount = 0;
148
149                MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
150
151                ds.setURL(BaseTestCase.dbUrl);
152
153                this.cpds = ds;
154        }
155
156        /**
157         * Runs all test cases in this test suite
158         *
159         * @param args
160         */
161        public static void main(String[] args) {
162                junit.textui.TestRunner.run(PooledConnectionRegressionTest.class);
163        }
164
165        /**
166         * DOCUMENT ME!
167         *
168         * @return a test suite composed of this test case.
169         */
170        public static Test suite() {
171                TestSuite suite = new TestSuite(PooledConnectionRegressionTest.class);
172
173                return suite;
174        }
175
176        /**
177         * After the test is run.
178         */
179        public void tearDown() throws Exception {
180                this.cpds = null;
181                super.tearDown();
182        }
183
184        /**
185         * Tests fix for BUG#7136 ... Statement.getConnection() returning physical
186         * connection instead of logical connection.
187         */
188        public void testBug7136() {
189                final ConnectionEventListener conListener = new ConnectionListener();
190                PooledConnection pc = null;
191                this.closeEventCount = 0;
192
193                try {
194                        pc = this.cpds.getPooledConnection();
195
196                        pc.addConnectionEventListener(conListener);
197
198                        Connection _conn = pc.getConnection();
199
200                        Connection connFromStatement = _conn.createStatement()
201                                        .getConnection();
202
203                        // This should generate a close event.
204
205                        connFromStatement.close();
206
207                        assertEquals("One close event should've been registered", 1,
208                                        this.closeEventCount);
209
210                        this.closeEventCount = 0;
211
212                        _conn = pc.getConnection();
213
214                        Connection connFromPreparedStatement = _conn.prepareStatement(
215                                        "SELECT 1").getConnection();
216
217                        // This should generate a close event.
218
219                        connFromPreparedStatement.close();
220
221                        assertEquals("One close event should've been registered", 1,
222                                        this.closeEventCount);
223
224                } catch (SQLException ex) {
225                        fail(ex.toString());
226                } finally {
227                        if (pc != null) {
228                                try {
229                                        pc.close();
230                                } catch (SQLException ex) {
231                                        ex.printStackTrace();
232                                }
233                        }
234                }
235        }
236
237        /**
238         * Test the nb of closeEvents generated when a Connection is reclaimed. No
239         * event should be generated in that case.
240         */
241        public void testConnectionReclaim() {
242                final ConnectionEventListener conListener = new ConnectionListener();
243                PooledConnection pc = null;
244                final int NB_TESTS = 5;
245
246                try {
247                        pc = this.cpds.getPooledConnection();
248
249                        pc.addConnectionEventListener(conListener);
250
251                        for (int i = 0; i < NB_TESTS; i++) {
252                                Connection _conn = pc.getConnection();
253
254                                try {
255                                        // Try to reclaim connection.
256                                        System.out.println("Before connection reclaim.");
257
258                                        _conn = pc.getConnection();
259
260                                        System.out.println("After connection reclaim.");
261                                } finally {
262                                        if (_conn != null) {
263                                                System.out.println("Before connection.close().");
264
265                                                // This should generate a close event.
266                                                _conn.close();
267
268                                                System.out.println("After connection.close().");
269                                        }
270                                }
271                        }
272                } catch (SQLException ex) {
273                        ex.printStackTrace();
274                        fail(ex.toString());
275                } finally {
276                        if (pc != null) {
277                                try {
278                                        System.out.println("Before pooledConnection.close().");
279
280                                        // This should not generate a close event.
281                                        pc.close();
282
283                                        System.out.println("After pooledConnection.close().");
284                                } catch (SQLException ex) {
285                                        ex.printStackTrace();
286                                        fail(ex.toString());
287                                }
288                        }
289                }
290
291                assertEquals("Wrong nb of CloseEvents: ", NB_TESTS,
292                                this.closeEventCount);
293        }
294
295        /**
296         * Tests that PacketTooLargeException doesn't clober the connection.
297         *
298         * @throws Exception
299         *             if the test fails.
300         */
301        public void testPacketTooLargeException() throws Exception {
302                final ConnectionEventListener conListener = new ConnectionListener();
303                PooledConnection pc = null;
304
305                pc = this.cpds.getPooledConnection();
306
307                pc.addConnectionEventListener(conListener);
308
309                createTable("testPacketTooLarge", "(field1 LONGBLOB)");
310
311                Connection connFromPool = pc.getConnection();
312                PreparedStatement pstmtFromPool = ((ConnectionWrapper) connFromPool)
313                                .clientPrepare("INSERT INTO testPacketTooLarge VALUES (?)");
314
315                this.rs = this.stmt
316                                .executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'");
317                this.rs.next();
318
319                int maxAllowedPacket = this.rs.getInt(2);
320
321                int numChars = (int) (maxAllowedPacket * 1.2);
322
323                pstmtFromPool.setBinaryStream(
324                                1,
325                                new BufferedInputStream(new FileInputStream(newTempBinaryFile(
326                                                "testPacketTooLargeException", numChars))), numChars);
327
328                try {
329                        pstmtFromPool.executeUpdate();
330                        fail("Expecting PacketTooLargeException");
331                } catch (PacketTooBigException ptbe) {
332                        // We're expecting this one...
333                }
334
335                // This should still work okay, even though the last query on the
336                // same
337                // connection didn't...
338                connFromPool.createStatement().executeQuery("SELECT 1");
339
340                assertTrue(this.connectionErrorEventCount == 0);
341                assertTrue(this.closeEventCount == 0);
342        }
343
344        /**
345         * Test the nb of closeEvents generated by a PooledConnection. A
346         * JDBC-compliant driver should only generate 1 closeEvent each time
347         * connection.close() is called.
348         */
349        public void testCloseEvent() {
350                final ConnectionEventListener conListener = new ConnectionListener();
351                PooledConnection pc = null;
352                final int NB_TESTS = 5;
353
354                try {
355                        pc = this.cpds.getPooledConnection();
356
357                        pc.addConnectionEventListener(conListener);
358
359                        for (int i = 0; i < NB_TESTS; i++) {
360                                Connection pConn = pc.getConnection();
361
362                                System.out.println("Before connection.close().");
363
364                                // This should generate a close event.
365                                pConn.close();
366
367                                System.out.println("After connection.close().");
368                        }
369                } catch (SQLException ex) {
370                        fail(ex.toString());
371                } finally {
372                        if (pc != null) {
373                                try {
374                                        System.out.println("Before pooledConnection.close().");
375
376                                        // This should not generate a close event.
377                                        pc.close();
378
379                                        System.out.println("After pooledConnection.close().");
380                                } catch (SQLException ex) {
381                                        ex.printStackTrace();
382                                }
383                        }
384                }
385                assertEquals("Wrong nb of CloseEvents: ", NB_TESTS,
386                                this.closeEventCount);
387        }
388
389        /**
390         * Listener for PooledConnection events.
391         */
392        protected final class ConnectionListener implements ConnectionEventListener {
393                /** */
394                public void connectionClosed(ConnectionEvent event) {
395                        PooledConnectionRegressionTest.this.closeEventCount++;
396                        System.out
397                                        .println(PooledConnectionRegressionTest.this.closeEventCount
398                                                        + " - Connection closed.");
399                }
400
401                /** */
402                public void connectionErrorOccurred(ConnectionEvent event) {
403                        PooledConnectionRegressionTest.this.connectionErrorEventCount++;
404                        System.out.println("Connection error: " + event.getSQLException());
405                }
406        }
407
408        /**
409         * Tests fix for BUG#35489 - Prepared statements from pooled connections
410         * cause NPE when closed() under JDBC4
411         *
412         * @throws Exception
413         *             if the test fails
414         */
415        public void testBug35489() throws Exception {
416                MysqlConnectionPoolDataSource pds = new MysqlConnectionPoolDataSource();
417                pds.setUrl(dbUrl);
418                this.pstmt = pds.getPooledConnection().getConnection()
419                                .prepareStatement("SELECT 1");
420                this.pstmt.execute();
421                this.pstmt.close();
422
423                MysqlXADataSource xads = new MysqlXADataSource();
424                xads.setUrl(dbUrl);
425                this.pstmt = xads.getXAConnection().getConnection()
426                                .prepareStatement("SELECT 1");
427                this.pstmt.execute();
428                this.pstmt.close();
429
430                xads = new MysqlXADataSource();
431                xads.setUrl(dbUrl);
432                xads.setPinGlobalTxToPhysicalConnection(true);
433                this.pstmt = xads.getXAConnection().getConnection()
434                                .prepareStatement("SELECT 1");
435                this.pstmt.execute();
436                this.pstmt.close();
437        }
438}
Note: See TracBrowser for help on using the repository browser.