001: /*
002:
003: Derby - Class org.apache.derbyTesting.functionTests.tests.compatibility.CompatibilitySuite
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021: /**
022: * <p>
023: * This is the JUnit suite verifying compatibility of Derby clients and
024: * servers across Derby version levels and supported VMs. When you want
025: * to add a new class of tests to this suite, just add the classname to
026: * the accumulator in suite().
027: * </p>
028: *
029: * @author Rick
030: */package org.apache.derbyTesting.functionTests.tests.junitTests.compatibility;
031:
032: import java.io.*;
033: import java.sql.*;
034: import java.util.*;
035:
036: import junit.framework.*;
037:
038: import org.apache.derbyTesting.functionTests.util.DerbyJUnitTest;
039:
040: public class CompatibilitySuite extends DerbyJUnitTest {
041: /////////////////////////////////////////////////////////////
042: //
043: // CONSTANTS
044: //
045: /////////////////////////////////////////////////////////////
046:
047: // Supported versions of the db2jcc client.
048: public static final Version IBM_2_4 = new Version(2, 4);
049:
050: // Supported versions of Derby.
051: public static final Version DRB_10_0 = new Version(10, 0);
052: public static final Version DRB_10_1 = new Version(10, 1);
053: public static final Version DRB_10_2 = new Version(10, 2);
054:
055: // Supported VM versions.
056: public static final Version VM_1_3 = new Version(1, 3);
057: public static final Version VM_1_4 = new Version(1, 4);
058: public static final Version VM_1_5 = new Version(1, 5);
059:
060: public static final String SERVER_VERSION_FUNCTION = "getVMVersion";
061:
062: private static final String VERSION_PROPERTY = "java.version";
063:
064: private static final int EXPECTED_CLIENT_COUNT = 1;
065:
066: /////////////////////////////////////////////////////////////
067: //
068: // STATE
069: //
070: /////////////////////////////////////////////////////////////
071:
072: private static Driver _driver; // the corresponding jdbc driver
073: private static Version _clientVMLevel; // level of client-side vm
074: private static Version _serverVMLevel; // level of server vm
075: private static Version _driverLevel; // client rev level
076: private static Version _serverLevel; // server rev level
077:
078: /////////////////////////////////////////////////////////////
079: //
080: // JUnit BEHAVIOR
081: //
082: /////////////////////////////////////////////////////////////
083:
084: /**
085: * <p>
086: * JUnit boilerplate which adds as test cases all public methods
087: * whose names start with the string "test" in the named classes.
088: * When you want to add a new class of tests, just wire it into
089: * this suite.
090: * </p>
091: */
092: public static Test suite() {
093: TestSuite testSuite = new TestSuite();
094:
095: testSuite.addTestSuite(JDBCDriverTest.class);
096:
097: return testSuite;
098: }
099:
100: /////////////////////////////////////////////////////////////
101: //
102: // ENTRY POINT
103: //
104: /////////////////////////////////////////////////////////////
105:
106: /**
107: * <p>
108: * Run JDBC compatibility tests using either the specified client or
109: * the client that is visible
110: * on the classpath. If there is more than one client on the classpath,
111: * exits with an error.
112: * </p>
113: *
114: * <ul>
115: * <li>arg[ 0 ] = required name of database to connect to</li>
116: * <li>arg[ 1 ] = optional driver to use. if not specified, we'll look for a
117: * client on the classpath</li>
118: * </ul>
119: */
120: public static void main(String args[]) throws Exception {
121: int exitStatus = FAILURE_EXIT;
122:
123: if (parseDebug() && parseArgs(args) && parseVMLevel()
124: && findClient() && findServer()) {
125: TestResult result = junit.textui.TestRunner.run(suite());
126:
127: exitStatus = result.errorCount() + result.failureCount();
128: }
129:
130: Runtime.getRuntime().exit(exitStatus);
131: }
132:
133: /////////////////////////////////////////////////////////////
134: //
135: // PUBLIC BEHAVIOR
136: //
137: /////////////////////////////////////////////////////////////
138:
139: /**
140: * <p>
141: * Get the version of the server.
142: * </p>
143: */
144: public Version getServerVersion() {
145: return _serverLevel;
146: }
147:
148: /**
149: * <p>
150: * Get the version of the client.
151: * </p>
152: */
153: public Version getDriverVersion() {
154: return _driverLevel;
155: }
156:
157: /**
158: * <p>
159: * Get the vm level of the server.
160: * </p>
161: */
162: public static Version getServerVMVersion() {
163: return _serverVMLevel;
164: }
165:
166: /**
167: * <p>
168: * Get the vm level of the client.
169: * </p>
170: */
171: public Version getClientVMVersion() {
172: return _clientVMLevel;
173: }
174:
175: /////////////////////////////////////////////////////////////
176: //
177: // DATABASE-SIDE FUNCTIONS
178: //
179: /////////////////////////////////////////////////////////////
180:
181: /**
182: * <p>
183: * Get the vm level of the server.
184: * </p>
185: */
186: public static String getVMVersion() {
187: return System.getProperty(VERSION_PROPERTY);
188: }
189:
190: /////////////////////////////////////////////////////////////
191: //
192: // MINIONS
193: //
194: /////////////////////////////////////////////////////////////
195:
196: ///////////////////
197: //
198: // GENERAL MINIONS
199: //
200: ///////////////////
201:
202: //////////////////////////
203: //
204: // INITIALIZATION MINIONS
205: //
206: //////////////////////////
207:
208: //
209: // Initialize client settings based on the client found.
210: // Return true if one and only one client found, false otherwise.
211: // We allow for the special case when we're running the embedded client
212: // off the current compiled class tree rather than off product jars.
213: //
214: private static boolean findClient() throws Exception {
215: //
216: // The client may have been specified on the command line.
217: // In that case, we don't bother looking for a client on
218: // the classpath.
219: //
220: if (getClientSettings() != null) {
221: faultInDriver(getClientSettings());
222: } else {
223: String currentClientName = null;
224: int legalCount = LEGAL_CLIENTS.length;
225: int foundCount = 0;
226:
227: for (int i = 0; i < legalCount; i++) {
228: String[] candidate = LEGAL_CLIENTS[i];
229:
230: if (faultInDriver(candidate)) {
231: setClient(candidate);
232: foundCount++;
233: }
234: }
235:
236: if (foundCount != EXPECTED_CLIENT_COUNT) {
237: throw new Exception("Wrong number of drivers: "
238: + foundCount);
239: }
240: }
241:
242: // Now make sure that the JDBC driver is what we expect
243:
244: try {
245: _driver = DriverManager
246: .getDriver(getClientSettings()[DATABASE_URL]);
247: _driverLevel = new Version(_driver.getMajorVersion(),
248: _driver.getMinorVersion());
249: } catch (SQLException e) {
250: printStackTrace(e);
251:
252: throw new Exception(
253: "Driver doesn't understand expected URL: "
254: + getClientSettings()[DATABASE_URL]);
255: }
256:
257: println("Driver " + _driver.getClass().getName()
258: + " Version = " + _driverLevel);
259:
260: return true;
261: }
262:
263: //
264: // Initialize server settings. Assumes that you have called
265: // findClient().
266: //
267: private static boolean findServer() throws Exception {
268: try {
269: Connection conn = getConnection();
270: DatabaseMetaData dmd = conn.getMetaData();
271: String dbProductVersion = dmd.getDatabaseProductVersion();
272:
273: _serverLevel = new Version(dbProductVersion);
274:
275: parseServerVMVersion(conn);
276: } catch (Exception e) {
277: printStackTrace(e);
278:
279: throw new Exception("Error lookup up server info: "
280: + e.getMessage());
281: }
282:
283: println("Server Version = " + _serverLevel);
284:
285: return true;
286: }
287:
288: private static boolean parseVMLevel() throws Exception {
289: String vmVersion = getVMVersion();
290:
291: try {
292: _clientVMLevel = new Version(vmVersion);
293: } catch (NumberFormatException e) {
294: throw new Exception("Badly formatted vm version: "
295: + vmVersion);
296: }
297:
298: println("VM Version = " + _clientVMLevel);
299:
300: return true;
301: }
302:
303: private static boolean parseArgs(String args[]) throws Exception {
304: if ((args == null) || (args.length == 0)) {
305: throw new Exception("Missing database name.");
306: }
307:
308: setDatabaseName(args[0]);
309:
310: if ((args.length > 1) && !"".equals(args[1])) {
311: String desiredClientName = args[1];
312: int count = LEGAL_CLIENTS.length;
313:
314: for (int i = 0; i < count; i++) {
315: String[] candidate = LEGAL_CLIENTS[i];
316:
317: if (desiredClientName.equals(candidate[DRIVER_NAME])) {
318: setClient(candidate);
319: break;
320: }
321: }
322:
323: if (getClientSettings() == null) {
324: throw new Exception("Could not find client "
325: + desiredClientName + " on the classpath.");
326: }
327: }
328:
329: return true;
330: }
331:
332: /**
333: * <p>
334: * Get the vm level of the server.
335: * </p>
336: */
337: private static void parseServerVMVersion(Connection conn)
338: throws SQLException {
339: dropFunction(conn, SERVER_VERSION_FUNCTION);
340:
341: PreparedStatement ps = prepare(
342: conn,
343: "create function "
344: + SERVER_VERSION_FUNCTION
345: + "() returns varchar(50)\n"
346: + "parameter style java no sql language java\n"
347: + "external name 'org.apache.derbyTesting.functionTests.tests.junitTests.compatibility.CompatibilitySuite.getVMVersion'");
348: ps.execute();
349: close(ps);
350:
351: ps = prepare(conn, "values " + SERVER_VERSION_FUNCTION + "()");
352:
353: ResultSet rs = ps.executeQuery();
354: rs.next();
355: String rawVersion = rs.getString(1);
356: close(rs);
357: close(ps);
358:
359: _serverVMLevel = new Version(rawVersion);
360:
361: println("Server VM Version = " + _serverVMLevel);
362: }
363:
364: ///////////////
365: //
366: // SQL MINIONS
367: //
368: ///////////////
369:
370: /////////////////////////////////////////////////////////////
371: //
372: // INNER CLASSES
373: //
374: /////////////////////////////////////////////////////////////
375:
376: /**
377: * <p>
378: * This helper class exposes an entry point for creating an empty database.
379: * </p>
380: */
381: public static final class Creator {
382: private static CompatibilitySuite _driver = new CompatibilitySuite();
383:
384: /**
385: * <p>
386: * Wait for server to come up, then create the database.
387: * </p>
388: *
389: * <ul>
390: * <li>args[ 0 ] = name of database to create.</li>
391: * </ul>
392: */
393: public static void main(String[] args) throws Exception {
394: String databaseName = args[0];
395:
396: CompatibilitySuite.findClient();
397:
398: _driver.createDB(databaseName);
399: }
400:
401: }
402:
403: /**
404: * <p>
405: * A class for storing a major and minor version number. This class
406: * assumes that more capable versions compare greater than less capable versions.
407: * </p>
408: */
409: public static final class Version implements Comparable {
410: private int _major;
411: private int _minor;
412:
413: public Version(int major, int minor) {
414: constructorMinion(major, minor);
415: }
416:
417: public Version(String desc) throws NumberFormatException {
418: StringTokenizer tokens = new StringTokenizer(desc, ".");
419:
420: constructorMinion(java.lang.Integer.parseInt(tokens
421: .nextToken()), java.lang.Integer.parseInt(tokens
422: .nextToken()));
423: }
424:
425: private void constructorMinion(int major, int minor) {
426: _major = major;
427: _minor = minor;
428: }
429:
430: /**
431: * <p>
432: * Returns true if this Version is at least as advanced
433: * as that Version.
434: * </p>
435: */
436: public boolean atLeast(Version that) {
437: return this .compareTo(that) > -1;
438: }
439:
440: ////////////////////////////////////////////////////////
441: //
442: // Comparable BEHAVIOR
443: //
444: ////////////////////////////////////////////////////////
445:
446: public int compareTo(Object other) {
447: if (other == null) {
448: return -1;
449: }
450: if (!(other instanceof Version)) {
451: return -1;
452: }
453:
454: Version that = (Version) other;
455:
456: if (this ._major < that._major) {
457: return -1;
458: }
459: if (this ._major > that._major) {
460: return 1;
461: }
462:
463: return this ._minor - that._minor;
464: }
465:
466: ////////////////////////////////////////////////////////
467: //
468: // Object OVERLOADS
469: //
470: ////////////////////////////////////////////////////////
471:
472: public String toString() {
473: return Integer.toString(_major) + '.'
474: + Integer.toString(_minor);
475: }
476:
477: public boolean equals(Object other) {
478: return (compareTo(other) == 0);
479: }
480:
481: public int hashCode() {
482: return _major ^ _minor;
483: }
484:
485: }
486:
487: }
|