Merge pull request #557 from sbrannen/SPR-7655
Introduce annotation to execute SQL scripts in the TCF
This commit is contained in:
@@ -26,6 +26,7 @@ import javax.sql.DataSource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Populates, initializes, or cleans up a database using SQL scripts defined in
|
||||
@@ -95,7 +96,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
* @param ignoreFailedDrops flag to indicate that a failed SQL {@code DROP}
|
||||
* statement can be ignored
|
||||
* @param sqlScriptEncoding the encoding for the supplied SQL scripts, if
|
||||
* different from the platform encoding; may be {@code null}
|
||||
* different from the platform encoding; may be {@code null} or empty
|
||||
* @param scripts the scripts to execute to initialize or populate the database;
|
||||
* never {@code null}
|
||||
* @since 4.0.3
|
||||
@@ -105,7 +106,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
this(scripts);
|
||||
this.continueOnError = continueOnError;
|
||||
this.ignoreFailedDrops = ignoreFailedDrops;
|
||||
this.sqlScriptEncoding = sqlScriptEncoding;
|
||||
setSqlScriptEncoding(sqlScriptEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +144,7 @@ public class ResourceDatabasePopulator implements DatabasePopulator {
|
||||
* @see #addScript(Resource)
|
||||
*/
|
||||
public void setSqlScriptEncoding(String sqlScriptEncoding) {
|
||||
this.sqlScriptEncoding = sqlScriptEncoding;
|
||||
this.sqlScriptEncoding = StringUtils.hasText(sqlScriptEncoding) ? sqlScriptEncoding : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.jdbc.datasource.init.ScriptUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* {@code @DatabaseInitializer} is used to annotate a test class or test method
|
||||
* to configure SQL scripts to be executed against a given database during
|
||||
* integration tests.
|
||||
*
|
||||
* <p>Method-level declarations override class-level declarations.
|
||||
*
|
||||
* <p>Script execution is performed by the {@link DatabaseInitializerTestExecutionListener},
|
||||
* which is enabled by default.
|
||||
*
|
||||
* <p>The configuration options provided by this annotation are a superset of
|
||||
* those provided by the {@code <jdbc:initialize-database />} XML namespace
|
||||
* element. Consult the Javadoc of individual attributes for details.
|
||||
*
|
||||
* <p>Beginning with Java 8, {@code @DatabaseInitializer} can be used as a
|
||||
* <em>{@linkplain Repeatable repeatable}</em> annotation. Otherwise,
|
||||
* {@link DatabaseInitializers @DatabaseInitializers} can be used as an explicit
|
||||
* container for declaring multiple instances of {@code @DatabaseInitializer}.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em>; however, attribute overrides are not currently
|
||||
* supported for {@linkplain Repeatable repeatable} annotations that are used as
|
||||
* meta-annotations.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Tadaya Tsuyukubo
|
||||
* @since 4.1
|
||||
* @see DatabaseInitializers
|
||||
* @see DatabaseInitializerTestExecutionListener
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* @see org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
|
||||
* @see org.springframework.jdbc.datasource.init.ScriptUtils
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
@Target({ TYPE, METHOD })
|
||||
@Repeatable(DatabaseInitializers.class)
|
||||
public @interface DatabaseInitializer {
|
||||
|
||||
/**
|
||||
* Enumeration of <em>phases</em> that dictate when SQL scripts are executed.
|
||||
*/
|
||||
static enum ExecutionPhase {
|
||||
|
||||
/**
|
||||
* The configured SQL scripts will be executed <em>before</em> the
|
||||
* corresponding test method.
|
||||
*/
|
||||
BEFORE_TEST_METHOD,
|
||||
|
||||
/**
|
||||
* The configured SQL scripts will be executed <em>after</em> the
|
||||
* corresponding test method.
|
||||
*/
|
||||
AFTER_TEST_METHOD;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Alias for {@link #scripts}.
|
||||
* <p>This attribute may <strong>not</strong> be used in conjunction with
|
||||
* {@link #scripts}, but it may be used instead of {@link #scripts}.
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* The paths to the SQL scripts to execute.
|
||||
*
|
||||
* <p>This attribute may <strong>not</strong> be used in conjunction with
|
||||
* {@link #value}, but it may be used instead of {@link #value}.
|
||||
*
|
||||
* <h3>Path Resource Semantics</h3>
|
||||
* <p>Each path will be interpreted as a Spring
|
||||
* {@link org.springframework.core.io.Resource Resource}. A plain path
|
||||
* — for example, {@code "schema.sql"} — will be treated as a
|
||||
* classpath resource that is <em>relative</em> to the package in which the
|
||||
* test class is defined. A path starting with a slash will be treated as an
|
||||
* <em>absolute</em> classpath resource, for example:
|
||||
* {@code "/org/example/schema.sql"}. A path which references a
|
||||
* URL (e.g., a path prefixed with
|
||||
* {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
|
||||
* {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:}, etc.) will be
|
||||
* loaded using the specified resource protocol.
|
||||
*
|
||||
* <h3>Default Script Detection</h3>
|
||||
* <p>If no SQL scripts are specified, an attempt will be made to detect a
|
||||
* <em>default</em> script depending on where this annotation is declared.
|
||||
* If a default cannot be detected, an {@link IllegalStateException} will be
|
||||
* thrown.
|
||||
* <ul>
|
||||
* <li><strong>class-level declaration</strong>: if the annotated test class
|
||||
* is {@code com.example.MyTest}, the corresponding default script is
|
||||
* {@code "classpath:com/example/MyTest.sql"}.</li>
|
||||
* <li><strong>method-level declaration</strong>: if the annotated test
|
||||
* method is named {@code testMethod()} and is defined in the class
|
||||
* {@code com.example.MyTest}, the corresponding default script is
|
||||
* {@code "classpath:com/example/MyTest.testMethod.sql"}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
String[] scripts() default {};
|
||||
|
||||
/**
|
||||
* The encoding for the supplied SQL scripts, if different from the platform
|
||||
* encoding.
|
||||
* <p>An empty string denotes that the platform encoding should be used.
|
||||
*/
|
||||
String encoding() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the {@link javax.sql.DataSource} against which the scripts
|
||||
* should be executed.
|
||||
* <p>The name is only used if there is more than one bean of type
|
||||
* {@code DataSource} in the test's {@code ApplicationContext}. If there is
|
||||
* only one such bean, it is not necessary to specify a bean name.
|
||||
* <p>Defaults to an empty string, requiring that one of the following is
|
||||
* true:
|
||||
* <ol>
|
||||
* <li>There is only one bean of type {@code DataSource} in the test's
|
||||
* {@code ApplicationContext}.</li>
|
||||
* <li>The {@code DataSource} to use is named {@code "dataSource"}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
String dataSource() default "";
|
||||
|
||||
/**
|
||||
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
|
||||
* PlatformTransactionManager} that should be used to drive transactions.
|
||||
* <p>The name is only used if there is more than one bean of type
|
||||
* {@code PlatformTransactionManager} in the test's {@code ApplicationContext}.
|
||||
* If there is only one such bean, it is not necessary to specify a bean name.
|
||||
* <p>Defaults to an empty string, requiring that one of the following is
|
||||
* true:
|
||||
* <ol>
|
||||
* <li>There is only one bean of type {@code PlatformTransactionManager} in
|
||||
* the test's {@code ApplicationContext}.</li>
|
||||
* <li>{@link org.springframework.transaction.annotation.TransactionManagementConfigurer
|
||||
* TransactionManagementConfigurer} has been implemented to specify which
|
||||
* {@code PlatformTransactionManager} bean should be used for annotation-driven
|
||||
* transaction management.</li>
|
||||
* <li>The {@code PlatformTransactionManager} to use is named
|
||||
* {@code "transactionManager"}.</li>
|
||||
* </ol>
|
||||
*/
|
||||
String transactionManager() default "";
|
||||
|
||||
/**
|
||||
* Flag to indicate that the SQL scripts must be executed in a new transaction.
|
||||
* <p>Defaults to {@code false}, meaning that the SQL scripts will be executed
|
||||
* within the current transaction if present. The <em>current</em> transaction
|
||||
* will typically be managed by the
|
||||
* {@link org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* TransactionalTestExecutionListener}.
|
||||
* <p>Can be set to {@code true} to ensure that the scripts are executed in
|
||||
* a new, isolated transaction that will be immediately committed.
|
||||
*/
|
||||
boolean requireNewTransaction() default false;
|
||||
|
||||
/**
|
||||
* The character string used to separate individual statements within the
|
||||
* SQL scripts.
|
||||
* <p>Defaults to {@code ";"} if not specified and falls back to {@code "\n"}
|
||||
* as a last resort; may be set to {@link ScriptUtils#EOF_STATEMENT_SEPARATOR}
|
||||
* to signal that each script contains a single statement without a separator.
|
||||
*/
|
||||
String separator() default ScriptUtils.DEFAULT_STATEMENT_SEPARATOR;
|
||||
|
||||
/**
|
||||
* The prefix that identifies single-line comments within the SQL scripts.
|
||||
* <p>Defaults to {@code "--"}.
|
||||
*/
|
||||
String commentPrefix() default ScriptUtils.DEFAULT_COMMENT_PREFIX;
|
||||
|
||||
/**
|
||||
* The start delimiter that identifies block comments within the SQL scripts.
|
||||
* <p>Defaults to {@code "/*"}.
|
||||
* @see #blockCommentEndDelimiter
|
||||
*/
|
||||
String blockCommentStartDelimiter() default ScriptUtils.DEFAULT_BLOCK_COMMENT_START_DELIMITER;
|
||||
|
||||
/**
|
||||
* The end delimiter that identifies block comments within the SQL scripts.
|
||||
* <p>Defaults to <code>"*/"</code>.
|
||||
* @see #blockCommentStartDelimiter
|
||||
*/
|
||||
String blockCommentEndDelimiter() default ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER;
|
||||
|
||||
/**
|
||||
* Flag to indicate that all failures in SQL should be logged but not cause
|
||||
* a failure.
|
||||
* <p>Defaults to {@code false}.
|
||||
* @see #ignoreFailedDrops
|
||||
*/
|
||||
boolean continueOnError() default false;
|
||||
|
||||
/**
|
||||
* Flag to indicate that a failed SQL {@code DROP} statement can be ignored.
|
||||
* <p>This is useful for a non-embedded database whose SQL dialect does not
|
||||
* support an {@code IF EXISTS} clause in a {@code DROP} statement.
|
||||
* <p>The default is {@code false} so that if a script is accidentally
|
||||
* executed, it will fail fast if the script starts with a {@code DROP}
|
||||
* statement.
|
||||
* @see #continueOnError
|
||||
*/
|
||||
boolean ignoreFailedDrops() default false;
|
||||
|
||||
/**
|
||||
* When the SQL scripts should be executed.
|
||||
* <p>Defaults to {@link ExecutionPhase#BEFORE_TEST_METHOD BEFORE_TEST_METHOD}.
|
||||
*/
|
||||
ExecutionPhase executionPhase() default ExecutionPhase.BEFORE_TEST_METHOD;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.test.context.jdbc.DatabaseInitializer.ExecutionPhase;
|
||||
import org.springframework.test.context.support.AbstractTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TestContextTransactionUtils;
|
||||
import org.springframework.test.context.util.TestContextResourceUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* {@code TestExecutionListener} that provides support for executing SQL scripts
|
||||
* configured via the {@link DatabaseInitializer @DatabaseInitializer} annotation.
|
||||
*
|
||||
* <p>SQL scripts will be executed {@linkplain #beforeTestMethod(TestContext) before}
|
||||
* or {@linkplain #afterTestMethod(TestContext) after} execution of the corresponding
|
||||
* {@linkplain java.lang.reflect.Method test method}, depending on the configured
|
||||
* value of the {@link DatabaseInitializer#requireNewTransaction requireNewTransaction}
|
||||
* flag.
|
||||
*
|
||||
* <h3>Script Resources</h3>
|
||||
* <p>For details on default script detection and how explicit script locations
|
||||
* are interpreted, see {@link DatabaseInitializer#scripts}.
|
||||
*
|
||||
* <h3>Required Spring Beans</h3>
|
||||
* <p>A {@link DataSource} and {@link PlatformTransactionManager} must be defined
|
||||
* as beans in the Spring {@link ApplicationContext} for the corresponding test.
|
||||
* Consult the Javadoc for {@link TestContextTransactionUtils#retrieveDataSource}
|
||||
* and {@link TestContextTransactionUtils#retrieveTransactionManager} for details
|
||||
* on the algorithms used to locate these beans.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see DatabaseInitializer
|
||||
* @see DatabaseInitializers
|
||||
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* @see org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
|
||||
* @see org.springframework.jdbc.datasource.init.ScriptUtils
|
||||
*/
|
||||
public class DatabaseInitializerTestExecutionListener extends AbstractTestExecutionListener {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DatabaseInitializerTestExecutionListener.class);
|
||||
|
||||
|
||||
/**
|
||||
* Execute SQL scripts configured via {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* for the supplied {@link TestContext} <em>before</em> the current test method.
|
||||
*/
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
executeDatabaseInitializers(testContext, ExecutionPhase.BEFORE_TEST_METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL scripts configured via {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* for the supplied {@link TestContext} <em>after</em> the current test method.
|
||||
*/
|
||||
@Override
|
||||
public void afterTestMethod(TestContext testContext) throws Exception {
|
||||
executeDatabaseInitializers(testContext, ExecutionPhase.AFTER_TEST_METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute SQL scripts configured via {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* for the supplied {@link TestContext} and {@link ExecutionPhase}.
|
||||
*/
|
||||
private void executeDatabaseInitializers(TestContext testContext, ExecutionPhase executionPhase) throws Exception {
|
||||
boolean classLevel = false;
|
||||
|
||||
Set<DatabaseInitializer> databaseInitializers = AnnotationUtils.getRepeatableAnnotation(
|
||||
testContext.getTestMethod(), DatabaseInitializers.class, DatabaseInitializer.class);
|
||||
if (databaseInitializers.isEmpty()) {
|
||||
databaseInitializers = AnnotationUtils.getRepeatableAnnotation(testContext.getTestClass(),
|
||||
DatabaseInitializers.class, DatabaseInitializer.class);
|
||||
if (!databaseInitializers.isEmpty()) {
|
||||
classLevel = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (DatabaseInitializer databaseInitializer : databaseInitializers) {
|
||||
executeDatabaseInitializer(databaseInitializer, executionPhase, testContext, classLevel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the SQL scripts configured via the supplied
|
||||
* {@link DatabaseInitializer @DatabaseInitializer} for the given
|
||||
* {@link ExecutionPhase} and {@link TestContext}.
|
||||
*
|
||||
* <p>Special care must be taken in order to properly support the
|
||||
* {@link DatabaseInitializer#requireNewTransaction requireNewTransaction}
|
||||
* flag.
|
||||
*
|
||||
* @param databaseInitializer the {@code @DatabaseInitializer} to parse
|
||||
* @param executionPhase the current execution phase
|
||||
* @param testContext the current {@code TestContext}
|
||||
* @param classLevel {@code true} if {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* was declared at the class level
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
private void executeDatabaseInitializer(DatabaseInitializer databaseInitializer, ExecutionPhase executionPhase,
|
||||
TestContext testContext, boolean classLevel) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Processing %s for execution phase [%s] and test context %s.",
|
||||
databaseInitializer, executionPhase, testContext));
|
||||
}
|
||||
|
||||
if (executionPhase != databaseInitializer.executionPhase()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
|
||||
populator.setSqlScriptEncoding(databaseInitializer.encoding());
|
||||
populator.setSeparator(databaseInitializer.separator());
|
||||
populator.setCommentPrefix(databaseInitializer.commentPrefix());
|
||||
populator.setBlockCommentStartDelimiter(databaseInitializer.blockCommentStartDelimiter());
|
||||
populator.setBlockCommentEndDelimiter(databaseInitializer.blockCommentEndDelimiter());
|
||||
populator.setContinueOnError(databaseInitializer.continueOnError());
|
||||
populator.setIgnoreFailedDrops(databaseInitializer.ignoreFailedDrops());
|
||||
|
||||
String[] scripts = getScripts(databaseInitializer, testContext, classLevel);
|
||||
scripts = TestContextResourceUtils.convertToClasspathResourcePaths(testContext.getTestClass(), scripts);
|
||||
populator.setScripts(TestContextResourceUtils.convertToResources(testContext.getApplicationContext(), scripts));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing SQL scripts: " + ObjectUtils.nullSafeToString(scripts));
|
||||
}
|
||||
|
||||
final DataSource dataSource = TestContextTransactionUtils.retrieveDataSource(testContext,
|
||||
databaseInitializer.dataSource());
|
||||
final PlatformTransactionManager transactionManager = TestContextTransactionUtils.retrieveTransactionManager(
|
||||
testContext, databaseInitializer.transactionManager());
|
||||
|
||||
int propagation = databaseInitializer.requireNewTransaction() ? TransactionDefinition.PROPAGATION_REQUIRES_NEW
|
||||
: TransactionDefinition.PROPAGATION_REQUIRED;
|
||||
|
||||
TransactionAttribute transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(
|
||||
testContext, new DefaultTransactionAttribute(propagation));
|
||||
|
||||
new TransactionTemplate(transactionManager, transactionAttribute).execute(new TransactionCallbackWithoutResult() {
|
||||
|
||||
@Override
|
||||
public void doInTransactionWithoutResult(TransactionStatus status) {
|
||||
populator.execute(dataSource);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private String[] getScripts(DatabaseInitializer databaseInitializer, TestContext testContext, boolean classLevel) {
|
||||
String[] scripts = databaseInitializer.scripts();
|
||||
String[] value = databaseInitializer.value();
|
||||
boolean scriptsDeclared = !ObjectUtils.isEmpty(scripts);
|
||||
boolean valueDeclared = !ObjectUtils.isEmpty(value);
|
||||
|
||||
if (valueDeclared && scriptsDeclared) {
|
||||
String elementType = (classLevel ? "class" : "method");
|
||||
String elementName = (classLevel ? testContext.getTestClass().getName()
|
||||
: testContext.getTestMethod().toString());
|
||||
String msg = String.format("Test %s [%s] has been configured with @DatabaseInitializer's 'value' [%s] "
|
||||
+ "and 'scripts' [%s] attributes. Only one declaration of SQL script "
|
||||
+ "paths is permitted per @DatabaseInitializer annotation.", elementType, elementName,
|
||||
ObjectUtils.nullSafeToString(value), ObjectUtils.nullSafeToString(scripts));
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (valueDeclared) {
|
||||
scripts = value;
|
||||
}
|
||||
if (ObjectUtils.isEmpty(scripts)) {
|
||||
scripts = new String[] { detectDefaultScript(testContext, classLevel) };
|
||||
}
|
||||
return scripts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect a default SQL script by implementing the algorithm defined in
|
||||
* {@link DatabaseInitializer#scripts}.
|
||||
*/
|
||||
private String detectDefaultScript(TestContext testContext, boolean classLevel) {
|
||||
Class<?> clazz = testContext.getTestClass();
|
||||
Method method = testContext.getTestMethod();
|
||||
String elementType = (classLevel ? "class" : "method");
|
||||
String elementName = (classLevel ? clazz.getName() : method.toString());
|
||||
|
||||
String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName());
|
||||
if (!classLevel) {
|
||||
resourcePath += "." + method.getName();
|
||||
}
|
||||
resourcePath += ".sql";
|
||||
|
||||
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
|
||||
|
||||
if (classPathResource.exists()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Detected default SQL script \"%s\" for test %s [%s]", prefixedResourcePath,
|
||||
elementType, elementName));
|
||||
}
|
||||
return prefixedResourcePath;
|
||||
}
|
||||
else {
|
||||
String msg = String.format("Could not detect default SQL script for test %s [%s]: "
|
||||
+ "%s does not exist. Either declare scripts via @DatabaseInitializer or make the "
|
||||
+ "default SQL script available.", elementType, elementName, classPathResource);
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* Container annotation that aggregates several {@link DatabaseInitializer}
|
||||
* annotations.
|
||||
*
|
||||
* <p>Can be used natively, declaring several nested {@link DatabaseInitializer}
|
||||
* annotations. Can also be used in conjunction with Java 8's support for
|
||||
* repeatable annotations, where {@code @DatabaseInitializer} can simply be
|
||||
* declared several times on the same class or method, implicitly generating
|
||||
* this container annotation.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em>.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see DatabaseInitializer
|
||||
*/
|
||||
@Documented
|
||||
@Inherited
|
||||
@Retention(RUNTIME)
|
||||
@Target({ TYPE, METHOD })
|
||||
public @interface DatabaseInitializers {
|
||||
|
||||
DatabaseInitializer[] value();
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
import org.springframework.test.jdbc.JdbcTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
@@ -63,6 +64,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.TestExecutionListeners
|
||||
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* @see org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener
|
||||
* @see org.springframework.test.context.transaction.TransactionConfiguration
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see org.springframework.test.annotation.Rollback
|
||||
@@ -71,7 +73,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @see org.springframework.test.jdbc.JdbcTestUtils
|
||||
* @see org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests
|
||||
*/
|
||||
@TestExecutionListeners(TransactionalTestExecutionListener.class)
|
||||
@TestExecutionListeners({ TransactionalTestExecutionListener.class, DatabaseInitializerTestExecutionListener.class })
|
||||
@Transactional
|
||||
public abstract class AbstractTransactionalJUnit4SpringContextTests extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -22,7 +22,6 @@ import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
@@ -30,16 +29,15 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.test.context.util.TestContextResourceUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Abstract application context loader that provides a basis for all concrete
|
||||
@@ -63,8 +61,6 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
private static final String SLASH = "/";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractContextLoader.class);
|
||||
|
||||
|
||||
@@ -87,7 +83,8 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
*/
|
||||
@Override
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
String[] processedLocations = processLocations(configAttributes.getDeclaringClass(), configAttributes.getLocations());
|
||||
String[] processedLocations = processLocations(configAttributes.getDeclaringClass(),
|
||||
configAttributes.getLocations());
|
||||
configAttributes.setLocations(processedLocations);
|
||||
}
|
||||
|
||||
@@ -118,25 +115,23 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
protected void prepareContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
context.getEnvironment().setActiveProfiles(mergedConfig.getActiveProfiles());
|
||||
|
||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses =
|
||||
mergedConfig.getContextInitializerClasses();
|
||||
Set<Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>>> initializerClasses = mergedConfig.getContextInitializerClasses();
|
||||
if (initializerClasses.isEmpty()) {
|
||||
// no ApplicationContextInitializers have been declared -> nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances =
|
||||
new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||
List<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerInstances = new ArrayList<ApplicationContextInitializer<ConfigurableApplicationContext>>();
|
||||
Class<?> contextClass = context.getClass();
|
||||
|
||||
for (Class<? extends ApplicationContextInitializer<? extends ConfigurableApplicationContext>> initializerClass : initializerClasses) {
|
||||
Class<?> initializerContextClass = GenericTypeResolver.resolveTypeArgument(initializerClass,
|
||||
ApplicationContextInitializer.class);
|
||||
ApplicationContextInitializer.class);
|
||||
Assert.isAssignable(initializerContextClass, contextClass, String.format(
|
||||
"Could not add context initializer [%s] since its generic parameter [%s] " +
|
||||
"is not assignable from the type of application context used by this " +
|
||||
"context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
||||
contextClass.getName()));
|
||||
"Could not add context initializer [%s] since its generic parameter [%s] "
|
||||
+ "is not assignable from the type of application context used by this "
|
||||
+ "context loader [%s]: ", initializerClass.getName(), initializerContextClass.getName(),
|
||||
contextClass.getName()));
|
||||
initializerInstances.add((ApplicationContextInitializer<ConfigurableApplicationContext>) BeanUtils.instantiateClass(initializerClass));
|
||||
}
|
||||
|
||||
@@ -171,8 +166,8 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
*/
|
||||
@Override
|
||||
public final String[] processLocations(Class<?> clazz, String... locations) {
|
||||
return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ?
|
||||
generateDefaultLocations(clazz) : modifyLocations(clazz, locations);
|
||||
return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ? generateDefaultLocations(clazz)
|
||||
: modifyLocations(clazz, locations);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,7 +175,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* supplied class.
|
||||
* <p>For example, if the supplied class is {@code com.example.MyTest},
|
||||
* the generated locations will contain a single string with a value of
|
||||
* "classpath:/com/example/MyTest{@code <suffix>}",
|
||||
* "classpath:com/example/MyTest{@code <suffix>}",
|
||||
* where {@code <suffix>} is the value of the
|
||||
* {@link #getResourceSuffix() resource suffix} string.
|
||||
* <p>As of Spring 3.1, the implementation of this method adheres to the
|
||||
@@ -199,21 +194,21 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
String suffix = getResourceSuffix();
|
||||
Assert.hasText(suffix, "Resource suffix must not be empty");
|
||||
String resourcePath = SLASH + ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix;
|
||||
String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix;
|
||||
String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourcePath, clazz);
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
|
||||
|
||||
if (classPathResource.exists()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Detected default resource location \"%s\" for test class [%s]",
|
||||
prefixedResourcePath, clazz.getName()));
|
||||
prefixedResourcePath, clazz.getName()));
|
||||
}
|
||||
return new String[] {prefixedResourcePath};
|
||||
return new String[] { prefixedResourcePath };
|
||||
}
|
||||
else {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Could not detect default resource locations for test class [%s]: " +
|
||||
"%s does not exist", clazz.getName(), classPathResource));
|
||||
logger.info(String.format("Could not detect default resource locations for test class [%s]: "
|
||||
+ "%s does not exist", clazz.getName(), classPathResource));
|
||||
}
|
||||
return EMPTY_STRING_ARRAY;
|
||||
}
|
||||
@@ -221,15 +216,8 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
|
||||
/**
|
||||
* Generate a modified version of the supplied locations array and return it.
|
||||
* <p>A plain path — for example, "context.xml" — will
|
||||
* be treated as a classpath resource that is relative to the package in which
|
||||
* the specified class is defined. A path starting with a slash is treated
|
||||
* as an absolute classpath location, for example:
|
||||
* "/org/springframework/whatever/foo.xml". A path which
|
||||
* references a URL (e.g., a path prefixed with
|
||||
* {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
|
||||
* {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:},
|
||||
* etc.) will be added to the results unchanged.
|
||||
* <p>The default implementation simply delegates to
|
||||
* {@link TestContextResourceUtils#convertToClasspathResourcePaths}.
|
||||
* <p>Subclasses can override this method to implement a different
|
||||
* <em>location modification</em> strategy.
|
||||
* @param clazz the class with which the locations are associated
|
||||
@@ -238,21 +226,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* @since 2.5
|
||||
*/
|
||||
protected String[] modifyLocations(Class<?> clazz, String... locations) {
|
||||
String[] modifiedLocations = new String[locations.length];
|
||||
for (int i = 0; i < locations.length; i++) {
|
||||
String path = locations[i];
|
||||
if (path.startsWith(SLASH)) {
|
||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||
}
|
||||
else if (!ResourcePatternUtils.isUrl(path)) {
|
||||
modifiedLocations[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH +
|
||||
StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
|
||||
}
|
||||
else {
|
||||
modifiedLocations[i] = StringUtils.cleanPath(path);
|
||||
}
|
||||
}
|
||||
return modifiedLocations;
|
||||
return TestContextResourceUtils.convertToClasspathResourcePaths(clazz, locations);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.test.context.TestExecutionListener;
|
||||
* <li>{@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.transaction.TransactionalTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener}
|
||||
* </ol>
|
||||
* <li>Uses {@link DelegatingSmartContextLoader} as the default {@link ContextLoader}.
|
||||
* <li>Builds a standard {@link MergedContextConfiguration}.
|
||||
@@ -51,7 +52,8 @@ public class DefaultTestContextBootstrapper extends AbstractTestContextBootstrap
|
||||
private static final List<String> DEFAULT_TEST_EXECUTION_LISTENER_CLASS_NAMES = Collections.unmodifiableList(Arrays.asList(
|
||||
"org.springframework.test.context.support.DependencyInjectionTestExecutionListener",
|
||||
"org.springframework.test.context.support.DirtiesContextTestExecutionListener",
|
||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener"));
|
||||
"org.springframework.test.context.transaction.TransactionalTestExecutionListener",
|
||||
"org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener"));
|
||||
|
||||
|
||||
/**
|
||||
@@ -61,6 +63,7 @@ public class DefaultTestContextBootstrapper extends AbstractTestContextBootstrap
|
||||
* <li>{@link org.springframework.test.context.support.DependencyInjectionTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.support.DirtiesContextTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.transaction.TransactionalTestExecutionListener}
|
||||
* <li>{@link org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener}
|
||||
* </ol>
|
||||
*/
|
||||
protected List<String> getDefaultTestExecutionListenerClassNames() {
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener;
|
||||
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
|
||||
import org.springframework.test.jdbc.JdbcTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
@@ -54,6 +55,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @see org.springframework.test.context.ContextConfiguration
|
||||
* @see org.springframework.test.context.TestExecutionListeners
|
||||
* @see org.springframework.test.context.transaction.TransactionalTestExecutionListener
|
||||
* @see org.springframework.test.context.jdbc.DatabaseInitializerTestExecutionListener
|
||||
* @see org.springframework.test.context.transaction.TransactionConfiguration
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see org.springframework.test.annotation.Rollback
|
||||
@@ -62,7 +64,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @see org.springframework.test.jdbc.JdbcTestUtils
|
||||
* @see org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests
|
||||
*/
|
||||
@TestExecutionListeners(TransactionalTestExecutionListener.class)
|
||||
@TestExecutionListeners({ TransactionalTestExecutionListener.class, DatabaseInitializerTestExecutionListener.class })
|
||||
@Transactional
|
||||
public abstract class AbstractTransactionalTestNGSpringContextTests extends AbstractTestNGSpringContextTests {
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.transaction;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.test.context.TestContext;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
|
||||
import org.springframework.transaction.interceptor.DelegatingTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for working with transactions and data access related beans
|
||||
* within the <em>Spring TestContext Framework</em>. Mainly for internal use
|
||||
* within the framework.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class TestContextTransactionUtils {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestContextTransactionUtils.class);
|
||||
|
||||
/**
|
||||
* Default bean name for a {@link DataSource}: {@code "dataSource"}.
|
||||
*/
|
||||
public static final String DEFAULT_DATA_SOURCE_NAME = "dataSource";
|
||||
|
||||
/**
|
||||
* Default bean name for a {@link PlatformTransactionManager}:
|
||||
* {@code "transactionManager"}.
|
||||
*/
|
||||
public static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
|
||||
|
||||
|
||||
private TestContextTransactionUtils() {
|
||||
/* prevent instantiation */
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the {@link DataSource} to use for the supplied {@linkplain TestContext
|
||||
* test context}.
|
||||
* <p>The following algorithm is used to retrieve the {@code DataSource}
|
||||
* from the {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* of the supplied test context:
|
||||
* <ol>
|
||||
* <li>Look up the {@code DataSource} by type and name, if the supplied
|
||||
* {@code name} is non-empty.
|
||||
* <li>Look up the {@code DataSource} by type.
|
||||
* <li>Look up the {@code DataSource} by type and the
|
||||
* {@linkplain #DEFAULT_DATA_SOURCE_NAME default data source name}.
|
||||
* @param testContext the test context for which the {@code DataSource}
|
||||
* should be retrieved; never {@code null}
|
||||
* @param name the name of the {@code DataSource} to retrieve; may be {@code null}
|
||||
* or <em>empty</em>
|
||||
* @return the {@code DataSource} to use, or {@code null} if not found
|
||||
* @throws BeansException if an error occurs while retrieving the {@code DataSource}
|
||||
*/
|
||||
public static DataSource retrieveDataSource(TestContext testContext, String name) {
|
||||
Assert.notNull(testContext, "TestContext must not be null");
|
||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
|
||||
try {
|
||||
// look up by type and explicit name
|
||||
if (StringUtils.hasText(name)) {
|
||||
return bf.getBean(name, DataSource.class);
|
||||
}
|
||||
|
||||
if (bf instanceof ListableBeanFactory) {
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||
|
||||
// look up single bean by type
|
||||
Map<String, DataSource> dataSources = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
||||
DataSource.class);
|
||||
if (dataSources.size() == 1) {
|
||||
return dataSources.values().iterator().next();
|
||||
}
|
||||
}
|
||||
|
||||
// look up by type and default name
|
||||
return bf.getBean(DEFAULT_DATA_SOURCE_NAME, DataSource.class);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Caught exception while retrieving DataSource for test context " + testContext, ex);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the {@linkplain PlatformTransactionManager transaction manager}
|
||||
* to use for the supplied {@linkplain TestContext test context}.
|
||||
* <p>The following algorithm is used to retrieve the transaction manager
|
||||
* from the {@link org.springframework.context.ApplicationContext ApplicationContext}
|
||||
* of the supplied test context:
|
||||
* <ol>
|
||||
* <li>Look up the transaction manager by type and name, if the supplied
|
||||
* {@code name} is non-empty.
|
||||
* <li>Look up the transaction manager by type.
|
||||
* <li>Look up the transaction manager via a {@link TransactionManagementConfigurer},
|
||||
* if present.
|
||||
* <li>Look up the transaction manager by type and the
|
||||
* {@linkplain #DEFAULT_TRANSACTION_MANAGER_NAME default transaction manager
|
||||
* name}.
|
||||
* @param testContext the test context for which the transaction manager
|
||||
* should be retrieved; never {@code null}
|
||||
* @param name the name of the transaction manager to retrieve; may be
|
||||
* {@code null} or <em>empty</em>
|
||||
* @return the transaction manager to use, or {@code null} if not found
|
||||
* @throws BeansException if an error occurs while retrieving the transaction manager
|
||||
*/
|
||||
public static PlatformTransactionManager retrieveTransactionManager(TestContext testContext, String name) {
|
||||
Assert.notNull(testContext, "TestContext must not be null");
|
||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
|
||||
try {
|
||||
// look up by type and explicit name
|
||||
if (StringUtils.hasText(name)) {
|
||||
return bf.getBean(name, PlatformTransactionManager.class);
|
||||
}
|
||||
|
||||
if (bf instanceof ListableBeanFactory) {
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||
|
||||
// look up single bean by type
|
||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
||||
PlatformTransactionManager.class);
|
||||
if (txMgrs.size() == 1) {
|
||||
return txMgrs.values().iterator().next();
|
||||
}
|
||||
|
||||
// look up single TransactionManagementConfigurer
|
||||
Map<String, TransactionManagementConfigurer> configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
lbf, TransactionManagementConfigurer.class);
|
||||
if (configurers.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Only one TransactionManagementConfigurer may exist in the ApplicationContext");
|
||||
}
|
||||
if (configurers.size() == 1) {
|
||||
return configurers.values().iterator().next().annotationDrivenTransactionManager();
|
||||
}
|
||||
}
|
||||
|
||||
// look up by type and default name
|
||||
return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Caught exception while retrieving transaction manager for test context " + testContext, ex);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delegating {@link TransactionAttribute} for the supplied target
|
||||
* {@link TransactionAttribute} and {@link TestContext}, using the names of
|
||||
* the test class and test method as the name of the transaction.
|
||||
*
|
||||
* @param testContext the {@code TestContext} upon which to base the name; never {@code null}
|
||||
* @param targetAttribute the {@code TransactionAttribute} to delegate to; never {@code null}
|
||||
* @return the delegating {@code TransactionAttribute}
|
||||
*/
|
||||
public static TransactionAttribute createDelegatingTransactionAttribute(TestContext testContext,
|
||||
TransactionAttribute targetAttribute) {
|
||||
Assert.notNull(testContext, "TestContext must not be null");
|
||||
Assert.notNull(targetAttribute, "Target TransactionAttribute must not be null");
|
||||
return new TestContextTransactionAttribute(targetAttribute, testContext);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static class TestContextTransactionAttribute extends DelegatingTransactionAttribute {
|
||||
|
||||
private final String name;
|
||||
|
||||
|
||||
public TestContextTransactionAttribute(TransactionAttribute targetAttribute, TestContext testContext) {
|
||||
super(targetAttribute);
|
||||
this.name = testContext.getTestClass().getName() + "." + testContext.getTestMethod().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -45,17 +45,22 @@ public @interface TransactionConfiguration {
|
||||
* The bean name of the {@link org.springframework.transaction.PlatformTransactionManager
|
||||
* PlatformTransactionManager} that should be used to drive transactions.
|
||||
*
|
||||
* <p>This attribute is not required and only needs to be declared if there
|
||||
* are multiple beans of type {@code PlatformTransactionManager} in the test's
|
||||
* {@code ApplicationContext} <em>and</em> if one of the following is true.
|
||||
* <ul>
|
||||
* <li>the bean name of the desired {@code PlatformTransactionManager} is not
|
||||
* "transactionManager"</li>
|
||||
* <p>The name is only used if there is more than one bean of type
|
||||
* {@code PlatformTransactionManager} in the test's {@code ApplicationContext}.
|
||||
* If there is only one such bean, it is not necessary to specify a bean name.
|
||||
*
|
||||
* <p>Defaults to an empty string, requiring that one of the following is
|
||||
* true:
|
||||
* <ol>
|
||||
* <li>There is only one bean of type {@code PlatformTransactionManager} in
|
||||
* the test's {@code ApplicationContext}.</li>
|
||||
* <li>{@link org.springframework.transaction.annotation.TransactionManagementConfigurer
|
||||
* TransactionManagementConfigurer} was not implemented to specify which
|
||||
* TransactionManagementConfigurer} has been implemented to specify which
|
||||
* {@code PlatformTransactionManager} bean should be used for annotation-driven
|
||||
* transaction management
|
||||
* </ul>
|
||||
* transaction management.</li>
|
||||
* <li>The {@code PlatformTransactionManager} to use is named
|
||||
* {@code "transactionManager"}.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p><b>NOTE:</b> The XML {@code <tx:annotation-driven>} element also refers
|
||||
* to a bean named "transactionManager" by default. If you are using both
|
||||
@@ -63,7 +68,7 @@ public @interface TransactionConfiguration {
|
||||
* bean - here in {@code @TransactionConfiguration} and also in
|
||||
* {@code <tx:annotation-driven transaction-manager="...">}.
|
||||
*/
|
||||
String transactionManager() default "transactionManager";
|
||||
String transactionManager() default "";
|
||||
|
||||
/**
|
||||
* Should transactions be rolled back by default?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -29,8 +29,6 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
@@ -44,7 +42,6 @@ import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
|
||||
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
|
||||
import org.springframework.transaction.interceptor.DelegatingTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeSource;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -126,10 +123,10 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
* @see org.springframework.transaction.annotation.Transactional
|
||||
* @see #getTransactionManager(TestContext, String)
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@Override
|
||||
public void beforeTestMethod(TestContext testContext) throws Exception {
|
||||
public void beforeTestMethod(final TestContext testContext) throws Exception {
|
||||
final Method testMethod = testContext.getTestMethod();
|
||||
final Class<?> testClass = testContext.getTestClass();
|
||||
Assert.notNull(testMethod, "The test method of the supplied TestContext must not be null");
|
||||
|
||||
if (this.transactionContextCache.remove(testMethod) != null) {
|
||||
@@ -138,17 +135,11 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
}
|
||||
|
||||
PlatformTransactionManager tm = null;
|
||||
TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod,
|
||||
testContext.getTestClass());
|
||||
TransactionAttribute transactionAttribute = this.attributeSource.getTransactionAttribute(testMethod, testClass);
|
||||
|
||||
if (transactionAttribute != null) {
|
||||
transactionAttribute = new DelegatingTransactionAttribute(transactionAttribute) {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return testMethod.getName();
|
||||
}
|
||||
};
|
||||
transactionAttribute = TestContextTransactionUtils.createDelegatingTransactionAttribute(testContext,
|
||||
transactionAttribute);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Explicit transaction definition [" + transactionAttribute + "] found for test context "
|
||||
@@ -302,7 +293,7 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
|
||||
/**
|
||||
* Get the {@link PlatformTransactionManager transaction manager} to use
|
||||
* for the supplied {@link TestContext test context} and {@code qualifier}.
|
||||
* for the supplied {@linkplain TestContext test context} and {@code qualifier}.
|
||||
* <p>Delegates to {@link #getTransactionManager(TestContext)} if the
|
||||
* supplied {@code qualifier} is {@code null} or empty.
|
||||
* @param testContext the test context for which the transaction manager
|
||||
@@ -340,6 +331,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
/**
|
||||
* Get the {@link PlatformTransactionManager transaction manager} to use
|
||||
* for the supplied {@link TestContext test context}.
|
||||
* <p>The default implementation simply delegates to
|
||||
* {@link TestContextTransactionUtils#retrieveTransactionManager}.
|
||||
* @param testContext the test context for which the transaction manager
|
||||
* should be retrieved
|
||||
* @return the transaction manager to use, or {@code null} if not found
|
||||
@@ -347,47 +340,8 @@ public class TransactionalTestExecutionListener extends AbstractTestExecutionLis
|
||||
* @see #getTransactionManager(TestContext, String)
|
||||
*/
|
||||
protected PlatformTransactionManager getTransactionManager(TestContext testContext) {
|
||||
BeanFactory bf = testContext.getApplicationContext().getAutowireCapableBeanFactory();
|
||||
String tmName = retrieveConfigurationAttributes(testContext).getTransactionManagerName();
|
||||
|
||||
try {
|
||||
// look up by type and explicit name from @TransactionConfiguration
|
||||
if (StringUtils.hasText(tmName) && !DEFAULT_TRANSACTION_MANAGER_NAME.equals(tmName)) {
|
||||
return bf.getBean(tmName, PlatformTransactionManager.class);
|
||||
}
|
||||
|
||||
if (bf instanceof ListableBeanFactory) {
|
||||
ListableBeanFactory lbf = (ListableBeanFactory) bf;
|
||||
|
||||
// look up single bean by type
|
||||
Map<String, PlatformTransactionManager> txMgrs = BeanFactoryUtils.beansOfTypeIncludingAncestors(lbf,
|
||||
PlatformTransactionManager.class);
|
||||
if (txMgrs.size() == 1) {
|
||||
return txMgrs.values().iterator().next();
|
||||
}
|
||||
|
||||
// look up single TransactionManagementConfigurer
|
||||
Map<String, TransactionManagementConfigurer> configurers = BeanFactoryUtils.beansOfTypeIncludingAncestors(
|
||||
lbf, TransactionManagementConfigurer.class);
|
||||
if (configurers.size() > 1) {
|
||||
throw new IllegalStateException(
|
||||
"Only one TransactionManagementConfigurer may exist in the ApplicationContext");
|
||||
}
|
||||
if (configurers.size() == 1) {
|
||||
return configurers.values().iterator().next().annotationDrivenTransactionManager();
|
||||
}
|
||||
}
|
||||
|
||||
// look up by type and default name from @TransactionConfiguration
|
||||
return bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
|
||||
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Caught exception while retrieving transaction manager for test context " + testContext, ex);
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
return TestContextTransactionUtils.retrieveTransactionManager(testContext, tmName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Utility methods for working with resources within the <em>Spring TestContext
|
||||
* Framework</em>. Mainly for internal use within the framework.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Tadaya Tsuyukubo
|
||||
* @since 4.1
|
||||
* @see org.springframework.util.ResourceUtils
|
||||
* @see org.springframework.core.io.Resource
|
||||
* @see org.springframework.core.io.ClassPathResource
|
||||
* @see org.springframework.core.io.FileSystemResource
|
||||
* @see org.springframework.core.io.UrlResource
|
||||
* @see org.springframework.core.io.ResourceLoader
|
||||
*/
|
||||
public abstract class TestContextResourceUtils {
|
||||
|
||||
private static final String SLASH = "/";
|
||||
|
||||
|
||||
private TestContextResourceUtils() {
|
||||
/* prevent instantiation */
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the supplied paths to classpath resource paths.
|
||||
*
|
||||
* <p>For each of the supplied paths:
|
||||
* <ul>
|
||||
* <li>A plain path — for example, {@code "context.xml"} — will
|
||||
* be treated as a classpath resource that is relative to the package in
|
||||
* which the specified class is defined.
|
||||
* <li>A path starting with a slash will be treated as an absolute path
|
||||
* within the classpath, for example: {@code "/org/example/schema.sql"}.
|
||||
* <li>A path which is prefixed with a URL protocol (e.g.,
|
||||
* {@link ResourceUtils#CLASSPATH_URL_PREFIX classpath:},
|
||||
* {@link ResourceUtils#FILE_URL_PREFIX file:}, {@code http:}, etc.) will be
|
||||
* {@link StringUtils#cleanPath cleaned} but otherwise unmodified.
|
||||
*
|
||||
* @param clazz the class with which the paths are associated
|
||||
* @param paths the paths to be converted
|
||||
* @return a new array of converted resource paths
|
||||
* @see #convertToResources
|
||||
*/
|
||||
public static String[] convertToClasspathResourcePaths(Class<?> clazz, String... paths) {
|
||||
String[] convertedPaths = new String[paths.length];
|
||||
for (int i = 0; i < paths.length; i++) {
|
||||
String path = paths[i];
|
||||
if (path.startsWith(SLASH)) {
|
||||
convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||
}
|
||||
else if (!ResourcePatternUtils.isUrl(path)) {
|
||||
convertedPaths[i] = ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
|
||||
+ StringUtils.cleanPath(ClassUtils.classPackageAsResourcePath(clazz) + SLASH + path);
|
||||
}
|
||||
else {
|
||||
convertedPaths[i] = StringUtils.cleanPath(path);
|
||||
}
|
||||
}
|
||||
return convertedPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the supplied paths to {@link Resource} handles using the given
|
||||
* {@link ResourceLoader}.
|
||||
*
|
||||
* @param resourceLoader the {@code ResourceLoader} to use to convert the paths
|
||||
* @param paths the paths to be converted
|
||||
* @return a new array of resources
|
||||
* @see #convertToClasspathResourcePaths
|
||||
*/
|
||||
public static Resource[] convertToResources(ResourceLoader resourceLoader, String... paths) {
|
||||
List<Resource> list = new ArrayList<Resource>();
|
||||
for (String path : paths) {
|
||||
list.add(resourceLoader.getResource(path));
|
||||
}
|
||||
return list.toArray(new Resource[list.size()]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public class TestExecutionListenersTests {
|
||||
@Test
|
||||
public void verifyNumDefaultListenersRegistered() throws Exception {
|
||||
TestContextManager testContextManager = new TestContextManager(DefaultListenersExampleTestCase.class);
|
||||
assertEquals("Num registered TELs for DefaultListenersExampleTestCase.", 3,
|
||||
assertEquals("Num registered TELs for DefaultListenersExampleTestCase.", 4,
|
||||
testContextManager.getTestExecutionListeners().size());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests that verify support for custom SQL script syntax
|
||||
* configured via {@link DatabaseInitializer @DatabaseInitializer}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DirtiesContext
|
||||
public class CustomScriptSyntaxDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers({//
|
||||
@DatabaseInitializer("schema.sql"),//
|
||||
@DatabaseInitializer(//
|
||||
scripts = "data-add-users-with-custom-script-syntax.sql",//
|
||||
commentPrefix = "`",//
|
||||
blockCommentStartDelimiter = "#$",//
|
||||
blockCommentEndDelimiter = "$#",//
|
||||
separator = "@@"//
|
||||
) //
|
||||
})
|
||||
public void methodLevelScripts() {
|
||||
assertNumUsers(3);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.test.context.TestContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DatabaseInitializerTestExecutionListener}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
public class DatabaseInitializerTestExecutionListenerTests {
|
||||
|
||||
private final DatabaseInitializerTestExecutionListener listener = new DatabaseInitializerTestExecutionListener();
|
||||
|
||||
private final TestContext testContext = mock(TestContext.class);
|
||||
|
||||
|
||||
@Test
|
||||
public void missingValueAndScriptsAtClassLevel() throws Exception {
|
||||
Class<?> clazz = MissingValueAndScriptsAtClassLevel.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("foo"));
|
||||
|
||||
assertExceptionContains(clazz.getSimpleName() + ".sql");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingValueAndScriptsAtMethodLevel() throws Exception {
|
||||
Class<?> clazz = MissingValueAndScriptsAtMethodLevel.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("foo"));
|
||||
|
||||
assertExceptionContains(clazz.getSimpleName() + ".foo" + ".sql");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void valueAndScriptsDeclared() throws Exception {
|
||||
Class<?> clazz = ValueAndScriptsDeclared.class;
|
||||
Mockito.<Class<?>> when(testContext.getTestClass()).thenReturn(clazz);
|
||||
when(testContext.getTestMethod()).thenReturn(clazz.getDeclaredMethod("valueAndScriptsDeclared"));
|
||||
|
||||
assertExceptionContains("Only one declaration of SQL script paths is permitted");
|
||||
}
|
||||
|
||||
private void assertExceptionContains(String msg) throws Exception {
|
||||
try {
|
||||
listener.beforeTestMethod(testContext);
|
||||
fail("Should have thrown an IllegalStateException.");
|
||||
}
|
||||
catch (IllegalStateException e) {
|
||||
assertTrue("Exception message should contain: " + msg, e.getMessage().contains(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@DatabaseInitializer
|
||||
static class MissingValueAndScriptsAtClassLevel {
|
||||
|
||||
public void foo() {
|
||||
}
|
||||
}
|
||||
|
||||
static class MissingValueAndScriptsAtMethodLevel {
|
||||
|
||||
@DatabaseInitializer
|
||||
public void foo() {
|
||||
}
|
||||
}
|
||||
|
||||
static class ValueAndScriptsDeclared {
|
||||
|
||||
@DatabaseInitializer(value = "foo", scripts = "bar")
|
||||
public void valueAndScriptsDeclared() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests that verify support for default SQL script detection.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DatabaseInitializer
|
||||
@DirtiesContext
|
||||
public class DefaultScriptDetectionDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Test
|
||||
public void classLevel() {
|
||||
assertNumUsers(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializer
|
||||
public void methodLevel() {
|
||||
assertNumUsers(3);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
DROP TABLE user IF EXISTS;
|
||||
|
||||
CREATE TABLE user (
|
||||
name VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY(name)
|
||||
);
|
||||
|
||||
INSERT INTO user VALUES('Dilbert');
|
||||
INSERT INTO user VALUES('Dogbert');
|
||||
INSERT INTO user VALUES('Catbert');
|
||||
@@ -0,0 +1,9 @@
|
||||
DROP TABLE user IF EXISTS;
|
||||
|
||||
CREATE TABLE user (
|
||||
name VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY(name)
|
||||
);
|
||||
|
||||
INSERT INTO user VALUES('Dilbert');
|
||||
INSERT INTO user VALUES('Dogbert');
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Empty database configuration class for SQL script integration tests.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@Configuration
|
||||
public class EmptyDatabaseConfig {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return new DataSourceTransactionManager(dataSource());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return new EmbeddedDatabaseBuilder().build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests that verify support for using
|
||||
* {@link DatabaseInitializer @DatabaseInitializer} and
|
||||
* {@link DatabaseInitializers @DatabaseInitializers} as a meta-annotations.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DirtiesContext
|
||||
public class MetaAnnotationDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Test
|
||||
@MetaDbInitializer
|
||||
public void metaDatabaseInitializer() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@MetaDbInitializers
|
||||
public void metaDatabaseInitializers() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
|
||||
@DatabaseInitializer({ "drop-schema.sql", "schema.sql", "data.sql" })
|
||||
@Retention(RUNTIME)
|
||||
@Target(METHOD)
|
||||
static @interface MetaDbInitializer {
|
||||
}
|
||||
|
||||
@DatabaseInitializers({//
|
||||
@DatabaseInitializer("drop-schema.sql"),//
|
||||
@DatabaseInitializer("schema.sql"),//
|
||||
@DatabaseInitializer("data.sql") //
|
||||
})
|
||||
@Retention(RUNTIME)
|
||||
@Target(METHOD)
|
||||
static @interface MetaDbInitializers {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link DatabaseInitializer @DatabaseInitializer} that
|
||||
* verify support for multiple {@link DataSource}s and {@link PlatformTransactionManager}s.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
* @see MultipleDataSourcesAndTransactionManagersTransactionalDatabaseInitializerTests
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class MultipleDataSourcesAndTransactionManagersDatabaseInitializerTests {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource1;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource2;
|
||||
|
||||
|
||||
@Test
|
||||
@DatabaseInitializer(scripts = "data-add-dogbert.sql", dataSource = "dataSource1", transactionManager = "txMgr1")
|
||||
public void database1() {
|
||||
assertUsersExist(new JdbcTemplate(dataSource1), "Dilbert", "Dogbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializer(scripts = "data-add-catbert.sql", dataSource = "dataSource2", transactionManager = "txMgr2")
|
||||
public void database2() {
|
||||
assertUsersExist(new JdbcTemplate(dataSource2), "Dilbert", "Catbert");
|
||||
}
|
||||
|
||||
private void assertUsersExist(JdbcTemplate jdbcTemplate, String... users) {
|
||||
String query = "select count(name) from user where name =?";
|
||||
for (String user : users) {
|
||||
assertTrue("User [" + user + "] must exist.",
|
||||
jdbcTemplate.queryForObject(query, Integer.class, user).intValue() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txMgr1() {
|
||||
return new DataSourceTransactionManager(dataSource1());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txMgr2() {
|
||||
return new DataSourceTransactionManager(dataSource2());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource1() {
|
||||
return new EmbeddedDatabaseBuilder()//
|
||||
.setName("database1")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/data.sql")//
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource2() {
|
||||
return new EmbeddedDatabaseBuilder()//
|
||||
.setName("database2")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/data.sql")//
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Exact copy of {@link MultipleDataSourcesAndTransactionManagersDatabaseInitializerTests},
|
||||
* except that the test methods are transactional.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
@DirtiesContext
|
||||
public class MultipleDataSourcesAndTransactionManagersTransactionalDatabaseInitializerTests {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource1;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource2;
|
||||
|
||||
|
||||
@Test
|
||||
@Transactional("txMgr1")
|
||||
@DatabaseInitializer(scripts = "data-add-dogbert.sql", dataSource = "dataSource1", transactionManager = "txMgr1")
|
||||
public void database1() {
|
||||
assertUsersExist(new JdbcTemplate(dataSource1), "Dilbert", "Dogbert");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Transactional("txMgr2")
|
||||
@DatabaseInitializer(scripts = "data-add-catbert.sql", dataSource = "dataSource2", transactionManager = "txMgr2")
|
||||
public void database2() {
|
||||
assertUsersExist(new JdbcTemplate(dataSource2), "Dilbert", "Catbert");
|
||||
}
|
||||
|
||||
private void assertUsersExist(JdbcTemplate jdbcTemplate, String... users) {
|
||||
String query = "select count(name) from user where name =?";
|
||||
for (String user : users) {
|
||||
assertTrue("User [" + user + "] must exist.",
|
||||
jdbcTemplate.queryForObject(query, Integer.class, user).intValue() == 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txMgr1() {
|
||||
return new DataSourceTransactionManager(dataSource1());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager txMgr2() {
|
||||
return new DataSourceTransactionManager(dataSource2());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource1() {
|
||||
return new EmbeddedDatabaseBuilder()//
|
||||
.setName("database1")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/data.sql")//
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource2() {
|
||||
return new EmbeddedDatabaseBuilder()//
|
||||
.setName("database2")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql")//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/data.sql")//
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.jdbc.JdbcTestUtils;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Integration tests which verify that scripts executed via
|
||||
* {@link DatabaseInitializer @DatabaseInitializer} will persist between
|
||||
* non-transactional test methods.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DatabaseInitializer({ "schema.sql", "data.sql" })
|
||||
@DirtiesContext
|
||||
public class NonTransactionalDatabaseInitializerTests {
|
||||
|
||||
protected JdbcTemplate jdbcTemplate;
|
||||
|
||||
|
||||
@Autowired
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
@Test
|
||||
// test##_ prefix is required for @FixMethodOrder.
|
||||
public void test01_classLevelScripts() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers(@DatabaseInitializer("data-add-dogbert.sql"))
|
||||
// test##_ prefix is required for @FixMethodOrder.
|
||||
public void test02_methodLevelScripts() {
|
||||
assertNumUsers(2);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected,
|
||||
JdbcTestUtils.countRowsInTable(jdbcTemplate, "user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Database configuration class for SQL script integration tests with the 'user'
|
||||
* table already created.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@Configuration
|
||||
public class PopulatedSchemaDatabaseConfig {
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
return new DataSourceTransactionManager(dataSource());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
return new EmbeddedDatabaseBuilder()//
|
||||
.addScript("classpath:/org/springframework/test/context/jdbc/schema.sql") //
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.transaction.AfterTransaction;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Transactional integration tests that verify rollback semantics for
|
||||
* {@link DatabaseInitializer @DatabaseInitializer} support.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = PopulatedSchemaDatabaseConfig.class)
|
||||
@DirtiesContext
|
||||
public class PopulatedSchemaTransactionalDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@BeforeTransaction
|
||||
@AfterTransaction
|
||||
public void verifyPreAndPostTransactionDatabaseState() {
|
||||
assertNumUsers(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers(@DatabaseInitializer("data-add-dogbert.sql"))
|
||||
public void methodLevelScripts() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.transaction.AfterTransaction;
|
||||
import org.springframework.test.context.transaction.BeforeTransaction;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Transactional integration tests that verify commit semantics for
|
||||
* {@link DatabaseInitializer#requireNewTransaction}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@ContextConfiguration(classes = PopulatedSchemaDatabaseConfig.class)
|
||||
@DirtiesContext
|
||||
public class RequiresNewTransactionDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@BeforeTransaction
|
||||
public void beforeTransaction() {
|
||||
assertNumUsers(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers(@DatabaseInitializer(scripts = "data-add-dogbert.sql", requireNewTransaction = true))
|
||||
public void methodLevelScripts() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
@AfterTransaction
|
||||
public void afterTransaction() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.jdbc.DatabaseInitializer.ExecutionPhase;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.transaction.AfterTransaction;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Transactional integration tests for {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* that verify proper support for {@link ExecutionPhase#AFTER_TEST_METHOD}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DirtiesContext
|
||||
public class TransactionalAfterTestMethodDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Rule
|
||||
public TestName testName = new TestName();
|
||||
|
||||
|
||||
@AfterTransaction
|
||||
public void afterTransaction() {
|
||||
if ("test01".equals(testName.getMethodName())) {
|
||||
try {
|
||||
assertNumUsers(99);
|
||||
fail("Should throw a BadSqlGrammarException after test01, assuming 'drop-schema.sql' was executed");
|
||||
}
|
||||
catch (BadSqlGrammarException e) {
|
||||
/* expected */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers({//
|
||||
@DatabaseInitializer({ "schema.sql", "data.sql" }),//
|
||||
@DatabaseInitializer(scripts = "drop-schema.sql", executionPhase = ExecutionPhase.AFTER_TEST_METHOD) //
|
||||
})
|
||||
// test## is required for @FixMethodOrder.
|
||||
public void test01() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers(@DatabaseInitializer({ "schema.sql", "data.sql", "data-add-dogbert.sql" }))
|
||||
// test## is required for @FixMethodOrder.
|
||||
public void test02() {
|
||||
assertNumUsers(2);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2002-2014 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.context.jdbc;
|
||||
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Transactional integration tests for {@link DatabaseInitializer @DatabaseInitializer}
|
||||
* support.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.1
|
||||
*/
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
@ContextConfiguration(classes = EmptyDatabaseConfig.class)
|
||||
@DatabaseInitializers(@DatabaseInitializer({ "schema.sql", "data.sql" }))
|
||||
@DirtiesContext
|
||||
public class TransactionalDatabaseInitializerTests extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
|
||||
@Test
|
||||
// test##_ prefix is required for @FixMethodOrder.
|
||||
public void test01_classLevelScripts() {
|
||||
assertNumUsers(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DatabaseInitializers(@DatabaseInitializer({ "drop-schema.sql", "schema.sql", "data.sql", "data-add-dogbert.sql" }))
|
||||
// test##_ prefix is required for @FixMethodOrder.
|
||||
public void test02_methodLevelScripts() {
|
||||
assertNumUsers(2);
|
||||
}
|
||||
|
||||
protected void assertNumUsers(int expected) {
|
||||
assertEquals("Number of rows in the 'user' table.", expected, countRowsInTable("user"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO user VALUES('Catbert');
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO user VALUES('Dogbert');
|
||||
@@ -0,0 +1,22 @@
|
||||
` custom single-line comment
|
||||
|
||||
#$ custom
|
||||
block
|
||||
comment
|
||||
$#
|
||||
|
||||
INSERT
|
||||
|
||||
INTO
|
||||
|
||||
user
|
||||
|
||||
VALUES('Dilbert')
|
||||
|
||||
@@
|
||||
|
||||
` custom single-line comment
|
||||
|
||||
|
||||
INSERT INTO user VALUES('Dogbert')@@
|
||||
INSERT INTO user VALUES('Catbert')@@
|
||||
@@ -0,0 +1 @@
|
||||
INSERT INTO user VALUES('Dilbert');
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE user IF EXISTS;
|
||||
@@ -0,0 +1,4 @@
|
||||
CREATE TABLE user (
|
||||
name VARCHAR(20) NOT NULL,
|
||||
PRIMARY KEY(name)
|
||||
);
|
||||
@@ -44,7 +44,7 @@ public class ContextLoaderUtilsMergedConfigTests extends AbstractContextLoaderUt
|
||||
assertMergedConfig(
|
||||
mergedConfig,
|
||||
testClass,
|
||||
new String[] { "classpath:/org/springframework/test/context/support/AbstractContextLoaderUtilsTests$BareAnnotations-context.xml" },
|
||||
new String[] { "classpath:org/springframework/test/context/support/AbstractContextLoaderUtilsTests$BareAnnotations-context.xml" },
|
||||
EMPTY_CLASS_ARRAY, DelegatingSmartContextLoader.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 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.
|
||||
@@ -96,7 +96,7 @@ public class GenericXmlContextLoaderResourceLocationsTests {
|
||||
|
||||
{
|
||||
ClasspathExistentDefaultLocationsTestCase.class,
|
||||
new String[] { "classpath:/org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests$1ClasspathExistentDefaultLocationsTestCase-context.xml" } },
|
||||
new String[] { "classpath:org/springframework/test/context/support/GenericXmlContextLoaderResourceLocationsTests$1ClasspathExistentDefaultLocationsTestCase-context.xml" } },
|
||||
|
||||
{
|
||||
ImplicitClasspathLocationsTestCase.class,
|
||||
|
||||
@@ -192,13 +192,13 @@ public class TransactionalTestExecutionListenerTests {
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesWithMissingTransactionConfiguration() throws Exception {
|
||||
assertTransactionConfigurationAttributes(MissingTransactionConfigurationTestCase.class, "transactionManager",
|
||||
assertTransactionConfigurationAttributes(MissingTransactionConfigurationTestCase.class, "",
|
||||
true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveConfigurationAttributesWithEmptyTransactionConfiguration() throws Exception {
|
||||
assertTransactionConfigurationAttributes(EmptyTransactionConfigurationTestCase.class, "transactionManager",
|
||||
assertTransactionConfigurationAttributes(EmptyTransactionConfigurationTestCase.class, "",
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user