001/* 002 * Copyright 2006-2007 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.batch.test; 018 019import java.util.Date; 020import java.util.HashMap; 021import java.util.Map; 022 023import org.apache.commons.logging.Log; 024import org.apache.commons.logging.LogFactory; 025import org.springframework.batch.core.Job; 026import org.springframework.batch.core.JobExecution; 027import org.springframework.batch.core.JobParameter; 028import org.springframework.batch.core.JobParameters; 029import org.springframework.batch.core.Step; 030import org.springframework.batch.core.job.AbstractJob; 031import org.springframework.batch.core.job.SimpleJob; 032import org.springframework.batch.core.job.flow.FlowJob; 033import org.springframework.batch.core.launch.JobLauncher; 034import org.springframework.batch.core.repository.JobRepository; 035import org.springframework.batch.item.ExecutionContext; 036import org.springframework.beans.BeansException; 037import org.springframework.beans.factory.annotation.Autowired; 038import org.springframework.context.ApplicationContext; 039import org.springframework.context.ApplicationContextAware; 040 041/** 042 * <p> 043 * Base class for testing batch jobs. It provides methods for launching an 044 * entire {@link AbstractJob}, allowing for end to end testing of individual 045 * steps, without having to run every step in the job. Any test classes 046 * inheriting from this class should make sure they are part of an 047 * {@link ApplicationContext}, which is generally expected to be done as part of 048 * the Spring test framework. Furthermore, the {@link ApplicationContext} in 049 * which it is a part of is expected to have one {@link JobLauncher}, 050 * {@link JobRepository}, and a single {@link AbstractJob} implementation. 051 * 052 * <p> 053 * This class also provides the ability to run {@link Step}s from a 054 * {@link FlowJob} or {@link SimpleJob} individually. By launching {@link Step}s 055 * within a {@link Job} on their own, end to end testing of individual steps can 056 * be performed without having to run every step in the job. 057 * 058 * <p> 059 * It should be noted that using any of the methods that don't contain 060 * {@link JobParameters} in their signature, will result in one being created 061 * with the current system time as a parameter. This will ensure restartability 062 * when no parameters are provided. 063 * 064 * @author Lucas Ward 065 * @author Dan Garrette 066 * @since 2.0 067 * 068 * @deprecated (from 2.1) use {@link JobLauncherTestUtils} instead 069 */ 070@Deprecated 071public abstract class AbstractJobTests implements ApplicationContextAware { 072 073 /** Logger */ 074 protected final Log logger = LogFactory.getLog(getClass()); 075 076 @Autowired 077 private JobLauncher launcher; 078 079 @Autowired 080 private AbstractJob job; 081 082 @Autowired 083 private JobRepository jobRepository; 084 085 private StepRunner stepRunner; 086 087 private ApplicationContext applicationContext; 088 089 /** 090 * {@inheritDoc} 091 */ 092 @Override 093 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 094 this.applicationContext = applicationContext; 095 } 096 097 /** 098 * @return the applicationContext 099 */ 100 protected ApplicationContext getApplicationContext() { 101 return applicationContext; 102 } 103 104 /** 105 * @return the job repository which is autowired by type 106 */ 107 public JobRepository getJobRepository() { 108 return jobRepository; 109 } 110 111 /** 112 * @return the job which is autowired by type 113 */ 114 public AbstractJob getJob() { 115 return job; 116 } 117 118 /** 119 * @return the launcher 120 */ 121 protected JobLauncher getJobLauncher() { 122 return launcher; 123 } 124 125 /** 126 * Launch the entire job, including all steps. 127 * 128 * @return JobExecution, so that the test can validate the exit status 129 * 130 * @throws Exception is thrown if error occurs. 131 */ 132 protected JobExecution launchJob() throws Exception { 133 return this.launchJob(this.getUniqueJobParameters()); 134 } 135 136 /** 137 * Launch the entire job, including all steps 138 * 139 * @param jobParameters parameters for the job 140 * @return JobExecution, so that the test can validate the exit status 141 * 142 * @throws Exception is thrown if error occurs. 143 */ 144 protected JobExecution launchJob(JobParameters jobParameters) throws Exception { 145 return getJobLauncher().run(this.job, jobParameters); 146 } 147 148 /** 149 * @return a new JobParameters object containing only a parameter for the 150 * current timestamp, to ensure that the job instance will be unique. 151 */ 152 protected JobParameters getUniqueJobParameters() { 153 Map<String, JobParameter> parameters = new HashMap<String, JobParameter>(); 154 parameters.put("timestamp", new JobParameter(new Date().getTime())); 155 return new JobParameters(parameters); 156 } 157 158 /** 159 * Convenient method for subclasses to grab a {@link StepRunner} for running 160 * steps by name. 161 * 162 * @return a {@link StepRunner} 163 */ 164 protected StepRunner getStepRunner() { 165 if (this.stepRunner == null) { 166 this.stepRunner = new StepRunner(getJobLauncher(), getJobRepository()); 167 } 168 return this.stepRunner; 169 } 170 171 /** 172 * Launch just the specified step in the job. A unique set of JobParameters 173 * will automatically be generated. An IllegalStateException is thrown if 174 * there is no Step with the given name. 175 * 176 * @param stepName The name of the step to launch 177 * @return JobExecution 178 */ 179 public JobExecution launchStep(String stepName) { 180 return this.launchStep(stepName, this.getUniqueJobParameters(), null); 181 } 182 183 /** 184 * Launch just the specified step in the job. A unique set of JobParameters 185 * will automatically be generated. An IllegalStateException is thrown if 186 * there is no Step with the given name. 187 * 188 * @param stepName The name of the step to launch 189 * @param jobExecutionContext An ExecutionContext whose values will be 190 * loaded into the Job ExecutionContext prior to launching the step. 191 * @return JobExecution 192 */ 193 public JobExecution launchStep(String stepName, ExecutionContext jobExecutionContext) { 194 return this.launchStep(stepName, this.getUniqueJobParameters(), jobExecutionContext); 195 } 196 197 /** 198 * Launch just the specified step in the job. An IllegalStateException is 199 * thrown if there is no Step with the given name. 200 * 201 * @param stepName The name of the step to launch 202 * @param jobParameters The JobParameters to use during the launch 203 * @return JobExecution 204 */ 205 public JobExecution launchStep(String stepName, JobParameters jobParameters) { 206 return this.launchStep(stepName, jobParameters, null); 207 } 208 209 /** 210 * Launch just the specified step in the job. An IllegalStateException is 211 * thrown if there is no Step with the given name. 212 * 213 * @param stepName The name of the step to launch 214 * @param jobParameters The JobParameters to use during the launch 215 * @param jobExecutionContext An ExecutionContext whose values will be 216 * loaded into the Job ExecutionContext prior to launching the step. 217 * @return JobExecution 218 */ 219 public JobExecution launchStep(String stepName, JobParameters jobParameters, ExecutionContext jobExecutionContext) { 220 Step step = this.job.getStep(stepName); 221 if (step == null) { 222 step = this.job.getStep(this.job.getName() + "." + stepName); 223 } 224 if (step == null) { 225 throw new IllegalStateException("No Step found with name: [" + stepName + "]"); 226 } 227 return getStepRunner().launchStep(step, jobParameters, jobExecutionContext); 228 } 229}