org.springframework.batch.core.step.tasklet.SystemCommandTaskletIntegrationTests.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.batch.core.step.tasklet.SystemCommandTaskletIntegrationTests.java

Source

/*
 * Copyright 2008-2013 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.batch.core.step.tasklet;

import java.io.File;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.scope.context.StepContext;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.util.Assert;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;

/**
 * Tests for {@link SystemCommandTasklet}.
 */
public class SystemCommandTaskletIntegrationTests {

    private static final Log log = LogFactory.getLog(SystemCommandTaskletIntegrationTests.class);

    private SystemCommandTasklet tasklet;

    private StepExecution stepExecution = new StepExecution("systemCommandStep", new JobExecution(
            new JobInstance(1L, "systemCommandJob"), 1L, new JobParameters(), "configurationName"));

    @Mock
    private JobExplorer jobExplorer;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        initializeTasklet();
        tasklet.afterPropertiesSet();

        tasklet.beforeStep(stepExecution);
    }

    private void initializeTasklet() {
        tasklet = new SystemCommandTasklet();
        tasklet.setEnvironmentParams(null); // inherit from parent process
        tasklet.setWorkingDirectory(null); // inherit from parent process
        tasklet.setSystemProcessExitCodeMapper(new TestExitCodeMapper());
        tasklet.setTimeout(5000); // long enough timeout
        tasklet.setTerminationCheckInterval(500);
        tasklet.setCommand("invalid command, change value for successful execution");
        tasklet.setInterruptOnCancel(true);
        tasklet.setTaskExecutor(new SimpleAsyncTaskExecutor());
    }

    /*
     * Regular usage scenario - successful execution of system command.
     */
    @Test
    public void testExecute() throws Exception {
        String command = getJavaCommand() + " --version";
        tasklet.setCommand(command);
        tasklet.afterPropertiesSet();

        log.info("Executing command: " + command);
        RepeatStatus exitStatus = tasklet.execute(stepExecution.createStepContribution(), null);

        assertEquals(RepeatStatus.FINISHED, exitStatus);
    }

    /*
     * Failed execution scenario - error exit code returned by system command.
     */
    @Test
    public void testExecuteFailure() throws Exception {
        String command = getJavaCommand() + " org.springframework.batch.sample.tasklet.UnknownClass";
        tasklet.setCommand(command);
        tasklet.setTimeout(200L);
        tasklet.afterPropertiesSet();

        log.info("Executing command: " + command);
        try {
            StepContribution contribution = stepExecution.createStepContribution();
            RepeatStatus exitStatus = tasklet.execute(contribution, null);
            assertEquals(RepeatStatus.FINISHED, exitStatus);
            assertEquals(ExitStatus.FAILED, contribution.getExitStatus());
        } catch (RuntimeException e) {
            // on some platforms the system call does not return
            assertEquals("Execution of system command did not finish within the timeout", e.getMessage());
        }
    }

    /*
     * The attempt to execute the system command results in exception
     */
    @Test(expected = java.util.concurrent.ExecutionException.class)
    public void testExecuteException() throws Exception {
        String command = "non-sense-that-should-cause-exception-when-attempted-to-execute";
        tasklet.setCommand(command);
        tasklet.afterPropertiesSet();

        tasklet.execute(null, null);
    }

    /*
     * Failed execution scenario - execution time exceeds timeout.
     */
    @Test
    public void testExecuteTimeout() throws Exception {
        String command = System.getProperty("os.name").toLowerCase().contains("win") ? "ping 1.1.1.1 -n 1 -w 3000"
                : "sleep 3";
        tasklet.setCommand(command);
        tasklet.setTimeout(10);
        tasklet.afterPropertiesSet();

        log.info("Executing command: " + command);
        try {
            tasklet.execute(null, null);
            fail();
        } catch (SystemCommandException e) {
            assertTrue(e.getMessage().contains("did not finish within the timeout"));
        }
    }

    /*
     * Job interrupted scenario.
     */
    @Test
    public void testInterruption() throws Exception {
        String command = System.getProperty("os.name").toLowerCase().contains("win") ? "ping 1.1.1.1 -n 1 -w 5000"
                : "sleep 5";
        tasklet.setCommand(command);
        tasklet.setTerminationCheckInterval(10);
        tasklet.afterPropertiesSet();

        stepExecution.setTerminateOnly();
        try {
            tasklet.execute(null, null);
            fail();
        } catch (JobInterruptedException e) {
            System.out.println(e.getMessage());
            assertTrue(e.getMessage().contains("Job interrupted while executing system command"));
            assertTrue(e.getMessage().contains(command));
        }
    }

    /*
     * Command property value is required to be set.
     */
    @Test
    public void testCommandNotSet() throws Exception {
        tasklet.setCommand(null);
        try {
            tasklet.afterPropertiesSet();
            fail();
        } catch (IllegalArgumentException e) {
            // expected
        }

        tasklet.setCommand("");
        try {
            tasklet.afterPropertiesSet();
            fail();
        } catch (IllegalArgumentException e) {
            // expected
        }
    }

    /*
     * Timeout must be set to non-zero value.
     */
    @Test
    public void testTimeoutNotSet() throws Exception {
        tasklet.setCommand("not-empty placeholder");
        tasklet.setTimeout(0);
        try {
            tasklet.afterPropertiesSet();
            fail();
        } catch (IllegalArgumentException e) {
            // expected
        }
    }

    /*
     * Working directory property must point to an existing location and it must
     * be a directory
     */
    @Test
    public void testWorkingDirectory() throws Exception {
        File notExistingFile = new File("not-existing-path");
        Assert.state(!notExistingFile.exists());

        try {
            tasklet.setWorkingDirectory(notExistingFile.getCanonicalPath());
            fail();
        } catch (IllegalArgumentException e) {
            // expected
        }

        File notDirectory = File.createTempFile(this.getClass().getName(), null);
        Assert.state(notDirectory.exists());
        Assert.state(!notDirectory.isDirectory());

        try {
            tasklet.setWorkingDirectory(notDirectory.getCanonicalPath());
            fail();
        } catch (IllegalArgumentException e) {
            // expected
        }

        File directory = notDirectory.getParentFile();
        Assert.state(directory.exists());
        Assert.state(directory.isDirectory());

        // no error expected now
        tasklet.setWorkingDirectory(directory.getCanonicalPath());
    }

    /*
     * test stopping a tasklet
     */
    @Test
    public void testStopped() throws Exception {
        initializeTasklet();
        tasklet.setJobExplorer(jobExplorer);
        tasklet.afterPropertiesSet();
        tasklet.beforeStep(stepExecution);

        JobExecution stoppedJobExecution = new JobExecution(stepExecution.getJobExecution());
        stoppedJobExecution.setStatus(BatchStatus.STOPPING);

        when(jobExplorer.getJobExecution(1L)).thenReturn(stepExecution.getJobExecution(),
                stepExecution.getJobExecution(), stoppedJobExecution);

        String command = System.getProperty("os.name").toLowerCase().contains("win") ? "ping 1.1.1.1 -n 1 -w 5000"
                : "sleep 15";
        tasklet.setCommand(command);
        tasklet.setTerminationCheckInterval(10);
        tasklet.afterPropertiesSet();

        StepContribution contribution = stepExecution.createStepContribution();
        StepContext stepContext = new StepContext(stepExecution);
        ChunkContext chunkContext = new ChunkContext(stepContext);
        tasklet.execute(contribution, chunkContext);

        assertEquals(contribution.getExitStatus().getExitCode(), ExitStatus.STOPPED.getExitCode());
    }

    private String getJavaCommand() {
        String javaHome = System.getProperty("java.home");
        String fileSeparator = System.getProperty("file.separator");
        StringBuilder command = new StringBuilder();
        command.append(javaHome);
        command.append(fileSeparator);
        command.append("bin");
        command.append(fileSeparator);
        command.append("java");

        if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) {
            command.append(".exe");
        }

        return command.toString();
    }

    /**
     * Exit code mapper containing mapping logic expected by the tests. 0 means
     * finished successfully, other value means failure.
     */
    private static class TestExitCodeMapper implements SystemProcessExitCodeMapper {

        @Override
        public ExitStatus getExitStatus(int exitCode) {
            if (exitCode == 0) {
                return ExitStatus.COMPLETED;
            } else {
                return ExitStatus.FAILED;
            }
        }

    }

}