/* * Copyright 2016-2019 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 * * https://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.partition; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeoutException; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobInstance; import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.partition.StepExecutionSplitter; import org.springframework.cloud.deployer.spi.core.AppDefinition; import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest; import org.springframework.cloud.deployer.spi.task.TaskLauncher; import org.springframework.cloud.task.repository.TaskExecution; import org.springframework.cloud.task.repository.TaskRepository; import org.springframework.core.env.Environment; import org.springframework.core.io.Resource; import org.springframework.mock.env.MockEnvironment; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** * @author Michael Minella * @author Glenn Renfro */ public class DeployerPartitionHandlerTests { @Captor ArgumentCaptor<AppDeploymentRequest> appDeploymentRequestArgumentCaptor; @Mock private TaskLauncher taskLauncher; @Mock private JobExplorer jobExplorer; @Mock private Resource resource; @Mock private StepExecutionSplitter splitter; @Mock private TaskRepository taskRepository; private Environment environment; @Before public void setUp() { MockitoAnnotations.initMocks(this); this.environment = new MockEnvironment(); TaskExecution taskExecution = new TaskExecution(2, 0, "name", new Date(), new Date(), "", Collections.emptyList(), null, null, null); when(taskRepository.createTaskExecution()).thenReturn(taskExecution); } @Test public void testDeprecatedConstructorValidation() { validateDeprecatedConstructorValidation(null, null, null, null, "A taskLauncher is required"); validateDeprecatedConstructorValidation(this.taskLauncher, null, null, null, "A jobExplorer is required"); validateDeprecatedConstructorValidation(this.taskLauncher, this.jobExplorer, null, null, "A resource is required"); validateDeprecatedConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource, null, "A step name is required"); new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step-name"); } @Test public void testConstructorValidation() { validateConstructorValidation(null, null, null, null, null, "A taskLauncher is required"); validateConstructorValidation(this.taskLauncher, null, null, null, null, "A jobExplorer is required"); validateConstructorValidation(this.taskLauncher, this.jobExplorer, null, null, null, "A resource is required"); validateConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource, null, null, "A step name is required"); validateConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource, null, null, "A step name is required"); validateConstructorValidation(this.taskLauncher, this.jobExplorer, this.resource, "step-name", null, "A TaskRepository is required"); new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step-name", this.taskRepository); } @Test public void testNoPartitions() throws Exception { DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1"); handler.setEnvironment(this.environment); StepExecution stepExecution = new StepExecution("step1", new JobExecution(1L)); when(this.splitter.split(stepExecution, 1)).thenReturn(new HashSet<>()); Collection<StepExecution> results = handler.handle(this.splitter, stepExecution); verify(this.taskLauncher, never()).launch((AppDeploymentRequest) any()); assertThat(results.isEmpty()).isTrue(); } @Test public void testSinglePartition() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDeploymentProperties().size()).isEqualTo(0); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue(); assertThat(request.getCommandlineArguments() .contains(formatArgs("spring.cloud.task.executionid", "2"))).isTrue(); assertThat(results.size()).isEqualTo(1); StepExecution resultStepExecution = results.iterator().next(); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1"); } @Test public void testSinglePartitionAsEnvVars() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setDefaultArgsAsEnvironmentVars(true); TaskExecution taskExecution = new TaskExecution(55, null, null, null, null, null, new ArrayList<>(), null, null); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDeploymentProperties().size()).isEqualTo(0); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().isEmpty()).isTrue(); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID)) .isEqualTo("1"); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) .isEqualTo("4"); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME)) .isEqualTo("step1"); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_NAME)) .isEqualTo("partitionedJobTask_partitionedJob_step1:partition1"); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID)) .isEqualTo("55"); assertThat(request.getDefinition().getProperties() .get(DeployerPartitionHandler.SPRING_CLOUD_TASK_EXECUTION_ID)) .isEqualTo("2"); assertThat(results.size()).isEqualTo(1); StepExecution resultStepExecution = results.iterator().next(); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1"); } @Test public void testParentExecutionId() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); TaskExecution taskExecution = new TaskExecution(55, null, null, null, null, null, new ArrayList<>(), null, null); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_PARENT_EXECUTION_ID, "55"))) .isTrue(); } @Test public void testThreePartitions() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish( workerStepExecutionStart3, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart3); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); when(this.jobExplorer.getStepExecution(1L, 6L)) .thenReturn(workerStepExecutionFinish3); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher, times(3)) .launch(this.appDeploymentRequestArgumentCaptor.capture()); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor .getAllValues(); validateAppDeploymentRequests(allValues, 3); validateStepExecutionResults(results); } @Test public void testThreePartitionsTwoWorkers() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish( workerStepExecutionStart3, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setMaxWorkers(2); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart3); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); when(this.jobExplorer.getStepExecution(1L, 6L)) .thenReturn(workerStepExecutionFinish3); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher, times(3)) .launch(this.appDeploymentRequestArgumentCaptor.capture()); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor .getAllValues(); validateAppDeploymentRequests(allValues, 3); validateStepExecutionResults(results); } @Test public void testFailedWorker() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.FAILED); StepExecution workerStepExecutionStart3 = getStepExecutionStart(jobExecution, 6L); StepExecution workerStepExecutionFinish3 = getStepExecutionFinish( workerStepExecutionStart3, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setMaxWorkers(2); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); stepExecutions.add(workerStepExecutionStart3); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); when(this.jobExplorer.getStepExecution(1L, 6L)) .thenReturn(workerStepExecutionFinish3); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher, times(3)) .launch(this.appDeploymentRequestArgumentCaptor.capture()); List<AppDeploymentRequest> allValues = this.appDeploymentRequestArgumentCaptor .getAllValues(); validateAppDeploymentRequests(allValues, 3); Iterator<StepExecution> resultsIterator = results.iterator(); Set<String> names = new HashSet<>(results.size()); while (resultsIterator.hasNext()) { StepExecution curResult = resultsIterator.next(); if (curResult.getStepName().equals("step1:partition2")) { assertThat(curResult.getStatus()).isEqualTo(BatchStatus.FAILED); } else { assertThat(curResult.getStatus()).isEqualTo(BatchStatus.COMPLETED); } assertThat(!names.contains(curResult.getStepName())).isTrue(); names.add(curResult.getStepName()); } } @Test public void testPassingEnvironmentProperties() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); Map<String, String> environmentParameters = new HashMap<>(2); environmentParameters.put("foo", "bar"); environmentParameters.put("baz", "qux"); SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider( this.environment); environmentVariablesProvider.setEnvironmentProperties(environmentParameters); handler.setEnvironmentVariablesProvider(environmentVariablesProvider); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDefinition().getProperties().size()).isEqualTo(2); assertThat(request.getDefinition().getProperties().get("foo")).isEqualTo("bar"); assertThat(request.getDefinition().getProperties().get("baz")).isEqualTo("qux"); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue(); assertThat(results.size()).isEqualTo(1); StepExecution resultStepExecution = results.iterator().next(); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1"); } @Test public void testOverridingEnvironmentProperties() throws Exception { ((MockEnvironment) this.environment).setProperty("foo", "zoo"); ((MockEnvironment) this.environment).setProperty("task", "batch"); StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); Map<String, String> environmentParameters = new HashMap<>(2); environmentParameters.put("foo", "bar"); environmentParameters.put("baz", "qux"); SimpleEnvironmentVariablesProvider environmentVariablesProvider = new SimpleEnvironmentVariablesProvider( this.environment); environmentVariablesProvider.setEnvironmentProperties(environmentParameters); handler.setEnvironmentVariablesProvider(environmentVariablesProvider); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDefinition().getProperties().size()).isEqualTo(3); assertThat(request.getDefinition().getProperties().get("foo")).isEqualTo("bar"); assertThat(request.getDefinition().getProperties().get("baz")).isEqualTo("qux"); assertThat(request.getDefinition().getProperties().get("task")) .isEqualTo("batch"); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue(); assertThat(results.size()).isEqualTo(1); StepExecution resultStepExecution = results.iterator().next(); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1"); } @Test public void testPollInterval() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setPollInterval(20000L); handler.setMaxWorkers(1); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Date startTime = new Date(); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); Date endTime = new Date(); verify(this.taskLauncher, times(2)) .launch(this.appDeploymentRequestArgumentCaptor.capture()); List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor .getAllValues(); validateAppDeploymentRequests(allRequests, 2); validateStepExecutionResults(results); assertThat(endTime.getTime() - startTime.getTime() >= 19999) .as("Time difference was too small: " + (endTime.getTime() - startTime.getTime())) .isTrue(); } @Test(expected = TimeoutException.class) public void testTimeout() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setPollInterval(20000L); handler.setMaxWorkers(1); handler.setTimeout(1000L); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); handler.handle(this.splitter, masterStepExecution); } @Test public void testGridSize() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart1 = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish1 = getStepExecutionFinish( workerStepExecutionStart1, BatchStatus.COMPLETED); StepExecution workerStepExecutionStart2 = getStepExecutionStart(jobExecution, 5L); StepExecution workerStepExecutionFinish2 = getStepExecutionFinish( workerStepExecutionStart2, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); handler.setGridSize(2); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart1); stepExecutions.add(workerStepExecutionStart2); when(this.splitter.split(masterStepExecution, 2)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish1); when(this.jobExplorer.getStepExecution(1L, 5L)) .thenReturn(workerStepExecutionFinish2); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher, times(2)) .launch(this.appDeploymentRequestArgumentCaptor.capture()); List<AppDeploymentRequest> allRequests = this.appDeploymentRequestArgumentCaptor .getAllValues(); validateAppDeploymentRequests(allRequests, 2); validateStepExecutionResults(results); } @Test public void testDeployerProperties() throws Exception { StepExecution masterStepExecution = createMasterStepExecution(); JobExecution jobExecution = masterStepExecution.getJobExecution(); StepExecution workerStepExecutionStart = getStepExecutionStart(jobExecution, 4L); StepExecution workerStepExecutionFinish = getStepExecutionFinish( workerStepExecutionStart, BatchStatus.COMPLETED); DeployerPartitionHandler handler = new DeployerPartitionHandler(this.taskLauncher, this.jobExplorer, this.resource, "step1", this.taskRepository); handler.setEnvironment(this.environment); Map<String, String> deploymentProperties = new HashMap<>(2); deploymentProperties.put("foo", "bar"); deploymentProperties.put("baz", "qux"); handler.setDeploymentProperties(deploymentProperties); TaskExecution taskExecution = new TaskExecution(); taskExecution.setTaskName("partitionedJobTask"); Set<StepExecution> stepExecutions = new HashSet<>(); stepExecutions.add(workerStepExecutionStart); when(this.splitter.split(masterStepExecution, 1)).thenReturn(stepExecutions); when(this.jobExplorer.getStepExecution(1L, 4L)) .thenReturn(workerStepExecutionFinish); handler.afterPropertiesSet(); handler.beforeTask(taskExecution); Collection<StepExecution> results = handler.handle(this.splitter, masterStepExecution); verify(this.taskLauncher) .launch(this.appDeploymentRequestArgumentCaptor.capture()); AppDeploymentRequest request = this.appDeploymentRequestArgumentCaptor.getValue(); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDeploymentProperties().size()).isEqualTo(2); assertThat(request.getDeploymentProperties().get("foo")).isEqualTo("bar"); assertThat(request.getDeploymentProperties().get("baz")).isEqualTo("qux"); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, "4"))) .isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))).isTrue(); assertThat(results.size()).isEqualTo(1); StepExecution resultStepExecution = results.iterator().next(); assertThat(resultStepExecution.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(resultStepExecution.getStepName()).isEqualTo("step1:partition1"); } private String formatArgs(String key, String value) { return String.format("--%s=%s", key, value); } private StepExecution getStepExecutionFinish(StepExecution stepExecutionStart, BatchStatus status) { StepExecution workerStepExecutionFinish = new StepExecution( stepExecutionStart.getStepName(), stepExecutionStart.getJobExecution()); workerStepExecutionFinish.setId(stepExecutionStart.getId()); workerStepExecutionFinish.setStatus(status); return workerStepExecutionFinish; } private StepExecution getStepExecutionStart(JobExecution jobExecution, long id) { StepExecution workerStepExecutionStart = new StepExecution( "step1:partition" + (id - 3), jobExecution); workerStepExecutionStart.setId(id); return workerStepExecutionStart; } private StepExecution createMasterStepExecution() { JobExecution jobExecution = new JobExecution(1L); jobExecution.setJobInstance(new JobInstance(2L, "partitionedJob")); StepExecution masterStepExecution = new StepExecution("masterStep", jobExecution); masterStepExecution.setId(3L); return masterStepExecution; } private void validateStepExecutionResults(Collection<StepExecution> results) { Iterator<StepExecution> resultsIterator = results.iterator(); Set<String> names = new HashSet<>(results.size()); while (resultsIterator.hasNext()) { StepExecution curResult = resultsIterator.next(); assertThat(curResult.getStatus()).isEqualTo(BatchStatus.COMPLETED); assertThat(!names.contains(curResult.getStepName())).isTrue(); names.add(curResult.getStepName()); } } private void validateAppDeploymentRequests(List<AppDeploymentRequest> allRequests, int numberOfPartitions) { Collections.sort(allRequests, new Comparator<AppDeploymentRequest>() { @Override public int compare(AppDeploymentRequest o1, AppDeploymentRequest o2) { List<String> commandlineArguments = o1.getCommandlineArguments(); String o1Command = ""; for (String commandlineArgument : commandlineArguments) { if (commandlineArgument.contains( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) { o1Command = commandlineArgument; break; } } commandlineArguments = o2.getCommandlineArguments(); String o2Command = ""; for (String commandlineArgument : commandlineArguments) { if (commandlineArgument.contains( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID)) { o2Command = commandlineArgument; break; } } return o1Command.compareTo(o2Command); } }); for (int i = 4; i < (numberOfPartitions + 4); i++) { AppDeploymentRequest request = allRequests.get(i - 4); assertThat(request.getResource()).isEqualTo(this.resource); assertThat(request.getDeploymentProperties().size()).isEqualTo(0); AppDefinition appDefinition = request.getDefinition(); assertThat(appDefinition.getName()).isEqualTo("partitionedJobTask"); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_JOB_EXECUTION_ID, "1"))) .isTrue(); assertThat(request.getCommandlineArguments() .contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_EXECUTION_ID, String.valueOf(i)))).isTrue(); assertThat(request.getCommandlineArguments().contains(formatArgs( DeployerPartitionHandler.SPRING_CLOUD_TASK_STEP_NAME, "step1"))) .isTrue(); assertThat(request.getCommandlineArguments() .contains(formatArgs("spring.cloud.task.executionid", "2"))).isTrue(); } } private void validateDeprecatedConstructorValidation(TaskLauncher taskLauncher, JobExplorer jobExplorer, Resource resource, String stepName, String expectedMessage) { try { new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, stepName, this.taskRepository); } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()).isEqualTo(expectedMessage); } } private void validateConstructorValidation(TaskLauncher taskLauncher, JobExplorer jobExplorer, Resource resource, String stepName, TaskRepository taskRepository, String expectedMessage) { try { new DeployerPartitionHandler(taskLauncher, jobExplorer, resource, stepName, taskRepository); } catch (IllegalArgumentException iae) { assertThat(iae.getMessage()).isEqualTo(expectedMessage); } } }