@Test
  public void testApplicationException() throws Exception {

    taskletStep.execute(stepExecution);
    assertEquals(FAILED, stepExecution.getStatus());
    assertEquals(FAILED.toString(), stepExecution.getExitStatus().getExitCode());
  }
  @Test
  public void testUnexpectedRollback() throws Exception {

    taskletStep.setTransactionManager(
        new ResourcelessTransactionManager() {
          @Override
          protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
            super.doRollback(status);
            throw new UnexpectedRollbackException("bar");
          }
        });

    taskletStep.setTasklet(
        new Tasklet() {

          public RepeatStatus execute(StepContribution contribution, ChunkContext attributes)
              throws Exception {
            attributes
                .getStepContext()
                .getStepExecution()
                .getExecutionContext()
                .putString("foo", "bar");
            return RepeatStatus.FINISHED;
          }
        });

    taskletStep.execute(stepExecution);
    assertEquals(FAILED, stepExecution.getStatus());
    Throwable e = stepExecution.getFailureExceptions().get(0);
    assertEquals("bar", e.getMessage());
    assertEquals(0, stepExecution.getCommitCount());
    assertEquals(1, stepExecution.getRollbackCount()); // Failed transaction counts as rollback
    assertEquals(0, stepExecution.getExecutionContext().size());
  }
  /**
   * @throws IOException if a temporary file cannot be created.
   * @throws NoSuchJobException if SpeciesPageHarvestingJob cannot be located
   * @throws JobParametersInvalidException if the job parameters are invalid
   * @throws JobInstanceAlreadyCompleteException if the job has already completed
   * @throws JobRestartException if the job cannot be restarted
   * @throws JobExecutionAlreadyRunningException if the job is already running
   */
  @Test
  public final void testNotModifiedResponse()
      throws IOException, NoSuchJobException, JobExecutionAlreadyRunningException,
          JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
    Map<String, JobParameter> parameters = new HashMap<String, JobParameter>();
    parameters.put("query.string", new JobParameter("select i from Image i"));

    JobParameters jobParameters = new JobParameters(parameters);

    Job job = jobLocator.getJob("ImageProcessing");
    assertNotNull("ImageProcessing must not be null", job);
    JobExecution jobExecution = jobLauncher.run(job, jobParameters);
    assertEquals(
        "The job should complete successfully",
        jobExecution.getExitStatus().getExitCode(),
        "COMPLETED");

    for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
      logger.info(
          stepExecution.getStepName()
              + " "
              + stepExecution.getReadCount()
              + " "
              + stepExecution.getFilterCount()
              + " "
              + stepExecution.getWriteCount());
    }
  }
 @Test
 public void testInterrupted() throws Exception {
   taskletStep.setStepExecutionListeners(new StepExecutionListener[] {new InterruptionListener()});
   taskletStep.execute(stepExecution);
   assertEquals(STOPPED, stepExecution.getStatus());
   assertEquals(STOPPED.toString(), stepExecution.getExitStatus().getExitCode());
 }
  private void launchWorker(StepExecution workerStepExecution) {
    List<String> arguments = new ArrayList<>();
    arguments.addAll(this.taskExecution.getArguments());
    arguments.add(
        formatArgument(
            SPRING_CLOUD_TASK_JOB_EXECUTION_ID,
            String.valueOf(workerStepExecution.getJobExecution().getId())));
    arguments.add(
        formatArgument(
            SPRING_CLOUD_TASK_STEP_EXECUTION_ID, String.valueOf(workerStepExecution.getId())));
    arguments.add(formatArgument(SPRING_CLOUD_TASK_STEP_NAME, this.stepName));

    Map<String, String> environmentProperties = new HashMap<>(this.environmentProperties.size());
    environmentProperties.putAll(getCurrentEnvironmentProperties());
    environmentProperties.putAll(this.environmentProperties);

    AppDefinition definition =
        new AppDefinition(
            String.format(
                "%s:%s:%s",
                taskExecution.getTaskName(),
                workerStepExecution.getJobExecution().getJobInstance().getJobName(),
                workerStepExecution.getStepName()),
            environmentProperties);

    AppDeploymentRequest request =
        new AppDeploymentRequest(definition, this.resource, this.deploymentProperties, arguments);

    taskLauncher.launch(request);
  }
  @Before
  public void init() throws Exception {

    earlierExecution =
        MetaDataInstanceFactory.createJobExecutionWithStepExecutions(122L, Arrays.asList("step"));
    earlierExecution.setStatus(BatchStatus.FAILED);
    earlierExecution.setExitStatus(ExitStatus.FAILED);
    earlierExecution.setStartTime(new Date());
    earlierExecution.setEndTime(new Date(earlierExecution.getStartTime().getTime() + 100));
    assertFalse(earlierExecution.isRunning());

    jobExecution =
        MetaDataInstanceFactory.createJobExecutionWithStepExecutions(
            123L, Arrays.asList("first", "step"));
    jobExecution.setStatus(BatchStatus.COMPLETED);
    jobExecution.setExitStatus(ExitStatus.COMPLETED);
    jobExecution.setStartTime(new Date());
    jobExecution.setEndTime(new Date(earlierExecution.getEndTime().getTime() + 100));
    assertFalse(jobExecution.isRunning());

    Iterator<StepExecution> iterator = jobExecution.getStepExecutions().iterator();
    iterator.next();
    StepExecution stepExecution = iterator.next();
    stepExecution.setStatus(BatchStatus.COMPLETED);
    stepExecution.setExitStatus(ExitStatus.COMPLETED.addExitDescription("Foo"));

    metrics = new SimpleJobExecutionMetrics(jobService, "job");
  }
 @Override
 public JobExecutionInfoResource getSerializationValue() {
   JobInstance jobInstance = new JobInstance(1l, "job1");
   JobExecution jobExecution =
       new JobExecution(
           jobInstance,
           2l,
           new JobParametersBuilder()
               .addString("foo", "bar")
               .addDouble("baz", 3.0, false)
               .toJobParameters(),
           "configName.xml");
   jobExecution.setVersion(1);
   jobExecution.setStatus(BatchStatus.STARTED);
   jobExecution.setCreateTime(new Date(0));
   jobExecution.setStartTime(new Date(1000));
   jobExecution.setLastUpdated(new Date(3000));
   StepExecution stepExecution = new StepExecution("step1", jobExecution, 3l);
   stepExecution.setStatus(BatchStatus.STARTED);
   stepExecution.setStartTime(new Date(1000));
   stepExecution.setLastUpdated(new Date(3000));
   jobExecution.addStepExecutions(Arrays.asList(stepExecution));
   JobExecutionInfoResource jobExecutionInfoResource =
       new JobExecutionInfoResource(jobExecution, TimeZone.getTimeZone("America/Chicago"));
   jobExecutionInfoResource.setStepExecutions(
       Arrays.asList(
           new StepExecutionInfoResource(stepExecution, TimeZone.getTimeZone("America/Chicago"))));
   return jobExecutionInfoResource;
 }
  @Test
  public void testAfterStepFailureWhenTaskletSucceeds() throws Exception {

    final RuntimeException exception = new RuntimeException();
    taskletStep.setStepExecutionListeners(
        new StepExecutionListenerSupport[] {
          new StepExecutionListenerSupport() {
            @Override
            public ExitStatus afterStep(StepExecution stepExecution) {
              throw exception;
            }
          }
        });
    taskletStep.setTasklet(
        new Tasklet() {

          public RepeatStatus execute(StepContribution contribution, ChunkContext attributes)
              throws Exception {
            return RepeatStatus.FINISHED;
          }
        });
    taskletStep.execute(stepExecution);
    assertEquals(COMPLETED, stepExecution.getStatus());
    assertFalse(stepExecution.getFailureExceptions().contains(exception));
    assertEquals(3, jobRepository.getUpdateCount());
  }
 @Override
 public ExitStatus afterStep(StepExecution stepExecution) {
   if (!ExitStatus.FAILED.equals(stepExecution.getExitStatus())
       && stepExecution.getSkipCount() > 0) {
     return new ExitStatus("COMPLETED WITH SKIPS");
   } else {
     return stepExecution.getExitStatus();
   }
 }
  /**
   * Mock up the necessary job parameters
   *
   * @param outputFileName The filename we want the ItemWriter to write to
   */
  private StepExecution getStepExecution(String outputFileName) throws IOException {

    JobParameters jobParams = mock(JobParameters.class);
    when(jobParams.getString("output.file")).thenReturn(outputFileName);

    StepExecution stepExecution = mock(StepExecution.class);
    when(stepExecution.getJobParameters()).thenReturn(jobParams);

    return stepExecution;
  }
 @Test
 public void testSunnyDayFaultTolerant() throws Exception {
   JobExecution jobExecution =
       jobLauncher.run(
           job, new JobParameters(Collections.singletonMap("item.three", new JobParameter("3"))));
   assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
   StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
   assertEquals(9, stepExecution.getReadCount());
   assertEquals(9, stepExecution.getWriteCount());
 }
  @Test
  @Ignore // FIXME
  public void testTransactionException() throws Exception {

    final SkipWriterStub<String> writer = new SkipWriterStub<String>();
    FaultTolerantStepFactoryBean<String, String> factory =
        new FaultTolerantStepFactoryBean<String, String>();
    factory.setItemWriter(writer);

    @SuppressWarnings("serial")
    DataSourceTransactionManager transactionManager =
        new DataSourceTransactionManager(dataSource) {
          private boolean failed = false;

          @Override
          protected void doCommit(DefaultTransactionStatus status) throws TransactionException {
            if (writer.getWritten().isEmpty()
                || failed
                || !isExistingTransaction(status.getTransaction())) {
              super.doCommit(status);
              return;
            }
            failed = true;
            status.setRollbackOnly();
            super.doRollback(status);
            throw new UnexpectedRollbackException("Planned");
          }
        };

    factory.setBeanName("stepName");
    factory.setTransactionManager(transactionManager);
    factory.setCommitInterval(2);

    ItemReader<String> reader = new ListItemReader<String>(Arrays.asList("1", "2"));
    factory.setItemReader(reader);

    JobRepositoryFactoryBean repositoryFactory = new JobRepositoryFactoryBean();
    repositoryFactory.setDataSource(dataSource);
    repositoryFactory.setTransactionManager(transactionManager);
    repositoryFactory.afterPropertiesSet();
    JobRepository repository = repositoryFactory.getObject();
    factory.setJobRepository(repository);

    JobExecution jobExecution = repository.createJobExecution("job", new JobParameters());
    StepExecution stepExecution = jobExecution.createStepExecution(factory.getName());
    repository.add(stepExecution);

    Step step = factory.getObject();

    step.execute(stepExecution);
    assertEquals(BatchStatus.FAILED, stepExecution.getStatus());

    assertEquals("[]", writer.getCommitted().toString());
  }
 @Test
 public void testFailedStepOnError() throws Exception {
   JobExecution jobExecution =
       jobLauncher.run(
           job,
           new JobParameters(Collections.singletonMap("item.three", new JobParameter("error"))));
   assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
   StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
   assertEquals(9, stepExecution.getReadCount());
   // In principle the write count could be more than 2 and less than 9...
   assertEquals(7, stepExecution.getWriteCount());
 }
  public void alertEmail(StepExecution stepExecution) {
    try {

      String jobName = stepExecution.getJobExecution().getJobInstance().getJobName();
      String jobInstanceId = "" + stepExecution.getJobExecution().getJobInstance().getId();
      String jobExecutionId = "" + stepExecution.getJobExecution().getId();
      String stepExecutionId = "" + stepExecution.getId();

      SimpleMailMessage message = new SimpleMailMessage(this.templateMessage);
      message.setTo(emailTo);
      StringBuffer messageText = new StringBuffer();
      messageText.append("\n\n");
      messageText.append("This job fail: " + jobName + "\n");
      messageText.append("\n\n");
      messageText.append("## Job");
      messageText.append("\n\n");
      messageText.append("Name: " + jobName + "");
      messageText.append("\n");
      messageText.append("Id: " + jobInstanceId + "");
      messageText.append("\n");
      messageText.append("Job instance list url: " + urlPrefix + "jobs/" + jobName);
      messageText.append("\n\n");
      messageText.append("## Job Execution");
      messageText.append("\n\n");
      messageText.append(
          "Job execution list url: " + urlPrefix + "jobs/" + jobName + "/" + jobInstanceId);
      messageText.append("\n\n");
      messageText.append("## Step Error Details");
      messageText.append("\n\n");
      messageText.append(
          "Job execution url: " + urlPrefix + "jobs/executions/" + jobExecutionId + "");
      messageText.append("\n\n");
      messageText.append(
          "Job error details url: "
              + urlPrefix
              + "jobs/executions/"
              + jobExecutionId
              + "/steps/"
              + stepExecutionId
              + "/progress");
      messageText.append("\n\n");
      messageText.append("## Step Summary");
      messageText.append("\n\n");
      messageText.append("" + stepExecution.getSummary());
      message.setText(messageText.toString());
      this.mailSender.send(message);

    } catch (MailException e) {
      logger.error("erro with the email MailSender", e);
    }
  }
 @Test
 public void testExecuteException() throws Exception {
   step.setJob(
       new JobSupport("child") {
         @Override
         public void execute(JobExecution execution) throws UnexpectedJobExecutionException {
           throw new RuntimeException("FOO");
         }
       });
   step.afterPropertiesSet();
   step.execute(stepExecution);
   assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
   assertEquals("FOO", stepExecution.getFailureExceptions().get(0).getMessage());
 }
 @Test
 public void testInterruptedWithCustomStatus() throws Exception {
   taskletStep.setTasklet(
       new Tasklet() {
         public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)
             throws Exception {
           contribution.setExitStatus(new ExitStatus("FUNNY"));
           throw new JobInterruptedException("Planned");
         }
       });
   taskletStep.execute(stepExecution);
   assertEquals(STOPPED, stepExecution.getStatus());
   assertEquals("FUNNY", stepExecution.getExitStatus().getExitCode());
 }
 @Test
 public void testSkipsInWriter() throws Exception {
   JobExecution jobExecution =
       jobLauncher.run(
           job,
           new JobParametersBuilder()
               .addString("item.three", "fail")
               .addLong("run.id", 1L)
               .toJobParameters());
   assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
   StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
   assertEquals(9, stepExecution.getReadCount());
   assertEquals(7, stepExecution.getWriteCount());
   // The whole chunk gets skipped...
   assertEquals(2, stepExecution.getWriteSkipCount());
 }
 @Test
 public void testNextStatus() {
   // Step 에서 Write 작업이 5번 일어났다면...
   stepExecution.setWriteCount(5);
   FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
   assertThat(status.getName()).isEqualTo("NEXT");
 }
 @Test
 public void testCompletedStatus() {
   // Step에서 Write 작업이 한번도 일어나지 않았다면... 더 이상 할 일이 없다...
   stepExecution.setWriteCount(0);
   FlowExecutionStatus status = decider.decide(jobExecution, stepExecution);
   assertThat(status).isEqualTo(FlowExecutionStatus.COMPLETED);
 }
  public Collection<StepExecution> getStepExecutions(Long jobExecutionId)
      throws NoSuchJobExecutionException {

    JobExecution jobExecution = jobExecutionDao.getJobExecution(jobExecutionId);
    if (jobExecution == null) {
      throw new NoSuchJobExecutionException("No JobExecution with id=" + jobExecutionId);
    }

    stepExecutionDao.addStepExecutions(jobExecution);

    String jobName =
        jobExecution.getJobInstance() == null ? null : jobExecution.getJobInstance().getJobName();
    Collection<String> missingStepNames = new LinkedHashSet<String>();

    if (jobName != null) {
      missingStepNames.addAll(
          stepExecutionDao.findStepNamesForJobExecution(jobName, "*:partition*"));
      logger.debug("Found step executions in repository: " + missingStepNames);
    }

    Job job = null;
    try {
      job = jobLocator.getJob(jobName);
    } catch (NoSuchJobException e) {
      // expected
    }
    if (job instanceof StepLocator) {
      Collection<String> stepNames = ((StepLocator) job).getStepNames();
      missingStepNames.addAll(stepNames);
      logger.debug("Added step executions from job: " + missingStepNames);
    }

    for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
      String stepName = stepExecution.getStepName();
      if (missingStepNames.contains(stepName)) {
        missingStepNames.remove(stepName);
      }
      logger.debug("Removed step executions from job execution: " + missingStepNames);
    }

    for (String stepName : missingStepNames) {
      StepExecution stepExecution = jobExecution.createStepExecution(stepName);
      stepExecution.setStatus(BatchStatus.UNKNOWN);
    }

    return jobExecution.getStepExecutions();
  }
 public Collection<String> getStepNamesForJob(String jobName) throws NoSuchJobException {
   try {
     Job job = jobLocator.getJob(jobName);
     if (job instanceof StepLocator) {
       return ((StepLocator) job).getStepNames();
     }
   } catch (NoSuchJobException e) {
     // ignore
   }
   Collection<String> stepNames = new LinkedHashSet<String>();
   for (JobExecution jobExecution : listJobExecutionsForJob(jobName, 0, 100)) {
     for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
       stepNames.add(stepExecution.getStepName());
     }
   }
   return Collections.unmodifiableList(new ArrayList<String>(stepNames));
 }
  @Test
  @SuppressWarnings({"unchecked", "rawtypes"})
  public void testWrite() throws Exception {
    File file = new File(tmpDir, "foo.txt");
    file.delete();

    ByteArrayInputStream data = new ByteArrayInputStream("foobarbaz".getBytes());
    Session session = mock(Session.class);
    SessionFactory factory = mock(SessionFactory.class);
    when(factory.getSession()).thenReturn(session);
    when(session.readRaw("foo.txt")).thenReturn(data);
    when(session.finalizeRaw()).thenReturn(true);

    StepExecution stepExecution = new StepExecution("foo", null);
    ExecutionContext stepExecutionContext = new ExecutionContext();
    stepExecutionContext.putString("filePath", "foo.txt");
    stepExecution.setExecutionContext(stepExecutionContext);
    StepContext stepContext = new StepContext(stepExecution);
    ChunkContext chunkContext = new ChunkContext(stepContext);

    RemoteFileTemplate template = new RemoteFileTemplate(factory);
    template.setBeanFactory(mock(BeanFactory.class));
    template.afterPropertiesSet();

    // clean up from old tests
    FileSystem fs = FileSystem.get(configuration);
    Path p = new Path("/qux/foo.txt");
    fs.delete(p, true);
    assertFalse(fs.exists(p));

    RemoteFileToHadoopTasklet tasklet =
        new RemoteFileToHadoopTasklet(template, configuration, "/qux");

    assertEquals(RepeatStatus.FINISHED, tasklet.execute(null, chunkContext));

    assertTrue(fs.exists(p));

    FSDataInputStream stream = fs.open(p);
    byte[] out = new byte[9];
    stream.readFully(out);
    stream.close();
    assertEquals("foobarbaz", new String(out));

    fs.close();
  }
  public void afterJob(JobExecution jobExecution) {
    StringBuilder protocol = new StringBuilder();
    protocol.append("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");
    protocol.append("Protocol for " + jobExecution.getJobInstance().getJobName() + " \n");
    protocol.append("  Started     : " + jobExecution.getStartTime() + "\n");
    protocol.append("  Finished    : " + jobExecution.getEndTime() + "\n");
    protocol.append("  Exit-Code   : " + jobExecution.getExitStatus().getExitCode() + "\n");
    protocol.append("  Exit-Descr. : " + jobExecution.getExitStatus().getExitDescription() + "\n");
    protocol.append("  Status      : " + jobExecution.getStatus() + "\n");
    protocol.append("+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");

    protocol.append("Job-Parameter: \n");
    JobParameters jp = jobExecution.getJobParameters();
    for (Iterator<Entry<String, JobParameter>> iter = jp.getParameters().entrySet().iterator();
        iter.hasNext(); ) {
      Entry<String, JobParameter> entry = iter.next();
      protocol.append("  " + entry.getKey() + "=" + entry.getValue() + "\n");
    }
    protocol.append("+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");

    for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
      protocol.append("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");
      protocol.append("Step " + stepExecution.getStepName() + " \n");
      protocol.append("WriteCount: " + stepExecution.getWriteCount() + "\n");
      protocol.append("Commits: " + stepExecution.getCommitCount() + "\n");
      protocol.append("SkipCount: " + stepExecution.getSkipCount() + "\n");
      protocol.append("Rollbacks: " + stepExecution.getRollbackCount() + "\n");
      protocol.append("Filter: " + stepExecution.getFilterCount() + "\n");
      protocol.append("+++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n");
    }
    LOGGER.info(protocol.toString());
  }
  @Test
  public void testDecisionUnmappedExitStatus() throws Exception {
    ApplicationContext context =
        new GenericXmlApplicationContext(
            "classpath:/org/springframework/batch/core/jsr/step/DecisionStepTests-decisionInvalidExitStatus-context.xml");

    JobLauncher launcher = context.getBean(JobLauncher.class);
    Job job = context.getBean(Job.class);

    JobExecution execution = launcher.run(job, new JobParameters());
    assertEquals(BatchStatus.COMPLETED, execution.getStatus());
    assertEquals(2, execution.getStepExecutions().size());

    for (org.springframework.batch.core.StepExecution curExecution :
        execution.getStepExecutions()) {
      assertEquals(BatchStatus.COMPLETED, curExecution.getStatus());
    }
  }
  @Test
  public void testBeforeStepFailure() throws Exception {

    final RuntimeException exception = new RuntimeException();
    taskletStep.setStepExecutionListeners(
        new StepExecutionListenerSupport[] {
          new StepExecutionListenerSupport() {
            @Override
            public void beforeStep(StepExecution stepExecution) {
              throw exception;
            }
          }
        });
    taskletStep.execute(stepExecution);
    assertEquals(FAILED, stepExecution.getStatus());
    assertTrue(stepExecution.getFailureExceptions().contains(exception));
    assertEquals(2, jobRepository.getUpdateCount());
  }
 public StepExecution getStepExecution(Long jobExecutionId, Long stepExecutionId)
     throws NoSuchJobExecutionException, NoSuchStepExecutionException {
   JobExecution jobExecution = getJobExecution(jobExecutionId);
   StepExecution stepExecution = stepExecutionDao.getStepExecution(jobExecution, stepExecutionId);
   if (stepExecution == null) {
     throw new NoSuchStepExecutionException(
         "There is no StepExecution with jobExecutionId="
             + jobExecutionId
             + " and id="
             + stepExecutionId);
   }
   try {
     stepExecution.setExecutionContext(executionContextDao.getExecutionContext(stepExecution));
   } catch (Exception e) {
     logger.info("Cannot load execution context for step execution: " + stepExecution);
   }
   return stepExecution;
 }
  @Test
  public void testOpenFailure() throws Exception {
    final RuntimeException exception = new RuntimeException();
    taskletStep.setStreams(
        new ItemStream[] {
          new ItemStreamSupport() {
            @Override
            public void open(ExecutionContext executionContext) throws ItemStreamException {
              throw exception;
            }
          }
        });

    taskletStep.execute(stepExecution);
    assertEquals(FAILED, stepExecution.getStatus());
    assertTrue(stepExecution.getFailureExceptions().contains(exception));
    assertEquals(2, jobRepository.getUpdateCount());
  }
 public String getJobFailDescription(String jobName) {
   String failDescription = null;
   JobExplorer explorer = getBatchJobExplorer();
   List<JobInstance> jobInstances = explorer.getJobInstances(jobName, 0, 1);
   if (jobInstances.size() > 0) {
     List<JobExecution> jobExecutions = explorer.getJobExecutions(jobInstances.get(0));
     if (jobExecutions.size() > 0) {
       Collection<StepExecution> steps = jobExecutions.get(0).getStepExecutions();
       if (steps.size() > 0) {
         StepExecution step = steps.iterator().next();
         if (!step.getExitStatus().getExitDescription().isEmpty()) {
           failDescription = step.getExitStatus().getExitDescription();
         }
       }
     }
   }
   return failDescription;
 }
  @Test
  public void testRepositoryErrorOnFailure() throws Exception {

    taskletStep.setTasklet(
        new Tasklet() {

          public RepeatStatus execute(StepContribution contribution, ChunkContext attributes)
              throws Exception {
            throw new RuntimeException("Tasklet exception");
          }
        });

    jobRepository.setFailOnUpdateExecutionContext(true);
    taskletStep.execute(stepExecution);
    assertEquals(UNKNOWN, stepExecution.getStatus());
    Throwable e = stepExecution.getFailureExceptions().get(0);
    assertEquals("Expected exception in step execution context persistence", e.getMessage());
  }
  @Test
  public void testRepositoryErrorOnUpdateStepExecution() throws Exception {

    taskletStep.setTasklet(
        new Tasklet() {

          public RepeatStatus execute(StepContribution contribution, ChunkContext attributes)
              throws Exception {
            return RepeatStatus.FINISHED;
          }
        });

    jobRepository.setFailOnUpdateStepExecution(1);
    taskletStep.execute(stepExecution);
    assertEquals(UNKNOWN, stepExecution.getStatus());
    Throwable e = stepExecution.getFailureExceptions().get(0);
    assertEquals("JobRepository failure forcing exit with unknown status", e.getMessage());
  }