diff --git a/README.adoc b/README.adoc index 6729a9ef..2c083101 100644 --- a/README.adoc +++ b/README.adoc @@ -23,7 +23,6 @@ $ ./mvnw clean install [source,java,indent=2] ---- @SpringBootApplication -@EnableTask public class MyApp { @Bean diff --git a/pom.xml b/pom.xml index 7e424ff4..4a8a3db8 100755 --- a/pom.xml +++ b/pom.xml @@ -5,13 +5,13 @@ org.springframework.cloud spring-cloud-build - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom Spring Cloud Task Build Spring Cloud Task Build @@ -57,7 +57,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -132,15 +132,16 @@ - 2.0.0.RELEASE - 1.3.2.RELEASE - 1.3.5.RELEASE - 2.0.0.RELEASE - 1.3.2.RELEASE - 1.3.2.RELEASE - 4.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT + 1.3.3.RELEASE + 1.3.6.RELEASE + 2.1.0.BUILD-SNAPSHOT + 1.3.3.RELEASE + 1.3.3.RELEASE + 4.1.0.RELEASE 1.1 8.0 + 5.3.1 UTF-8 ${project.build.directory}/coverage-reports/jacoco-ut.exec diff --git a/spring-cloud-starter-task/pom.xml b/spring-cloud-starter-task/pom.xml index 2d0008ca..9a99b465 100644 --- a/spring-cloud-starter-task/pom.xml +++ b/spring-cloud-starter-task/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-starter-task diff --git a/spring-cloud-task-batch/pom.xml b/spring-cloud-task-batch/pom.xml index 2a8d7e86..ab60d4c8 100644 --- a/spring-cloud-task-batch/pom.xml +++ b/spring-cloud-task-batch/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-batch @@ -50,6 +50,10 @@ spring-test test + + org.springframework.boot + spring-boot-test + junit junit @@ -69,6 +73,7 @@ org.springframework.boot spring-boot-configuration-processor true + ${spring-boot.version} org.assertj @@ -76,8 +81,11 @@ test - org.springframework.boot - spring-boot-test + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java index fe7d7755..b3c8de7e 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskBatchProperties.java @@ -37,12 +37,27 @@ public class TaskBatchProperties { private String jobNames = ""; /** - * The order for the {@coce CommandLineRunner} used to run batch jobs when + * The order for the {@code CommandLineRunner} used to run batch jobs when * {@code spring.cloud.task.batch.fail-on-job-failure=true}. Defaults to 0 (same as the * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner}). */ private int commandLineRunnerOrder = 0; + /** + * Maximum wait time in milliseconds that Spring Cloud Task will wait for tasks to complete + * when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults + * to 0. 0 indicates no wait time is enforced. + */ + private long failOnJobFailurewaitTime = 0; + + /** + * Fixed delay in milliseconds that Spring Cloud Task will wait when checking if + * {@link org.springframework.batch.core.JobExecution}s have completed, + * when spring.cloud.task.batch.failOnJobFailure is set to true. Defaults + * to 5000. + */ + private long failOnJobFailurePollInterval = 5000l; + public String getJobNames() { return this.jobNames; } @@ -58,4 +73,20 @@ public class TaskBatchProperties { public void setCommandLineRunnerOrder(int commandLineRunnerOrder) { this.commandLineRunnerOrder = commandLineRunnerOrder; } + + public long getFailOnJobFailurewaitTime() { + return failOnJobFailurewaitTime; + } + + public void setFailOnJobFailurewaitTime(long failOnJobFailurewaitTime) { + this.failOnJobFailurewaitTime = failOnJobFailurewaitTime; + } + + public long getFailOnJobFailurePollInterval() { + return failOnJobFailurePollInterval; + } + + public void setFailOnJobFailurePollInterval(long failOnJobFailurePollInterval) { + this.failOnJobFailurePollInterval = failOnJobFailurePollInterval; + } } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java index 71f331ee..e94c9260 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfiguration.java @@ -18,11 +18,19 @@ package org.springframework.cloud.task.batch.configuration; import java.util.List; +import javax.sql.DataSource; + import org.springframework.batch.core.Job; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean; +import org.springframework.batch.core.repository.support.SimpleJobRepository; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -37,22 +45,31 @@ import org.springframework.context.annotation.Configuration; @Configuration @ConditionalOnProperty(name = "spring.cloud.task.batch.fail-on-job-failure", havingValue = "true", matchIfMissing = false) @EnableConfigurationProperties(TaskBatchProperties.class) +@AutoConfigureBefore(BatchAutoConfiguration.class) public class TaskJobLauncherAutoConfiguration { @Autowired private TaskBatchProperties properties; + + @Bean + @ConditionalOnMissingBean(JobRepository.class) + public JobRepository jobRepository(DataSource dataSource) throws Exception{ + JobRepositoryFactoryBean factoryBean = new JobRepositoryFactoryBean(); + factoryBean.setDataSource(dataSource); + return factoryBean.getObject(); + } + @Bean public TaskJobLauncherCommandLineRunnerFactoryBean jobLauncherCommandLineRunner(JobLauncher jobLauncher, - JobExplorer jobExplorer, List jobs, JobRegistry jobRegistry) { + JobExplorer jobExplorer, List jobs, JobRegistry jobRegistry, JobRepository jobRepository) { TaskJobLauncherCommandLineRunnerFactoryBean taskJobLauncherCommandLineRunnerFactoryBean = new TaskJobLauncherCommandLineRunnerFactoryBean(jobLauncher, jobExplorer, jobs, - this.properties.getJobNames(), - jobRegistry); - - taskJobLauncherCommandLineRunnerFactoryBean.setOrder(this.properties.getCommandLineRunnerOrder()); + this.properties, + jobRegistry, + jobRepository); return taskJobLauncherCommandLineRunnerFactoryBean; } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java index f5df4c50..1a658d52 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherCommandLineRunnerFactoryBean.java @@ -22,6 +22,7 @@ import org.springframework.batch.core.Job; import org.springframework.batch.core.configuration.JobRegistry; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.beans.factory.FactoryBean; import org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner; import org.springframework.util.Assert; @@ -46,15 +47,23 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< private Integer order = 0; + private TaskBatchProperties taskBatchProperties; + + private JobRepository jobRepository; + public TaskJobLauncherCommandLineRunnerFactoryBean(JobLauncher jobLauncher, - JobExplorer jobExplorer, List jobs, String jobNames, - JobRegistry jobRegistry) { + JobExplorer jobExplorer, List jobs, TaskBatchProperties taskBatchProperties, + JobRegistry jobRegistry, JobRepository jobRepository) { + Assert.notNull(taskBatchProperties, "properties must not be null"); this.jobLauncher = jobLauncher; this.jobExplorer = jobExplorer; Assert.notEmpty(jobs, "jobs must not be null nor empty"); this.jobs = jobs; - this.jobNames = jobNames; + this.jobNames = taskBatchProperties.getJobNames(); this.jobRegistry = jobRegistry; + this.taskBatchProperties = taskBatchProperties; + this.order = taskBatchProperties.getCommandLineRunnerOrder(); + this.jobRepository = jobRepository; } public void setOrder(int order) { @@ -62,9 +71,9 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< } @Override - public TaskJobLauncherCommandLineRunner getObject() throws Exception { + public TaskJobLauncherCommandLineRunner getObject() { TaskJobLauncherCommandLineRunner taskJobLauncherCommandLineRunner = - new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer); + new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, this.jobRepository, this.taskBatchProperties); taskJobLauncherCommandLineRunner.setJobs(this.jobs); if(StringUtils.hasText(this.jobNames)) { taskJobLauncherCommandLineRunner.setJobNames(this.jobNames); @@ -74,7 +83,6 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< if(this.order != null) { taskJobLauncherCommandLineRunner.setOrder(this.order); } - return taskJobLauncherCommandLineRunner; } @@ -82,4 +90,5 @@ public class TaskJobLauncherCommandLineRunnerFactoryBean implements FactoryBean< public Class getObjectType() { return TaskJobLauncherCommandLineRunner.class; } + } diff --git a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java index fb3c54a7..3f8a3cf8 100644 --- a/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java +++ b/spring-cloud-task-batch/src/main/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunner.java @@ -16,177 +16,218 @@ package org.springframework.cloud.task.batch.handler; +import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.Properties; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionException; +import org.springframework.batch.core.JobParameter; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.JobParametersIncrementer; import org.springframework.batch.core.JobParametersInvalidException; -import org.springframework.batch.core.configuration.JobRegistry; -import org.springframework.batch.core.converter.DefaultJobParametersConverter; -import org.springframework.batch.core.converter.JobParametersConverter; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.launch.JobLauncher; -import org.springframework.batch.core.launch.JobParametersNotFoundException; -import org.springframework.batch.core.launch.NoSuchJobException; import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; +import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.repository.JobRestartException; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.batch.repeat.RepeatCallback; +import org.springframework.batch.repeat.RepeatContext; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.batch.repeat.support.RepeatTemplate; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.autoconfigure.batch.JobExecutionEvent; +import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner; +import org.springframework.cloud.task.batch.configuration.TaskBatchProperties; import org.springframework.cloud.task.listener.TaskException; import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationEventPublisherAware; -import org.springframework.core.Ordered; -import org.springframework.util.PatternMatchUtils; +import org.springframework.core.task.TaskExecutor; import org.springframework.util.StringUtils; /** * {@link CommandLineRunner} to {@link JobLauncher launch} Spring Batch jobs. Runs all - * jobs in the surrounding context by default and throw an exception upon the - * first job that returns an {@link ExitStatus} of FAILED. - * Can also be used to launch a specific job by providing a jobName. The - * TaskJobLaunchercommandLineRunner takes the place of the - * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} - * when it is in use. + * jobs in the surrounding context by default and throws an exception upon the first job + * that returns an {@link BatchStatus} of FAILED if a {@link TaskExecutor} in the + * {@link JobLauncher} is not specified. If a {@link TaskExecutor} is specified + * in the {@link JobLauncher} then all Jobs are launched and an + * exception is thrown if one or more of the jobs has an {@link BatchStatus} of FAILED. + * TaskJobLauncherCommandLineRunner can also be used to launch a specific job by + * providing a jobName. The TaskJobLaunchercommandLineRunner takes the place of the + * {@link org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner} when + * it is in use. * * @author Glenn Renfro * @since 2.0.0 */ -public class TaskJobLauncherCommandLineRunner implements CommandLineRunner, Ordered, ApplicationEventPublisherAware{ - /** - * The default order for the command line runner. - */ - public static final int DEFAULT_ORDER = 0; +public class TaskJobLauncherCommandLineRunner extends JobLauncherCommandLineRunner { + + private JobLauncher taskJobLauncher; + + private JobExplorer taskJobExplorer; + + private JobRepository taskJobRepository; private static final Log logger = LogFactory .getLog(TaskJobLauncherCommandLineRunner.class); - private JobParametersConverter converter = new DefaultJobParametersConverter(); + private List jobExecutionList = new ArrayList<>(); - private JobLauncher jobLauncher; + private ApplicationEventPublisher taskApplicationEventPublisher; - private JobRegistry jobRegistry; + private TaskBatchProperties taskBatchProperties; - private JobExplorer jobExplorer; - - private String jobNames; - - private Collection jobs = Collections.emptySet(); - - private int order = DEFAULT_ORDER; - - private ApplicationEventPublisher publisher; - - public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher, - JobExplorer jobExplorer) { - this.jobLauncher = jobLauncher; - this.jobExplorer = jobExplorer; + /** + * Create a new {@link TaskJobLauncherCommandLineRunner}. + * @param jobLauncher to launch jobs + * @param jobExplorer to check the job repository for previous executions + * @param jobRepository to check if a job instance exists with the given parameters + * when running a job + * @param taskBatchProperties the properties used to configure the taskBatchProperties. + */ + public TaskJobLauncherCommandLineRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, + JobRepository jobRepository, TaskBatchProperties taskBatchProperties) { + super(jobLauncher, jobExplorer, jobRepository); + this.taskJobLauncher = jobLauncher; + this.taskJobExplorer = jobExplorer; + this.taskJobRepository = jobRepository; + this.taskBatchProperties = taskBatchProperties; } - public void setOrder(int order) { - this.order = order; - } - - @Override - public int getOrder() { - return this.order; - } - - @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { - this.publisher = publisher; - } - - public void setJobRegistry(JobRegistry jobRegistry) { - this.jobRegistry = jobRegistry; - } - - public void setJobNames(String jobNames) { - this.jobNames = jobNames; - } - - public void setJobParametersConverter(JobParametersConverter converter) { - this.converter = converter; - } - - public void setJobs(Collection jobs) { - this.jobs = jobs; + super.setApplicationEventPublisher(publisher); + this.taskApplicationEventPublisher = publisher; } @Override public void run(String... args) throws JobExecutionException { logger.info("Running default command line with: " + Arrays.asList(args)); launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "=")); - } - - protected void launchJobFromProperties(Properties properties) - throws JobExecutionException { - JobParameters jobParameters = this.converter.getJobParameters(properties); - executeLocalJobs(jobParameters); - executeRegisteredJobs(jobParameters); - } - - private void executeRegisteredJobs(JobParameters jobParameters) - throws JobExecutionException { - if (this.jobRegistry != null && StringUtils.hasText(this.jobNames)) { - String[] jobsToRun = this.jobNames.split(","); - for (String jobName : jobsToRun) { - try { - Job job = this.jobRegistry.getJob(jobName); - if (this.jobs.contains(job)) { - continue; - } - execute(job, jobParameters); - } - catch (NoSuchJobException ex) { - logger.debug("No job found in registry for job name: " + jobName); - } - } - } + validateJobExecutions(); } protected void execute(Job job, JobParameters jobParameters) throws JobExecutionAlreadyRunningException, JobRestartException, - JobInstanceAlreadyCompleteException, JobParametersInvalidException, - JobParametersNotFoundException { - JobParameters nextParameters = new JobParametersBuilder(jobParameters, - this.jobExplorer).getNextJobParameters(job).toJobParameters(); - JobExecution execution = this.jobLauncher.run(job, nextParameters); - if (this.publisher != null) { - this.publisher.publishEvent(new JobExecutionEvent(execution)); + JobInstanceAlreadyCompleteException, JobParametersInvalidException { + String jobName = job.getName(); + JobParameters parameters = jobParameters; + boolean jobInstanceExists = this.taskJobRepository.isJobInstanceExists(jobName, + parameters); + if (jobInstanceExists) { + JobExecution lastJobExecution = this.taskJobRepository + .getLastJobExecution(jobName, jobParameters); + if (lastJobExecution != null && isStoppedOrFailed(lastJobExecution) + && job.isRestartable()) { + // Retry a failed or stopped execution with previous parameters + JobParameters previousParameters = lastJobExecution.getJobParameters(); + /* + * remove Non-identifying parameters from the previous execution's + * parameters since there is no way to remove them programmatically. If + * they are required (or need to be modified) on a restart, they need to + * be (re)specified. + */ + JobParameters previousIdentifyingParameters = removeNonIdentifying( + previousParameters); + // merge additional parameters with previous ones (overriding those with + // the same key) + parameters = merge(previousIdentifyingParameters, jobParameters); + } } - if(execution.getExitStatus().getExitCode().equals(ExitStatus.FAILED.getExitCode())) { - String message = String.format("Job %s failed during " + - "execution for jobId %s with jobExecutionId of %s", - execution.getJobInstance().getJobName(), - execution.getJobId(), execution.getId()); - logger.error(message); - throw new TaskException(message); + else { + JobParametersIncrementer incrementer = job.getJobParametersIncrementer(); + if (incrementer != null) { + JobParameters nextParameters = new JobParametersBuilder(jobParameters, + this.taskJobExplorer).getNextJobParameters(job).toJobParameters(); + parameters = merge(nextParameters, jobParameters); + } + } + JobExecution execution = this.taskJobLauncher.run(job, parameters); + if (this.taskApplicationEventPublisher != null) { + this.taskApplicationEventPublisher.publishEvent(new JobExecutionEvent(execution)); + } + this.jobExecutionList.add(execution); + if (execution.getStatus().equals(BatchStatus.FAILED)) { + throwJobFailedException(Collections.singletonList(execution)); } } - private void executeLocalJobs(JobParameters jobParameters) - throws JobExecutionException { - for (Job job : this.jobs) { - if (StringUtils.hasText(this.jobNames)) { - String[] jobsToRun = this.jobNames.split(","); - if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) { - logger.debug("Skipped job: " + job.getName()); - continue; + private void validateJobExecutions() { + RepeatTemplate template = new RepeatTemplate(); + + Date startDate = new Date(); + + template.iterate(new RepeatCallback() { + + public RepeatStatus doInIteration(RepeatContext context) throws InterruptedException { + List failedJobExecutions = new ArrayList<>(); + RepeatStatus repeatStatus = RepeatStatus.FINISHED; + for (JobExecution jobExecution : jobExecutionList) { + JobExecution currentJobExecution = taskJobExplorer.getJobExecution(jobExecution.getId()); + BatchStatus batchStatus = currentJobExecution.getStatus(); + if (batchStatus.isRunning()) { + repeatStatus = RepeatStatus.CONTINUABLE; + } + if (batchStatus.equals(BatchStatus.FAILED)) { + failedJobExecutions.add(jobExecution); + } } + Thread.sleep(taskBatchProperties.getFailOnJobFailurePollInterval()); + + if (repeatStatus.equals(RepeatStatus.FINISHED) && failedJobExecutions.size() > 0) { + throwJobFailedException(failedJobExecutions); + } + if (repeatStatus.isContinuable() && taskBatchProperties.getFailOnJobFailurewaitTime() != 0 + && (new Date()).getTime() - startDate.getTime() > taskBatchProperties.getFailOnJobFailurewaitTime()) { + throw new IllegalStateException("Not all jobs were completed " + + "within the time specified by spring.cloud.task.batch." + + "failOnJobFailurewaitTime."); + } + return repeatStatus; } - execute(job, jobParameters); + + }); + } + + public void throwJobFailedException(List failedJobExecutions) { + String message = "The following Jobs have failed: \n"; + for (JobExecution failedJobExecution : failedJobExecutions) { + message += String.format("Job %s failed during " + + "execution for jobId %s with jobExecutionId of %s \n", + failedJobExecution.getJobInstance().getJobName(), + failedJobExecution.getJobId(), failedJobExecution.getId()); } + logger.error(message); + throw new TaskException(message); + + } + private JobParameters removeNonIdentifying(JobParameters parameters) { + Map parameterMap = parameters.getParameters(); + HashMap copy = new HashMap<>(parameterMap); + for (Map.Entry parameter : copy.entrySet()) { + if (!parameter.getValue().isIdentifying()) { + parameterMap.remove(parameter.getKey()); + } + } + return new JobParameters(parameterMap); + } + private boolean isStoppedOrFailed(JobExecution execution) { + BatchStatus status = execution.getStatus(); + return (status == BatchStatus.STOPPED || status == BatchStatus.FAILED); + } + private JobParameters merge(JobParameters parameters, JobParameters additionals) { + Map merged = new HashMap<>(); + merged.putAll(parameters.getParameters()); + merged.putAll(additionals.getParameters()); + return new JobParameters(merged); } } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java new file mode 100644 index 00000000..e5797cb0 --- /dev/null +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskBatchTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2018 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.cloud.task.batch.configuration; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; + +/** + * Contains the common configurations to run a unit test for the task batch features of + * SCT. + * + * @author Glenn Renfro + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@ImportAutoConfiguration +public @interface TaskBatchTest { +} diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java index f8f1c8c2..9d7ecd2f 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/configuration/TaskJobLauncherAutoConfigurationTests.java @@ -42,13 +42,10 @@ public class TaskJobLauncherAutoConfigurationTests { @Test public void testAutoBuiltDataSourceWithTaskJobLauncherCLR() { - this.contextRunner. - withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true"). - run(context -> { + this.contextRunner.withPropertyValues("spring.cloud.task.batch.fail-on-job-failure=true").run(context -> { assertThat(context).hasSingleBean(TaskJobLauncherCommandLineRunner.class); - assertThat(context).doesNotHaveBean(JobLauncherCommandLineRunner.class); - assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) - .getOrder()) + assertThat(context.getBean(TaskJobLauncherCommandLineRunner.class) + .getOrder()) .isEqualTo(0); }); } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java index 38cd20a8..9d62b9a9 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerCoreTests.java @@ -16,11 +16,16 @@ package org.springframework.cloud.task.batch.handler; + +import org.assertj.core.api.AssertionsForClassTypes; import org.junit.Before; import org.junit.Test; +import org.junit.jupiter.api.function.Executable; import org.junit.runner.RunWith; import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.Step; @@ -34,10 +39,12 @@ import org.springframework.batch.core.launch.JobLauncher; import org.springframework.batch.core.launch.support.RunIdIncrementer; import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.JobRestartException; import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.task.batch.configuration.TaskBatchProperties; import org.springframework.cloud.task.listener.TaskException; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.SyncTaskExecutor; @@ -47,6 +54,7 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.PlatformTransactionManager; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Glenn Renfro @@ -64,6 +72,9 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { @Autowired private JobExplorer jobExplorer; + @Autowired + private BatchConfiguration batchConfigurer; + @Autowired private PlatformTransactionManager transactionManager; @@ -79,12 +90,14 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { @Before public void init() { + batchConfigurer.clear(); this.jobs = new JobBuilderFactory(this.jobRepository); this.steps = new StepBuilderFactory(this.jobRepository, this.transactionManager); Tasklet tasklet = (contribution, chunkContext) -> null; this.step = this.steps.get("step").tasklet(tasklet).build(); this.job = this.jobs.get("job").start(this.step).build(); - this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer); + this.runner = new TaskJobLauncherCommandLineRunner(this.jobLauncher, this.jobExplorer, jobRepository, new TaskBatchProperties()); + } @@ -115,10 +128,27 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { .start(this.steps.get("step").tasklet(throwingTasklet()).build()) .incrementer(new RunIdIncrementer()).build(); runFailedJob(new JobParameters()); - runFailedJob(new JobParameters()); + runFailedJob(new JobParametersBuilder().addLong("run.id", 1L).toJobParameters()); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); } + @Test + public void runDifferentInstances() throws Exception { + this.job = this.jobs.get("job") + .start(this.steps.get("step").tasklet(throwingTasklet()).build()).build(); + // start a job instance + JobParameters jobParameters = new JobParametersBuilder().addString("name", "foo") + .toJobParameters(); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + // start a different job instance + JobParameters otherJobParameters = new JobParametersBuilder() + .addString("name", "bar").toJobParameters(); + runFailedJob(otherJobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2); + } + + @DirtiesContext @Test public void retryFailedExecutionOnNonRestartableJob() throws Exception { @@ -130,6 +160,15 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { // A failed job that is not restartable does not re-use the job params of // the last execution, but creates a new job instance when running it again. assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(2); + + // try to re-run a failed execution + Executable executable = () -> { + this.runner.execute(this.job, + new JobParametersBuilder().addLong("run.id", 1L).toJobParameters()); + }; + Throwable exception = assertThrows(JobRestartException.class, executable); + AssertionsForClassTypes.assertThat(exception.getMessage()) + .isEqualTo("JobInstance already exists and is not restartable"); } @DirtiesContext @@ -140,11 +179,47 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { .incrementer(new RunIdIncrementer()).build(); JobParameters jobParameters = new JobParametersBuilder().addLong("id", 1L, false) .addLong("foo", 2L, false).toJobParameters(); - runFailedJob(new JobParameters()); - runFailedJob(new JobParameters()); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + runFailedJob(new JobParametersBuilder(jobParameters) + .addLong("run.id", 1L).toJobParameters()); assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); } + + @Test + public void retryFailedExecutionWithDifferentNonIdentifyingParametersFromPreviousExecution() + throws Exception { + this.job = this.jobs.get("job") + .start(this.steps.get("step").tasklet(throwingTasklet()).build()) + .incrementer(new RunIdIncrementer()).build(); + JobParameters jobParameters = new JobParametersBuilder().addLong("id", 1L, false) + .addLong("foo", 2L, false).toJobParameters(); + runFailedJob(jobParameters); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + // try to re-run a failed execution with non identifying parameters + runFailedJob( new JobParametersBuilder().addLong("run.id", 1L) + .addLong("id", 2L, false).addLong("foo", 3L, false).toJobParameters()); + assertThat(this.jobExplorer.getJobInstances("job", 0, 100)).hasSize(1); + JobInstance jobInstance = this.jobExplorer.getJobInstance(0L); + assertThat(this.jobExplorer.getJobExecutions(jobInstance)).hasSize(2); + // first execution + JobExecution firstJobExecution = this.jobExplorer.getJobExecution(0L); + JobParameters parameters = firstJobExecution.getJobParameters(); + assertThat(parameters.getLong("run.id")).isEqualTo(1L); + assertThat(parameters.getLong("id")).isEqualTo(1L); + assertThat(parameters.getLong("foo")).isEqualTo(2L); + // second execution + JobExecution secondJobExecution = this.jobExplorer.getJobExecution(1L); + parameters = secondJobExecution.getJobParameters(); + // identifying parameters should be the same as previous execution + assertThat(parameters.getLong("run.id")).isEqualTo(1L); + // non-identifying parameters should be the newly specified ones + assertThat(parameters.getLong("id")).isEqualTo(2L); + assertThat(parameters.getLong("foo")).isEqualTo(3L); + } + + private Tasklet throwingTasklet() { return (contribution, chunkContext) -> { throw new RuntimeException("Planned"); @@ -154,7 +229,7 @@ public class TaskJobLauncherCommandLineRunnerCoreTests { private void runFailedJob(JobParameters jobParameters) throws Exception { boolean isExceptionThrown = false; try { - this.runner.execute(this.job, new JobParameters()); + this.runner.execute(this.job, jobParameters); } catch (TaskException taskException) { isExceptionThrown = true; diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java index 31e89939..96a155fb 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/handler/TaskJobLauncherCommandLineRunnerTests.java @@ -18,36 +18,49 @@ package org.springframework.cloud.task.batch.handler; import java.util.Set; +import javax.sql.DataSource; + import org.junit.After; import org.junit.Test; +import org.junit.jupiter.api.function.Executable; import org.springframework.batch.core.Job; import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.configuration.annotation.BatchConfigurer; +import org.springframework.batch.core.configuration.annotation.DefaultBatchConfigurer; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; import org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; import org.springframework.cloud.task.batch.configuration.TaskJobLauncherAutoConfiguration; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; +import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * @author Glenn Renfro @@ -56,6 +69,9 @@ public class TaskJobLauncherCommandLineRunnerTests { private ConfigurableApplicationContext applicationContext; + private static final String DEFAULT_ERROR_MESSAGE = "The following Jobs have failed: \n" + + "Job jobA failed during execution for jobId 1 with jobExecutionId of 1 \n"; + @After public void tearDown() { if (this.applicationContext != null) { @@ -65,37 +81,55 @@ public class TaskJobLauncherCommandLineRunnerTests { @Test public void testTaskJobLauncherCLRSuccessFail() { - String[] enabledArgs = new String[] { "--spring.cloud.task.batch.fail-on-job-failure=true" }; - boolean isExceptionThrown = false; - try { - this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); - } - catch (IllegalStateException exception) { - isExceptionThrown = true; - } - assertThat(isExceptionThrown).isTrue(); + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, + enabledArgs); + } + + /** + * Verifies that the task will return an exit code other than zero if the + * job fails with the deprecated EnableTask annotation. + */ + @Test + public void testTaskJobLauncherCLRSuccessFailWithAnnotation() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureAnnotatedConfiguration.class, + enabledArgs); + } + + @Test + public void testTaskJobLauncherCLRSuccessFailWithTaskExecutor() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true", + "--spring.cloud.task.batch.failOnJobFailurePollInterval=500"}; + validateForFail(DEFAULT_ERROR_MESSAGE, TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorConfiguration.class, + enabledArgs); + } + + + @Test + public void testTaskJobLauncherCLRSuccessWithLongWaitTaskExecutor() { + String[] enabledArgs = new String[] { + "--spring.cloud.task.batch.failOnJobFailure=true", + "--spring.cloud.task.batch.failOnJobFailurePollInterval=500", + "--spring.cloud.task.batch.failOnJobFailurewaitTime=1000" + }; + validateForFail("Not all jobs were completed within the time specified by spring.cloud.task.batch.failOnJobFailurewaitTime.", + TaskJobLauncherCommandLineRunnerTests.JobWithFailureTaskExecutorLongWaitConfiguration.class, + enabledArgs); } @Test public void testTaskJobLauncherPickOneJob() { String[] enabledArgs = new String[] { "--spring.cloud.task.batch.fail-on-job-failure=true", - "--spring.cloud.task.batch.jobNames=jobSucceed" }; + "--spring.cloud.task.batch.jobNames=jobSucceed"}; boolean isExceptionThrown = false; try { this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); + .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobWithFailureConfiguration.class }, enabledArgs); } catch (IllegalStateException exception) { isExceptionThrown = true; @@ -106,24 +140,18 @@ public class TaskJobLauncherCommandLineRunnerTests { @Test public void testCommandLineRunnerSetToFalse() { - String[] enabledArgs = new String[] { }; + String[] enabledArgs = new String[] {}; this.applicationContext = SpringApplication - .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class, - TaskJobLauncherAutoConfiguration.class }, enabledArgs); + .run(new Class[] { TaskJobLauncherCommandLineRunnerTests.JobConfiguration.class }, enabledArgs); validateContext(); assertThat(applicationContext.getBean(JobLauncherCommandLineRunner.class)).isNotNull(); - boolean exceptionThrown = false; - try { + + Executable executable = () -> { applicationContext.getBean(TaskJobLauncherCommandLineRunner.class); - } - catch (NoSuchBeanDefinitionException exception) { - exceptionThrown = true; - } - assertThat(exceptionThrown).isTrue(); + }; + Throwable exception = assertThrows(NoSuchBeanDefinitionException.class, executable); + assertThat(exception.getMessage()).isEqualTo("No qualifying bean of type " + + "'org.springframework.cloud.task.batch.handler.TaskJobLauncherCommandLineRunner' available"); validateContext(); } @@ -137,12 +165,20 @@ public class TaskJobLauncherCommandLineRunnerTests { assertThat(jobExecutionIds.size()).isEqualTo(1); assertThat(taskExplorer.getTaskExecution(jobExecutionIds.iterator().next()).getExecutionId()).isEqualTo(1); - } - @Configuration + private void validateForFail(String errorMessage, Class clazz, String [] enabledArgs) { + Executable executable = () -> { + this.applicationContext = SpringApplication + .run(new Class[] { clazz,PropertyPlaceholderAutoConfiguration.class}, enabledArgs);}; + Throwable exception = assertThrows(IllegalStateException.class, executable); + assertThat(exception.getCause().getMessage()).isEqualTo(errorMessage); + } + + @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfiguration { @Autowired @@ -156,8 +192,7 @@ public class TaskJobLauncherCommandLineRunnerTests { return jobBuilderFactory.get("job") .start(stepBuilderFactory.get("step1").tasklet(new Tasklet() { @Override - public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) - throws Exception { + public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) { System.out.println("Executed"); return RepeatStatus.FINISHED; } @@ -166,9 +201,15 @@ public class TaskJobLauncherCommandLineRunnerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @ImportAutoConfiguration({ + PropertyPlaceholderAutoConfiguration.class, + BatchAutoConfiguration.class, + TaskBatchAutoConfiguration.class, + TaskJobLauncherAutoConfiguration.class, + SingleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class }) + @Import(EmbeddedDataSourceConfiguration.class) public static class JobWithFailureConfiguration { @Autowired @@ -198,8 +239,7 @@ public class TaskJobLauncherCommandLineRunnerTests { .start(stepBuilderFactory.get("step1Succeed").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, - ChunkContext chunkContext) - throws Exception { + ChunkContext chunkContext) { System.out.println("Executed"); return RepeatStatus.FINISHED; } @@ -207,4 +247,83 @@ public class TaskJobLauncherCommandLineRunnerTests { .build(); } } + + @EnableTask + public static class JobWithFailureAnnotatedConfiguration extends JobWithFailureConfiguration{ + + } + + public static class JobWithFailureTaskExecutorConfiguration extends JobWithFailureConfiguration{ + @Bean + public BatchConfigurer batchConfigurer(DataSource dataSource) { + return new TestBatchConfigurer(dataSource); + } + } + + + @EnableBatchProcessing + @ImportAutoConfiguration({ + PropertyPlaceholderAutoConfiguration.class, + BatchAutoConfiguration.class, + TaskBatchAutoConfiguration.class, + TaskJobLauncherAutoConfiguration.class, + SingleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class }) + @Import(EmbeddedDataSourceConfiguration.class) + public static class JobWithFailureTaskExecutorLongWaitConfiguration { + + @Autowired + private JobBuilderFactory jobBuilderFactory; + + @Autowired + private StepBuilderFactory stepBuilderFactory; + @Bean + public BatchConfigurer batchConfigurer(DataSource dataSource) { + return new TestBatchConfigurer(dataSource); + } + + @Bean + public Job jobShortRunner() { + return jobBuilderFactory.get("jobSucceedShort") + .start(stepBuilderFactory.get("step1SucceedSort").tasklet(new Tasklet() { + @Override + public RepeatStatus execute(StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + System.out.println("Executed Short Runner"); + return RepeatStatus.FINISHED; + } + }).build()) + .build(); + } + + @Bean + public Job jobLongRunner() { + return jobBuilderFactory.get("jobSucceedLong") + .start(stepBuilderFactory.get("step1SucceedLong").tasklet(new Tasklet() { + @Override + public RepeatStatus execute(StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + System.out.println("Executed Long Runner"); + Thread.sleep(5000); + return RepeatStatus.FINISHED; + } + }).build()) + .build(); + } + } + + private static class TestBatchConfigurer extends DefaultBatchConfigurer{ + public TestBatchConfigurer(DataSource dataSource) { + super(dataSource); + } + protected JobLauncher createJobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(getJobRepository()); + jobLauncher.setTaskExecutor(new ConcurrentTaskExecutor()); + jobLauncher.afterPropertiesSet(); + return jobLauncher; + } + } } diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java index a187139a..f7ff20fe 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/PrefixTests.java @@ -29,10 +29,7 @@ import org.springframework.batch.core.configuration.annotation.StepBuilderFactor import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -58,11 +55,8 @@ public class PrefixTests { @Test public void testPrefix() { - this.applicationContext = SpringApplication.run(new Class[] { - JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class }, new String[] { "--spring.cloud.task.tablePrefix=FOO_" }); + this.applicationContext = SpringApplication.run( + JobConfiguration.class, new String[] { "--spring.cloud.task.tablePrefix=FOO_" }); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -73,7 +67,7 @@ public class PrefixTests { @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest public static class JobConfiguration { @Autowired diff --git a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java index 83827b55..8bce0a2b 100644 --- a/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java +++ b/spring-cloud-task-batch/src/test/java/org/springframework/cloud/task/batch/listener/TaskBatchExecutionListenerTests.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; + import javax.sql.DataSource; import org.junit.After; @@ -43,15 +44,16 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration; import org.springframework.cloud.task.batch.configuration.TaskBatchExecutionListenerBeanPostProcessor; +import org.springframework.cloud.task.batch.configuration.TaskBatchTest; import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.support.TaskRepositoryInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Primary; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -62,6 +64,7 @@ import static org.junit.Assert.assertEquals; /** * @author Michael Minella + * @author Glenn Renfro */ public class TaskBatchExecutionListenerTests { @@ -78,71 +81,50 @@ public class TaskBatchExecutionListenerTests { @Test public void testAutobuiltDataSource() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + ARGS); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationEnabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enabled=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class, + new String[] {"--spring.cloud.task.batch.listener.enabled=false"}); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationEnable() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=false"}); validateContext(); } @Test(expected = AssertionError.class) public void testNoAutoConfigurationBothDisabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=false --spring.cloud.task.batch.listener.enabled=false"}); validateContext(); } @Test public void testAutoConfigurationEnable() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enable=true"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enable=true"}); validateContext(); } @Test public void testAutoConfigurationEnabled() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, new String[] {"--spring.cloud.task.batch.listener.enabled=true"}); + this.applicationContext = SpringApplication.run(JobConfiguration.class , + new String[] {"--spring.cloud.task.batch.listener.enabled=true"}); validateContext(); } @Test public void testFactoryBean() { - this.applicationContext = SpringApplication.run(new Class[]{JobFactoryBeanConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobFactoryBeanConfiguration.class, + ARGS); validateContext(); } @@ -159,11 +141,7 @@ public class TaskBatchExecutionListenerTests { } @Test public void testMultipleDataSources() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfigurationMultipleDataSources.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfigurationMultipleDataSources.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -177,11 +155,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testAutobuiltDataSourceNoJob() { - this.applicationContext = SpringApplication.run(new Class[] {NoJobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(NoJobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -194,10 +168,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testMapBased() { - this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(JobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -211,10 +182,7 @@ public class TaskBatchExecutionListenerTests { @Test public void testMultipleJobs() { - this.applicationContext = SpringApplication.run(new Class[] {EmbeddedDataSourceConfiguration.class, MultipleJobConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + this.applicationContext = SpringApplication.run(MultipleJobConfiguration.class, ARGS); TaskExplorer taskExplorer = this.applicationContext.getBean(TaskExplorer.class); @@ -267,7 +235,9 @@ public class TaskBatchExecutionListenerTests { this.applicationContext = SpringApplication.run(new Class[] {JobConfiguration.class, PropertyPlaceholderAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, BatchAutoConfiguration.class, - TaskBatchAutoConfiguration.class}, ARGS); + TaskBatchAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class }, ARGS); TaskBatchExecutionListenerBeanPostProcessor beanPostProcessor = this.applicationContext.getBean( @@ -277,16 +247,16 @@ public class TaskBatchExecutionListenerTests { return beanPostProcessor; } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class NoJobConfiguration { } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfiguration { @Autowired @@ -309,9 +279,9 @@ public class TaskBatchExecutionListenerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobFactoryBeanConfiguration { @Autowired @@ -349,9 +319,9 @@ public class TaskBatchExecutionListenerTests { } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class JobConfigurationMultipleDataSources { @Autowired @@ -396,24 +366,15 @@ public class TaskBatchExecutionListenerTests { return new DefaultTaskConfigurer(myDataSource()); } - @Bean - public TaskRepositoryInitializer taskRepositoryInitializer() { - TaskRepositoryInitializer taskRepositoryInitializer = new TaskRepositoryInitializer(); - - taskRepositoryInitializer.setDataSource(myDataSource()); - - return taskRepositoryInitializer; - } - @Bean public DefaultBatchConfigurer batchConfigurer() { return new DefaultBatchConfigurer(myDataSource()); } } - @Configuration @EnableBatchProcessing - @EnableTask + @TaskBatchTest + @Import(EmbeddedDataSourceConfiguration.class) public static class MultipleJobConfiguration { @Autowired diff --git a/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories b/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories new file mode 100644 index 00000000..ddec7ef9 --- /dev/null +++ b/spring-cloud-task-batch/src/test/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.cloud.task.batch.configuration.TaskBatchTest=\ +org.springframework.cloud.task.batch.configuration.TaskBatchAutoConfiguration,\ +org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\ +org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\ +org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration,\ +org.springframework.cloud.task.configuration.SingleTaskConfiguration diff --git a/spring-cloud-task-core/pom.xml b/spring-cloud-task-core/pom.xml index 4283f505..702057be 100755 --- a/spring-cloud-task-core/pom.xml +++ b/spring-cloud-task-core/pom.xml @@ -6,7 +6,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-core @@ -91,6 +91,12 @@ spring-boot-configuration-processor true + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java index 26d99364..9b731de4 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/EnableTask.java @@ -1,6 +1,5 @@ - /* - * Copyright 2015 the original author or authors. + * Copyright 2015-2018 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. @@ -54,11 +53,15 @@ import org.springframework.context.annotation.Import; * * * @author Glenn Renfro + * + * @deprecated The EnableTask annotation is no longer be required to initialize + * Spring Cloud Task. This will be handled by AutoConfiguration provided by Spring Cloud Task. */ +@Deprecated @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited -@Import({ SimpleTaskConfiguration.class, SingleTaskConfiguration.class }) +@Import({ }) public @interface EnableTask { } diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskAutoConfiguration.java similarity index 90% rename from spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java rename to spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskAutoConfiguration.java index e5815a52..54171a61 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskConfiguration.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/configuration/SimpleTaskAutoConfiguration.java @@ -29,9 +29,11 @@ import org.apache.commons.logging.LogFactory; import org.springframework.aop.scope.ScopedProxyUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.task.listener.TaskLifecycleListener; -import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean; +import org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskNameResolver; import org.springframework.cloud.task.repository.TaskRepository; @@ -55,9 +57,10 @@ import org.springframework.util.CollectionUtils; @Configuration @EnableTransactionManagement @EnableConfigurationProperties(TaskProperties.class) -public class SimpleTaskConfiguration { +@ConditionalOnProperty(prefix = "spring.cloud.task.autoconfiguration", name = "enabled", havingValue = "true", matchIfMissing = true) +public class SimpleTaskAutoConfiguration { - protected static final Log logger = LogFactory.getLog(SimpleTaskConfiguration.class); + protected static final Log logger = LogFactory.getLog(SimpleTaskAutoConfiguration.class); @Autowired(required = false) private Collection dataSources; @@ -77,8 +80,6 @@ public class SimpleTaskConfiguration { private TaskLifecycleListener taskLifecycleListener; - private TaskListenerExecutorFactoryBean taskListenerExecutorFactoryBean; - private PlatformTransactionManager platformTransactionManager; private TaskExplorer taskExplorer; @@ -94,12 +95,7 @@ public class SimpleTaskConfiguration { } @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor() - throws Exception { - return this.taskListenerExecutorFactoryBean; - } - - @Bean + @ConditionalOnMissingBean public PlatformTransactionManager transactionManager() { return this.platformTransactionManager; } @@ -140,12 +136,11 @@ public class SimpleTaskConfiguration { taskConfigurer.getClass().getName())); this.taskRepository = taskConfigurer.getTaskRepository(); - this.taskListenerExecutorFactoryBean = new TaskListenerExecutorFactoryBean(context); this.platformTransactionManager = taskConfigurer.getTransactionManager(); this.taskExplorer = taskConfigurer.getTaskExplorer(); this.taskLifecycleListener = new TaskLifecycleListener(this.taskRepository, taskNameResolver(), - this.applicationArguments, taskExplorer, taskProperties); + this.applicationArguments, taskExplorer, taskProperties, new TaskListenerExecutorObjectFactory(context)); initialized = true; } diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java index 9a426ed3..c6e3c9ec 100644 --- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java +++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/listener/TaskLifecycleListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2016-2018 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. @@ -46,6 +46,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.SmartLifecycle; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; /** @@ -74,7 +75,9 @@ public class TaskLifecycleListener implements ApplicationListener taskExecutionListeners; + private Collection taskExecutionListenersFromContext; + + private List taskExecutionListeners; private final static Log logger = LogFactory.getLog(TaskLifecycleListener.class); @@ -82,6 +85,8 @@ public class TaskLifecycleListener implements ApplicationListener(); + this.taskListenerExecutorObjectFactory.getObject(); + if(!CollectionUtils.isEmpty(this.taskExecutionListenersFromContext)) { + this.taskExecutionListeners.addAll(this.taskExecutionListenersFromContext); + } + this.taskExecutionListeners.add(this.taskListenerExecutorObjectFactory.getObject()); + List args = new ArrayList<>(0); if(this.applicationArguments != null) { @@ -258,11 +273,11 @@ public class TaskLifecycleListener implements ApplicationListener startupListenerList = new ArrayList<>(this.taskExecutionListeners); + if (startupListenerList != null) { try { - List starterList = new ArrayList<>(taskExecutionListeners); - Collections.reverse(starterList); - for (TaskExecutionListener taskExecutionListener : starterList) { + Collections.reverse(startupListenerList); + for (TaskExecutionListener taskExecutionListener : startupListenerList) { taskExecutionListener.onTaskStartup(listenerTaskExecution); } } @@ -300,7 +315,7 @@ public class TaskLifecycleListener implements ApplicationListener { +public class TaskListenerExecutorObjectFactory implements ObjectFactory { private final static Log logger = LogFactory.getLog(TaskListenerExecutor.class); @@ -56,29 +65,19 @@ public class TaskListenerExecutorFactoryBean implements FactoryBean failedTaskInstances; - public TaskListenerExecutorFactoryBean(ConfigurableApplicationContext context){ + public TaskListenerExecutorObjectFactory(ConfigurableApplicationContext context){ this.context = context; } @Override - public TaskListenerExecutor getObject() throws Exception { - beforeTaskInstances = new HashMap<>(); - afterTaskInstances = new HashMap<>(); - failedTaskInstances = new HashMap<>(); + public TaskListenerExecutor getObject() { + this.beforeTaskInstances = new HashMap<>(); + this.afterTaskInstances = new HashMap<>(); + this.failedTaskInstances = new HashMap<>(); initializeExecutor(); return new TaskListenerExecutor(beforeTaskInstances, afterTaskInstances, failedTaskInstances); } - @Override - public Class getObjectType() { - return TaskListenerExecutor.class; - } - - @Override - public boolean isSingleton() { - return false; - } - private void initializeExecutor( ) { ConfigurableListableBeanFactory factory = context.getBeanFactory(); for( String beanName : context.getBeanDefinitionNames()) { diff --git a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories index 22ff66d1..ea2f98ee 100644 --- a/spring-cloud-task-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-task-core/src/main/resources/META-INF/spring.factories @@ -1 +1,4 @@ -org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.ResourceLoadingAutoConfiguration +org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.springframework.cloud.task.configuration.SingleTaskConfiguration,\ +org.springframework.cloud.task.configuration.ResourceLoadingAutoConfiguration,\ +org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration\ + diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java index 671e4d9e..945ca4a8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -17,17 +17,13 @@ package org.springframework.cloud.task; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.SingleTaskConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; -import org.springframework.cloud.task.configuration.TaskProperties; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -39,24 +35,23 @@ import static org.junit.Assert.assertNotNull; * @author Glenn Renfro * @since 2.0.0 */ -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = {TaskProperties.class, SimpleTaskConfiguration.class, SingleTaskConfiguration.class}) -@TestPropertySource(properties = { - "spring.cloud.task.single-instance-enabled=true", -}) public class SimpleSingleTaskAutoConfigurationTests { - @Autowired - private ConfigurableApplicationContext context; @Test public void testConfiguration() throws Exception { - SingleInstanceTaskListener singleInstanceTaskListener = this.context.getBean(SingleInstanceTaskListener.class); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); + applicationContextRunner.run((context) -> { + SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); - assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); - - assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); + assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); }); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java index b86b1ac3..350fc2d8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleSingleTaskAutoConfigurationWithDataSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -17,17 +17,14 @@ package org.springframework.cloud.task; import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SingleTaskConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.SingleInstanceTaskListener; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -39,25 +36,24 @@ import static org.junit.Assert.assertNotNull; * @author Glenn Renfro * @since 2.0.0 */ -@RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, - SingleTaskConfiguration.class, - EmbeddedDataSourceConfiguration.class}) -@TestPropertySource(properties = { - "spring.cloud.task.single-instance-enabled=true", -}) public class SimpleSingleTaskAutoConfigurationWithDataSourceTests { - @Autowired - private ConfigurableApplicationContext context; - @Test public void testConfiguration() throws Exception { - SingleInstanceTaskListener singleInstanceTaskListener = this.context.getBean(SingleInstanceTaskListener.class); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class, + EmbeddedDataSourceConfiguration.class)) + .withPropertyValues("spring.cloud.task.singleInstanceEnabled=true"); + applicationContextRunner.run((context) -> { + SingleInstanceTaskListener singleInstanceTaskListener = context.getBean(SingleInstanceTaskListener.class); - assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); + assertNotNull("singleInstanceTaskListener should not be null", singleInstanceTaskListener); - assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + assertEquals(singleInstanceTaskListener.getClass(), SingleInstanceTaskListener.class); + }); } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java new file mode 100644 index 00000000..5bfc1f04 --- /dev/null +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskAutoConfigurationTests.java @@ -0,0 +1,251 @@ +/* + * Copyright 2015-2018 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.cloud.task; + +import javax.sql.DataSource; + +import org.junit.After; +import org.junit.Test; +import org.junit.jupiter.api.function.Executable; + +import org.springframework.aop.framework.AopProxyUtils; +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; +import org.springframework.cloud.task.configuration.TaskConfigurer; +import org.springframework.cloud.task.repository.TaskExplorer; +import org.springframework.cloud.task.repository.TaskRepository; +import org.springframework.cloud.task.repository.support.SimpleTaskRepository; +import org.springframework.context.ApplicationContextException; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +/** + * Verifies that the beans created by the SimpleTaskAutoConfiguration. + * + * @author Glenn Renfro + * @author Michael Minella + */ +public class SimpleTaskAutoConfigurationTests { + + private ConfigurableApplicationContext context; + + @After + public void tearDown() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void testRepository() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)); + applicationContextRunner.run((context) -> { + + TaskRepository taskRepository = context.getBean(TaskRepository.class); + assertThat(taskRepository).isNotNull(); + Class targetClass = AopProxyUtils.ultimateTargetClass(taskRepository); + assertThat(targetClass).isEqualTo(SimpleTaskRepository.class); + }); + } + + @Test + public void testAutoConfigurationDisabled() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.autoconfiguration.enabled=false"); + Executable executable = () -> { + applicationContextRunner.run((context) -> { + context.getBean(TaskRepository.class); + }); + }; + verifyExceptionThrown(NoSuchBeanDefinitionException.class, "No qualifying " + + "bean of type 'org.springframework.cloud.task.repository.TaskRepository' " + + "available", executable); + } + + @Test + public void testRepositoryInitialized() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)); + applicationContextRunner.run((context) -> { + TaskExplorer taskExplorer = context.getBean(TaskExplorer.class); + assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); + }); + } + + @Test + public void testRepositoryNotInitialized() throws Exception { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withPropertyValues("spring.cloud.task.tablePrefix=foobarless"); + + verifyExceptionThrownDefaultExecutable(ApplicationContextException.class, "Failed to start " + + "bean 'taskLifecycleListener'; nested exception is " + + "org.springframework.dao.DataAccessResourceFailureException: " + + "Could not obtain sequence value; nested exception is org.h2.jdbc.JdbcSQLException: " + + "Syntax error in SQL statement \"SELECT FOOBARLESSSEQ.NEXTVAL FROM[*] DUAL \"; " + + "expected \"identifier\"; SQL statement:\n" + + "select foobarlessSEQ.nextval from dual [42001-197]", applicationContextRunner); + } + + @Test + public void testMultipleConfigurers() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(MultipleConfigurers.class); + + verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + + "with name 'simpleTaskAutoConfiguration': Invocation of init " + + "method failed; nested exception is java.lang.IllegalStateException:" + + " Expected one TaskConfigurer but found 2", applicationContextRunner); + } + + @Test + public void testMultipleDataSources() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(MultipleDataSources.class); + + verifyExceptionThrownDefaultExecutable(BeanCreationException.class, "Error creating bean " + + "with name 'simpleTaskAutoConfiguration': Invocation of init method " + + "failed; nested exception is java.lang.IllegalStateException: To use " + + "the default TaskConfigurer the context must contain no more than " + + "one DataSource, found 2", applicationContextRunner); + + } + + public void verifyExceptionThrownDefaultExecutable(Class classToCheck, String message, + ApplicationContextRunner applicationContextRunner) { + Executable executable = () -> { + applicationContextRunner.run((context) -> { + Throwable expectedException = context.getStartupFailure(); + assertThat(expectedException).isNotNull(); + throw expectedException; + }); + }; + verifyExceptionThrown(classToCheck, message, executable); + } + + public void verifyExceptionThrown(Class classToCheck, String message, Executable executable) { + Throwable exception = assertThrows(classToCheck, executable); + assertThat(exception.getMessage()).isEqualTo(message); + } + + /** + * Verify that the verifyEnvironment method skips DataSource Proxy Beans when determining + * the number of available dataSources. + */ + @Test + public void testWithDataSourceProxy() { + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + EmbeddedDataSourceConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(DataSourceProxyConfiguration.class); + applicationContextRunner.run((context) -> { + assertThat(context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); + SimpleTaskAutoConfiguration taskConfiguration = context.getBean(SimpleTaskAutoConfiguration.class); + assertThat(taskConfiguration).isNotNull(); + assertThat(taskConfiguration.taskExplorer()).isNotNull(); + }); + } + + @Configuration + public static class MultipleConfigurers { + + @Bean + public TaskConfigurer taskConfigurer1() { + return new DefaultTaskConfigurer((DataSource) null); + } + + @Bean + public TaskConfigurer taskConfigurer2() { + return new DefaultTaskConfigurer((DataSource) null); + } + } + + @Configuration + public static class MultipleDataSources { + + @Bean + public DataSource dataSource() { + return mock(DataSource.class); + }; + + @Bean + public DataSource dataSource2() { + return mock(DataSource.class); + }; + + } + + @Configuration + public static class DataSourceProxyConfiguration { + + @Autowired + private ConfigurableApplicationContext context; + + @Bean + public BeanDefinitionHolder proxyDataSource() { + GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); + proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); + BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition, "dataSource2"); + ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), + true); + return myDataSource; + } + + } + +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java deleted file mode 100644 index d5f38101..00000000 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/SimpleTaskConfigurationTests.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2015-2016 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.cloud.task; - -import java.util.Properties; - -import javax.sql.DataSource; - -import org.junit.After; -import org.junit.Test; - -import org.springframework.aop.framework.AopProxyUtils; -import org.springframework.aop.scope.ScopedProxyUtils; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; -import org.springframework.cloud.task.configuration.TaskConfigurer; -import org.springframework.cloud.task.configuration.TaskProperties; -import org.springframework.cloud.task.repository.TaskExplorer; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.support.SimpleTaskRepository; -import org.springframework.context.ApplicationContextException; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.PropertiesPropertySource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -/** - * Verifies that the beans created by the SimpleTaskConfiguration. - * - * @author Glenn Renfro - * @author Michael Minella - */ -public class SimpleTaskConfigurationTests { - - private ConfigurableApplicationContext context; - - @After - public void tearDown() { - if(this.context != null) { - this.context.close(); - } - } - - @Test - public void testRepository() throws Exception { - this.context = new AnnotationConfigApplicationContext(SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - - TaskRepository taskRepository = this.context.getBean(TaskRepository.class); - - assertThat(taskRepository).isNotNull(); - - Class targetClass = AopProxyUtils.ultimateTargetClass(taskRepository); - - assertThat(targetClass).isEqualTo(SimpleTaskRepository.class); - } - - - @Test - public void testRepositoryInitialized() throws Exception { - this.context = new AnnotationConfigApplicationContext(EmbeddedDataSourceConfiguration.class, SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - - TaskExplorer taskExplorer = this.context.getBean(TaskExplorer.class); - - assertThat(taskExplorer.getTaskExecutionCount()).isEqualTo(1l); - } - - @Test - public void testRepositoryNotInitialized() throws Exception { - Properties properties = new Properties(); - - properties.put("spring.cloud.task.tablePrefix", "foobarless"); - PropertiesPropertySource propertiesSource = new PropertiesPropertySource("test", properties); - - this.context = new AnnotationConfigApplicationContext(); - this.context.getEnvironment().getPropertySources().addLast(propertiesSource); - ((AnnotationConfigApplicationContext)context).register(SimpleTaskConfiguration.class); - ((AnnotationConfigApplicationContext)context).register(PropertyPlaceholderAutoConfiguration.class); - ((AnnotationConfigApplicationContext)context).register(EmbeddedDataSourceConfiguration.class); - boolean wasExceptionThrown = false; - try { - this.context.refresh(); - } - catch (ApplicationContextException ex) { - wasExceptionThrown = true; - } - assertThat( wasExceptionThrown).isTrue(); - } - - - @Test(expected = BeanCreationException.class) - public void testMultipleConfigurers() { - this.context = new AnnotationConfigApplicationContext(MultipleConfigurers.class, - PropertyPlaceholderAutoConfiguration.class); - } - - @Test(expected = BeanCreationException.class) - public void testMultipleDataSources() { - this.context = new AnnotationConfigApplicationContext( - MultipleDataSources.class, SimpleTaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - } - - /** - * Verify that the verifyEnvironment method skips DataSource Proxy Beans - * when determining the number of available dataSources. - */ - @Test - public void testWithDataSourceProxy() { - this.context = new AnnotationConfigApplicationContext(EmbeddedDataSourceConfiguration.class, TaskProperties.class, - PropertyPlaceholderAutoConfiguration.class, DataSourceProxyConfiguration.class - ); - - assertThat(this.context.getBeanNamesForType(DataSource.class).length).isEqualTo(2); - SimpleTaskConfiguration taskConfiguration = this.context.getBean(SimpleTaskConfiguration.class); - assertThat(taskConfiguration).isNotNull(); - assertThat(taskConfiguration.taskExplorer()).isNotNull(); - } - - @Configuration - @EnableTask - public static class MultipleConfigurers { - - @Bean - public TaskConfigurer taskConfigurer1() { - return new DefaultTaskConfigurer((DataSource) null); - } - - @Bean - public TaskConfigurer taskConfigurer2() { - return new DefaultTaskConfigurer((DataSource) null); - } - } - - @Configuration - public static class MultipleDataSources { - - @Bean - public DataSource dataSource() { - return mock(DataSource.class); - }; - - @Bean - public DataSource dataSource2() { - return mock(DataSource.class); - }; - - } - - @Configuration - public static class DataSourceProxyConfiguration { - - @Autowired - private ConfigurableApplicationContext context; - - @Bean - public SimpleTaskConfiguration simpleTaskConfiguration() { - GenericBeanDefinition proxyBeanDefinition = new GenericBeanDefinition(); - proxyBeanDefinition.setBeanClassName("javax.sql.DataSource"); - BeanDefinitionHolder myDataSource = new BeanDefinitionHolder(proxyBeanDefinition,"dataSource2"); - ScopedProxyUtils.createScopedProxy(myDataSource, (BeanDefinitionRegistry) this.context.getBeanFactory(), true); - return new SimpleTaskConfiguration(); - } - - } - -} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java index 95e2eb40..df30c003 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskCoreTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2015-2018 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.cloud.task; import org.junit.After; @@ -5,14 +21,15 @@ import org.junit.Rule; import org.junit.Test; import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.context.ApplicationContextException; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import static org.junit.Assert.assertTrue; @@ -48,11 +65,31 @@ public class TaskCoreTests { @Test public void successfulTaskTest() { - applicationContext = new SpringApplicationBuilder().sources(new Class[]{TaskConfiguration.class, - PropertyPlaceholderAutoConfiguration.class}).build().run(new String[]{ - "--spring.cloud.task.closecontext.enable=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false"}); + this.applicationContext = SpringApplication.run( TaskConfiguration.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); + + String output = this.outputCapture.toString(); + assertTrue("Test results do not show create task message: " + output, + output.contains(CREATE_TASK_MESSAGE)); + assertTrue("Test results do not show success message: " + output, + output.contains(UPDATE_TASK_MESSAGE)); + assertTrue("Test results have incorrect exit code: " + output, + output.contains(SUCCESS_EXIT_CODE_MESSAGE)); + } + + /** + * Test to verify that deprecated annotation does not affect task execution. + */ + @Test + public void successfulTaskTestWithAnnotation() { + this.applicationContext = SpringApplication.run( TaskConfigurationWithAnotation.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); String output = this.outputCapture.toString(); assertTrue("Test results do not show create task message: " + output, @@ -67,11 +104,11 @@ public class TaskCoreTests { public void exceptionTaskTest() { boolean exceptionFired = false; try { - applicationContext = new SpringApplicationBuilder().sources(TaskExceptionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class).build().run(new String[]{ - "--spring.cloud.task.closecontext.enable=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false"}); + this.applicationContext = SpringApplication.run( TaskExceptionConfiguration.class, + new String[] { + "--spring.cloud.task.closecontext.enable=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false" }); } catch (IllegalStateException exception) { exceptionFired = true; @@ -95,8 +132,8 @@ public class TaskCoreTests { public void invalidExecutionId() { boolean exceptionFired = false; try { - applicationContext = new SpringApplicationBuilder().sources(TaskExceptionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class).build().run(new String[]{ + applicationContext = this.applicationContext = SpringApplication.run( + TaskExceptionConfiguration.class, new String[]{ "--spring.cloud.task.closecontext.enable=false", "--spring.cloud.task.name=" + TASK_NAME, "--spring.main.web-environment=false", @@ -112,8 +149,7 @@ public class TaskCoreTests { output.contains(EXCEPTION_INVALID_TASK_EXECUTION_ID)); } - @Configuration - @EnableTask + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public static class TaskConfiguration { @Bean @@ -126,8 +162,21 @@ public class TaskCoreTests { } } - @Configuration @EnableTask + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) + public static class TaskConfigurationWithAnotation { + + @Bean + public CommandLineRunner commandLineRunner() { + return new CommandLineRunner() { + @Override + public void run(String... strings) throws Exception { + } + }; + } + } + + @ImportAutoConfiguration({SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public static class TaskExceptionConfiguration { @Bean diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java index 3fcce0e7..8174e9a0 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerDefaultTaskConfigurerTests.java @@ -26,7 +26,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; @@ -42,7 +42,7 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; * @since 2.0.0 */ @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, +@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class}) public class TaskRepositoryInitializerDefaultTaskConfigurerTests { diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java index 0705ba20..00ab42d8 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/TaskRepositoryInitializerNoDataSourceTaskConfigurerTests.java @@ -27,7 +27,8 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.configuration.TaskConfigurer; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ContextConfiguration; @@ -43,7 +44,7 @@ import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; * @since 2.0.0 */ @RunWith(SpringRunner.class) -@ContextConfiguration(classes = {SimpleTaskConfiguration.class, +@ContextConfiguration(classes = {SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class, EmbeddedDataSourceConfiguration.class, DefaultTaskConfigurer.class}) public class TaskRepositoryInitializerNoDataSourceTaskConfigurerTests { diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java index ed6495b8..b8b1aa72 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/configuration/TaskPropertiesTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2017-2018 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.cloud.task.configuration; import org.junit.Test; @@ -7,10 +23,6 @@ import org.junit.runners.Suite.SuiteClasses; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.cloud.task.repository.TaskRepository; -import org.springframework.cloud.task.repository.support.SimpleTaskRepository; -import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; @@ -21,7 +33,7 @@ import static org.junit.Assert.assertThat; @RunWith(Suite.class) @SuiteClasses({ - TaskPropertiesTests.CloseContextEnabledTest.class, + TaskPropertiesTests.CloseContextEnabledTest.class }) @@ -36,21 +48,15 @@ public class TaskPropertiesTests { } @RunWith(SpringRunner.class) - @SpringBootTest(classes={TaskPropertiesTests.Config.class}, properties = { "spring.cloud.task.closecontextEnabled=false" }) + @SpringBootTest(classes={TaskPropertiesTests.Config.class, + SimpleTaskAutoConfiguration.class, SingleTaskConfiguration.class}, + properties = { "spring.cloud.task.closecontextEnabled=false" }) @DirtiesContext public static class CloseContextEnabledTest extends TaskPropertiesTests {} @Configuration - @EnableTask public static class Config { - @Bean - TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean() { - return new TaskExecutionDaoFactoryBean(); - } - @Bean - public TaskRepository taskRepository(TaskExecutionDaoFactoryBean tefb) { - return new SimpleTaskRepository(tefb); - } + } } diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java index a1f4d25c..3f78bcbe 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskExecutionListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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,11 +29,9 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.task.listener.annotation.AfterTask; import org.springframework.cloud.task.listener.annotation.BeforeTask; import org.springframework.cloud.task.listener.annotation.FailedTask; -import org.springframework.cloud.task.listener.annotation.TaskListenerExecutorFactoryBean; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.util.TestDefaultConfiguration; import org.springframework.cloud.task.util.TestListener; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -290,12 +288,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener extends TestListener { @BeforeTask @@ -331,12 +323,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener { @BeforeTask @@ -365,11 +351,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } public static class AnnotatedTaskListener { @@ -400,12 +381,6 @@ public class TaskExecutionListenerTests { return new AnnotatedTaskListener(); } - @Bean - public TaskListenerExecutorFactoryBean taskListenerExecutor(ConfigurableApplicationContext context) throws Exception - { - return new TaskListenerExecutorFactoryBean(context); - } - public static class AnnotatedTaskListener extends TestListener{ @BeforeTask diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java new file mode 100644 index 00000000..0fd11c0d --- /dev/null +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/listener/TaskListenerExecutorObjectFactoryTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2018 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.cloud.task.listener; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.task.listener.annotation.AfterTask; +import org.springframework.cloud.task.listener.annotation.BeforeTask; +import org.springframework.cloud.task.listener.annotation.FailedTask; +import org.springframework.cloud.task.listener.annotation.TaskListenerExecutor; +import org.springframework.cloud.task.repository.TaskExecution; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Verifies that the {@link TaskListenerExecutorObjectFactory} retrieves the + * {@link TaskListenerExecutor}. + * + * @author Glenn Renfro + * @since 2.1.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = { TaskListenerExecutorObjectFactoryTests.TaskExecutionListenerConfiguration.class }) +public class TaskListenerExecutorObjectFactoryTests { + + public static final String BEFORE_LISTENER = "BEFORE LISTENER"; + + public static final String AFTER_LISTENER = "AFTER LISTENER"; + + public static final String FAIL_LISTENER = "FAIL LISTENER"; + + public static List taskExecutionListenerResults = new ArrayList<>(3); + + @Autowired + private ConfigurableApplicationContext context; + + private TaskListenerExecutor taskListenerExecutor; + + private TaskListenerExecutorObjectFactory taskListenerExecutorObjectFactory; + + @Before + public void setup() { + taskExecutionListenerResults.clear(); + this.taskListenerExecutorObjectFactory = new TaskListenerExecutorObjectFactory(this.context); + this.taskListenerExecutor = this.taskListenerExecutorObjectFactory.getObject(); + } + + @Test + public void verifyTaskStartupListener() { + this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); + validateSingleEntry(BEFORE_LISTENER); + } + + @Test + public void verifyTaskFailedListener() { + this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER), + new IllegalStateException("oops")); + validateSingleEntry(FAIL_LISTENER); + } + + @Test + public void verifyTaskEndListener() { + this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER)); + validateSingleEntry(AFTER_LISTENER); + } + + @Test + public void verifyAllListener() { + this.taskListenerExecutor.onTaskStartup(createSampleTaskExecution(BEFORE_LISTENER)); + this.taskListenerExecutor.onTaskFailed(createSampleTaskExecution(FAIL_LISTENER), + new IllegalStateException("oops")); + this.taskListenerExecutor.onTaskEnd(createSampleTaskExecution(AFTER_LISTENER)); + assertThat(taskExecutionListenerResults.size()).isEqualTo(3); + assertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(BEFORE_LISTENER); + assertThat(taskExecutionListenerResults.get(1).getTaskName()).isEqualTo(FAIL_LISTENER); + assertThat(taskExecutionListenerResults.get(2).getTaskName()).isEqualTo(AFTER_LISTENER); + } + + private TaskExecution createSampleTaskExecution(String taskName) { + TaskExecution taskExecution = new TaskExecution(); + taskExecution.setTaskName(taskName); + return taskExecution; + } + + private void validateSingleEntry(String event) { + assertThat(taskExecutionListenerResults.size()).isEqualTo(1); + assertThat(taskExecutionListenerResults.get(0).getTaskName()).isEqualTo(event); + } + + @Configuration + public static class TaskExecutionListenerConfiguration { + + @Bean + public TaskRunComponent taskRunComponent() { + return new TaskRunComponent(); + } + } + + public static class TaskRunComponent { + + @BeforeTask + public void initBeforeListener(TaskExecution taskExecution) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + + @AfterTask + public void initAfterListener(TaskExecution taskExecution) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + + @FailedTask + public void initFailedListener(TaskExecution taskExecution, Throwable exception) { + TaskListenerExecutorObjectFactoryTests.taskExecutionListenerResults.add(taskExecution); + } + } +} diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java index caa30426..55506eef 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/SimpleTaskRepositoryJdbcTests.java @@ -28,7 +28,7 @@ import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskRepository; @@ -49,7 +49,7 @@ import static org.junit.Assert.assertEquals; */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {EmbeddedDataSourceConfiguration.class, - SimpleTaskConfiguration.class, + SimpleTaskAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class}) public class SimpleTaskRepositoryJdbcTests { diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java index b758ab6f..c0e7e324 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/support/TaskDatabaseInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 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. @@ -26,7 +26,7 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; -import org.springframework.cloud.task.configuration.SimpleTaskConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.configuration.TestConfiguration; import org.springframework.cloud.task.repository.dao.MapTaskExecutionDao; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -89,7 +89,7 @@ public class TaskDatabaseInitializerTests { @Test(expected = BeanCreationException.class) public void testMultipleDataSourcesContext() throws Exception { this.context = new AnnotationConfigApplicationContext(); - this.context.register( SimpleTaskConfiguration.class, + this.context.register( SimpleTaskAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class); DataSource dataSource = mock(DataSource.class); diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java index a171a07b..7732c0e4 100644 --- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java +++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/util/TestDefaultConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 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. @@ -24,6 +24,7 @@ import org.springframework.boot.ApplicationArguments; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cloud.task.configuration.TaskProperties; import org.springframework.cloud.task.listener.TaskLifecycleListener; +import org.springframework.cloud.task.listener.TaskListenerExecutorObjectFactory; import org.springframework.cloud.task.repository.TaskExplorer; import org.springframework.cloud.task.repository.TaskNameResolver; import org.springframework.cloud.task.repository.TaskRepository; @@ -74,10 +75,15 @@ public class TestDefaultConfiguration implements InitializingBean { return new SimpleTaskNameResolver(); } + @Bean + public TaskListenerExecutorObjectFactory taskListenerExecutorObjectProvider(ConfigurableApplicationContext context) { + return new TaskListenerExecutorObjectFactory(context); + } + @Bean public TaskLifecycleListener taskHandler(TaskExplorer taskExplorer){ return new TaskLifecycleListener(taskRepository(), taskNameResolver(), - applicationArguments, taskExplorer, taskProperties); + applicationArguments, taskExplorer, taskProperties, taskListenerExecutorObjectProvider(context)); } @Override diff --git a/spring-cloud-task-dependencies/pom.xml b/spring-cloud-task-dependencies/pom.xml index 3a2fd0d2..3e3dede8 100644 --- a/spring-cloud-task-dependencies/pom.xml +++ b/spring-cloud-task-dependencies/pom.xml @@ -2,7 +2,7 @@ 4.0.0 spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom Spring Cloud Task Dependencies Spring Cloud Task Dependencies @@ -10,7 +10,7 @@ spring-cloud-dependencies-parent org.springframework.cloud - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -19,22 +19,22 @@ org.springframework.cloud spring-cloud-starter-task - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-core - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-batch - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT org.springframework.cloud spring-cloud-task-stream - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT diff --git a/spring-cloud-task-docs/pom.xml b/spring-cloud-task-docs/pom.xml index 0f4ef93b..8eaf32b3 100644 --- a/spring-cloud-task-docs/pom.xml +++ b/spring-cloud-task-docs/pom.xml @@ -4,7 +4,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT spring-cloud-task-docs Spring Cloud Task Docs diff --git a/spring-cloud-task-docs/src/main/asciidoc/batch.adoc b/spring-cloud-task-docs/src/main/asciidoc/batch.adoc index da5d6321..e1cd3825 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/batch.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/batch.adoc @@ -217,7 +217,7 @@ Batch/Boot behavior. Keep in mind that a task is a boot application and that the returned from the task is the same as a boot application. To override this behavior and allow the task to return an exit code other than zero when a batch job returns an -https://docs.spring.io/spring-batch/4.0.x/reference/html/step.html#conditionalFlow[ExitStatus] +https://docs.spring.io/spring-batch/4.0.x/reference/html/step.html#batchStatusVsExitStatus[BatchStatus] of `FAILED`, set `spring.cloud.task.batch.fail-on-job-failure` to `true`. Then the exit code can be 1 (the default) or be based on the https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-application-exit[specified diff --git a/spring-cloud-task-docs/src/main/asciidoc/features.adoc b/spring-cloud-task-docs/src/main/asciidoc/features.adoc index 743dd5cd..00b4cacd 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/features.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/features.adoc @@ -33,8 +33,7 @@ processes, typified by most web applications, do not save their lifecycle events tasks at the heart of Spring Cloud Task do. The lifecycle consists of a single task execution. This is a physical execution of a -Spring Boot application configured to be a task (that is, it has the `@EnableTask` -annotation). +Spring Boot application configured to be a task (that is, it has the Sprint Cloud Task dependencies). At the beginning of a task, before any `CommandLineRunner` or `ApplicationRunner` implementations have been run, an entry in the `TaskRepository` that records the start @@ -367,3 +366,14 @@ application: org.springframework.integration spring-integration-jdbc + +=== Disabling Spring Cloud Task Auto Configuration + +In cases where Spring Cloud Task should not be auto configured for an implementation, you can disable Task's auto configuration. +This can be done either by adding the following annotation to your Task application: +``` +@EnableAutoConfiguration(exclude={SimpleTaskAutoConfiguration.class}) +``` +You may also disable Task auto configuration by setting the `spring.cloud.task.autoconfiguration.enabled` property to `false`. + + diff --git a/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc b/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc index d039d752..e5e877e2 100755 --- a/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/getting-started.adoc @@ -77,12 +77,11 @@ package io.spring.demo.helloworld; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; @SpringBootApplication -@EnableTask public class HelloworldApplication { +public class SampleTask { @Bean public CommandLineRunner commandLineRunner() { @@ -124,13 +123,10 @@ spring.application.name=helloWorld ---- [[getting-started-at-task]] -==== The @EnableTask annotation +==== Task Auto Configuration -The first non-boot annotation in our example is the `@EnableTask` annotation. This -class-level annotation tells Spring Cloud Task to bootstrap it's functionality. By -default, it imports an additional configuration class (`SimpleTaskConfiguration`). This -additional configuration registers the `TaskRepository` and the infrastructure for its -use. +When including Spring Cloud Task Starter dependency, Task auto configures all beans to bootstrap it's functionality. +Part of this configuration registers the `TaskRepository` and the infrastructure for its use. In our demo, the `TaskRepository` uses an embedded H2 database to record the results of a task. This H2 embedded database is not a practical solution for a production environment, since diff --git a/spring-cloud-task-docs/src/main/asciidoc/stream.adoc b/spring-cloud-task-docs/src/main/asciidoc/stream.adoc index f4a0d7d8..af473d66 100644 --- a/spring-cloud-task-docs/src/main/asciidoc/stream.adoc +++ b/spring-cloud-task-docs/src/main/asciidoc/stream.adoc @@ -93,7 +93,6 @@ event on the `task-events` channel (at both the start and the end of the task): [source, java] ---- @SpringBootApplication -@EnableTask public class TaskEventsApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-integration-tests/pom.xml b/spring-cloud-task-integration-tests/pom.xml index 24202898..ead1a69d 100644 --- a/spring-cloud-task-integration-tests/pom.xml +++ b/spring-cloud-task-integration-tests/pom.xml @@ -3,7 +3,7 @@ spring-cloud-task-parent org.springframework.cloud - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT 4.0.0 Spring Cloud Task Integration Tests @@ -16,7 +16,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -72,7 +72,7 @@ io.spring.cloud partitioned-batch-job - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java b/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java index d09c9d55..cc6591c2 100644 --- a/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java +++ b/spring-cloud-task-integration-tests/src/test/java/configuration/JobConfiguration.java @@ -32,7 +32,6 @@ import org.springframework.batch.item.ItemWriter; import org.springframework.batch.item.support.ListItemReader; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,7 +40,6 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableBatchProcessing -@EnableTask public class JobConfiguration { @Autowired private JobBuilderFactory jobBuilderFactory; diff --git a/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java b/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java index 0b33f572..dfa5e584 100644 --- a/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java +++ b/spring-cloud-task-integration-tests/src/test/java/configuration/JobSkipConfiguration.java @@ -27,7 +27,6 @@ import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -36,7 +35,6 @@ import org.springframework.context.annotation.Configuration; */ @Configuration @EnableBatchProcessing -@EnableTask public class JobSkipConfiguration { @Autowired private JobBuilderFactory jobBuilderFactory; diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java index d07d5ca3..c09e3079 100644 --- a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java +++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/executionid/TaskStartApplication.java @@ -19,14 +19,12 @@ package org.springframework.cloud.task.executionid; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; /** * @author Glenn Renfro */ @SpringBootApplication -@EnableTask public class TaskStartApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java index f88b094b..ffad327e 100644 --- a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java +++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java @@ -22,18 +22,22 @@ import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.StreamListener; import org.springframework.cloud.stream.binder.rabbit.config.RabbitServiceAutoConfiguration; import org.springframework.cloud.stream.binder.test.junit.rabbit.RabbitTestSupport; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; import org.springframework.cloud.stream.messaging.Sink; -import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.cloud.task.repository.TaskExecution; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.test.context.junit4.SpringRunner; @@ -59,21 +63,26 @@ public class TaskEventTests { @Test public void testTaskEventListener() throws Exception { - ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder().sources(new Class[] {TaskEventsConfiguration.class, - TaskEventAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - RabbitServiceAutoConfiguration.class}).build().run("--spring.cloud.task.closecontext_enabled=false", - "--spring.cloud.task.name=" + TASK_NAME, - "--spring.main.web-environment=false", - "--spring.cloud.stream.defaultBinder=rabbit", - "--spring.cloud.stream.bindings.task-events.destination=test"); - assertNotNull(applicationContext.getBean("taskEventListener")); - assertNotNull(applicationContext.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(TaskEventsConfiguration.class, + TaskEventAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + RabbitServiceAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + BindingServiceConfiguration.class)) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", + "--spring.cloud.task.name=" + TASK_NAME, + "--spring.main.web-environment=false", + "--spring.cloud.stream.defaultBinder=rabbit", + "--spring.cloud.stream.bindings.task-events.destination=test"); + applicationContextRunner.run((context) -> { + assertNotNull(context.getBean("taskEventListener")); + assertNotNull(context.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + }); assertTrue(latch.await(1, TimeUnit.SECONDS)); } @Configuration - @EnableTask public static class TaskEventsConfiguration { } @@ -87,5 +96,15 @@ public class TaskEventTests { assertTrue(String.format("Task name should be '%s'", TASK_NAME), execution.getTaskName().equals(TASK_NAME)); latch.countDown(); } + + @Bean + public CommandLineRunner commandLineRunner(){ + return new CommandLineRunner() { + @Override + public void run(String... args) throws Exception { + System.out.println("Hello World"); + } + }; + } } } diff --git a/spring-cloud-task-samples/batch-events/pom.xml b/spring-cloud-task-samples/batch-events/pom.xml index 53e77e63..e8e1b958 100644 --- a/spring-cloud-task-samples/batch-events/pom.xml +++ b/spring-cloud-task-samples/batch-events/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud batch-events - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Batch Events Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -47,19 +47,19 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile org.springframework.cloud spring-cloud-stream-binder-rabbit-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test org.springframework.cloud spring-cloud-stream-test-support-internal - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test @@ -70,6 +70,7 @@ org.hsqldb hsqldb + diff --git a/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java b/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java index cfee7c96..3a31a627 100644 --- a/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java +++ b/spring-cloud-task-samples/batch-events/src/main/java/io/spring/cloud/BatchEventsApplication.java @@ -34,12 +34,10 @@ import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication -@EnableTask @EnableBatchProcessing public class BatchEventsApplication { diff --git a/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java b/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java index 8d4563e0..5c69aa2d 100644 --- a/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java +++ b/spring-cloud-task-samples/batch-events/src/test/java/io/spring/cloud/BatchEventsApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -50,12 +50,14 @@ public class BatchEventsApplicationTests { context.close(); } } - + @Test public void testExecution() throws Exception { SpringApplication.run(JobExecutionListenerBinding.class, "--spring.main.web-environment=false"); SpringApplication.run(BatchEventsApplication.class, "--server.port=0", - "--spring.cloud.stream.bindings.output.producer.requiredGroups=testgroup"); + "--spring.cloud.stream.bindings.output.producer.requiredGroups=testgroup", + "--spring.jmx.default-domain=fakedomain", + "--spring.main.webEnvironment=false"); Assert.assertTrue("The latch did not count down to zero before timeout", jobExecutionLatch.await(60, TimeUnit.SECONDS)); } diff --git a/spring-cloud-task-samples/batch-job/pom.xml b/spring-cloud-task-samples/batch-job/pom.xml index 39cc65cc..484f2853 100644 --- a/spring-cloud-task-samples/batch-job/pom.xml +++ b/spring-cloud-task-samples/batch-job/pom.xml @@ -5,7 +5,7 @@ io.spring.cloud batch-job jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Spring Cloud Task Batch Example Batch Job Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -53,6 +53,10 @@ spring-boot-starter-test test + + org.mariadb.jdbc + mariadb-java-client + diff --git a/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java b/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java index b05f5579..d2237984 100644 --- a/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java +++ b/spring-cloud-task-samples/batch-job/src/main/java/io/spring/BatchJobApplication.java @@ -3,10 +3,8 @@ package io.spring; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication -@EnableTask @EnableBatchProcessing public class BatchJobApplication { diff --git a/spring-cloud-task-samples/jpa-sample/pom.xml b/spring-cloud-task-samples/jpa-sample/pom.xml index 54aa371d..5ee60343 100644 --- a/spring-cloud-task-samples/jpa-sample/pom.xml +++ b/spring-cloud-task-samples/jpa-sample/pom.xml @@ -19,7 +19,7 @@ io.spring.cloud jpa-sample jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT To show users how to enable a task with a JPA application. Spring Cloud Task JPA Sample Application @@ -27,7 +27,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -41,7 +41,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java b/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java index 7675425b..46d76fe8 100644 --- a/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java +++ b/spring-cloud-task-samples/jpa-sample/src/main/java/io/spring/JpaApplication.java @@ -18,10 +18,8 @@ package io.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication -@EnableTask public class JpaApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java b/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java index 4b192bf0..67d64c29 100644 --- a/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java +++ b/spring-cloud-task-samples/jpa-sample/src/test/java/io/spring/JpaApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2018 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. @@ -101,7 +101,7 @@ public class JpaApplicationTests { assertTrue("Unable to find the insert message: " + output, output.contains(INSERT_MESSAGE)); JdbcTemplate template = new JdbcTemplate(this.dataSource); Map result = template.queryForMap("Select * from TASK_RUN_OUTPUT"); - assertThat((result.get("ID")), is(1L)); + assertThat((Long)(result.get("ID")), is(1L)); assertThat(((String) result.get("OUTPUT")), containsString("Executed at")); } diff --git a/spring-cloud-task-samples/multiple-datasources/pom.xml b/spring-cloud-task-samples/multiple-datasources/pom.xml index e5ab27f2..9daa1427 100644 --- a/spring-cloud-task-samples/multiple-datasources/pom.xml +++ b/spring-cloud-task-samples/multiple-datasources/pom.xml @@ -5,7 +5,7 @@ io.spring.cloud multiple-datasources jar - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT To show users how to enable a task with a multiple DataSources. Spring Cloud Task Multiple DataSources Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java b/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java index 13311519..8d34fca5 100644 --- a/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java +++ b/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/MultipleDataSourcesApplication.java @@ -18,14 +18,12 @@ package io.spring; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; /** * @author Michael Minella */ @SpringBootApplication -@EnableTask public class MultipleDataSourcesApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/partitioned-batch-job/pom.xml b/spring-cloud-task-samples/partitioned-batch-job/pom.xml index 317625d9..2483fc15 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/pom.xml +++ b/spring-cloud-task-samples/partitioned-batch-job/pom.xml @@ -6,13 +6,13 @@ partitioned-batch-job jar Partitioned Batch Job - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Sample of using the DeployerPartitionHandler org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -26,7 +26,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java index 113fc983..3e81dfc1 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java +++ b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/JobConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -81,15 +81,6 @@ public class JobConfiguration { private static final int GRID_SIZE = 4; - @Bean - public JobExplorerFactoryBean jobExplorer() { - JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean(); - - jobExplorerFactoryBean.setDataSource(this.dataSource); - - return jobExplorerFactoryBean; - } - @Bean public PartitionHandler partitionHandler(TaskLauncher taskLauncher, JobExplorer jobExplorer) throws Exception { Resource resource = resourceLoader.getResource("maven://io.spring.cloud:partitioned-batch-job:1.1.0.RELEASE"); diff --git a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java index 7a042cf1..692699aa 100644 --- a/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java +++ b/spring-cloud-task-samples/partitioned-batch-job/src/main/java/io/spring/PartitionedBatchJobApplication.java @@ -3,11 +3,9 @@ package io.spring; import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; @SpringBootApplication @EnableBatchProcessing -@EnableTask public class PartitionedBatchJobApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/pom.xml b/spring-cloud-task-samples/pom.xml index 77b592e5..5800d766 100644 --- a/spring-cloud-task-samples/pom.xml +++ b/spring-cloud-task-samples/pom.xml @@ -11,7 +11,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT @@ -36,7 +36,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import diff --git a/spring-cloud-task-samples/task-events/pom.xml b/spring-cloud-task-samples/task-events/pom.xml index 5529cbf3..90be4a6b 100644 --- a/spring-cloud-task-samples/task-events/pom.xml +++ b/spring-cloud-task-samples/task-events/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud task-events - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Events @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -43,10 +43,9 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile - org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java b/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java index ee7093b7..4858e200 100644 --- a/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java +++ b/spring-cloud-task-samples/task-events/src/main/java/io/spring/TaskEventsApplication.java @@ -18,12 +18,10 @@ package io.spring; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication -@EnableTask public class TaskEventsApplication { public static void main(String[] args) { diff --git a/spring-cloud-task-samples/taskprocessor/pom.xml b/spring-cloud-task-samples/taskprocessor/pom.xml index df29d82a..15f5f3e0 100644 --- a/spring-cloud-task-samples/taskprocessor/pom.xml +++ b/spring-cloud-task-samples/taskprocessor/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud taskprocessor - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Processor Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -42,7 +42,7 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile @@ -52,7 +52,7 @@ org.springframework.cloud spring-cloud-stream-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-samples/tasksink/pom.xml b/spring-cloud-task-samples/tasksink/pom.xml index 0f966b54..f5ddabce 100644 --- a/spring-cloud-task-samples/tasksink/pom.xml +++ b/spring-cloud-task-samples/tasksink/pom.xml @@ -4,7 +4,7 @@ io.spring.cloud tasksink - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT jar Task Sink Sample Application @@ -13,7 +13,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -42,13 +42,13 @@ org.springframework.cloud spring-cloud-starter-stream-rabbit - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT compile org.springframework.cloud spring-cloud-stream-test-support - 2.0.0.RELEASE + 2.1.0.BUILD-SNAPSHOT test diff --git a/spring-cloud-task-samples/timestamp/pom.xml b/spring-cloud-task-samples/timestamp/pom.xml index adf64e93..89e804c3 100644 --- a/spring-cloud-task-samples/timestamp/pom.xml +++ b/spring-cloud-task-samples/timestamp/pom.xml @@ -7,13 +7,13 @@ timestamp-task jar Timestamp Task - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT Spring Cloud Timestamp Task org.springframework.boot spring-boot-starter-parent - 2.0.1.RELEASE + 2.1.0.BUILD-SNAPSHOT @@ -27,7 +27,7 @@ org.springframework.cloud spring-cloud-task-dependencies - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT pom import @@ -57,6 +57,10 @@ com.h2database h2 + + org.mariadb.jdbc + mariadb-java-client + diff --git a/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java b/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java index 22e0cb0d..3d9bd8d8 100644 --- a/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java +++ b/spring-cloud-task-samples/timestamp/src/main/java/org/springframework/cloud/task/timestamp/TaskApplication.java @@ -29,14 +29,12 @@ import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; /** * Spring Boot Application that has tasks enabled. */ @SpringBootApplication -@EnableTask @EnableConfigurationProperties({ TimestampTaskProperties.class }) public class TaskApplication { diff --git a/spring-cloud-task-stream/pom.xml b/spring-cloud-task-stream/pom.xml index 44e0a2e2..5059753d 100644 --- a/spring-cloud-task-stream/pom.xml +++ b/spring-cloud-task-stream/pom.xml @@ -10,7 +10,7 @@ org.springframework.cloud spring-cloud-task-parent - 2.0.1.BUILD-SNAPSHOT + 2.1.0.BUILD-SNAPSHOT diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java index 7c2707da..d28e5973 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/batch/listener/BatchEventAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -24,6 +24,7 @@ import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.SkipListener; import org.springframework.batch.core.StepExecutionListener; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -33,6 +34,7 @@ import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; import org.springframework.cloud.task.batch.listener.support.TaskBatchEventListenerBeanPostProcessor; import org.springframework.cloud.task.batch.listener.support.TaskEventProperties; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.cloud.task.listener.TaskLifecycleListener; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -60,6 +62,7 @@ import org.springframework.messaging.MessageChannel; @ConditionalOnClass(Job.class) @ConditionalOnBean(value = { Job.class, TaskLifecycleListener.class }) @ConditionalOnProperty(prefix = "spring.cloud.task.batch.events", name = "enabled", havingValue = "true", matchIfMissing = true) +@AutoConfigureAfter(SimpleTaskAutoConfiguration.class) public class BatchEventAutoConfiguration { public final static String JOB_EXECUTION_EVENTS_LISTENER = "jobExecutionEventsListener"; diff --git a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java index 36142271..a5de53e8 100644 --- a/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java +++ b/spring-cloud-task-stream/src/main/java/org/springframework/cloud/task/listener/TaskEventAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2016-2018 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. @@ -15,12 +15,15 @@ */ package org.springframework.cloud.task.listener; -import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cloud.stream.annotation.EnableBinding; import org.springframework.cloud.stream.annotation.Output; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @@ -36,21 +39,20 @@ import org.springframework.messaging.MessageChannel; @ConditionalOnBean(TaskLifecycleListener.class) @ConditionalOnProperty(prefix = "spring.cloud.task.events", name = "enabled", havingValue = "true", matchIfMissing = true) @PropertySource("classpath:/org/springframework/cloud/task/application.properties") +@AutoConfigureBefore(BindingServiceConfiguration.class) +@AutoConfigureAfter(SimpleTaskAutoConfiguration.class) public class TaskEventAutoConfiguration { @Configuration @EnableBinding(TaskEventChannels.class) public static class ListenerConfiguration { - @Autowired - private TaskEventChannels taskEventChannels; - @Bean public GatewayProxyFactoryBean taskEventListener() { GatewayProxyFactoryBean factoryBean = new GatewayProxyFactoryBean(TaskExecutionListener.class); - factoryBean.setDefaultRequestChannel(taskEventChannels.taskEvents()); + factoryBean.setDefaultRequestChannelName(TaskEventChannels.TASK_EVENTS); return factoryBean; } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java index e0770cb7..1e8088f9 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/batch/listener/JobExecutionEventTests.java @@ -34,15 +34,16 @@ import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.StepExecution; import org.springframework.batch.item.ExecutionContext; import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration; import org.springframework.cloud.task.batch.listener.support.JobExecutionEvent; import org.springframework.cloud.task.batch.listener.support.JobInstanceEvent; import org.springframework.cloud.task.batch.listener.support.StepExecutionEvent; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; @@ -275,12 +276,15 @@ public class JobExecutionEventTests { @Test public void testOrderConfiguration() { - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class, - EventJobExecutionConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{"--spring.cloud.task.closecontext_enabled=false", + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( + EventJobExecutionConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", "--spring.main.web-environment=false", "--spring.cloud.task.batch.events.chunk-order=5", "--spring.cloud.task.batch.events.item-process-order=5", @@ -288,30 +292,35 @@ public class JobExecutionEventTests { "--spring.cloud.task.batch.events.item-write-order=5", "--spring.cloud.task.batch.events.job-execution-order=5", "--spring.cloud.task.batch.events.skip-order=5", - "--spring.cloud.task.batch.events.step-execution-order=5" - }); + "--spring.cloud.task.batch.events.step-execution-order=5"); + applicationContextRunner.run((context) -> { for (String beanName : LISTENER_BEAN_NAMES) { - Ordered ordered = (Ordered)applicationContext.getBean(beanName); + Ordered ordered = (Ordered)context.getBean(beanName); assertEquals("Expected order value of 5 for " + beanName,ordered.getOrder(),5); } + + }); } private void testDisabledConfiguration(String property, String disabledListener) { - boolean exceptionThrown = false; String disabledPropertyArg = (property != null) ? "--" + property + "=false" : ""; - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class, + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of( EventJobExecutionConfiguration.class, PropertyPlaceholderAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{"--spring.cloud.task.closecontext_enabled=false", - "--spring.main.web-environment=false", - disabledPropertyArg}); - + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class)) + .withUserConfiguration(BatchEventAutoConfiguration.JobExecutionListenerConfiguration.class) + .withPropertyValues("--spring.cloud.task.closecontext_enabled=false", + "--spring.main.web-environment=false", + disabledPropertyArg); + applicationContextRunner.run((context) -> { + boolean exceptionThrown = false; for (String beanName : LISTENER_BEAN_NAMES) { if (disabledListener != null && disabledListener.equals(beanName)) { try { - applicationContext.getBean(disabledListener); + context.getBean(disabledListener); } catch (NoSuchBeanDefinitionException nsbde) { exceptionThrown = true; @@ -319,15 +328,15 @@ public class JobExecutionEventTests { assertTrue(String.format("Did not expect %s bean in context", beanName), exceptionThrown); } else { - applicationContext.getBean(beanName); + context.getBean(beanName); } } - applicationContext.getBean(BatchEventAutoConfiguration.BatchEventsChannels.class); + }); + } @Configuration - @EnableTask public static class EventJobExecutionConfiguration { } } diff --git a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java index 6baaccb4..6c81adf1 100644 --- a/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java +++ b/spring-cloud-task-stream/src/test/java/org/springframework/cloud/task/listener/TaskEventTests.java @@ -17,13 +17,18 @@ package org.springframework.cloud.task.listener; import org.junit.Test; -import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.stream.config.BindingServiceConfiguration; import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration; -import org.springframework.cloud.task.configuration.EnableTask; -import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration; +import org.springframework.cloud.task.configuration.SingleTaskConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.integration.annotation.BridgeFrom; +import org.springframework.integration.channel.NullChannel; import static org.junit.Assert.assertNotNull; @@ -38,20 +43,31 @@ public class TaskEventTests { @Test public void testDefaultConfiguration() { - ConfigurableApplicationContext applicationContext = - SpringApplication.run(new Class[]{PropertyPlaceholderAutoConfiguration.class,EmbeddedDataSourceConfiguration.class,TaskEventsConfiguration.class, - TaskEventAutoConfiguration.class, - TestSupportBinderAutoConfiguration.class}, - new String[]{ "--spring.cloud.task.closecontext_enabled=false", - "--spring.main.web-environment=false"}); - - assertNotNull(applicationContext.getBean("taskEventListener")); - assertNotNull(applicationContext.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(EmbeddedDataSourceConfiguration.class, + TaskEventAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + TestSupportBinderAutoConfiguration.class, + SimpleTaskAutoConfiguration.class, + SingleTaskConfiguration.class, + BindingServiceConfiguration.class)) + .withUserConfiguration(TaskEventsConfiguration.class) + .withPropertyValues("spring.cloud.task.closecontext_enabled=false", + "spring.main.web-environment=false"); + applicationContextRunner.run((context) -> { + assertNotNull(context.getBean("taskEventListener")); + assertNotNull(context.getBean(TaskEventAutoConfiguration.TaskEventChannels.class)); + }); } @Configuration - @EnableTask public static class TaskEventsConfiguration { + + @Bean + @BridgeFrom(TaskEventAutoConfiguration.TaskEventChannels.TASK_EVENTS) + public NullChannel testEmptyChannel() { + return new NullChannel(); + } } }