/* * Copyright 2013-2015 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.admin.web; import static org.hamcrest.Matchers.contains; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.Arrays; import java.util.Date; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.batch.admin.service.JobSupport; import org.springframework.batch.core.BatchStatus; 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.StepExecution; import org.springframework.batch.core.configuration.JobLocator; import org.springframework.batch.core.job.DefaultJobParametersValidator; import org.springframework.batch.core.job.SimpleJob; import org.springframework.batch.core.launch.JobExecutionNotRunningException; import org.springframework.batch.core.launch.NoSuchJobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; /** * Tests REST compliance of {@link BatchJobExecutionsController} endpoints. * * @author Ilayaperumal Gopinathan * @author Gunnar Hillert * @author Michael Minella */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TestDependencies.class, RestConfiguration.class}) @WebAppConfiguration public class BatchJobExecutionsControllerIntegrationTests extends AbstractControllerIntegrationTest { @Autowired private JobLocator jobLocator; private JobExecution execution1; private JobExecution execution2; @SuppressWarnings("unchecked") @Before public void before() throws Exception { JobInstance jobInstance1 = new JobInstance(2l, "job1"); JobInstance jobInstance2 = new JobInstance(0l, "job1"); execution1 = new JobExecution(jobInstance1, 3l, new JobParametersBuilder().addString("param1", "test").addLong("param2", 123l, false).toJobParameters(), null); execution1.setLastUpdated(new Date()); execution2 = new JobExecution(jobInstance2, 0l, new JobParametersBuilder().addString("param1", "test").addLong("param2", 123l, false).toJobParameters(), null); execution2.setLastUpdated(new Date()); StepExecution step1 = new StepExecution("step1", execution2); step1.setLastUpdated(new Date()); step1.setId(1l); StepExecution step2 = new StepExecution("step2", execution2); step2.setLastUpdated(new Date()); step2.setId(4l); execution2.addStepExecutions(Arrays.asList(step1, step2)); } @Test public void testGetJobExecutionsByName() throws Exception { when(jobService.listJobExecutionsForJob("job1", 0, 20)).thenReturn(Arrays.asList(execution1)); when(jobLocator.getJob("job1")).thenReturn(new JobSupport("job1")); when(jobService.countJobExecutions()).thenReturn(1); mockMvc.perform( get("/batch/executions").param("jobname", "job1").param("startJobInstance", "0").param("pageSize", "20").accept( MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk()) .andExpect(jsonPath("$.pagedResources.content", Matchers.hasSize(1))) .andExpect(jsonPath("$.pagedResources.content[0].executionId").value(3)) .andExpect(jsonPath("$.pagedResources.content[0].jobId").value(2)) .andExpect( jsonPath("$.pagedResources.content[0].jobParameters.parameters.param1.value").value("test")) .andExpect( jsonPath("$.pagedResources.content[0].jobParameters.parameters.param1.type").value("STRING")) .andExpect(jsonPath("$.pagedResources.content[0].jobParameters.parameters.param1.identifying").value( true)) .andExpect( jsonPath("$.pagedResources.content[0].jobParameters.parameters.param2.value").value(123)) .andExpect( jsonPath("$.pagedResources.content[0].jobParameters.parameters.param2.type").value("LONG")) .andExpect(jsonPath("$.pagedResources.content[0].jobParameters.parameters.param2.identifying").value( false)); } @Test public void testGetBatchJobExecutions() throws Exception { when(jobService.listJobExecutions(0, 20)).thenReturn(Arrays.asList(execution2, execution1)); when(jobLocator.getJob("job1")).thenReturn(new JobSupport("job1")); when(jobService.countJobExecutions()).thenReturn(1); mockMvc.perform( get("/batch/executions").accept( MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk()) .andExpect(jsonPath("$.pagedResources.content", Matchers.hasSize(2))) .andExpect(jsonPath("$.pagedResources.content[*].executionId", contains(0, 3))) .andExpect(jsonPath("$.pagedResources.content[*].stepExecutions", Matchers.hasSize(2))) .andExpect(jsonPath("$.pagedResources.content[*].jobId", contains(0, 2))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param1.value", contains("test", "test"))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param1.type", contains("STRING", "STRING"))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param1.identifying", contains(true, true))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param2.value", contains(123, 123))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param2.type", contains("LONG", "LONG"))) .andExpect(jsonPath("$.pagedResources.content[*].jobParameters.parameters.param2.identifying", contains(false, false))); } @Test public void testGetBatchJobExecutionsPaginated() throws Exception { when(jobService.listJobExecutions(5, 5)).thenReturn(Arrays.asList(execution2, execution1)); when(jobLocator.getJob("job1")).thenReturn(new JobSupport("job1")); when(jobService.countJobExecutions()).thenReturn(1); mockMvc.perform( get("/batch/executions").param("page", "1").param("size", "5").accept( MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect( jsonPath("$.pagedResources.content[*]", Matchers.hasSize(2))); } @Test public void testGetSingleBatchJobExecution() throws Exception { when(jobService.getJobExecution(0l)).thenReturn(execution2); when(jobLocator.getJob("job1")).thenReturn(new JobSupport("job1")); mockMvc.perform( get("/batch/executions/0").accept(MediaType.APPLICATION_JSON)).andDo(print()).andExpect(status().isOk()) .andExpect(jsonPath("$.jobExecutionInfoResource.executionId", Matchers.is(0))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param1.type", Matchers.is("STRING"))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param1.identifying", Matchers.is(true))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param1.value", Matchers.is("test"))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param2.type", Matchers.is("LONG"))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param2.identifying", Matchers.is(false))) .andExpect(jsonPath("$.jobExecutionInfoResource.jobParameters.parameters.param2.value", Matchers.is(123))) .andExpect(jsonPath("$.jobExecutionInfoResource.stepExecutions", Matchers.hasSize(2))) .andExpect(jsonPath("$.jobExecutionInfoResource.stepExecutionCount", Matchers.is(2))) .andExpect(jsonPath("$.jobExecutionInfoResource.name", Matchers.is("job1"))); } @Test public void testGetNonExistingBatchJobExecution() throws Exception { when(jobService.getJobExecution(99999l)).thenThrow(new NoSuchJobExecutionException("Could not find jobExecution with id 99999")); mockMvc.perform(get("/batch/executions/99999").accept(MediaType.APPLICATION_JSON)) .andExpect(status().isNotFound()).andDo(print()) .andExpect(jsonPath("$[1][0].message", Matchers.is("Could not find jobExecution with id 99999"))); } @Test public void testStopAllJobExecutions() throws Exception { mockMvc.perform(put("/batch/executions?stop=true")).andExpect(status().isOk()); verify(jobService).stopAll(); } @Test public void testStopJobExecution() throws Exception { mockMvc.perform(put("/batch/executions/{executionId}?stop=true", "0")).andExpect(status().isOk()); verify(jobService).stop(0l); } @Test public void testRestartNonExistingJobExecution() throws Exception { when(jobService.getJobExecution(1234l)).thenThrow(new NoSuchJobExecutionException("")); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "1234")).andExpect(status().isNotFound()).andExpect( jsonPath("$[1][0].message", Matchers.is("Could not find jobExecution with id 1234"))); } @Test public void testRestartAlreadyRunningJobExecution() throws Exception { JobInstance instance = new JobInstance(4l, "job4running"); JobExecution execution = new JobExecution(instance, 4l, new JobParameters(), null); when(jobService.getJobExecution(4l)).thenReturn(execution); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "4")).andExpect(status().isBadRequest()).andExpect( jsonPath( "$[1][0].message", Matchers.is("Job Execution for this job is already running: JobInstance: id=4, version=null, Job=[job4running]"))); } @Test public void testRestartAlreadyCompleteJobExecution() throws Exception { JobInstance instance = new JobInstance(33l, "job4running"); JobExecution execution = new JobExecution(instance, 33l, new JobParameters(), null); execution.setEndTime(new Date()); execution.upgradeStatus(BatchStatus.COMPLETED); when(jobService.getJobExecution(33l)).thenReturn(execution); when(jobLocator.getJob("job4running")).thenReturn(new JobSupport("job4running")); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "33")).andExpect(status().isBadRequest()).andExpect( jsonPath("$[1][0].message", Matchers.is("Job Execution 33 is already complete."))); } @Test public void testRestartJobExecutionWithJobNotAvailable() throws Exception { when(jobService.getJobExecution(3333l)).thenThrow(new NoSuchJobExecutionException("")); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "3333")).andExpect(status().isNotFound()).andExpect( jsonPath("$[1][0].message", Matchers.is("Could not find jobExecution with id 3333"))); } @Test public void testRestartJobExecutionWithInvalidJobParameters() throws Exception { JobInstance instance = new JobInstance(5l, "job4running"); JobExecution execution = new JobExecution(instance, 5l, new JobParameters(), null); execution.setEndTime(new Date()); SimpleJob job4running = new SimpleJob("job4running"); DefaultJobParametersValidator validator = new DefaultJobParametersValidator(); validator.setRequiredKeys(new String [] {"missing-key"}); job4running.setJobParametersValidator(validator); when(jobService.getJobExecution(5l)).thenReturn(execution); when(jobLocator.getJob("job4running")).thenReturn(job4running); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "5")).andExpect(status().isBadRequest()).andExpect( jsonPath("$[1][0].message", Matchers.is("The Job Parameters for Job Execution 5 are invalid."))); } @Test public void testRestartNonRestartableJob() throws Exception { JobInstance instance = new JobInstance(2l, "job2"); JobExecution execution = new JobExecution(instance, 2l, new JobParameters(), null); execution.setEndTime(new Date()); SimpleJob job4running = new SimpleJob("job2"); job4running.setRestartable(false); when(jobService.getJobExecution(2l)).thenReturn(execution); when(jobLocator.getJob("job2")).thenReturn(job4running); mockMvc.perform(put("/batch/executions/{executionId}?restart=true", "2")).andExpect(status().isBadRequest()).andExpect( jsonPath("$[1][0].message", Matchers.is("The job 'job2' is not restartable."))); } @Test public void testStopJobExecutionNotRunning() throws Exception { when(jobService.stop(3l)).thenThrow(new JobExecutionNotRunningException("")); mockMvc.perform(put("/batch/executions/{executionId}?stop=true", "3")).andExpect(status().isNotFound()).andDo(print()).andExpect( jsonPath("$[1][0].message", Matchers.is("Job execution with executionId 3 is not running."))); } @Test public void testStopJobExecutionNotExists() throws Exception { when(jobService.stop(5l)).thenThrow(new NoSuchJobExecutionException("")); mockMvc.perform(put("/batch/executions/{executionId}?stop=true", "5")).andExpect(status().isNotFound()).andExpect( jsonPath("$[1][0].message", Matchers.is("Could not find jobExecution with id 5"))); } }