| /* |
| * |
| * Derby - Class org.apache.derbyTesting.junit.TestConfiguration |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, |
| * either express or implied. See the License for the specific |
| * language governing permissions and limitations under the License. |
| */ |
| package org.apache.derbyTesting.junit; |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.security.PrivilegedActionException; |
| import java.sql.Connection; |
| import java.sql.SQLException; |
| import java.util.ArrayList; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Properties; |
| import junit.extensions.TestSetup; |
| import junit.framework.Assert; |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| |
| /** |
| * Class which holds information about the configuration of a Test. |
| * |
| * A configuration manages the pool of databases in use |
| * in <code>usedDbNames</code> property. One of those databases |
| * is supposed to be the default database. A new default database |
| * is added to the pool by <code>singleUseDatabaseDecorator</code> function. |
| * <br> |
| * Additional databases may be added by <code>additionalDatabaseDecorator</code> |
| * function. Each of the additional databases has its logical and physical name. |
| * Physical database name is automatically generated as 'singleUse/oneuseXX' |
| * where 'XX' is unique number. The logical database name is used to establish |
| * a connection to the database using |
| * a <code>TestConfiguration::openConnection(String logicalDatabaseName)</code> |
| * function. |
| * <br> |
| * The database files are supposed to be local and they will be |
| * removed by <code>DropDatabaseSetup</code>. |
| * |
| */ |
| public final class TestConfiguration { |
| /** |
| * Default values for configurations |
| */ |
| private final static String DEFAULT_DBNAME = "wombat"; |
| private final static String DEFAULT_DBNAME_SQL = "dbsqlauth"; |
| |
| private final static String DEFAULT_USER_NAME = "APP"; |
| private final static String DEFAULT_USER_PASSWORD = "APP"; |
| private final static int DEFAULT_PORT = 1527; |
| private final static String DEFAULT_FRAMEWORK = "embedded"; |
| private final static String DEFAULT_HOSTNAME = "localhost"; |
| |
| private static final int LOCKFILETIMEOUT = 300000; // 5 mins |
| |
| /** |
| * Maximum number of ports used by Suites.All |
| * If this changes, this constant and the Wiki |
| * page at http://wiki.apache.org/db-derby/DerbyJUnitTesting |
| * need to be updated. |
| */ |
| private final static int MAX_PORTS_USED = 22; |
| |
| /** This is the base port. This does NOT change EVER during the run of a suite. |
| * It is set using the property derby.tests.basePort and it is set to default when |
| * a property isn't used. */ |
| private final static int basePort; |
| private static int lastAssignedPort; |
| private static final int bogusPort; |
| static { |
| String port = BaseTestCase.getSystemProperty("derby.tests.basePort"); |
| if (port == null) { |
| lastAssignedPort = DEFAULT_PORT; |
| } else { |
| lastAssignedPort = Integer.parseInt(port); |
| } |
| basePort = lastAssignedPort; |
| bogusPort = ++lastAssignedPort; |
| } |
| private static int assignedPortCount = 2; |
| |
| private FileOutputStream serverOutput; |
| |
| /** Sleep for 1000 ms before pinging the network server (again) */ |
| private static final int SLEEP_TIME = 1000; |
| |
| /** |
| * Keys to use to look up values in properties files. |
| */ |
| private final static String KEY_DBNAME = "databaseName"; |
| private final static String KEY_FRAMEWORK = "framework"; |
| private final static String KEY_USER_PASSWORD = "password"; |
| private final static String KEY_USER_NAME = "user"; |
| private final static String KEY_HOSTNAME = "hostName"; |
| private final static String KEY_PORT = "port"; |
| private final static String KEY_VERBOSE = "derby.tests.debug"; |
| private final static String KEY_LOGIN_TIMEOUT = "derby.tests.login.timeout"; |
| private final static String KEY_TRACE = "derby.tests.trace"; |
| public final static String KEY_OMIT_LUCENE = "derby.tests.omitLucene"; |
| public final static String KEY_OMIT_JSON = "derby.tests.omitJson"; |
| |
| /** |
| * derby.tests.stopAfterFirstFail - debugging property to exit after |
| * first failure. Can be useful for debugging cascading failures or errors |
| * that lead to hang scenario. |
| */ |
| private final static String KEY_STOP_AFTER_FIRST_FAIL = "derby.tests.stopAfterFirstFail"; |
| private final static String KEY_SSL = "ssl"; |
| private final static String KEY_JMX_PORT = "jmxPort"; |
| |
| /** |
| * Simple count to provide a unique number for database |
| * names. |
| */ |
| private static int uniqueDB; |
| |
| /** Repository of old/previous Derby releases available on the local system. */ |
| private static ReleaseRepository releaseRepository; |
| |
| /** |
| * Default configuration for standalone JUnit tests, |
| * an embedded configuration. |
| */ |
| private static final TestConfiguration JUNIT_CONFIG |
| = new TestConfiguration(); |
| |
| /** |
| * The default configuration. |
| */ |
| private static final TestConfiguration DEFAULT_CONFIG; |
| |
| static { |
| DEFAULT_CONFIG = JUNIT_CONFIG; |
| |
| final File dsh = new File("system"); |
| |
| BaseTestCase.setSystemProperty( |
| "derby.system.home", dsh.getAbsolutePath()); |
| } |
| |
| /** |
| * Current configuration is stored in a ThreadLocal to |
| * allow the potential for multiple tests to be running |
| * concurrently with different configurations. |
| */ |
| private static final ThreadLocal<TestConfiguration> |
| CURRENT_CONFIG = new ThreadLocal<TestConfiguration>() { |
| protected TestConfiguration initialValue() { |
| return DEFAULT_CONFIG; |
| } |
| }; |
| |
| /** |
| * Get this Thread's current configuraiton for running |
| * the tests. |
| * Note this call must only be used while a test is |
| * running, they make no sense when setting up a suite. |
| * A suite itself sets up which test configurations |
| * the fixtures will run in. |
| |
| * @return TestConfiguration to use. |
| */ |
| public static TestConfiguration getCurrent() { |
| return (TestConfiguration) CURRENT_CONFIG.get(); |
| } |
| |
| /** |
| * Returns the release repository containing old Derby releases available |
| * on the local system. |
| * <p> |
| * <strong>NOTE</strong>: It is your responsibility to keep the repository |
| * up to date. This usually involves syncing the local Subversion repository |
| * of previous Derby releases with the master repository at Apache. |
| * |
| * @see ReleaseRepository |
| */ |
| public static synchronized ReleaseRepository getReleaseRepository() { |
| if (releaseRepository == null) { |
| try { |
| releaseRepository = ReleaseRepository.getInstance(); |
| } catch (IOException ioe) { |
| BaseTestCase.printStackTrace(ioe); |
| Assert.fail("failed to initialize the release repository: " + |
| ioe.getMessage()); |
| } |
| } |
| return releaseRepository; |
| } |
| |
| /** |
| * WORK IN PROGRESS |
| * Set this Thread's current configuration for running tests. |
| * @param config Configuration to set it to. |
| */ |
| static void setCurrent(TestConfiguration config) |
| { |
| CURRENT_CONFIG.set(config); |
| } |
| |
| |
| /** |
| * Return a Test suite that contains all the test fixtures |
| * for the passed in class running in embedded and the |
| * default client server configuration. |
| * <BR> |
| * Each set of embedded and set of client server tests |
| * is decorated with a CleanDatabaseTestSetup. |
| * <BR> |
| * The client server configuration is setup using clientServerSuite |
| */ |
| public static Test defaultSuite(Class testClass) |
| { |
| return defaultSuite(testClass, true); |
| } |
| |
| /** |
| * Does the work of "defaultSuite" as defined above. Takes |
| * a boolean argument to determine whether or not to "clean" |
| * the test database before each suite. If the resultant |
| * suite is going to be wrapped inside a TestSetup that creates |
| * database objects to be used throughout the tests, then the |
| * cleanDB parameter should be "false" to prevent cleanup of the |
| * database objects that TestSetup created. For example, see |
| * XMLBindingTest.suite(). |
| */ |
| public static Test defaultSuite(Class testClass, boolean cleanDB) |
| { |
| final BaseTestSuite suite = new BaseTestSuite(suiteName(testClass)); |
| |
| if (cleanDB) |
| { |
| suite.addTest(new CleanDatabaseTestSetup(embeddedSuite(testClass))); |
| suite.addTest(new CleanDatabaseTestSetup(clientServerSuite(testClass))); |
| } |
| else |
| { |
| suite.addTest(embeddedSuite(testClass)); |
| suite.addTest(clientServerSuite(testClass)); |
| } |
| |
| return (suite); |
| } |
| /** |
| * Equivalent to "defaultSuite" as defined above, but assumes a server |
| * has already been started. |
| * <BR> |
| * Does NOT decorate for running in embedded mode, only for running on |
| * the already started server. |
| * <BR> |
| * Return a Test suite that contains all the test fixtures |
| * for the passed in class running in client server configuration |
| * on an already started server. |
| * <BR> |
| * The set of client server tests |
| * is decorated with a CleanDatabaseTestSetup. |
| * <BR> |
| * The client server configuration is setup using clientExistingServerSuite |
| */ |
| public static Test defaultExistingServerSuite(Class testClass) |
| { |
| return defaultExistingServerSuite(testClass, true); |
| } |
| |
| /** |
| * Does the work of "defaultExistingServerSuite" as defined above. Takes |
| * a boolean argument to determine whether or not to "clean" |
| * the test database before each suite. If the resultant |
| * suite is going to be wrapped inside a TestSetup that creates |
| * database objects to be used throughout the tests, then the |
| * cleanDB parameter should be "false" to prevent cleanup of the |
| * database objects that TestSetup created. |
| * <BR> |
| * Does NOT decorate for running in embedded mode, only for running on |
| * an already started server. |
| */ |
| public static Test defaultExistingServerSuite(Class testClass, boolean cleanDB) |
| { |
| final BaseTestSuite suite = new BaseTestSuite(suiteName(testClass)); |
| |
| if (cleanDB) |
| { |
| suite.addTest(new CleanDatabaseTestSetup(clientExistingServerSuite(testClass))); |
| } |
| else |
| { |
| suite.addTest(clientExistingServerSuite(testClass)); |
| } |
| |
| return (suite); |
| } |
| |
| /** |
| * Return a Test suite that contains all the test fixtures |
| * for the passed in class running in client server configuration |
| * on an already started server on a given host and port number. |
| * <BR> |
| * Takes a boolean argument to determine whether or not to "clean" |
| * the test database before each suite. If the resultant |
| * suite is going to be wrapped inside a TestSetup that creates |
| * database objects to be used throughout the tests, then the |
| * cleanDB parameter should be "false" to prevent cleanup of the |
| * database objects that TestSetup created. |
| * <BR> |
| * Takes a String argument to specify which host the server runs on, and |
| * takes an int argument to specify the port number to use. |
| * <BR> |
| * Does NOT decorate for running in embedded mode, only for running on |
| * an already started server. |
| * <BR> |
| * The set of client server tests |
| * is decorated with a CleanDatabaseTestSetup. |
| * <BR> |
| * The client server configuration is setup using clientExistingServerSuite |
| */ |
| public static Test existingServerSuite(Class testClass, |
| boolean cleanDB, |
| String hostName, |
| int portNumber) |
| { |
| final BaseTestSuite suite = new BaseTestSuite(suiteName(testClass)); |
| |
| if (cleanDB) |
| { |
| suite.addTest(new CleanDatabaseTestSetup( |
| clientExistingServerSuite(testClass, hostName, portNumber))); |
| } |
| else |
| { |
| suite.addTest(clientExistingServerSuite(testClass, hostName, portNumber)); |
| } |
| |
| return (suite); |
| } |
| public static Test existingServerSuite(Class testClass, |
| boolean cleanDB, |
| String hostName, |
| int portNumber, |
| String dbPath) |
| { |
| final BaseTestSuite suite = new BaseTestSuite(suiteName(testClass)); |
| |
| if (cleanDB) |
| { |
| suite.addTest(new CleanDatabaseTestSetup( |
| clientExistingServerSuite(testClass, hostName, portNumber, dbPath))); |
| } |
| else |
| { |
| suite.addTest(clientExistingServerSuite(testClass, hostName, portNumber, dbPath)); |
| } |
| |
| return (suite); |
| } |
| |
| /** |
| * Return a Test suite that contains all the test fixtures |
| * for the passed in class running in embedded and client- |
| * server *JDBC3* configurations. |
| * <BR> |
| * Each set of embedded and set of client server tests is |
| * decorated with a CleanDatabaseTestSetup. |
| * <BR> |
| */ |
| public static Test forceJDBC3Suite(Class testClass) |
| { |
| final BaseTestSuite suite = new BaseTestSuite(suiteName(testClass)); |
| |
| suite.addTest( |
| new CleanDatabaseTestSetup( |
| forceJDBC3Embedded(embeddedSuite(testClass)))); |
| |
| suite.addTest( |
| new CleanDatabaseTestSetup( |
| forceJDBC3NetClient(clientServerSuite(testClass)))); |
| |
| return (suite); |
| } |
| |
| /** |
| * Generate a suite name from a class name, taking |
| * only the last element of the fully qualified class name. |
| */ |
| static String suiteName(Class testClass) |
| { |
| int lastDot = testClass.getName().lastIndexOf('.'); |
| String suiteName = testClass.getName(); |
| if (lastDot != -1) |
| suiteName = suiteName.substring(lastDot + 1, suiteName.length()); |
| |
| return suiteName; |
| } |
| |
| /** |
| * Create a suite for the passed test class that includes |
| * all the default fixtures from the class. |
| */ |
| public static Test embeddedSuite(Class testClass) |
| { |
| return new BaseTestSuite(testClass, |
| suiteName(testClass)+":embedded"); |
| } |
| |
| /** |
| * Create a suite for the passed test class that includes |
| * all the default fixtures from the class, wrapped in |
| * a derbyClientServerDecorator. |
| * |
| */ |
| public static Test clientServerSuite(Class testClass) |
| { |
| return clientServerDecorator(bareClientServerSuite(testClass)); |
| } |
| /** |
| * Create a suite for the passed test class that includes |
| * all the default fixtures from the class, wrapped in |
| * a derbyClientServerDecorator with alternative port. |
| * |
| */ |
| |
| public static Test clientServerSuiteWithAlternativePort(Class testClass) { |
| return clientServerDecoratorWithAlternativePort( |
| bareClientServerSuite(testClass)); |
| } |
| |
| /** |
| * Equivalent to 'clientServerSuite' above, but assumes server is |
| * already running. |
| * |
| */ |
| public static Test clientExistingServerSuite(Class testClass) |
| { |
| // Will not start server and does not stop it when done. |
| return defaultExistingServerDecorator(bareClientServerSuite(testClass)); |
| } |
| |
| /** |
| * Create a suite for the passed test class that includes |
| * all the default fixtures from the class, wrapped in |
| * a existingServerDecorator. |
| * <BR> |
| * Equivalent to 'clientServerSuite' above, but assumes server is |
| * already running. Will also NOT shut down the server. |
| * |
| */ |
| public static Test clientExistingServerSuite(Class testClass, String hostName, int portNumber) |
| { |
| // Will not start server and does not stop it when done!. |
| return existingServerDecorator(bareClientServerSuite(testClass), |
| hostName, portNumber); |
| } |
| public static Test clientExistingServerSuite(Class testClass, |
| String hostName, int portNumber, String dbPath) |
| { |
| // Will not start server and does not stop it when done!. |
| return existingServerDecorator(bareClientServerSuite(testClass), |
| hostName, portNumber, dbPath); |
| } |
| |
| /** |
| * Return a decorator for the passed in tests that sets the |
| * configuration for the client to be Derby's JDBC client |
| * and to start the network server at setUp. |
| * <BR> |
| * The database configuration (name etc.) is based upon |
| * the previous configuration. |
| * <BR> |
| * The previous TestConfiguration is restored at tearDown and |
| * the network server is shutdown. |
| * @param suite the suite to decorate |
| */ |
| public static Test clientServerDecorator(Test suite) |
| { |
| Test test = new NetworkServerTestSetup(suite, false); |
| |
| return defaultServerDecorator(test); |
| } |
| |
| /** |
| * Return a decorator for the passed in tests that sets the |
| * configuration for the client to be Derby's JDBC client |
| * and to start the network server at setUp. |
| * <BR> |
| * The database configuration (name etc.) is based upon |
| * the previous configuration. |
| * <BR> |
| * The previous TestConfiguration is restored at tearDown and |
| * the network server is shutdown. |
| * @param suite the suite to decorate |
| */ |
| public static Test clientServerDecoratorWithPort(Test suite, int port) |
| { |
| Test test = new NetworkServerTestSetup(suite, false); |
| |
| return existingServerDecorator(test,"localhost",port); |
| } |
| |
| /** |
| * Wrapper to use the alternative port number. |
| */ |
| public static Test clientServerDecoratorWithAlternativePort(Test suite) { |
| Test test = new NetworkServerTestSetup(suite, false); |
| |
| return defaultServerDecoratorWithAlternativePort(test); |
| } |
| /** |
| * Decorate a test to use suite's default host and port, |
| * but assuming the server is already running. |
| */ |
| public static Test defaultExistingServerDecorator(Test test) |
| { |
| // As defaultServerDecorator but assuming |
| // server is already started. |
| // Need to have client |
| // and not running in J2ME (JSR169). |
| if (!(Derby.hasClient()) |
| || JDBC.vmSupportsJSR169()) |
| { |
| return new BaseTestSuite( |
| "empty: no network server support in JSR169 " + |
| "(or derbyclient.jar missing)."); |
| } |
| |
| Test r = |
| new ServerSetup(test, DEFAULT_HOSTNAME, TestConfiguration.getCurrent().getPort()); |
| ((ServerSetup)r).setJDBCClient(JDBCClient.DERBYNETCLIENT); |
| |
| return r; |
| } |
| |
| /** |
| * Decorate a test to use suite's default host and port. |
| */ |
| public static Test defaultServerDecorator(Test test) |
| { |
| // Need to have network server and client and not |
| // running in J2ME (JSR169). |
| if (!supportsClientServer()) { |
| return new BaseTestSuite("empty: no network server support"); |
| } |
| |
| // |
| // This looks bogus to me. Shouldn't this get the hostname and port |
| // which are specific to this test run (perhaps overridden on the |
| // command line)? |
| // |
| return new ServerSetup(test, DEFAULT_HOSTNAME, TestConfiguration.getCurrent().getPort()); |
| } |
| /** |
| * A variant of defaultServerDecorator allowing |
| * non-default hostname and portnumber. |
| */ |
| public static Test existingServerDecorator(Test test, |
| String hostName, int PortNumber) |
| { |
| // Need to have network server and client and not |
| // running in J2ME (JSR169). |
| if (!supportsClientServer()) { |
| return new BaseTestSuite("empty: no network server support"); |
| } |
| |
| Test r = |
| new ServerSetup(test, hostName, PortNumber); |
| ((ServerSetup)r).setJDBCClient(JDBCClient.DERBYNETCLIENT); |
| return r; |
| } |
| /** |
| * A variant of defaultServerDecorator allowing |
| * non-default hostname, portnumber and database name. |
| */ |
| public static Test existingServerDecorator(Test test, |
| String hostName, int PortNumber, String dbPath) |
| { |
| // Need to have network server and client and not |
| // running in J2ME (JSR169). |
| if (!supportsClientServer()) { |
| return new BaseTestSuite("empty: no network server support"); |
| } |
| |
| Test r = |
| new ServerSetup(test, hostName, PortNumber); |
| ((ServerSetup)r).setJDBCClient(JDBCClient.DERBYNETCLIENT); |
| ((ServerSetup)r).setDbPath(dbPath); |
| return r; |
| } |
| |
| /** |
| * Decorate a test to use suite's default host and Alternative port. |
| */ |
| public static Test defaultServerDecoratorWithAlternativePort(Test test) { |
| // Need to have network server and client and not |
| // running in J2ME (JSR169). |
| if (!supportsClientServer()) { |
| return new BaseTestSuite("empty: no network server support"); |
| } |
| |
| int port = getCurrent().getNextAvailablePort(); |
| |
| // |
| // This looks bogus to me. Shouldn't this get the hostname and port |
| // which are specific to this test run (perhaps overridden on the |
| // command line)? |
| // |
| return new ServerSetup(test, DEFAULT_HOSTNAME, port); |
| } |
| |
| /** |
| * Check if client and server testing is supported in the test environment. |
| */ |
| private static boolean supportsClientServer() { |
| return JDBC.vmSupportsJDBC3() && Derby.hasClient() && Derby.hasServer(); |
| } |
| |
| /** |
| * Create a suite of test cases to run in a client/server environment. The |
| * returned test suite is not decorated with a ServerSetup. |
| * |
| * @param testClass the class from which to extract the test cases |
| * @return a test suite with all the test cases in {@code testClass}, or |
| * an empty test suite if client/server is not supported in the test |
| * environment |
| */ |
| private static Test bareClientServerSuite(Class testClass) { |
| BaseTestSuite suite = |
| new BaseTestSuite(suiteName(testClass) + ":client"); |
| |
| if (supportsClientServer()) { |
| suite.addTestSuite(testClass); |
| } |
| return suite; |
| } |
| |
| /** |
| * Generate the unique database name for single use. |
| */ |
| public static synchronized String generateUniqueDatabaseName() |
| { |
| // Forward slash is ok, Derby treats database names |
| // as URLs and translates forward slash to the local |
| // separator. |
| String dbName = "singleUse/oneuse"; |
| dbName = dbName.concat(Integer.toHexString(uniqueDB++)); |
| return dbName; |
| } |
| |
| |
| /** |
| * Decorate a test to use a new database that is created upon the |
| * first connection request to the database and shutdown and deleted at |
| * tearDown. The configuration differs only from the current configuration |
| * by the list of used databases. The new database name |
| * is generated automatically as 'singleUse/oneuseXX' where 'XX' is |
| * the unique number. The generated database name is added at the end |
| * of <code>usedDbNames</code> and assigned as a default database name. |
| * This decorator expects the database file to be local so it |
| * can be removed. |
| * @param test Test to be decorated |
| * @return decorated test. |
| */ |
| public static TestSetup singleUseDatabaseDecorator(Test test) |
| { |
| String dbName = generateUniqueDatabaseName(); |
| |
| return new DatabaseChangeSetup(new DropDatabaseSetup(test, dbName), dbName, dbName, true); |
| } |
| |
| |
| /** |
| * Decorate a test to use a new database that is created upon the first |
| * connection request to the database and shutdown and deleted at |
| * tearDown. The configuration differs only from the current configuration |
| * by the list of used databases. The generated database name is added at |
| * the end of <code>usedDbNames</code> and assigned as a default database |
| * name. This decorator expects the database file to be local so it can be |
| * removed. |
| * @param test Test to be decorated |
| * @param dbName We sometimes need to know outside to be able to pass it on |
| * to other VMs/processes. |
| * @return decorated test. |
| */ |
| public static TestSetup singleUseDatabaseDecorator(Test test, String dbName) |
| { |
| return new DatabaseChangeSetup( |
| new DropDatabaseSetup(test, dbName), dbName, dbName, true); |
| } |
| |
| /** |
| * Decorate a test to use a new database that is created upon the |
| * first connection request to the database and deleted at |
| * tearDown. In contrast to plain singleUseDatabaseDecorator, the |
| * database is expected to be shutdown by the test. The |
| * configuration differs only from the current configuration by |
| * the list of used databases. The new database name is generated |
| * automatically as 'singleUse/oneuseXX' where 'XX' is the unique |
| * number. The generated database name is added at the end of |
| * <code>usedDbNames</code> and assigned as a default database |
| * name. This decorator expects the database file to be local so |
| * it can be removed. |
| * @param test Test to be decorated |
| * @return decorated test. |
| */ |
| public static TestSetup singleUseDatabaseDecoratorNoShutdown(Test test) |
| { |
| String dbName = generateUniqueDatabaseName(); |
| |
| return new DatabaseChangeSetup( |
| new DropDatabaseSetup(test, dbName, false), |
| dbName, dbName, true); |
| } |
| |
| /** |
| * Decorate a test to use a new database that is created upon the |
| * first connection request to the database and shutdown and deleted at |
| * tearDown. The configuration differs only from the current configuration |
| * by the list of used databases. |
| * The passed database name is mapped to the generated database |
| * name 'singleUse/oneuseXX' where 'XX' is the unique number. |
| * (by generateUniqueDatabaseName). The generated database name is added |
| * at the end of <code>usedDbNames</code>. |
| * This decorator expects the database file to be local so it |
| * can be removed. |
| * @param test Test to be decorated |
| * @param logicalDbName The logical database name. This name is used to identify |
| * the database in openConnection(String logicalDatabaseName) method calls. |
| * @return decorated test. |
| */ |
| public static DatabaseChangeSetup additionalDatabaseDecorator(Test test, String logicalDbName) |
| { |
| return new DatabaseChangeSetup(new DropDatabaseSetup(test, logicalDbName), |
| logicalDbName, |
| generateUniqueDatabaseName(), |
| false); |
| } |
| |
| /** |
| * Similar to additionalDatabaseDecorator except the database will |
| * not be shutdown, only deleted. It is the responsibility of the |
| * test to shut it down. |
| * |
| * @param test Test to be decorated |
| * @param logicalDbName The logical database name. This name is |
| * used to identify the database in |
| * openConnection(String logicalDatabaseName) |
| * method calls. |
| * @return decorated test. |
| */ |
| public static DatabaseChangeSetup additionalDatabaseDecoratorNoShutdown( |
| Test test, |
| String logicalDbName) |
| { |
| return additionalDatabaseDecoratorNoShutdown( test, logicalDbName, false ); |
| } |
| |
| /** |
| * Similar to additionalDatabaseDecorator except the database will |
| * not be shutdown, only deleted. It is the responsibility of the |
| * test to shut it down. |
| * |
| * @param test Test to be decorated |
| * @param logicalDbName The logical database name. This name is |
| * used to identify the database in |
| * openConnection(String logicalDatabaseName) |
| * method calls. |
| * @param defaultDB True if the database should store its own name in its TestConfiguration. |
| * @return decorated test. |
| */ |
| public static DatabaseChangeSetup additionalDatabaseDecoratorNoShutdown |
| ( |
| Test test, |
| String logicalDbName, |
| boolean defaultDB |
| ) |
| { |
| return new DatabaseChangeSetup( |
| new DropDatabaseSetup(test, logicalDbName, false), |
| logicalDbName, |
| generateUniqueDatabaseName(), |
| defaultDB); |
| } |
| |
| /** |
| * Similar to additionalDatabaseDecorator except the database will |
| * not be shutdown, only deleted. It is the responsibility of the |
| * test to shut it down. |
| * |
| * @param test Test to be decorated |
| * @param logicalDbName The logical database name. This name is |
| * used to identify the database in |
| * openConnection(String logicalDatabaseName) |
| * method calls. |
| * @param physicalDbName - Real database name on disk. |
| * @return decorated test. |
| */ |
| public static DatabaseChangeSetup additionalDatabaseDecoratorNoShutdown( |
| Test test, |
| String logicalDbName, String physicalDbName ) |
| { |
| return new DatabaseChangeSetup( |
| new DropDatabaseSetup(test, logicalDbName, false), |
| logicalDbName, |
| physicalDbName, |
| false); |
| } |
| |
| /** |
| * Decorate a test changing the default user name and password. |
| * Typically used along with DatabasePropertyTestSetup.builtinAuthentication. |
| * The tearDown method resets the default user and password value to |
| * their previous settings. |
| * |
| * @param test Test to decorate |
| * @param user New default user |
| * @param password New password |
| * @return decorated test |
| * |
| * @see DatabasePropertyTestSetup#builtinAuthentication(Test, String[], String) |
| */ |
| public static Test changeUserDecorator(Test test, String user, String password) |
| { |
| return new ChangeUserSetup(test, user, password); |
| } |
| |
| /** |
| * Decorate a test to use the default database that has |
| * was created in SQL authorization mode. |
| * The tearDown reverts the configuration to the previous |
| * configuration. |
| * |
| * The database owner of this default SQL authorization mode |
| * database is TEST_DBO. This decorator sets the default user |
| * to be TEST_DBO. |
| * |
| * Tests can use this in conjunction with |
| * DatabasePropertyTestSetup.builtinAuthentication |
| * to set up BUILTIN authentication and changeUserDecorator |
| * to switch users. The database owner TEST_DBO must be included |
| * in the list of users provided to builtinAuthentication. |
| * This decorator must be the outer one in this mode. |
| * <code> |
| * test = DatabasePropertyTestSetup.builtinAuthentication(test, |
| new String[] {TEST_DBO,"U1","U2",}, |
| "nh32ew"); |
| test = TestConfiguration.sqlAuthorizationDecorator(test); |
| * </code> |
| * A utility version of sqlAuthorizationDecorator is provided |
| * that combines the two setups. |
| * |
| * @param test Test to be decorated |
| * @return decorated test. |
| * |
| * @see DatabasePropertyTestSetup#builtinAuthentication(Test, String[], String) |
| */ |
| public static Test sqlAuthorizationDecorator(Test test) |
| { |
| // Set the SQL authorization mode as a database property |
| // with a modified DatabasePropertyTestSetup that does not |
| // reset it. |
| final Properties sqlAuth = new Properties(); |
| sqlAuth.setProperty("derby.database.sqlAuthorization", "true"); |
| Test setSQLAuthMode = DatabasePropertyTestSetup.getNoTeardownInstance( |
| test, sqlAuth, true); |
| |
| return changeUserDecorator( |
| new DatabaseChangeSetup(setSQLAuthMode, DEFAULT_DBNAME_SQL, DEFAULT_DBNAME_SQL, true), |
| DerbyConstants.TEST_DBO, "dummy"); // DRDA doesn't like empty pw |
| } |
| |
| |
| /** |
| * Same as sqlAuthorizationDecorator, except that the database is dropped |
| * at teardown and the test is responsible for shutting down the database. |
| * |
| * @param test Test to be decorated |
| * @return decorated test. |
| * |
| * @see TestConfiguration#sqlAuthorizationDecorator(Test test) |
| */ |
| public static Test sqlAuthorizationDecoratorSingleUse(Test test) |
| { |
| return sqlAuthorizationDecoratorSingleUse( |
| test, DEFAULT_DBNAME_SQL, false); |
| } |
| |
| /** |
| * Same as sqlAuthorizationDecoratorSingleUse, except that you can name |
| * the database yourself, and you can choose whether or not the decorator |
| * should shut down the database before it attempts to drop it. |
| * |
| * @param test Test to be decorated |
| * @param dbName The name of the database to use in the test |
| * @param shutdownDatabase Whether or not to shut down the database |
| * before it is dropped |
| * @return decorated test. |
| * |
| * @see TestConfiguration#sqlAuthorizationDecorator(Test test) |
| */ |
| public static Test sqlAuthorizationDecoratorSingleUse( |
| Test test, String dbName, boolean shutdownDatabase) |
| { |
| // Set the SQL authorization mode as a database property |
| // with a modified DatabasePropertyTestSetup that does not |
| // reset it. |
| final Properties sqlAuth = new Properties(); |
| sqlAuth.setProperty("derby.database.sqlAuthorization", "true"); |
| Test setSQLAuthMode = DatabasePropertyTestSetup.getNoTeardownInstance( |
| test, sqlAuth, true); |
| |
| setSQLAuthMode = new DropDatabaseSetup( |
| setSQLAuthMode, dbName, shutdownDatabase); |
| |
| setSQLAuthMode = new DatabaseChangeSetup |
| ( setSQLAuthMode, dbName, dbName, true ); |
| |
| return changeUserDecorator(setSQLAuthMode, |
| DerbyConstants.TEST_DBO, |
| "dummy"); // DRDA doesn't like empty pw |
| } |
| |
| |
| /** |
| * Utility version of sqlAuthorizationDecorator that also sets |
| * up authentication. A combination of |
| * DatabasePropertyTestSetup.builtinAuthentication wrapped in |
| * sqlAuthorizationDecorator. |
| * <BR> |
| * The database owner of this default SQL authorization mode |
| * database is TEST_DBO. This decorator sets the default user |
| * to be TEST_DBO. |
| * <BR> |
| * Assumption is that no authentication is enabled on the default |
| * SQL authorization database on entry. |
| * |
| * @param users Set of users excluding the database owner, that will |
| * be added by this decorator. |
| */ |
| public static Test sqlAuthorizationDecorator(Test test, |
| String[] users, String passwordToken) |
| { |
| String[] usersWithDBO = new String[users.length + 1]; |
| usersWithDBO[0] = DerbyConstants.TEST_DBO; |
| System.arraycopy(users, 0, usersWithDBO, 1, users.length); |
| return sqlAuthorizationDecorator( |
| DatabasePropertyTestSetup.builtinAuthentication(test, |
| usersWithDBO, passwordToken)); |
| } |
| |
| /** |
| * Return a decorator that changes the configuration to obtain |
| * connections from a ConnectionPoolDataSource using |
| * <code>getPooledConnection().getConnection()</code> |
| * <p> |
| * Note that statement pooling is enabled in the data source and in all the |
| * connections created from it. |
| * <p> |
| * The tearDown reverts the configuration to the previous |
| * configuration. |
| * |
| * @param test the test/suite to decorate |
| * @return A test setup with the requested decorator. |
| */ |
| public static Test connectionCPDecorator(Test test) |
| { |
| if (JDBC.vmSupportsJDBC3()) { |
| return new ConnectorSetup(test, |
| "org.apache.derbyTesting.junit.ConnectionPoolDataSourceConnector"); |
| } else { |
| return new BaseTestSuite("ConnectionPoolDataSource not supported"); |
| } |
| |
| } |
| |
| /** |
| * Return a decorator that changes the configuration to obtain |
| * connections from an XADataSource using |
| * <code> |
| * getXAConnection().getConnection() |
| * </code> |
| * The connection is not connected to any global transaction, |
| * thus it is in local connection mode. |
| * The tearDown reverts the configuration to the previous |
| * configuration. |
| */ |
| public static Test connectionXADecorator(Test test) |
| { |
| if (JDBC.vmSupportsJDBC3()) { |
| return new ConnectorSetup(test, |
| "org.apache.derbyTesting.junit.XADataSourceConnector"); |
| } else { |
| return new BaseTestSuite("XADataSource not supported"); |
| } |
| } |
| /** |
| * Return a decorator that changes the configuration to obtain |
| * connections from a standard DataSource using |
| * <code> |
| * getConnection() |
| * </code> |
| * The tearDown reverts the configuration to the previous |
| * configuration. |
| */ |
| public static TestSetup connectionDSDecorator(Test test) |
| { |
| return new ConnectorSetup(test, |
| "org.apache.derbyTesting.junit.DataSourceConnector"); |
| } |
| |
| /** |
| * Returns a decorator that forces the JDBC 3 embedded client in |
| * a Java SE 6/JDBC 4 environment. The only difference is that |
| * the DataSource class names will be the "old" JDBC 3 versions |
| * and not the JDBC 4 specific ones. |
| * that |
| * @param test |
| */ |
| public static Test forceJDBC3Embedded(Test test) |
| { |
| if (JDBC.vmSupportsJDBC4()) { |
| test = new JDBCClientSetup(test, JDBCClient.EMBEDDED_30); |
| } |
| return test; |
| } |
| |
| /** |
| * Returns a decorator that forces the JDBC 3 network client in |
| * a Java SE 6/JDBC 4 environment. The only difference is that |
| * the DataSource class names will be the "old" JDBC 3 versions |
| * and not the JDBC 4 specific ones. |
| * |
| * Assumption is that the received Test is an instance of ServerSetup, |
| * which is the decorator for client server tests. If that is not |
| * the case then this method is a no-op. |
| * |
| * @param test Test around which to wrap the JDBC 3 network client |
| * configuration. |
| */ |
| public static Test forceJDBC3NetClient(Test test) |
| { |
| if (JDBC.vmSupportsJDBC4() && (test instanceof ServerSetup)) |
| ((ServerSetup)test).setJDBCClient(JDBCClient.DERBYNETCLIENT_30); |
| return test; |
| } |
| |
| /** |
| * Decorate a test changing the default ssl mode. |
| * The tearDown method resets the default user and password value to |
| * their previous settings. |
| * |
| * @param test Test to decorate |
| * @param ssl New ssl mode |
| * @return decorated test |
| */ |
| public static Test changeSSLDecorator(Test test, String ssl) |
| { |
| return new ChangeSSLSetup(test, ssl); |
| } |
| |
| /** |
| * Default embedded configuration |
| * |
| */ |
| private TestConfiguration() { |
| // Check for possibly passed in DatabaseName |
| // this is used in OCRecoveryTest |
| String propDefDbName = getSystemProperties().getProperty( |
| "derby.tests.defaultDatabaseName"); |
| if (propDefDbName != null) |
| this.defaultDbName = propDefDbName; |
| else |
| this.defaultDbName=DEFAULT_DBNAME; |
| usedDbNames.add(DEFAULT_DBNAME); |
| logicalDbMapping.put(DEFAULT_DBNAME, DEFAULT_DBNAME); |
| this.userName = DEFAULT_USER_NAME; |
| this.userPassword = DEFAULT_USER_PASSWORD; |
| this.connectionAttributes = new Properties(); |
| this.hostName = DEFAULT_HOSTNAME; |
| this.port = basePort; |
| this.isVerbose = Boolean.valueOf( |
| getSystemProperties().getProperty(KEY_VERBOSE)). |
| booleanValue(); |
| this.doTrace = Boolean.valueOf( |
| getSystemProperties().getProperty(KEY_TRACE)). |
| booleanValue(); |
| this.stopAfterFirstFail = Boolean.valueOf( |
| getSystemProperties().getProperty(KEY_STOP_AFTER_FIRST_FAIL)). |
| booleanValue(); |
| this.jdbcClient = JDBCClient.getDefaultEmbedded(); |
| this.ssl = null; |
| this.jmxPort = getNextAvailablePort(); |
| println("basePort=" + basePort + ", bogusPort=" + bogusPort + |
| ", jmxPort=" + jmxPort); |
| url = createJDBCUrlWithDatabaseName(defaultDbName); |
| initConnector(null); |
| |
| } |
| |
| /** |
| * Obtain a new configuration identical to the passed one. |
| */ |
| TestConfiguration(TestConfiguration copy) |
| { |
| this.defaultDbName = copy.defaultDbName; |
| this.usedDbNames.addAll(copy.usedDbNames); |
| logicalDbMapping.putAll(copy.logicalDbMapping); |
| this.userName = copy.userName; |
| this.userPassword = copy.userPassword; |
| this.connectionAttributes = new Properties(copy.connectionAttributes); |
| |
| this.isVerbose = copy.isVerbose; |
| this.doTrace = copy.doTrace; |
| this.port = copy.port; |
| this.jmxPort = copy.jmxPort; |
| |
| this.jdbcClient = copy.jdbcClient; |
| this.hostName = copy.hostName; |
| |
| this.ssl = copy.ssl; |
| |
| this.url = copy.url; |
| initConnector(copy.connector); |
| } |
| |
| TestConfiguration(TestConfiguration copy, JDBCClient client, |
| String hostName, int port) |
| { |
| this.defaultDbName = copy.defaultDbName; |
| this.usedDbNames.addAll(copy.usedDbNames); |
| logicalDbMapping.putAll(copy.logicalDbMapping); |
| this.userName = copy.userName; |
| this.userPassword = copy.userPassword; |
| this.connectionAttributes = new Properties(copy.connectionAttributes); |
| |
| this.isVerbose = copy.isVerbose; |
| this.doTrace = copy.doTrace; |
| this.port = port; |
| this.jmxPort = copy.jmxPort; |
| if (bogusPort == port) { |
| throw new IllegalStateException( |
| "port cannot equal bogusPort: " + bogusPort); |
| } |
| |
| this.jdbcClient = client; |
| this.hostName = hostName; |
| |
| this.ssl = copy.ssl; |
| |
| this.url = createJDBCUrlWithDatabaseName(defaultDbName); |
| initConnector(copy.connector); |
| } |
| |
| TestConfiguration(TestConfiguration copy, JDBCClient client, |
| String hostName, int port, String dataBasePath) |
| { |
| this.defaultDbName = dataBasePath; |
| this.usedDbNames.addAll(copy.usedDbNames); |
| logicalDbMapping.putAll(copy.logicalDbMapping); |
| this.userName = copy.userName; |
| this.userPassword = copy.userPassword; |
| this.connectionAttributes = new Properties(copy.connectionAttributes); |
| |
| this.isVerbose = copy.isVerbose; |
| this.doTrace = copy.doTrace; |
| this.port = port; |
| this.jmxPort = copy.jmxPort; |
| if (bogusPort == port) { |
| throw new IllegalStateException( |
| "port cannot equal bogusPort: " + bogusPort); |
| } |
| |
| this.jdbcClient = client; |
| this.hostName = hostName; |
| |
| this.ssl = copy.ssl; |
| |
| this.url = createJDBCUrlWithDatabaseName(defaultDbName); |
| initConnector(copy.connector); |
| } |
| |
| /** |
| * Obtain a new configuration identical to the passed in |
| * one except for the default user and password. |
| * @param copy Configuration to copy. |
| * @param user New default user |
| * @param password New default password. |
| */ |
| TestConfiguration(TestConfiguration copy, String user, |
| String password, String passwordToken) |
| { |
| this.defaultDbName = copy.defaultDbName; |
| this.usedDbNames.addAll(copy.usedDbNames); |
| logicalDbMapping.putAll(copy.logicalDbMapping); |
| this.userName = user; |
| this.userPassword = password; |
| this.passwordToken = passwordToken == null ? |
| copy.passwordToken : passwordToken; |
| this.connectionAttributes = new Properties(copy.connectionAttributes); |
| |
| this.isVerbose = copy.isVerbose; |
| this.doTrace = copy.doTrace; |
| this.port = copy.port; |
| this.jmxPort = copy.jmxPort; |
| |
| this.jdbcClient = copy.jdbcClient; |
| this.hostName = copy.hostName; |
| |
| this.ssl = copy.ssl; |
| |
| this.url = copy.url; |
| initConnector(copy.connector); |
| } |
| |
| /** |
| * Obtains a new configuration identical to the passed in one, except for |
| * the default SSL mode. |
| * <p> |
| * The modes supported at the moment are <tt>basic</tt> and <tt>off</tt>. |
| * The mode <tt>peerAuthentication</tt> is not yet supported. |
| * |
| * @param copy configuration to copy |
| * @param ssl default SSL mode |
| */ |
| TestConfiguration(TestConfiguration copy, String ssl) |
| { |
| this(copy); |
| this.ssl = ssl; |
| } |
| |
| /** |
| * Obtain a new configuration identical to the passed in |
| * one except for the database name. The passed database name |
| * is added at the end of the list of used databases. |
| * If the <code>defaulDb</code> parameter is <code>true</code> |
| * the new database name is used as a default database. |
| * @param copy Configuration to copy. |
| * @param dbName New database name |
| * @param defaultDb Indicates that the passed <code>dbName</code> is supposed |
| * to be used as the default database name. |
| */ |
| TestConfiguration(TestConfiguration copy, String logicalDbName, |
| String dbName, boolean defaultDb) |
| { |
| this.usedDbNames.addAll(copy.usedDbNames); |
| this.usedDbNames.add(dbName); |
| logicalDbMapping.putAll(copy.logicalDbMapping); |
| |
| // Can not use the same logical name for different database. |
| // If this assert will make failures it might be safely removed |
| // since having more physical databases accessible throught the same |
| // logical database name will access only the last physical database |
| Assert.assertNull(logicalDbMapping.put(logicalDbName, dbName)); |
| |
| if (defaultDb) { |
| this.defaultDbName = dbName; |
| } else { |
| this.defaultDbName = copy.defaultDbName; |
| } |
| |
| this.userName = copy.userName; |
| this.userPassword = copy.userPassword; |
| this.connectionAttributes = new Properties(copy.connectionAttributes); |
| |
| this.isVerbose = copy.isVerbose; |
| this.doTrace = copy.doTrace; |
| this.port = copy.port; |
| this.jmxPort = copy.jmxPort; |
| |
| this.jdbcClient = copy.jdbcClient; |
| this.hostName = copy.hostName; |
| |
| this.ssl = copy.ssl; |
| |
| this.url = createJDBCUrlWithDatabaseName(this.defaultDbName); |
| initConnector(copy.connector); |
| } |
| |
| /** |
| * This constructor creates a TestConfiguration from a Properties object. |
| * |
| * @throws NumberFormatException if the port specification is not an integer. |
| */ |
| private TestConfiguration(Properties props) |
| throws NumberFormatException { |
| |
| defaultDbName = props.getProperty(KEY_DBNAME, DEFAULT_DBNAME); |
| usedDbNames.add(defaultDbName); |
| logicalDbMapping.put(defaultDbName, defaultDbName); |
| userName = props.getProperty(KEY_USER_NAME, DEFAULT_USER_NAME); |
| userPassword = props.getProperty(KEY_USER_PASSWORD, |
| DEFAULT_USER_PASSWORD); |
| connectionAttributes = new Properties(); |
| hostName = props.getProperty(KEY_HOSTNAME, DEFAULT_HOSTNAME); |
| isVerbose = Boolean.valueOf(props.getProperty(KEY_VERBOSE)).booleanValue(); |
| doTrace = Boolean.valueOf(props.getProperty(KEY_TRACE)).booleanValue(); |
| port = basePort; |
| jmxPort = getNextAvailablePort(); |
| println("basePort=" + basePort + ", bogusPort=" + bogusPort + |
| ", jmxPort=" + jmxPort); |
| |
| ssl = props.getProperty(KEY_SSL); |
| |
| String framework = props.getProperty(KEY_FRAMEWORK, DEFAULT_FRAMEWORK); |
| |
| if ("DerbyNetClient".equals(framework)) { |
| jdbcClient = JDBCClient.DERBYNETCLIENT; |
| } else if ("DerbyNet".equals(framework)) { |
| jdbcClient = JDBCClient.DB2CLIENT; |
| } else { |
| jdbcClient = JDBCClient.getDefaultEmbedded(); |
| } |
| url = createJDBCUrlWithDatabaseName(defaultDbName); |
| initConnector(null); |
| } |
| |
| /** |
| * Create a copy of this configuration with some additional connection |
| * attributes. |
| * |
| * @param attrs the extra connection attributes |
| * @return a copy of the configuration with extra attributes |
| */ |
| TestConfiguration addConnectionAttributes(Properties attrs) { |
| TestConfiguration copy = new TestConfiguration(this); |
| Enumeration e = attrs.propertyNames(); |
| while (e.hasMoreElements()) { |
| String key = (String) e.nextElement(); |
| String val = attrs.getProperty(key); |
| copy.connectionAttributes.setProperty(key, val); |
| } |
| copy.initConnector(connector); |
| return copy; |
| } |
| |
| /** |
| * Get the system properties in a privileged block. |
| * |
| * @return the system properties. |
| */ |
| public static final Properties getSystemProperties() { |
| // Fetch system properties in a privileged block. |
| return AccessController.doPrivileged( |
| new PrivilegedAction<Properties>() { |
| public Properties run() { |
| return System.getProperties(); |
| } |
| }); |
| } |
| |
| /** |
| * Create JDBC connection url, including the name of the database. |
| * |
| * @return JDBC connection url, without attributes. |
| */ |
| private String createJDBCUrlWithDatabaseName(String name) { |
| if (JDBC.vmSupportsJDBC3()) |
| { |
| String url; |
| if (jdbcClient.isEmbedded()) { |
| url = jdbcClient.getUrlBase(); |
| } else { |
| url = jdbcClient.getUrlBase() + hostName + ":" + port + "/"; |
| } |
| return url.concat(name); |
| } |
| // No DriverManager support so no URL support. |
| return null; |
| } |
| |
| /** |
| * Initialize the connection factory. |
| * Defaults to the DriverManager implementation |
| * if running JDBC 2.0 or higher, otherwise a |
| * DataSource implementation for JSR 169. |
| * |
| */ |
| private void initConnector(Connector oldConnector) |
| { |
| if (oldConnector != null) |
| { |
| // Use the same type of connector as the |
| // configuration we are copying from. |
| |
| try { |
| Class<?> clazz = Class.forName(oldConnector.getClass().getName()); |
| connector = (Connector) clazz.getConstructor().newInstance(); |
| } catch (Exception e) { |
| Assert.fail(e.getMessage()); |
| } |
| } |
| else if (JDBC.vmSupportsJDBC3()) |
| { |
| try { |
| Class<?> clazz = Class.forName("org.apache.derbyTesting.junit.DriverManagerConnector"); |
| connector = (Connector) clazz.getConstructor().newInstance(); |
| } catch (Exception e) { |
| Assert.fail(e.getMessage()); |
| } |
| |
| } else { |
| connector = new DataSourceConnector(); |
| } |
| connector.setConfiguration(this); |
| |
| try { |
| String loginTimeoutString = BaseTestCase.getSystemProperty( KEY_LOGIN_TIMEOUT ); |
| |
| if ( loginTimeoutString != null ) |
| { |
| int loginTimeout = Integer.parseInt( loginTimeoutString ); |
| |
| connector.setLoginTimeout( loginTimeout ); |
| } |
| } |
| catch (Exception e) { Assert.fail(e.getMessage()); } |
| } |
| |
| /** |
| * Get configured JDBCClient object. |
| * |
| * @return JDBCClient |
| */ |
| public JDBCClient getJDBCClient() { |
| return jdbcClient; |
| } |
| |
| /** |
| * <p> |
| * Return the jdbc url for connecting to the default database. |
| * </p> |
| * |
| * <p> |
| * The returned URL does not include the connection attributes. These must |
| * either be appended to the URL when connecting, or they must be passed |
| * as a {@code Properties} object to {@code DriverManager.getConnection()}. |
| * </p> |
| * |
| * @return JDBC url. |
| */ |
| public String getJDBCUrl() { |
| return url; |
| } |
| |
| /** |
| * Return the jdbc url for a connecting to the database. |
| * |
| * @param databaseName name of database. |
| * @return JDBC connection url, including database name. |
| */ |
| public String getJDBCUrl(String databaseName) { |
| return createJDBCUrlWithDatabaseName(databaseName); |
| } |
| |
| /** |
| * Return the default database name. |
| * |
| * @return default database name. |
| */ |
| public String getDefaultDatabaseName() { |
| return defaultDbName; |
| } |
| |
| /** |
| * Return the physical name for a database |
| * given its logical name. |
| * |
| * @return Physical name of the database. |
| */ |
| public String getPhysicalDatabaseName(String logicalName) { |
| return (String) logicalDbMapping.get(logicalName); |
| } |
| |
| /** |
| * Return the user name. |
| * |
| * @return user name. |
| */ |
| public String getUserName() { |
| return userName; |
| } |
| |
| /** |
| * Return the user password. |
| * |
| * @return user password. |
| */ |
| public String getUserPassword() { |
| return userPassword; |
| } |
| |
| /** |
| * Return the connection attributes to use in this configuration. The |
| * attributes won't contain user name or password. Use |
| * {@link #getUserName()} or {@link #getUserPassword()} instead to |
| * retrieve those attributes. |
| * |
| * @return connection attributes (never {@code null}) |
| */ |
| public Properties getConnectionAttributes() { |
| return connectionAttributes; |
| } |
| |
| /** |
| * Get a flat string representation of the connection attributes. To |
| * be used in the connectionAttributes property of a data source. |
| * |
| * @return all connection attributes concatenated ({@code null} if there |
| * are no attributes) |
| */ |
| String getConnectionAttributesString() { |
| StringBuffer sb = new StringBuffer(); |
| Enumeration e = connectionAttributes.propertyNames(); |
| boolean first = true; |
| while (e.hasMoreElements()) { |
| if (!first) { |
| sb.append(';'); |
| } |
| String key = (String) e.nextElement(); |
| sb.append(key); |
| sb.append('='); |
| sb.append(connectionAttributes.getProperty(key)); |
| first = false; |
| } |
| |
| if (first) { |
| // No connection attributes. |
| return null; |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Return the host name for the network server. |
| * |
| * @return host name. |
| */ |
| public String getHostName() { |
| return hostName; |
| } |
| |
| /** |
| * Return if the base port is default or not. |
| * |
| * @return true if base port is default. |
| */ |
| public static boolean isDefaultBasePort() { |
| return (basePort == DEFAULT_PORT); |
| } |
| |
| public static int getBasePort() { |
| return basePort; |
| } |
| |
| /** |
| * Get port number for network server. |
| * |
| * @return port number. |
| */ |
| public int getPort() { |
| return port; |
| } |
| |
| /** |
| * Get the next available port. This method is multi-purposed. |
| * It can be used for alternative servers and also for JMX and replication. |
| * |
| * @return port number. |
| */ |
| public int getNextAvailablePort() { |
| /* We want to crash. If you are reading this, you have to increment |
| * the MAX_PORTS_USED constant and to edit the wiki page relative to |
| * concurrent test running */ |
| if (assignedPortCount+1 > MAX_PORTS_USED) { |
| Assert.fail("Port "+(lastAssignedPort+1)+" exceeeds expected maximum. " + |
| "You may need to update TestConfiguration.MAX_PORTS_USED and "+ |
| "the Wiki page at http://wiki.apache.org/db-derby/DerbyJUnitTesting "+ |
| "if test runs now require more available ports"); |
| } |
| |
| int possiblePort = lastAssignedPort + 1; |
| |
| assignedPortCount++; |
| |
| lastAssignedPort = possiblePort; |
| return possiblePort; |
| } |
| |
| /** |
| * Gets the value of the port number that may be used for "remote" |
| * JMX monitoring and management. |
| * @return the port number on which the JMX MBean server is listening for |
| * connections |
| */ |
| public int getJmxPort() { |
| return jmxPort; |
| } |
| |
| /** |
| * Returns a port number where no Derby network servers are supposed to |
| * be running. |
| * |
| * @return A port number where no Derby network servers are started. |
| */ |
| public int getBogusPort() { |
| return bogusPort; |
| } |
| |
| /** |
| * Get ssl mode for network server |
| * |
| * @return ssl mode |
| */ |
| public String getSsl() { |
| return ssl; |
| } |
| |
| |
| /** |
| * Open connection to the default database. |
| * If the database does not exist, it will be created. |
| * A default username and password will be used for the connection. |
| * |
| * @return connection to default database. |
| */ |
| public Connection openDefaultConnection() |
| throws SQLException { |
| return connector.openConnection(); |
| } |
| |
| /** |
| * Open connection to the default database. |
| * If the database does not exist, it will be created. |
| * |
| * @return connection to default database. |
| */ |
| Connection openDefaultConnection(String user, String password) |
| throws SQLException { |
| return connector.openConnection(user, password); |
| } |
| |
| /** |
| * Open connection to the specified database. |
| * If the database does not exist, it will be created. |
| * A default username and password will be used for the connection. |
| * Requires that the test has been decorated with |
| * additionalDatabaseDecorator with the matching name. |
| * The physical database name may differ. |
| * @param logicalDatabaseName A logical database name as passed |
| * to <code>additionalDatabaseDecorator</code> function. |
| * @return connection to specified database. |
| */ |
| Connection openConnection(String logicalDatabaseName) |
| throws SQLException |
| { |
| return connector.openConnection( getAndVetPhysicalDatabaseName( logicalDatabaseName ) ); |
| } |
| private String getAndVetPhysicalDatabaseName( String logicalDatabaseName ) |
| throws SQLException |
| { |
| String databaseName = getPhysicalDatabaseName( logicalDatabaseName ); |
| |
| if ( usedDbNames.contains(databaseName) ) { return databaseName; } |
| else |
| { |
| throw new SQLException("Database name \"" + logicalDatabaseName |
| + "\" is not in a list of used databases." |
| + "Use method TestConfiguration.additionalDatabaseDecorator first."); |
| } |
| } |
| |
| /** |
| * Open connection to the specified database using the supplied username and password. |
| * If the database does not exist, it will be created. |
| * Requires that the test has been decorated with |
| * additionalDatabaseDecorator with the matching name. |
| * The physical database name may differ. |
| * @param logicalDatabaseName A logical database name as passed |
| * to <code>additionalDatabaseDecorator</code> function. |
| * @return connection to specified database. |
| */ |
| public Connection openConnection( String logicalDatabaseName, String user, String password ) |
| throws SQLException |
| { |
| return connector.openConnection |
| ( |
| getAndVetPhysicalDatabaseName( logicalDatabaseName ), |
| user, |
| password |
| ); |
| } |
| |
| /** |
| * Open connection to the specified database using the supplied username and password. |
| * Treat the database name as a physical database name rather than as a logical name |
| * which needs to be mapped. |
| * If the database does not exist, it will be created. |
| * Requires that the test has been decorated with |
| * additionalDatabaseDecorator with the matching name. |
| * @param physicalDatabaseName The real database name to use. |
| * @param user name of user |
| * @param password password of user |
| * @param props extra properties to pass to the connection |
| * @return connection to specified database. |
| */ |
| public Connection openPhysicalConnection( String physicalDatabaseName, String user, String password, Properties props ) |
| throws SQLException |
| { |
| return connector.openConnection |
| ( |
| physicalDatabaseName, |
| user, |
| password, |
| props |
| ); |
| } |
| |
| /** |
| * Shutdown the database for this configuration |
| * assuming it is booted. |
| * |
| */ |
| public void shutdownDatabase() |
| { |
| try { |
| connector.shutDatabase(); |
| Assert.fail("Database failed to shut down"); |
| } catch (SQLException e) { |
| BaseJDBCTestCase.assertSQLState("Database shutdown", "08006", e); |
| } |
| } |
| |
| /** |
| * Shutdown the engine for this configuration |
| * assuming it is booted. |
| * This method can only be called when the engine |
| * is running embedded in this JVM. |
| * |
| */ |
| public void shutdownEngine() |
| { |
| try { |
| connector.shutEngine(true); |
| Assert.fail("Engine failed to shut down"); |
| } catch (SQLException e) { |
| BaseJDBCTestCase.assertSQLState("Engine shutdown", "XJ015", e); |
| } |
| } |
| |
| /** |
| * Shutdown the engine for this configuration |
| * assuming it is booted. |
| * This method can only be called when the engine |
| * is running embedded in this JVM. |
| * |
| * @param deregisterDeriver if true, deregister the driver |
| */ |
| public void shutdownEngine(boolean deregisterDeriver) |
| { |
| try { |
| connector.shutEngine(deregisterDeriver); |
| Assert.fail("Engine failed to shut down"); |
| } catch (SQLException e) { |
| BaseJDBCTestCase.assertSQLState("Engine shutdown", "XJ015", e); |
| } |
| } |
| |
| /** Get the login timeout from the connector */ |
| public int getLoginTimeout() throws SQLException |
| { |
| return connector.getLoginTimeout(); |
| } |
| |
| /** |
| * Set the login timeout for the connector. |
| * @param seconds the login timeout in seconds |
| * @throws SQLException if the timeout cannot be set |
| */ |
| public void setLoginTimeout(int seconds) throws SQLException { |
| connector.setLoginTimeout(seconds); |
| } |
| |
| public void waitForShutdownComplete(String physicalDatabaseName) { |
| String path = getDatabasePath(physicalDatabaseName); |
| boolean lockfilepresent = true; |
| int timeout = LOCKFILETIMEOUT; // 5 mins |
| int totalsleep = 0; |
| File lockfile = new File (path + File.separatorChar + "db.lck"); |
| File exlockfile = new File (path + File.separatorChar + "dbex.lck"); |
| while (lockfilepresent) { |
| if (totalsleep >= timeout) |
| { |
| System.out.println("TestConfigruation.waitForShutdownComplete: " + |
| "been looping waiting for lock files to be deleted for at least 5 minutes, giving up"); |
| break; |
| } |
| if (lockfile.exists() || exlockfile.exists()) |
| { |
| // TODO: is it interesting to know whether db.lck or dbex.lck or both is still present? |
| try { |
| System.out.println("TestConfiguration.waitForShutdownComplete: " + |
| "db*.lck files not deleted after " + totalsleep + " ms."); |
| Thread.sleep(1000); |
| totalsleep=totalsleep+1000; |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| } |
| else |
| lockfilepresent=false; |
| } |
| } |
| |
| /** |
| * stops the Network server for this configuration. |
| * |
| */ |
| public void stopNetworkServer() { |
| try { |
| NetworkServerControlWrapper networkServer = |
| new NetworkServerControlWrapper(); |
| |
| networkServer.shutdown(); |
| if (serverOutput != null) { |
| serverOutput.close(); |
| } |
| } catch(Exception e) { |
| SQLException se = new SQLException("Error shutting down server"); |
| se.initCause(e); |
| } |
| } |
| |
| /** |
| * starts the Networs server for this configuration. |
| * |
| */ |
| public void startNetworkServer() throws SQLException |
| { |
| Exception failException = null; |
| try { |
| |
| NetworkServerControlWrapper networkServer = |
| new NetworkServerControlWrapper(); |
| |
| serverOutput = AccessController.doPrivileged( |
| new PrivilegedAction<FileOutputStream>() { |
| public FileOutputStream run() { |
| File logs = new File("logs"); |
| logs.mkdir(); |
| File console = new File(logs, "serverConsoleOutput.log"); |
| FileOutputStream fos = null; |
| try { |
| fos = new FileOutputStream(console.getPath(), true); |
| } catch (FileNotFoundException ex) { |
| ex.printStackTrace(); |
| } |
| return fos; |
| } |
| }); |
| |
| networkServer.start(new PrintWriter(serverOutput)); |
| |
| // Wait for the network server to start |
| boolean started = false; |
| int retries = 10; // Max retries = max seconds to wait |
| |
| while (!started && retries > 0) { |
| try { |
| // Sleep 1 second and then ping the network server |
| Thread.sleep(SLEEP_TIME); |
| networkServer.ping(); |
| |
| // If ping does not throw an exception the server has started |
| started = true; |
| } catch(Exception e) { |
| retries--; |
| failException = e; |
| } |
| |
| } |
| |
| // Check if we got a reply on ping |
| if (!started) { |
| throw failException; |
| } |
| } catch (Exception e) { |
| SQLException se = new SQLException("Error starting network server"); |
| se.initCause(failException); |
| throw se; |
| } |
| } |
| /** |
| * Set the verbosity, i.e., whether debug statements print. |
| */ |
| public void setVerbosity( boolean isChatty ) { isVerbose = isChatty; } |
| /** |
| * Set JUnit test method tracing. |
| */ |
| public void setTrace( boolean isChatty ) { doTrace = isChatty; } |
| |
| /** |
| * Return verbose flag. |
| * |
| * @return verbose flag. |
| */ |
| public boolean isVerbose() { |
| return isVerbose; |
| } |
| |
| /** |
| * Private method printing debug information to standard out if debugging |
| * is enabled. |
| * <p> |
| * <em>Note:</em> This method may direct output to a different location |
| * than the println method in <tt>BaseJDBCTestCase</tt>. |
| */ |
| private void println(CharSequence msg) { |
| if (isVerbose) { |
| System.out.println("DEBUG: {TC@" + hashCode() + "} " + msg); |
| } |
| } |
| |
| /** |
| * Return JUnit test method trace flag. |
| * |
| * @return JUnit test method trace flag. |
| */ |
| public boolean doTrace() { |
| return doTrace; |
| } |
| |
| public boolean stopAfterFirstFail() { |
| return stopAfterFirstFail; |
| } |
| /** |
| * <p> |
| * Return true if we classes are being loaded from jar files. For the time |
| * being, this simply tests that the JVMInfo class (common to the client and |
| * the server) comes out of a jar file. |
| * </p> |
| */ |
| public static boolean loadingFromJars() |
| { |
| return SecurityManagerSetup.isJars; |
| } |
| |
| /** |
| * Returns true if this JUnit test being run by the old harness. |
| * Temp method to ease the switch over by allowing |
| * suites to alter their behaviour based upon the |
| * need to still run under the old harness. |
| */ |
| //public static boolean runningInDerbyHarness() |
| //{ |
| // return runningInDerbyHarness; |
| //} |
| |
| /** |
| * Get a folder already created where a test can |
| * write its failure information. The name of the folder, |
| * relative to ${user.dir} is: |
| * <BR> |
| * <code> |
| * fail/client/testclass/testname |
| * <code> |
| * <UL> |
| * <LI> client - value of JDBCClient.getName() for the test's configuration |
| * <LI> testclass - last element of the class name |
| * <LI> testname - value of test.getName() |
| * </UL> |
| */ |
| File getFailureFolder(TestCase test){ |
| |
| StringBuffer sb = new StringBuffer(); |
| |
| sb.append("fail"); |
| sb.append(File.separatorChar); |
| sb.append(getJDBCClient().getName()); |
| sb.append(File.separatorChar); |
| |
| String className = test.getClass().getName(); |
| int lastDot = className.lastIndexOf('.'); |
| if (lastDot != -1) |
| className = className.substring(lastDot+1, className.length()); |
| |
| sb.append(className); |
| sb.append(File.separatorChar); |
| // DERBY-5620: Ensure valid file name. |
| char[] tmpName = test.getName().toCharArray(); |
| for (int i=0; i < tmpName.length; i++) { |
| switch (tmpName[i]) { |
| case '-': |
| case '_': |
| continue; |
| default: |
| if (!Character.isLetterOrDigit(tmpName[i])) { |
| tmpName[i] = '_'; |
| } |
| } |
| } |
| sb.append(tmpName); |
| |
| String base = sb.toString().intern(); |
| final File folder = new File(base); |
| |
| // Create the folder |
| // TODO: Dump this configuration in some human readable format |
| synchronized (base) { |
| AccessController.doPrivileged(new PrivilegedAction<Boolean>() { |
| public Boolean run() { |
| if (folder.exists()) { |
| // do something |
| } |
| return folder.mkdirs(); |
| } |
| }); |
| } |
| |
| return folder; |
| |
| } |
| |
| /* |
| * Immutable data members in test configuration |
| */ |
| |
| /** The default database name for tests. */ |
| private final String defaultDbName; |
| /** Holds the names of all other databases used in a test to perform a proper cleanup. |
| * The <code>defaultDbName</code> is also contained here. */ |
| private final ArrayList<String> usedDbNames = new ArrayList<String>(); |
| /** Contains the mapping of logical database names to physical database names. */ |
| private final HashMap<String, String> logicalDbMapping = new HashMap<String, String>(); |
| private final String url; |
| private final String userName; |
| private final String userPassword; |
| private final int port; |
| private final String hostName; |
| private final JDBCClient jdbcClient; |
| private final int jmxPort; |
| private boolean isVerbose; |
| private boolean doTrace; |
| private boolean stopAfterFirstFail; |
| private String ssl; |
| |
| /** |
| * Extra connection attributes. Not for user name and password, use the |
| * fields {@link #userName} and {@link #userPassword} for those attributes. |
| */ |
| private Properties connectionAttributes; |
| |
| /** |
| * Password token used by the builtin authentication decorators. |
| * Default simple scheme is the password is a function |
| * of the user and a password token. password token |
| * is set by DatabasePropertyTestSetup.builtinAuthentication |
| */ |
| private String passwordToken = ""; |
| |
| /** |
| * Indirection for obtaining connections based upon |
| * this configuration. |
| */ |
| Connector connector; |
| |
| /* |
| * SecurityManager related configuration. |
| */ |
| |
| /** |
| * Install the default security manager setup, |
| * for the current configuration. |
| * @throws PrivilegedActionException |
| */ |
| boolean defaultSecurityManagerSetup() { |
| |
| // Testing with the DB2 client has not been performed |
| // under the security manager since it's not part |
| // of Derby so no real interest in tracking down issues. |
| if (jdbcClient.isDB2Client()) { |
| SecurityManagerSetup.noSecurityManager(); |
| return false; |
| } else { |
| if (SecurityManagerSetup.NO_POLICY.equals( |
| BaseTestCase.getSystemProperty("java.security.policy"))) |
| { |
| // Explict setting of no security manager |
| return false; |
| } |
| SecurityManagerSetup.installSecurityManager(); |
| return true; |
| } |
| } |
| |
| |
| /* |
| ** BUILTIN password handling. |
| */ |
| |
| /** |
| * Get the password that is a function of the user |
| * name and the passed in token. |
| */ |
| static final String getPassword(String user, String token) |
| { |
| return user.concat(token); |
| } |
| |
| /** |
| * Get the password that is a function of the user |
| * name and the token for the current configuration. |
| */ |
| public final String getPassword(String user) |
| { |
| return getPassword(user, passwordToken); |
| } |
| |
| public final String getDatabasePath(String physicalDatabaseName) |
| { |
| String dbName = physicalDatabaseName.replace('/', File.separatorChar); |
| String dsh = BaseTestCase.getSystemProperty("derby.system.home"); |
| if (dsh == null) { |
| Assert.fail("not implemented"); |
| } else { |
| dbName = dsh + File.separator + dbName; |
| } |
| return dbName; |
| } |
| } |