001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
002: // Copyright (C) 2004 The jTDS Project
003: //
004: // This library is free software; you can redistribute it and/or
005: // modify it under the terms of the GNU Lesser General Public
006: // License as published by the Free Software Foundation; either
007: // version 2.1 of the License, or (at your option) any later version.
008: //
009: // This library is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: // Lesser General Public License for more details.
013: //
014: // You should have received a copy of the GNU Lesser General Public
015: // License along with this library; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: //
018: package net.sourceforge.jtds.test;
019:
020: import java.sql.*;
021: import java.util.Properties;
022: import java.util.Enumeration;
023:
024: import junit.framework.Test;
025: import junit.framework.TestSuite;
026:
027: import net.sourceforge.jtds.jdbc.ConnectionJDBC2;
028: import net.sourceforge.jtds.jdbc.Driver;
029: import net.sourceforge.jtds.jdbc.DefaultProperties;
030: import net.sourceforge.jtds.jdbc.Messages;
031:
032: /**
033: * Unit test for the {@link ConnectionJDBC2} class.
034: *
035: * @author David Kilzer
036: * @author Alin Sinpalean
037: * @version $Id: ConnectionJDBC2UnitTest.java,v 1.11 2007/07/08 18:08:54 bheineman Exp $
038: */
039: public class ConnectionJDBC2UnitTest extends UnitTestBase {
040:
041: /**
042: * Construct a test suite for this class.
043: * <p/>
044: * The test suite includes the tests in this class, and adds tests
045: * from {@link DefaultPropertiesTestLibrary} after creating an
046: * anonymous {@link DefaultPropertiesTester} object.
047: *
048: * @return The test suite to run.
049: */
050: public static Test suite() {
051:
052: final TestSuite testSuite = new TestSuite(
053: ConnectionJDBC2UnitTest.class);
054:
055: testSuite
056: .addTest(ConnectionJDBC2UnitTest.Test_ConnectionJDBC2_unpackProperties
057: .suite("test_unpackProperties_DefaultProperties"));
058:
059: return testSuite;
060: }
061:
062: /**
063: * Constructor.
064: *
065: * @param name The name of the test.
066: */
067: public ConnectionJDBC2UnitTest(String name) {
068: super (name);
069: }
070:
071: /**
072: * Test that an {@link java.sql.SQLException} is thrown when
073: * parsing invalid integer (and long) properties.
074: */
075: public void test_unpackProperties_invalidIntegerProperty() {
076: assertSQLExceptionForBadWholeNumberProperty(Driver.PORTNUMBER);
077: assertSQLExceptionForBadWholeNumberProperty(Driver.SERVERTYPE);
078: assertSQLExceptionForBadWholeNumberProperty(Driver.PREPARESQL);
079: assertSQLExceptionForBadWholeNumberProperty(Driver.PACKETSIZE);
080: assertSQLExceptionForBadWholeNumberProperty(Driver.LOGINTIMEOUT);
081: assertSQLExceptionForBadWholeNumberProperty(Driver.LOBBUFFER);
082: }
083:
084: /**
085: * Assert that an SQLException is thrown when
086: * {@link ConnectionJDBC2#unpackProperties(Properties)} is called
087: * with an invalid integer (or long) string set on a property.
088: * <p/>
089: * Note that because Java 1.3 is still supported, the
090: * {@link RuntimeException} that is caught may not contain the
091: * original {@link Throwable} cause, only the original message.
092: *
093: * @param key The message key used to retrieve the property name.
094: */
095: private void assertSQLExceptionForBadWholeNumberProperty(
096: final String key) {
097:
098: final ConnectionJDBC2 instance = (ConnectionJDBC2) invokeConstructor(
099: ConnectionJDBC2.class, new Class[] {}, new Object[] {});
100:
101: Properties properties = (Properties) invokeStaticMethod(
102: Driver.class, "parseURL", new Class[] { String.class,
103: Properties.class }, new Object[] {
104: "jdbc:jtds:sqlserver://servername",
105: new Properties() });
106: properties = (Properties) invokeStaticMethod(
107: DefaultProperties.class, "addDefaultProperties",
108: new Class[] { Properties.class },
109: new Object[] { properties });
110:
111: properties.setProperty(Messages.get(key), "1.21 Gigawatts");
112:
113: try {
114: invokeInstanceMethod(instance, "unpackProperties",
115: new Class[] { Properties.class },
116: new Object[] { properties });
117: fail("RuntimeException expected");
118: } catch (RuntimeException e) {
119: assertEquals("Unexpected exception message", Messages.get(
120: "error.connection.badprop", Messages.get(key)), e
121: .getMessage());
122: }
123: }
124:
125: /**
126: * Class used to test <code>net.sourceforge.jtds.jdbc.ConnectionJDBC2.unpackProperties(Properties)</code>.
127: */
128: public static class Test_ConnectionJDBC2_unpackProperties extends
129: DefaultPropertiesTestLibrary {
130:
131: /**
132: * Construct a test suite for this library.
133: *
134: * @param name The name of the tests.
135: * @return The test suite.
136: */
137: public static Test suite(String name) {
138: return new TestSuite(
139: ConnectionJDBC2UnitTest.Test_ConnectionJDBC2_unpackProperties.class,
140: name);
141: }
142:
143: /**
144: * Default constructor.
145: */
146: public Test_ConnectionJDBC2_unpackProperties() {
147: setTester(new DefaultPropertiesTester() {
148:
149: public void assertDefaultProperty(String message,
150: String url, Properties properties,
151: String fieldName, String key, String expected) {
152:
153: // FIXME: Hack for ConnectionJDBC2
154: {
155: if ("sendStringParametersAsUnicode"
156: .equals(fieldName)) {
157: fieldName = "useUnicode";
158: } else if ("cacheMetaData".equals(fieldName)) {
159: fieldName = "useMetadataCache";
160: }
161: }
162:
163: Properties parsedProperties = (Properties) invokeStaticMethod(
164: Driver.class, "parseURL", new Class[] {
165: String.class, Properties.class },
166: new Object[] { url, properties });
167: parsedProperties = (Properties) invokeStaticMethod(
168: DefaultProperties.class,
169: "addDefaultProperties",
170: new Class[] { Properties.class },
171: new Object[] { parsedProperties });
172: ConnectionJDBC2 instance = (ConnectionJDBC2) invokeConstructor(
173: ConnectionJDBC2.class, new Class[] {},
174: new Object[] {});
175: invokeInstanceMethod(instance, "unpackProperties",
176: new Class[] { Properties.class },
177: new Object[] { parsedProperties });
178:
179: String actual = String
180: .valueOf(invokeInstanceMethod(instance,
181: "get" + ucFirst(fieldName),
182: new Class[] {}, new Object[] {}));
183:
184: // FIXME: Another hack for ConnectionJDBC2
185: {
186: if ("tdsVersion".equals(fieldName)) {
187: expected = String.valueOf(DefaultProperties
188: .getTdsVersion(expected));
189: }
190: }
191:
192: assertEquals(message, expected, actual);
193: }
194: });
195: }
196: }
197:
198: /**
199: * Creates a <code>Connection</code>, overriding the default properties
200: * with the ones provided.
201: *
202: * @param override the overriding properties
203: * @return a <code>Connection</code> object
204: */
205: private Connection getConnectionOverrideProperties(
206: Properties override) throws Exception {
207: // Get properties, override with provided values
208: Properties props = (Properties) TestBase.props.clone();
209: for (Enumeration e = override.keys(); e.hasMoreElements();) {
210: String key = (String) e.nextElement();
211: props.setProperty(key, override.getProperty(key));
212: }
213:
214: // Obtain connection
215: Class.forName(props.getProperty("driver"));
216: String url = props.getProperty("url");
217: return DriverManager.getConnection(url, props);
218: }
219:
220: /**
221: * Test correct behavior of the <code>charset</code> property.
222: * Values should be stored and retrieved using the requested charset rather
223: * than the server's as long as Unicode is not used.
224: */
225: public void testForceCharset1() throws Exception {
226: // Set charset to Cp1251 and Unicode parameters to false
227: Properties props = new Properties();
228: props.setProperty(Messages.get(Driver.CHARSET), "Cp1251");
229: props.setProperty(Messages
230: .get(Driver.SENDSTRINGPARAMETERSASUNICODE), "false");
231: // Obtain connection
232: Connection con = getConnectionOverrideProperties(props);
233:
234: try {
235: // Test both sending and retrieving of values
236: String value = "\u0410\u0411\u0412";
237: PreparedStatement pstmt = con.prepareStatement("select ?");
238: pstmt.setString(1, value);
239: ResultSet rs = pstmt.executeQuery();
240: assertTrue(rs.next());
241: assertEquals(value, rs.getString(1));
242: assertFalse(rs.next());
243: rs.close();
244:
245: pstmt.close();
246: } finally {
247: con.close();
248: }
249: }
250:
251: /**
252: * Test correct behavior of the <code>charset</code> property.
253: * Stored procedure output parameters should be decoded using the specified
254: * charset rather than the server's as long as they are non-Unicode.
255: */
256: public void testForceCharset2() throws Exception {
257: // Set charset to Cp1251 and Unicode parameters to false
258: Properties props = new Properties();
259: props.setProperty(Messages.get(Driver.CHARSET), "Cp1251");
260: props.setProperty(Messages
261: .get(Driver.SENDSTRINGPARAMETERSASUNICODE), "false");
262: // Obtain connection
263: Connection con = getConnectionOverrideProperties(props);
264:
265: try {
266: Statement stmt = con.createStatement();
267: assertEquals(
268: 0,
269: stmt
270: .executeUpdate("create procedure #testForceCharset2 "
271: + "@inParam varchar(10), @outParam varchar(10) output as "
272: + "set @outParam = @inParam"));
273: stmt.close();
274:
275: // Test both sending and retrieving of parameters
276: String value = "\u0410\u0411\u0412";
277: CallableStatement cstmt = con
278: .prepareCall("{call #testForceCharset2(?, ?)}");
279: cstmt.setString(1, value);
280: cstmt.registerOutParameter(2, Types.VARCHAR);
281: assertEquals(0, cstmt.executeUpdate());
282: assertEquals(value, cstmt.getString(2));
283: cstmt.close();
284: } finally {
285: con.close();
286: }
287: }
288:
289: /**
290: * Test for bug [1296482] setAutoCommit() behaviour.
291: * <p/>
292: * The behaviour of setAutoCommit() on ConnectionJDBC2 is inconsistent with
293: * the Sun JDBC 3.0 Specification. JDBC 3.0 Specification, section 10.1.1:
294: * <blockquote>"If the value of auto-commit is changed in the middle of a
295: * transaction, the current transaction is committed."</blockquote>
296: */
297: public void testAutoCommit() throws Exception {
298: Connection con = getConnectionOverrideProperties(new Properties());
299:
300: try {
301: Statement stmt = con.createStatement();
302: // Create temp table
303: assertEquals(
304: 0,
305: stmt
306: .executeUpdate("create table #testAutoCommit (i int)"));
307: // Manual commit mode
308: con.setAutoCommit(false);
309: // Insert one row
310: assertEquals(
311: 1,
312: stmt
313: .executeUpdate("insert into #testAutoCommit (i) values (0)"));
314: // Set commit mode to manual again; should have no effect
315: con.setAutoCommit(false);
316: // Rollback the transaction; should roll back the insert
317: con.rollback();
318: // Insert one more row
319: assertEquals(
320: 1,
321: stmt
322: .executeUpdate("insert into #testAutoCommit (i) values (1)"));
323: // Set commit mode to automatic; should commit everything
324: con.setAutoCommit(true);
325: // Go back to manual commit mode
326: con.setAutoCommit(false);
327: // Rollback transaction; should do nothing
328: con.rollback();
329: // And back to auto commit mode again
330: con.setAutoCommit(true);
331: // Now see if the second row is there
332: ResultSet rs = stmt
333: .executeQuery("select i from #testAutoCommit");
334: assertTrue(rs.next());
335: assertEquals(1, rs.getInt(1));
336: assertFalse(rs.next());
337: // We're done, close everything
338: rs.close();
339: stmt.close();
340: } finally {
341: con.close();
342: }
343: }
344: }
|