001: /*
002: *
003: * Derby - Class TestConfiguration
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,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
017: * either express or implied. See the License for the specific
018: * language governing permissions and limitations under the License.
019: */
020: package org.apache.derbyTesting.junit;
021:
022: import java.io.File;
023: import java.lang.reflect.Method;
024: import java.security.*;
025: import java.sql.Connection;
026: import java.sql.DriverManager;
027: import java.sql.SQLException;
028: import java.util.Properties;
029:
030: import junit.framework.Test;
031: import junit.framework.TestCase;
032:
033: import org.apache.derbyTesting.functionTests.util.TestDataSourceFactory;
034:
035: /**
036: * Class which holds information about the configuration of a Test.
037: */
038: public class TestConfiguration {
039: /**
040: * Default values for configurations
041: */
042: private final static String DEFAULT_DBNAME = "wombat";
043: private final static String DEFAULT_USER_NAME = "APP";
044: private final static String DEFAULT_USER_PASSWORD = "APP";
045: private final static int DEFAULT_PORT = 1527;
046: private final static String DEFAULT_FRAMEWORK = "embedded";
047: private final static String DEFAULT_HOSTNAME = "localhost";
048:
049: /**
050: * Keys to use to look up values in properties files.
051: */
052: private final static String KEY_DBNAME = "databaseName";
053: private final static String KEY_FRAMEWORK = "framework";
054: private final static String KEY_USER_PASSWORD = "password";
055: private final static String KEY_USER_NAME = "user";
056: private final static String KEY_HOSTNAME = "hostName";
057: private final static String KEY_PORT = "port";
058: private final static String KEY_VERBOSE = "derby.tests.debug";
059: private final static String KEY_SINGLE_LEG_XA = "derbyTesting.xa.single";
060:
061: /**
062: * Possible values of system properties.
063: */
064: private final static String UNUSED = "file://unused/";
065:
066: /**
067: * Default Derby test configuration object based
068: * upon system properties set by the old harness.
069: */
070: private static final TestConfiguration DERBY_HARNESS_CONFIG = new TestConfiguration(
071: getSystemProperties());
072:
073: /**
074: * Default configuration for standalone JUnit tests,
075: * an embedded configuration.
076: */
077: private static final TestConfiguration JUNIT_CONFIG = new TestConfiguration();
078:
079: /**
080: * The default configuration.
081: */
082: private static final TestConfiguration DEFAULT_CONFIG;
083:
084: /**
085: * Are we running in the harness, assume so if framework
086: * was set so the
087: */
088: private static final boolean runningInDerbyHarness;
089:
090: static {
091: boolean assumeHarness = false;
092:
093: // In the harness if the default configuration according
094: // to system properties is not embedded.
095: if (!DERBY_HARNESS_CONFIG.getJDBCClient().isEmbedded())
096: assumeHarness = true;
097:
098: // Assume harness if database name is not default
099: if (!DERBY_HARNESS_CONFIG.getDatabaseName().equals(
100: DEFAULT_DBNAME))
101: assumeHarness = true;
102:
103: // Assume harness if user name is not default
104: if (!DERBY_HARNESS_CONFIG.getUserName().equals(
105: DEFAULT_USER_NAME))
106: assumeHarness = true;
107:
108: // If derby.system.home set externally at startup assume
109: // running in harness
110: if (BaseTestCase.getSystemProperty("derby.system.home") != null)
111: assumeHarness = true;
112:
113: // for now always assume harness - still testing this code
114: assumeHarness = true;
115:
116: DEFAULT_CONFIG = assumeHarness ? DERBY_HARNESS_CONFIG
117: : JUNIT_CONFIG;
118: runningInDerbyHarness = assumeHarness;
119:
120: if (!assumeHarness) {
121: File dsh = new File("system");
122:
123: BaseTestCase.setSystemProperty("derby.system.home", dsh
124: .getAbsolutePath());
125: }
126: }
127:
128: /**
129: * Current configuration is stored in a ThreadLocal to
130: * allow the potential for multiple tests to be running
131: * concurrently with different configurations.
132: */
133: private static final ThreadLocal CURRENT_CONFIG = new ThreadLocal() {
134: protected Object initialValue() {
135: return DEFAULT_CONFIG;
136: }
137: };
138:
139: /**
140: * Get this Thread's current configuraiton for running
141: * the tests.
142: * @return TestConfiguration to use.
143: */
144: public static TestConfiguration getCurrent() {
145: return (TestConfiguration) CURRENT_CONFIG.get();
146: }
147:
148: /**
149: * WORK IN PROGRESS
150: * Set this Thread's current configuration for running tests.
151: * @param config Configuration to set it to.
152: */
153: static void setCurrent(TestConfiguration config) {
154: CURRENT_CONFIG.set(config);
155: }
156:
157: /**
158: * Return a decorator for the passed in tests that sets the
159: * configuration for the client to be Derby's JDBC client
160: * and to start the network server at setUp and shut it
161: * down at tearDown.
162: * <BR>
163: * The database configuration (name etc.) is based upon
164: * the previous configuration.
165: * <BR>
166: * The previous TestConfiguration is restored at tearDown.
167: * @param tests
168: * @return
169: * @throws Exception
170: */
171: public static Test derbyClientServerDecorator(Class suite)
172: throws Exception {
173: TestConfiguration config = TestConfiguration.getCurrent();
174:
175: TestConfiguration derbyClientConfig = new TestConfiguration(
176: config, JDBCClient.DERBYNETCLIENT, DEFAULT_HOSTNAME,
177: DEFAULT_PORT);
178:
179: TestConfiguration.setCurrent(derbyClientConfig);
180:
181: Test test = addSuiteByReflection(suite);
182:
183: TestConfiguration.setCurrent(config);
184:
185: test = new NetworkServerTestSetup(test);
186:
187: return new ChangeConfigurationSetup(derbyClientConfig, test);
188:
189: }
190:
191: private static Test addSuiteByReflection(Class clz)
192: throws Exception {
193: Method sm = clz.getMethod("suite", null);
194:
195: return (Test) sm.invoke(null, null);
196: }
197:
198: public static Test changeUserDecorator(Test test, String user,
199: String password) {
200: return new ChangeUserSetup(test, user, password);
201: }
202:
203: /**
204: * Default embedded configuration
205: *
206: */
207: private TestConfiguration() {
208: this .dbName = DEFAULT_DBNAME;
209: this .userName = DEFAULT_USER_NAME;
210: this .userPassword = DEFAULT_USER_PASSWORD;
211: this .hostName = null;
212: this .port = -1;
213: this .singleLegXA = false;
214:
215: this .jdbcClient = JDBCClient.EMBEDDED;
216: url = createJDBCUrlWithDatabaseName(dbName);
217:
218: }
219:
220: private TestConfiguration(TestConfiguration copy,
221: JDBCClient client, String hostName, int port) {
222: this .dbName = copy.dbName;
223: this .userName = copy.userName;
224: this .userPassword = copy.userPassword;
225:
226: this .isVerbose = copy.isVerbose;
227: this .singleLegXA = copy.singleLegXA;
228: this .port = port;
229:
230: this .jdbcClient = client;
231: this .hostName = hostName;
232:
233: this .url = createJDBCUrlWithDatabaseName(dbName);
234: }
235:
236: /**
237: * Obtain a new configuration identical to the passed in
238: * one except for the default user and password.
239: * @param copy Configuration to copy.
240: * @param user New default user
241: * @param password New default password.
242: */
243: TestConfiguration(TestConfiguration copy, String user,
244: String password) {
245: this .dbName = copy.dbName;
246: this .userName = user;
247: this .userPassword = password;
248:
249: this .isVerbose = copy.isVerbose;
250: this .singleLegXA = copy.singleLegXA;
251: this .port = copy.port;
252:
253: this .jdbcClient = copy.jdbcClient;
254: this .hostName = copy.hostName;
255:
256: this .url = copy.url;
257: }
258:
259: /**
260: * This constructor creates a TestConfiguration from a Properties object.
261: *
262: * @throws NumberFormatException if the port specification is not an integer.
263: */
264: private TestConfiguration(Properties props)
265: throws NumberFormatException {
266:
267: dbName = props.getProperty(KEY_DBNAME, DEFAULT_DBNAME);
268: userName = props.getProperty(KEY_USER_NAME, DEFAULT_USER_NAME);
269: userPassword = props.getProperty(KEY_USER_PASSWORD,
270: DEFAULT_USER_PASSWORD);
271: hostName = props.getProperty(KEY_HOSTNAME, DEFAULT_HOSTNAME);
272: isVerbose = Boolean.valueOf(props.getProperty(KEY_VERBOSE))
273: .booleanValue();
274: String portStr = props.getProperty(KEY_PORT);
275: singleLegXA = Boolean.valueOf(
276: props.getProperty(KEY_SINGLE_LEG_XA)).booleanValue();
277: if (portStr != null) {
278: try {
279: port = Integer.parseInt(portStr);
280: } catch (NumberFormatException nfe) {
281: // We lose stacktrace here, but it is not important.
282: throw new NumberFormatException(
283: "Port number must be an integer. Value: "
284: + portStr);
285: }
286: } else {
287: port = DEFAULT_PORT;
288: }
289:
290: String framework = props.getProperty(KEY_FRAMEWORK,
291: DEFAULT_FRAMEWORK);
292:
293: if ("DerbyNetClient".equals(framework)) {
294: jdbcClient = JDBCClient.DERBYNETCLIENT;
295: } else if ("DerbyNet".equals(framework)) {
296: jdbcClient = JDBCClient.DB2CLIENT;
297: } else {
298: jdbcClient = JDBCClient.EMBEDDED;
299: }
300: url = createJDBCUrlWithDatabaseName(dbName);
301: }
302:
303: /**
304: * Get the system properties in a privileged block.
305: *
306: * @return the system properties.
307: */
308: private static final Properties getSystemProperties() {
309: // Fetch system properties in a privileged block.
310: Properties sysProps = (Properties) AccessController
311: .doPrivileged(new PrivilegedAction() {
312: public Object run() {
313: return System.getProperties();
314: }
315: });
316: return sysProps;
317: }
318:
319: /**
320: * Create JDBC connection url, including the name of the database.
321: *
322: * @return JDBC connection url, without attributes.
323: */
324: private String createJDBCUrlWithDatabaseName(String name) {
325: if (jdbcClient == JDBCClient.EMBEDDED) {
326: return jdbcClient.getUrlBase() + name;
327: } else {
328: return jdbcClient.getUrlBase() + hostName + ":" + port
329: + "/" + name;
330: }
331: }
332:
333: /**
334: * Get configured JDBCClient object.
335: *
336: * @return JDBCClient
337: */
338: public JDBCClient getJDBCClient() {
339: return jdbcClient;
340: }
341:
342: /**
343: * Return the jdbc url for connecting to the default database.
344: *
345: * @return JDBC url.
346: */
347: public String getJDBCUrl() {
348: return url;
349: }
350:
351: /**
352: * Return the jdbc url for a connecting to the database.
353: *
354: * @param databaseName name of database.
355: * @return JDBC connection url, including database name.
356: */
357: public String getJDBCUrl(String databaseName) {
358: return createJDBCUrlWithDatabaseName(databaseName);
359: }
360:
361: /**
362: * Return the default database name.
363: *
364: * @return default database name.
365: */
366: public String getDatabaseName() {
367: return dbName;
368: }
369:
370: /**
371: * Return the user name.
372: *
373: * @return user name.
374: */
375: public String getUserName() {
376: return userName;
377: }
378:
379: /**
380: * Return the user password.
381: *
382: * @return user password.
383: */
384: public String getUserPassword() {
385: return userPassword;
386: }
387:
388: /**
389: * Return the host name for the network server.
390: *
391: * @return host name.
392: */
393: public String getHostName() {
394: return hostName;
395: }
396:
397: /**
398: * Get port number for network server.
399: *
400: * @return port number.
401: */
402: public int getPort() {
403: return port;
404: }
405:
406: /**
407: * Open connection to the default database.
408: * If the database does not exist, it will be created.
409: * A default username and password will be used for the connection.
410: *
411: * @return connection to default database.
412: */
413: public Connection openDefaultConnection() throws SQLException {
414: return getDefaultConnection("create=true");
415: }
416:
417: /**
418: * Open a connection to a database.
419: * If the database does not exist, it will be created.
420: * A default username and password will be used for the connection.
421: *
422: * @param databaseName database to connect to
423: *
424: * @return connection to database.
425: */
426: public Connection openConnection(String databaseName)
427: throws SQLException {
428: return getConnection(databaseName, "create=true");
429: }
430:
431: /**
432: * Get a connection to the default database using the specified connection
433: * attributes.
434: *
435: * @param connAttrs connection attributes
436: * @return connection to database.
437: * @throws SQLException
438: */
439: public Connection getDefaultConnection(String connAttrs)
440: throws SQLException {
441: return getConnection(getDatabaseName(), connAttrs);
442: }
443:
444: /**
445: * Get a connection to a database using the specified connection
446: * attributes.
447: *
448: * @param databaseName database to connect to
449: * @param connAttrs connection attributes
450: * @return connection to database.
451: * @throws SQLException
452: */
453: public Connection getConnection(String databaseName,
454: String connAttrs) throws SQLException {
455: Connection con = null;
456: JDBCClient client = getJDBCClient();
457: if (JDBC.vmSupportsJDBC2()) {
458: loadJDBCDriver(client.getJDBCDriverName());
459: if (!isSingleLegXA()) {
460: con = DriverManager.getConnection(
461: getJDBCUrl(databaseName) + ";" + connAttrs,
462: getUserName(), getUserPassword());
463: } else {
464: Properties attrs = getDataSourcePropertiesForDatabase(
465: databaseName, connAttrs);
466: con = TestDataSourceFactory.getXADataSource(attrs)
467: .getXAConnection(getUserName(),
468: getUserPassword()).getConnection();
469: }
470: } else {
471: //Use DataSource for JSR169
472: Properties attrs = getDataSourcePropertiesForDatabase(
473: databaseName, connAttrs);
474: con = TestDataSourceFactory.getDataSource(attrs)
475: .getConnection();
476: }
477: return con;
478: }
479:
480: /**
481: * Set the verbosity, i.e., whether debug statements print.
482: */
483: public void setVerbosity(boolean isChatty) {
484: isVerbose = isChatty;
485: }
486:
487: /**
488: * Return verbose flag.
489: *
490: * @return verbose flag.
491: */
492: public boolean isVerbose() {
493: return isVerbose;
494: }
495:
496: /**
497: * <p>
498: * Return true if we classes are being loaded from jar files. For the time
499: * being, this simply tests that the JVMInfo class (common to the client and
500: * the server) comes out of a jar file.
501: * </p>
502: */
503: public static boolean loadingFromJars() {
504: return SecurityManagerSetup.isJars;
505: }
506:
507: /**
508: * Is this JUnit test being run by the old harness.
509: * Temp method to ease the switch over by allowing
510: * suites to alter their behaviour based upon the
511: * need to still run under the old harness.
512: * @return
513: */
514: public static boolean runningInDerbyHarness() {
515: return runningInDerbyHarness;
516: }
517:
518: /**
519: * Return if it has to run under single legged xa transaction
520: * @return singleLegXA
521: */
522: public boolean isSingleLegXA() {
523: return singleLegXA;
524: }
525:
526: /**
527: * Get a folder already created where a test can
528: * write its failure information. The name of the folder,
529: * relative to ${user.dir} is:
530: * <BR>
531: * <code>
532: * fail/client/testclass/testname
533: * <code>
534: * <UL>
535: * <LI> client - value of JDBCClient.getName() for the test's configuration
536: * <LI> testclass - last element of the class name
537: * <LI> testname - value of test.getName()
538: * </UL>
539: */
540: File getFailureFolder(TestCase test) {
541:
542: StringBuffer sb = new StringBuffer();
543:
544: sb.append("fail");
545: sb.append(File.separatorChar);
546: sb.append(getJDBCClient().getName());
547: sb.append(File.separatorChar);
548:
549: String className = test.getClass().getName();
550: int lastDot = className.lastIndexOf('.');
551: if (lastDot != -1)
552: className = className.substring(lastDot + 1, className
553: .length());
554:
555: sb.append(className);
556: sb.append(File.separatorChar);
557: sb.append(test.getName());
558:
559: String base = sb.toString().intern();
560: final File folder = new File(base);
561:
562: // Create the folder
563: // TODO: Dump this configuration in some human readable format
564: synchronized (base) {
565:
566: AccessController
567: .doPrivileged(new java.security.PrivilegedAction() {
568: public Object run() {
569: if (folder.exists()) {
570: // do something
571: }
572: return new Boolean(folder.mkdirs());
573: }
574: });
575: }
576:
577: return folder;
578:
579: }
580:
581: /**
582: * Immutable data members in test configuration
583: */
584: private final String dbName;
585: private final String url;
586: private final String userName;
587: private final String userPassword;
588: private final int port;
589: private final String hostName;
590: private final JDBCClient jdbcClient;
591: private boolean isVerbose;
592: private final boolean singleLegXA;
593:
594: /**
595: * Generate properties which can be set on a
596: * <code>DataSource</code> in order to connect to the default
597: * database. If the database does not exist, it will be created.
598: *
599: * @return a <code>Properties</code> object containing server
600: * name, port number, database name and other attributes needed to
601: * connect to the default database
602: */
603: public static Properties getDefaultDataSourceProperties() {
604: return getDataSourcePropertiesForDatabase(getCurrent()
605: .getDatabaseName(), "create=true");
606: }
607:
608: /**
609: * Generate properties which can be set on a <code>DataSource</code>
610: * in order to connect to a database using the specified connection
611: * attributes.
612: *
613: * @param databaseName database to connect to
614: * @param connAttrs connection attributes
615: * @return
616: */
617: public static Properties getDataSourcePropertiesForDatabase(
618: String databaseName, String connAttrs) {
619: Properties attrs = new Properties();
620: if (!(getCurrent().getJDBCClient() == JDBCClient.EMBEDDED)) {
621: attrs.setProperty("serverName", getCurrent().getHostName());
622: attrs.setProperty("portNumber", Integer
623: .toString(getCurrent().getPort()));
624: }
625: attrs.setProperty("databaseName", databaseName);
626: attrs.setProperty("connectionAttributes", connAttrs);
627: return attrs;
628: }
629:
630: /**
631: * Load the specified JDBC driver
632: *
633: * @param driverClass name of the JDBC driver class.
634: * @throws SQLException if loading the driver fails.
635: */
636: private static void loadJDBCDriver(String driverClass)
637: throws SQLException {
638: try {
639: Class.forName(driverClass).newInstance();
640: } catch (ClassNotFoundException cnfe) {
641: throw new SQLException("Failed to load JDBC driver '"
642: + driverClass + "': " + cnfe.getMessage());
643: } catch (IllegalAccessException iae) {
644: throw new SQLException("Failed to load JDBC driver '"
645: + driverClass + "': " + iae.getMessage());
646: } catch (InstantiationException ie) {
647: throw new SQLException("Failed to load JDBC driver '"
648: + driverClass + "': " + ie.getMessage());
649: }
650: }
651:
652: /*
653: * SecurityManager related configuration.
654: */
655:
656: /**
657: * Install the default security manager setup,
658: * for the current configuration.
659: * @throws PrivilegedActionException
660: */
661: boolean defaultSecurityManagerSetup()
662: throws PrivilegedActionException {
663:
664: // Testing with the DB2 client has not been performed
665: // under the security manager since it's not part
666: // of Derby so no real interest in tracking down issues.
667: if (jdbcClient.isDB2Client()) {
668: SecurityManagerSetup.noSecurityManager();
669: return false;
670: } else {
671: SecurityManagerSetup.installSecurityManager();
672: return true;
673: }
674: }
675:
676: }
|