Я получаю следующее исключение, когда запускаю тест JUnit, в котором я тестирую контроллер Spring-MVC, который вызывает Spring-Batch работа. Задание включает в себя две задачи: сначала прочитайте из файла &, напишите в БД, затем обновите БД. Оба типа таблеток используют один и тот же БД. Насколько я вижу, исключение говорит мне, что источник данных закрыт, но в БД я вижу, что первая задача была выполнена, а вторая - нет.«SQLException: источник данных закрыт» при модульном тестировании контроллера, который вызывает Spring-пакетное задание
Не могли бы вы прийти к какому-либо предложению о том, почему источник данных закрыт (???) во время второй контрольной точки (обновление для БД)?
Задание выполняет оба таска, когда я вызываю контроллер из браузера.
ERROR [taskExecutor-1] (AbstractJob.java:306) - Encountered fatal error executing job
org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:141)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: org.springframework.batch.core.job.flow.FlowExecutionException: Ended flow=writeProductsJob at state=writeProductsJob.readWrite with exception
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:152)
at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124)
at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135)
... 5 more
Caused by: org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Data source is closed
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:240)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy27.getStepExecutionCount(Unknown Source)
at org.springframework.batch.core.job.SimpleStepHandler.shouldStart(SimpleStepHandler.java:210)
at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:117)
at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61)
at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60)
at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144)
... 7 more
Caused by: java.sql.SQLException: Data source is closed
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1362)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:202)
... 18 more
Exception in thread "taskExecutor-1" org.springframework.transaction.CannotCreateTransactionException: Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: Data source is closed
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:240)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy27.update(Unknown Source)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:329)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.sql.SQLException: Data source is closed
at org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1362)
at org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)
at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:202)
... 11 more
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 3.628 sec
ОБНОВЛЕНИЕ:
испытаний Класс:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext-test.xml"})
public class UploadFileValidatorTest {
@Autowired
private ApplicationContext applicationContext;
private MockMultipartHttpServletRequest request;
private MockHttpServletResponse response;
@Autowired
private MyController controller;
private MessageSource messageSource;
@Before
public void setUp() {
request = new MockMultipartHttpServletRequest();
response = new MockHttpServletResponse();
}
@Test
@DirtiesContext
public void testDoSomething() throws Exception {
DiskFileItem fileItem = null;
final File TEST_FILE = applicationContext.getResource("classpath:csv_example.txt").getFile();
try
{
fileItem = (DiskFileItem) new DiskFileItemFactory().createItem("fileData", "text/plain", true, TEST_FILE.getName());
InputStream input = new FileInputStream(TEST_FILE);
OutputStream os = fileItem.getOutputStream();
int ret = input.read();
while (ret != -1)
{
os.write(ret);
ret = input.read();
}
os.flush();
System.out.println("diskFileItem.getString() = " + fileItem.getString());
}
catch (Exception e)
{
e.printStackTrace();
}
/////////////////////////////////////////////////////////////////////
request.addFile(multipartFile);
request.addParameter("email", "[email protected]");
request.setRequestURI("/book/upload.html");
final ModelAndView mav = new AnnotationMethodHandlerAdapter().handle(request, response, controller);
BindingResult bindException = (BindingResult) mav.getModel().get(BindingResult.MODEL_KEY_PREFIX + "uploadFile");
for (Object object : bindException.getAllErrors()) {
if(object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
assertEquals(fieldError.getField(), "fileData");
System.out.println(messageSource.getMessage((FieldError) object, null));
}
}
}
}
Пакетный конфигурации:
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
<property name="taskExecutor" ref="taskExecutor"/>
</bean>
<bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="5" />
</bean>
ОБНОВЛЕНИЕ 2:
Я пытался добавить следующий код в конце метода testDoSomething()
теста:
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
int activeCount = threadGroup.activeCount();
Thread[] list = new Thread[activeCount];
threadGroup.enumerate(list);
for (Thread thread : list) {
if (thread.getName().startsWith("taskExecutor")) {
System.out.println("WAITING FOR THREAD: " + thread.getName());
try {
thread.join();
}
catch (InterruptedException ignore) {}
}
}
Теперь вся работа выполнена, но testDoSomething()
никогда не заканчивается, похоже, она ждет навсегда для taskExecutor
нити, чтобы умереть , Любая идея, почему taskExecutor
никогда не умирает?
Я могу только предположить, что это тасклет работает в отдельном потоке, а 'main' поток уже останавливая контекст приложения, вызов' BasicDataSource.close() '. Можете ли вы поставить точку останова на этот метод и посмотреть, кто отвечает за его вызов? Я уверен, что это 'ApplicationContext.close()' ... Кроме того, как выглядит ваш интеграционный тест? Как начать контекст Spring? –
Пожалуйста, см. ** ОБНОВЛЕНИЕ ** в нижней части моего оригинального сообщения. – rapt
@Tomasz Nurkiewicz - как вы видите, задание определено для запуска в другом потоке, кроме потока контроллера (и теста junit). Поэтому, я думаю, когда заканчивается поток контроллера, junit закрывает все открытые ресурсы (например, открытые источники данных). Как сообщить junit ждать с этим закрытием ресурсов до тех пор, пока не закончится задание? – rapt