10 changed files with 436 additions and 2 deletions
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
import javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
import org.springframework.jdbc.datasource.SimpleDriverDataSource; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
|
||||||
|
class HsqlTestDataSourceConfigurer extends TestDataSourceConfigurer { |
||||||
|
|
||||||
|
private static HsqlTestDataSourceConfigurer INSTANCE; |
||||||
|
|
||||||
|
public static synchronized HsqlTestDataSourceConfigurer getInstance() throws ClassNotFoundException { |
||||||
|
if (INSTANCE == null) { |
||||||
|
ClassUtils.forName("org.hsqldb.jdbcDriver", HsqlTestDataSourceConfigurer.class.getClassLoader()); |
||||||
|
INSTANCE = new HsqlTestDataSourceConfigurer(); |
||||||
|
} |
||||||
|
return INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public void configureConnectionProperties(SimpleDriverDataSource dataSource, String databaseName) { |
||||||
|
dataSource.setDriverClass(org.hsqldb.jdbcDriver.class); |
||||||
|
dataSource.setUrl("jdbc:hsqldb:mem:" + databaseName); |
||||||
|
dataSource.setUsername("sa"); |
||||||
|
dataSource.setPassword(""); |
||||||
|
} |
||||||
|
|
||||||
|
public void shutdown(DataSource dataSource) { |
||||||
|
new JdbcTemplate(dataSource).execute("SHUTDOWN"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
import org.springframework.core.io.ClassPathResource; |
||||||
|
import org.springframework.core.io.Resource; |
||||||
|
import org.springframework.core.io.support.EncodedResource; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; |
||||||
|
|
||||||
|
/** |
||||||
|
* Populates a test DataSource from schema and test-data SQL defined in external resources. |
||||||
|
* By default, looks for a schema.sql file and test-data.sql resource in the root of the classpath. |
||||||
|
* |
||||||
|
* May be configured. |
||||||
|
* Call {@link #setSchemaLocation(Resource)} to configure the location of the database schema file. |
||||||
|
* Call {@link #setTestDataLocation(Resource)} to configure the location of the test data file. |
||||||
|
* Call {@link #setSqlScriptEncoding(String)} to set the encoding for the schema and test data SQL. |
||||||
|
*/ |
||||||
|
public class ResourceTestDatabasePopulator implements TestDatabasePopulator { |
||||||
|
|
||||||
|
private Resource schemaLocation = new ClassPathResource("schema.sql"); |
||||||
|
|
||||||
|
private Resource testDataLocation = new ClassPathResource("test-data.sql"); |
||||||
|
|
||||||
|
private String sqlScriptEncoding; |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the location of .sql file containing the database schema to create. |
||||||
|
* @param schemaLocation the path to the db schema definition |
||||||
|
*/ |
||||||
|
public void setSchemaLocation(Resource schemaLocation) { |
||||||
|
this.schemaLocation = schemaLocation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the location of the .sql file containing the test data to load. |
||||||
|
* @param testDataLocation the path to the db test data file |
||||||
|
*/ |
||||||
|
public void setTestDataLocation(Resource testDataLocation) { |
||||||
|
this.testDataLocation = testDataLocation; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Specify the encoding for SQL scripts, if different from the platform encoding. |
||||||
|
*/ |
||||||
|
public void setSqlScriptEncoding(String sqlScriptEncoding) { |
||||||
|
this.sqlScriptEncoding = sqlScriptEncoding; |
||||||
|
} |
||||||
|
|
||||||
|
public void populate(JdbcTemplate template) { |
||||||
|
createDatabaseSchema(template); |
||||||
|
insertTestData(template); |
||||||
|
} |
||||||
|
|
||||||
|
// create the application's database schema (tables, indexes, etc.)
|
||||||
|
private void createDatabaseSchema(JdbcTemplate template) { |
||||||
|
// TODO SimpleJdbcTemplate is unnecessary now with Java5+ - make similar method available on JdbcTestUtils?
|
||||||
|
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(template), new EncodedResource(schemaLocation, sqlScriptEncoding), false); |
||||||
|
} |
||||||
|
|
||||||
|
// populate the tables with test data
|
||||||
|
private void insertTestData(JdbcTemplate template) { |
||||||
|
// TODO SimpleJdbcTemplate is unnecessary now with Java5+ - make similar method available on JdbcTestUtils?
|
||||||
|
SimpleJdbcTestUtils.executeSqlScript(new SimpleJdbcTemplate(template), new EncodedResource(testDataLocation, sqlScriptEncoding), false); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
import javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.springframework.jdbc.datasource.SimpleDriverDataSource; |
||||||
|
|
||||||
|
/** |
||||||
|
* Encapsulates the configuration required to connect to a specific type of test database such as HSQLdb or H2. |
||||||
|
* Create a subclass for each database type we wish to support. |
||||||
|
* |
||||||
|
* @see TestDataSourceConfigurerFactory |
||||||
|
*/ |
||||||
|
abstract class TestDataSourceConfigurer { |
||||||
|
|
||||||
|
/** |
||||||
|
* Configure the properties required to connect to databaseName. |
||||||
|
* @param dataSource the data source to configure |
||||||
|
* @param databaseName the name of the test database |
||||||
|
*/ |
||||||
|
public abstract void configureConnectionProperties(SimpleDriverDataSource dataSource, String databaseName); |
||||||
|
|
||||||
|
/** |
||||||
|
* Shutdown the test database backed by dataSource. |
||||||
|
* @param dataSource the data source |
||||||
|
*/ |
||||||
|
public abstract void shutdown(DataSource dataSource); |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
class TestDataSourceConfigurerFactory { |
||||||
|
|
||||||
|
public static TestDataSourceConfigurer getConfigurer(TestDatabaseType type) throws IllegalStateException { |
||||||
|
try { |
||||||
|
if (type == TestDatabaseType.HSQL) { |
||||||
|
return HsqlTestDataSourceConfigurer.getInstance(); |
||||||
|
} else { |
||||||
|
throw new UnsupportedOperationException("Other types not yet supported"); |
||||||
|
} |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
throw new IllegalStateException("Drivers for test database type [" + type + "] are not available in the classpath", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,143 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
import javax.sql.DataSource; |
||||||
|
|
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
||||||
|
import org.springframework.jdbc.datasource.SimpleDriverDataSource; |
||||||
|
import org.springframework.transaction.TransactionStatus; |
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult; |
||||||
|
import org.springframework.transaction.support.TransactionTemplate; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns a {@link DataSource} that connects to an in-memory test database pre-populated with test data. |
||||||
|
* When the DataSource is returned, callers are guaranteed that the database schema and test data will have already been loaded. |
||||||
|
* |
||||||
|
* Can be configured. |
||||||
|
* Call {@link #setDatabaseName(String)} to change the name of the test database. |
||||||
|
* Call {@link #setDatabaseType(TestDatabaseType)} to set the test database type. |
||||||
|
* Call {@link #setDatabasePopulator(TestDatabasePopulator)} to change the algorithm used to populate the test database. |
||||||
|
*/ |
||||||
|
public class TestDataSourceFactory { |
||||||
|
|
||||||
|
private static Log logger = LogFactory.getLog(TestDataSourceFactory.class); |
||||||
|
|
||||||
|
private String databaseName; |
||||||
|
|
||||||
|
private TestDataSourceConfigurer dataSourceConfigurer; |
||||||
|
|
||||||
|
private TestDatabasePopulator databasePopulator; |
||||||
|
|
||||||
|
private DataSource dataSource; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new TestDataSourceFactory that uses the default {@link ResourceTestDatabasePopulator}. |
||||||
|
*/ |
||||||
|
public TestDataSourceFactory() { |
||||||
|
setDatabaseName("testdb"); |
||||||
|
setDatabaseType(TestDatabaseType.HSQL); |
||||||
|
setDatabasePopulator(new ResourceTestDatabasePopulator()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the name of the test database. |
||||||
|
* Defaults to 'testdb'. |
||||||
|
* @param name of the test database |
||||||
|
*/ |
||||||
|
public void setDatabaseName(String name) { |
||||||
|
Assert.notNull(name, "The testDatabaseName is required"); |
||||||
|
databaseName = name; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the type of test database to use. |
||||||
|
* Defaults to HSQL. |
||||||
|
* @param type the test database type |
||||||
|
*/ |
||||||
|
public void setDatabaseType(TestDatabaseType type) { |
||||||
|
Assert.notNull(type, "The TestDatabaseType is required"); |
||||||
|
dataSourceConfigurer = TestDataSourceConfigurerFactory.getConfigurer(type); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the helper that will be invoked to populate the test database with data. |
||||||
|
* Defaults a {@link ResourceTestDatabasePopulator}. |
||||||
|
* @param populator |
||||||
|
*/ |
||||||
|
public void setDatabasePopulator(TestDatabasePopulator populator) { |
||||||
|
Assert.notNull(populator, "The TestDatabasePopulator is required"); |
||||||
|
databasePopulator = populator; |
||||||
|
} |
||||||
|
|
||||||
|
// other public methods
|
||||||
|
|
||||||
|
/** |
||||||
|
* The factory method that returns the {@link DataSource} that connects to the test database. |
||||||
|
*/ |
||||||
|
public DataSource getDataSource() { |
||||||
|
if (dataSource == null) { |
||||||
|
initDataSource(); |
||||||
|
} |
||||||
|
return dataSource; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Destroy the test database. |
||||||
|
* Does nothing if the database has not been initialized. |
||||||
|
*/ |
||||||
|
public void destroyDataSource() { |
||||||
|
if (dataSource != null) { |
||||||
|
dataSourceConfigurer.shutdown(dataSource); |
||||||
|
dataSource = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// internal helper methods
|
||||||
|
|
||||||
|
// encapsulates the steps involved in initializing the data source: creating it, and populating it
|
||||||
|
private void initDataSource() { |
||||||
|
// create the in-memory database source first
|
||||||
|
dataSource = createDataSource(); |
||||||
|
if (logger.isInfoEnabled()) { |
||||||
|
logger.info("Created in-memory test database '" + databaseName + "'"); |
||||||
|
} |
||||||
|
if (databasePopulator != null) { |
||||||
|
// now populate the database
|
||||||
|
populateDatabase(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected DataSource createDataSource() { |
||||||
|
SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); |
||||||
|
dataSourceConfigurer.configureConnectionProperties(dataSource, databaseName); |
||||||
|
return dataSource; |
||||||
|
} |
||||||
|
|
||||||
|
private void populateDatabase() { |
||||||
|
TransactionTemplate template = new TransactionTemplate(new DataSourceTransactionManager(dataSource)); |
||||||
|
template.execute(new TransactionCallbackWithoutResult() { |
||||||
|
@Override |
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) { |
||||||
|
databasePopulator.populate(new JdbcTemplate(dataSource)); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
import org.springframework.dao.DataAccessException; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
|
||||||
|
/** |
||||||
|
* Strategy for populating a test database with test data. |
||||||
|
* |
||||||
|
* @see ResourceTestDatabasePopulator |
||||||
|
*/ |
||||||
|
public interface TestDatabasePopulator { |
||||||
|
|
||||||
|
/** |
||||||
|
* Populate the test database using the JDBC-based data access template provided. |
||||||
|
* @param template the data access template to use to populate the db; already configured and ready to use |
||||||
|
* @throws DataAccessException if an unrecoverable data access exception occurs during database population |
||||||
|
*/ |
||||||
|
void populate(JdbcTemplate template); |
||||||
|
} |
||||||
@ -0,0 +1,24 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2009 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed 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.springframework.test.jdbc; |
||||||
|
|
||||||
|
/** |
||||||
|
* A supported test database type. |
||||||
|
* @author Keith Donald |
||||||
|
*/ |
||||||
|
public enum TestDatabaseType { |
||||||
|
HSQL; |
||||||
|
} |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
package org.springframework.test.jdbc; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
import org.junit.Test; |
||||||
|
import org.springframework.dao.DataAccessException; |
||||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||||
|
|
||||||
|
public class TestDataSourceFactoryTests { |
||||||
|
TestDataSourceFactory factory = new TestDataSourceFactory(); |
||||||
|
|
||||||
|
@Test |
||||||
|
public void testGetDataSource() { |
||||||
|
StubTestDataSourcePopulator populator = new StubTestDataSourcePopulator(); |
||||||
|
factory.setDatabasePopulator(populator); |
||||||
|
factory.getDataSource(); |
||||||
|
assertTrue(populator.populateCalled); |
||||||
|
factory.destroyDataSource(); |
||||||
|
} |
||||||
|
|
||||||
|
private static class StubTestDataSourcePopulator implements TestDatabasePopulator { |
||||||
|
|
||||||
|
private boolean populateCalled; |
||||||
|
|
||||||
|
public void populate(JdbcTemplate template) throws DataAccessException { |
||||||
|
this.populateCalled = true; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue