1
1
/*
2
- * Copyright 2002-2018 the original author or authors.
2
+ * Copyright 2002-2019 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
16
16
17
17
package org .springframework .test .context .jdbc ;
18
18
19
+ import java .lang .reflect .AnnotatedElement ;
19
20
import java .lang .reflect .Method ;
20
21
import java .util .List ;
21
22
import java .util .Set ;
30
31
import org .springframework .core .io .ClassPathResource ;
31
32
import org .springframework .core .io .Resource ;
32
33
import org .springframework .jdbc .datasource .init .ResourceDatabasePopulator ;
34
+ import org .springframework .lang .NonNull ;
33
35
import org .springframework .lang .Nullable ;
34
36
import org .springframework .test .context .TestContext ;
35
37
import org .springframework .test .context .jdbc .Sql .ExecutionPhase ;
36
38
import org .springframework .test .context .jdbc .SqlConfig .ErrorMode ;
37
39
import org .springframework .test .context .jdbc .SqlConfig .TransactionMode ;
40
+ import org .springframework .test .context .jdbc .SqlMergeMode .MergeMode ;
38
41
import org .springframework .test .context .support .AbstractTestExecutionListener ;
39
42
import org .springframework .test .context .transaction .TestContextTransactionUtils ;
40
43
import org .springframework .test .context .util .TestContextResourceUtils ;
81
84
* locate these beans.
82
85
*
83
86
* @author Sam Brannen
87
+ * @author Dmitry Semukhin
84
88
* @since 4.1
85
89
* @see Sql
86
90
* @see SqlConfig
@@ -108,7 +112,7 @@ public final int getOrder() {
108
112
* {@link TestContext} <em>before</em> the current test method.
109
113
*/
110
114
@ Override
111
- public void beforeTestMethod (TestContext testContext ) throws Exception {
115
+ public void beforeTestMethod (TestContext testContext ) {
112
116
executeSqlScripts (testContext , ExecutionPhase .BEFORE_TEST_METHOD );
113
117
}
114
118
@@ -117,30 +121,66 @@ public void beforeTestMethod(TestContext testContext) throws Exception {
117
121
* {@link TestContext} <em>after</em> the current test method.
118
122
*/
119
123
@ Override
120
- public void afterTestMethod (TestContext testContext ) throws Exception {
124
+ public void afterTestMethod (TestContext testContext ) {
121
125
executeSqlScripts (testContext , ExecutionPhase .AFTER_TEST_METHOD );
122
126
}
123
127
124
128
/**
125
129
* Execute SQL scripts configured via {@link Sql @Sql} for the supplied
126
130
* {@link TestContext} and {@link ExecutionPhase}.
127
131
*/
128
- private void executeSqlScripts (TestContext testContext , ExecutionPhase executionPhase ) throws Exception {
129
- boolean classLevel = false ;
130
-
131
- Set <Sql > sqlAnnotations = AnnotatedElementUtils .getMergedRepeatableAnnotations (
132
- testContext .getTestMethod (), Sql .class , SqlGroup .class );
133
- if (sqlAnnotations .isEmpty ()) {
134
- sqlAnnotations = AnnotatedElementUtils .getMergedRepeatableAnnotations (
135
- testContext .getTestClass (), Sql .class , SqlGroup .class );
136
- if (!sqlAnnotations .isEmpty ()) {
137
- classLevel = true ;
132
+ private void executeSqlScripts (TestContext testContext , ExecutionPhase executionPhase ) {
133
+ Method testMethod = testContext .getTestMethod ();
134
+ Class <?> testClass = testContext .getTestClass ();
135
+
136
+ if (mergeSqlAnnotations (testContext )) {
137
+ executeSqlScripts (getSqlAnnotationsFor (testClass ), testContext , executionPhase , true );
138
+ executeSqlScripts (getSqlAnnotationsFor (testMethod ), testContext , executionPhase , false );
139
+ }
140
+ else {
141
+ Set <Sql > methodLevelSqlAnnotations = getSqlAnnotationsFor (testMethod );
142
+ if (!methodLevelSqlAnnotations .isEmpty ()) {
143
+ executeSqlScripts (methodLevelSqlAnnotations , testContext , executionPhase , false );
144
+ }
145
+ else {
146
+ executeSqlScripts (getSqlAnnotationsFor (testClass ), testContext , executionPhase , true );
138
147
}
139
148
}
149
+ }
140
150
141
- for (Sql sql : sqlAnnotations ) {
142
- executeSqlScripts (sql , executionPhase , testContext , classLevel );
151
+ /**
152
+ * Determine if method-level {@code @Sql} annotations should be merged with
153
+ * class-level {@code @Sql} annotations.
154
+ */
155
+ private boolean mergeSqlAnnotations (TestContext testContext ) {
156
+ SqlMergeMode sqlMergeMode = getSqlMergeModeFor (testContext .getTestMethod ());
157
+ if (sqlMergeMode == null ) {
158
+ sqlMergeMode = getSqlMergeModeFor (testContext .getTestClass ());
143
159
}
160
+ return (sqlMergeMode != null && sqlMergeMode .value () == MergeMode .MERGE );
161
+ }
162
+
163
+ /**
164
+ * Get the {@code @SqlMergeMode} annotation declared on the supplied {@code element}.
165
+ */
166
+ private SqlMergeMode getSqlMergeModeFor (AnnotatedElement element ) {
167
+ return AnnotatedElementUtils .findMergedAnnotation (element , SqlMergeMode .class );
168
+ }
169
+
170
+ /**
171
+ * Get the {@code @Sql} annotations declared on the supplied {@code element}.
172
+ */
173
+ private Set <Sql > getSqlAnnotationsFor (AnnotatedElement element ) {
174
+ return AnnotatedElementUtils .getMergedRepeatableAnnotations (element , Sql .class , SqlGroup .class );
175
+ }
176
+
177
+ /**
178
+ * Execute SQL scripts for the supplied {@link Sql @Sql} annotations.
179
+ */
180
+ private void executeSqlScripts (
181
+ Set <Sql > sqlAnnotations , TestContext testContext , ExecutionPhase executionPhase , boolean classLevel ) {
182
+
183
+ sqlAnnotations .forEach (sql -> executeSqlScripts (sql , executionPhase , testContext , classLevel ));
144
184
}
145
185
146
186
/**
@@ -153,8 +193,8 @@ private void executeSqlScripts(TestContext testContext, ExecutionPhase execution
153
193
* @param testContext the current {@code TestContext}
154
194
* @param classLevel {@code true} if {@link Sql @Sql} was declared at the class level
155
195
*/
156
- private void executeSqlScripts (Sql sql , ExecutionPhase executionPhase , TestContext testContext , boolean classLevel )
157
- throws Exception {
196
+ private void executeSqlScripts (
197
+ Sql sql , ExecutionPhase executionPhase , TestContext testContext , boolean classLevel ) {
158
198
159
199
if (executionPhase != sql .executionPhase ()) {
160
200
return ;
@@ -166,15 +206,6 @@ private void executeSqlScripts(Sql sql, ExecutionPhase executionPhase, TestConte
166
206
mergedSqlConfig , executionPhase , testContext ));
167
207
}
168
208
169
- final ResourceDatabasePopulator populator = new ResourceDatabasePopulator ();
170
- populator .setSqlScriptEncoding (mergedSqlConfig .getEncoding ());
171
- populator .setSeparator (mergedSqlConfig .getSeparator ());
172
- populator .setCommentPrefix (mergedSqlConfig .getCommentPrefix ());
173
- populator .setBlockCommentStartDelimiter (mergedSqlConfig .getBlockCommentStartDelimiter ());
174
- populator .setBlockCommentEndDelimiter (mergedSqlConfig .getBlockCommentEndDelimiter ());
175
- populator .setContinueOnError (mergedSqlConfig .getErrorMode () == ErrorMode .CONTINUE_ON_ERROR );
176
- populator .setIgnoreFailedDrops (mergedSqlConfig .getErrorMode () == ErrorMode .IGNORE_FAILED_DROPS );
177
-
178
209
String [] scripts = getScripts (sql , testContext , classLevel );
179
210
scripts = TestContextResourceUtils .convertToClasspathResourcePaths (testContext .getTestClass (), scripts );
180
211
List <Resource > scriptResources = TestContextResourceUtils .convertToResourceList (
@@ -185,6 +216,8 @@ private void executeSqlScripts(Sql sql, ExecutionPhase executionPhase, TestConte
185
216
scriptResources .add (new ByteArrayResource (stmt .getBytes (), "from inlined SQL statement: " + stmt ));
186
217
}
187
218
}
219
+
220
+ ResourceDatabasePopulator populator = createDatabasePopulator (mergedSqlConfig );
188
221
populator .setScripts (scriptResources .toArray (new Resource [0 ]));
189
222
if (logger .isDebugEnabled ()) {
190
223
logger .debug ("Executing SQL scripts: " + ObjectUtils .nullSafeToString (scriptResources ));
@@ -225,13 +258,23 @@ private void executeSqlScripts(Sql sql, ExecutionPhase executionPhase, TestConte
225
258
TransactionDefinition .PROPAGATION_REQUIRED );
226
259
TransactionAttribute txAttr = TestContextTransactionUtils .createDelegatingTransactionAttribute (
227
260
testContext , new DefaultTransactionAttribute (propagation ));
228
- new TransactionTemplate (txMgr , txAttr ).execute (status -> {
229
- populator .execute (finalDataSource );
230
- return null ;
231
- });
261
+ new TransactionTemplate (txMgr , txAttr ).execute (() -> populator .execute (finalDataSource ));
232
262
}
233
263
}
234
264
265
+ @ NonNull
266
+ private ResourceDatabasePopulator createDatabasePopulator (MergedSqlConfig mergedSqlConfig ) {
267
+ ResourceDatabasePopulator populator = new ResourceDatabasePopulator ();
268
+ populator .setSqlScriptEncoding (mergedSqlConfig .getEncoding ());
269
+ populator .setSeparator (mergedSqlConfig .getSeparator ());
270
+ populator .setCommentPrefix (mergedSqlConfig .getCommentPrefix ());
271
+ populator .setBlockCommentStartDelimiter (mergedSqlConfig .getBlockCommentStartDelimiter ());
272
+ populator .setBlockCommentEndDelimiter (mergedSqlConfig .getBlockCommentEndDelimiter ());
273
+ populator .setContinueOnError (mergedSqlConfig .getErrorMode () == ErrorMode .CONTINUE_ON_ERROR );
274
+ populator .setIgnoreFailedDrops (mergedSqlConfig .getErrorMode () == ErrorMode .IGNORE_FAILED_DROPS );
275
+ return populator ;
276
+ }
277
+
235
278
@ Nullable
236
279
private DataSource getDataSourceFromTransactionManager (PlatformTransactionManager transactionManager ) {
237
280
try {
0 commit comments