Base Task Sink Case with Tests works
In process of migrating batch-events to streambridge BatchEvents Migrated Integration tests for TaskSink now work Batch Event Integration Tests updated Added tests to batch events Event integration tests added Updated with the last bit of tests baseline polishing
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2021-2021 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.
|
||||
@@ -32,6 +32,7 @@ import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -40,6 +41,8 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
@ConditionalOnProperty(prefix = "spring.cloud.task.test", name = "enable-job-configuration",
|
||||
havingValue = "true")
|
||||
public class JobConfiguration {
|
||||
|
||||
private static final int DEFAULT_CHUNK_COUNT = 3;
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -35,6 +36,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
*/
|
||||
@Configuration
|
||||
@EnableBatchProcessing
|
||||
@ConditionalOnProperty(prefix = "spring.cloud.task.test", name = "enable-fail-job-configuration")
|
||||
public class JobSkipConfiguration {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2021 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.
|
||||
@@ -36,7 +36,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.deployer.spi.local.LocalDeployerProperties;
|
||||
import org.springframework.cloud.deployer.spi.local.LocalTaskLauncher;
|
||||
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
|
||||
import org.springframework.cloud.stream.messaging.Sink;
|
||||
import org.springframework.cloud.stream.function.StreamBridge;
|
||||
import org.springframework.cloud.task.launcher.app.TaskLauncherSinkApplication;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.cloud.task.repository.TaskExplorer;
|
||||
@@ -62,7 +62,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
classes = { TaskLauncherSinkApplication.class,
|
||||
TaskLauncherSinkTests.TaskLauncherConfiguration.class },
|
||||
properties = {
|
||||
"maven.remote-repositories.repo1.url=https://repo.spring.io/libs-release" })
|
||||
"maven.remote-repositories.repo1.url=https://repo.spring.io/libs-release",
|
||||
"spring.cloud.stream.function.bindings.taskLauncherSink-in-0=input",
|
||||
"spring.cloud.stream.bindings.input.destination=taskLauncherSinkExchange" })
|
||||
public class TaskLauncherSinkTests {
|
||||
|
||||
private final static int WAIT_INTERVAL = 500;
|
||||
@@ -70,7 +72,7 @@ public class TaskLauncherSinkTests {
|
||||
private final static int MAX_WAIT_TIME = 120000;
|
||||
|
||||
private final static String URL = "maven://org.springframework.cloud.task.app:"
|
||||
+ "timestamp-task:2.0.0.RELEASE";
|
||||
+ "timestamp-task:2.1.1.RELEASE";
|
||||
|
||||
private final static String DATASOURCE_URL;
|
||||
|
||||
@@ -96,7 +98,7 @@ public class TaskLauncherSinkTests {
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Sink sink;
|
||||
private StreamBridge streamBridge;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
@@ -185,11 +187,10 @@ public class TaskLauncherSinkTests {
|
||||
}
|
||||
|
||||
private void launchTask(String artifactURL) {
|
||||
|
||||
TaskLaunchRequest request = new TaskLaunchRequest(artifactURL, null,
|
||||
this.properties, null, null);
|
||||
GenericMessage<TaskLaunchRequest> message = new GenericMessage<>(request);
|
||||
this.sink.input().send(message);
|
||||
this.streamBridge.send("taskLauncherSinkExchange", message);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2021 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.
|
||||
@@ -16,30 +16,30 @@
|
||||
|
||||
package org.springframework.cloud.task.listener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import configuration.JobConfiguration;
|
||||
import configuration.JobSkipConfiguration;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.RabbitMQContainer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.StreamListener;
|
||||
import org.springframework.cloud.stream.messaging.Sink;
|
||||
import org.springframework.cloud.task.batch.listener.BatchEventAutoConfiguration;
|
||||
import org.springframework.cloud.stream.binder.test.OutputDestination;
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
|
||||
import org.springframework.cloud.task.batch.listener.support.JobExecutionEvent;
|
||||
import org.springframework.cloud.task.batch.listener.support.StepExecutionEvent;
|
||||
import org.springframework.cloud.task.configuration.EnableTask;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -48,43 +48,16 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
public class BatchExecutionEventTests {
|
||||
|
||||
private static final String TASK_NAME = "jobEventTest";
|
||||
|
||||
static {
|
||||
GenericContainer rabbitmq = new RabbitMQContainer("rabbitmq:3.8.9")
|
||||
.withExposedPorts(5672);
|
||||
rabbitmq.start();
|
||||
final Integer mappedPort = rabbitmq.getMappedPort(5672);
|
||||
System.setProperty("spring.rabbitmq.test.port", mappedPort.toString());
|
||||
}
|
||||
|
||||
// Count for two job execution events per job
|
||||
static CountDownLatch jobExecutionLatch = new CountDownLatch(2);
|
||||
|
||||
// Count for four step execution events per job
|
||||
static CountDownLatch stepExecutionLatch = new CountDownLatch(4);
|
||||
static int stepOneCount = 0;
|
||||
static int stepTwoCount = 0;
|
||||
|
||||
// Count for twelve item process events per job
|
||||
static CountDownLatch itemProcessLatch = new CountDownLatch(6);
|
||||
|
||||
// Count for eight chunk events per job
|
||||
static CountDownLatch chunkEventsLatch = new CountDownLatch(8);
|
||||
|
||||
// Count for zero read events per job
|
||||
static CountDownLatch itemReadEventsLatch = new CountDownLatch(0);
|
||||
|
||||
// Count for six write events per job
|
||||
static CountDownLatch itemWriteEventsLatch = new CountDownLatch(2);
|
||||
|
||||
// Count for 3 skip events per job
|
||||
static CountDownLatch skipEventsLatch = new CountDownLatch(3);
|
||||
static int readSkipCount = 0;
|
||||
static int writeSkipCount = 0;
|
||||
private static final String TASK_NAME = "taskEventTest";
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
if (this.applicationContext != null && this.applicationContext.isActive()) {
|
||||
@@ -95,237 +68,185 @@ public class BatchExecutionEventTests {
|
||||
@Test
|
||||
public void testContext() {
|
||||
this.applicationContext = new SpringApplicationBuilder()
|
||||
.sources(this.getConfigurations(
|
||||
BatchExecutionEventTests.ListenerBinding.class,
|
||||
JobConfiguration.class))
|
||||
.build().run(getCommandLineParams(
|
||||
"--spring.cloud.stream.bindings.job-execution-events.destination=bazbar"));
|
||||
.sources(TestChannelBinderConfiguration
|
||||
.getCompleteConfiguration(BatchEventsApplication.class)).web(WebApplicationType.NONE)
|
||||
.build().run(getCommandLineParams(
|
||||
"--spring.cloud.stream.bindings.job-execution-events.destination=bazbar"));
|
||||
|
||||
assertThat(this.applicationContext.getBean("jobExecutionEventsListener"))
|
||||
.isNotNull();
|
||||
.isNotNull();
|
||||
assertThat(this.applicationContext.getBean("stepExecutionEventsListener"))
|
||||
.isNotNull();
|
||||
.isNotNull();
|
||||
assertThat(this.applicationContext.getBean("chunkEventsListener")).isNotNull();
|
||||
assertThat(this.applicationContext.getBean("itemReadEventsListener")).isNotNull();
|
||||
assertThat(this.applicationContext.getBean("itemWriteEventsListener"))
|
||||
.isNotNull();
|
||||
.isNotNull();
|
||||
assertThat(this.applicationContext.getBean("itemProcessEventsListener"))
|
||||
.isNotNull();
|
||||
.isNotNull();
|
||||
assertThat(this.applicationContext.getBean("skipEventsListener")).isNotNull();
|
||||
assertThat(this.applicationContext
|
||||
.getBean(BatchEventAutoConfiguration.BatchEventsChannels.class))
|
||||
.isNotNull();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobEventListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.job-execution-events.destination=foobar",
|
||||
jobExecutionLatch, BatchExecutionEventTests.ListenerBinding.class);
|
||||
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.jobExecutionEventBindingName=foobar", "foobar", 1);
|
||||
JobExecutionEvent jobExecutionEvent = this.objectMapper.readValue(result.get(0).getPayload(),
|
||||
JobExecutionEvent.class);
|
||||
Assertions.assertThat(jobExecutionEvent.getJobInstance().getJobName())
|
||||
.isEqualTo("job").as("Job name should be job");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStepEventListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.step-execution-events.destination=step-execution-foobar",
|
||||
stepExecutionLatch, BatchExecutionEventTests.StepListenerBinding.class);
|
||||
final String bindingName = "step-execution-foobar";
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.stepExecutionEventBindingName=" + bindingName,
|
||||
bindingName, 4);
|
||||
int stepOneCount = 0;
|
||||
int stepTwoCount = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
StepExecutionEvent stepExecutionEvent = this.objectMapper.readValue(result.get(i).getPayload(),
|
||||
StepExecutionEvent.class);
|
||||
if (stepExecutionEvent.getStepName().equals("step1")) {
|
||||
stepOneCount++;
|
||||
}
|
||||
if (stepExecutionEvent.getStepName().equals("step2")) {
|
||||
stepTwoCount++;
|
||||
}
|
||||
}
|
||||
|
||||
assertThat(stepOneCount).as("the number of step1 events did not match")
|
||||
.isEqualTo(2);
|
||||
.isEqualTo(2);
|
||||
assertThat(stepTwoCount).as("the number of step2 events did not match")
|
||||
.isEqualTo(2);
|
||||
.isEqualTo(2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemProcessEventListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.item-process-events.destination=item-process-foobar",
|
||||
itemProcessLatch,
|
||||
BatchExecutionEventTests.ItemProcessListenerBinding.class);
|
||||
public void testItemProcessEventListener() {
|
||||
final String bindingName = "item-execution-foobar";
|
||||
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.itemProcessEventBindingName=" + bindingName,
|
||||
bindingName, 1);
|
||||
String value = new String(result.get(0).getPayload());
|
||||
assertThat(value).isEqualTo("\"item did not equal result after processing\"");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChunkListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.chunk-events.destination=chunk-events-foobar",
|
||||
chunkEventsLatch,
|
||||
BatchExecutionEventTests.ChunkEventsListenerBinding.class);
|
||||
public void testChunkListener() {
|
||||
final String bindingName = "chunk-events-foobar";
|
||||
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.chunkEventBindingName=" + bindingName,
|
||||
bindingName, 2);
|
||||
String value = new String(result.get(0).getPayload());
|
||||
assertThat(value).isEqualTo("\"Before Chunk Processing\"");
|
||||
value = new String(result.get(1).getPayload());
|
||||
assertThat(value).isEqualTo("\"After Chunk Processing\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemReadListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.item-read-events.destination=item-read-events-foobar",
|
||||
itemReadEventsLatch,
|
||||
BatchExecutionEventTests.ItemReadEventsListenerBinding.class);
|
||||
}
|
||||
public void testWriteListener() {
|
||||
final String bindingName = "item-write-events-foobar";
|
||||
|
||||
@Test
|
||||
public void testWriteListener() throws Exception {
|
||||
testListener(
|
||||
"--spring.cloud.stream.bindings.item-write-events.destination=item-write-events-foobar",
|
||||
itemWriteEventsLatch,
|
||||
BatchExecutionEventTests.ItemWriteEventsListenerBinding.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipEventListener() throws Exception {
|
||||
testListenerSkip(
|
||||
"--spring.cloud.stream.bindings.skip-events.destination=skip-event-foobar",
|
||||
skipEventsLatch,
|
||||
BatchExecutionEventTests.SkipEventsListenerBinding.class);
|
||||
assertThat(readSkipCount).as("read skip count did not match expected result")
|
||||
.isEqualTo(2);
|
||||
assertThat(writeSkipCount).as("write skip count did not match expected result")
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
private Class[] getConfigurations(Class sinkClazz, Class jobConfigurationClazz) {
|
||||
return new Class[] { PropertyPlaceholderAutoConfiguration.class,
|
||||
jobConfigurationClazz, sinkClazz };
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.itemWriteEventBindingName=" + bindingName,
|
||||
bindingName, 2);
|
||||
String value = new String(result.get(0).getPayload());
|
||||
assertThat(value).isEqualTo("\"3 items to be written.\"");
|
||||
value = new String(result.get(1).getPayload());
|
||||
assertThat(value).isEqualTo("\"3 items have been written.\"");
|
||||
}
|
||||
|
||||
private String[] getCommandLineParams(String sinkChannelParam) {
|
||||
return new String[] { "--spring.cloud.task.closecontext_enable=false",
|
||||
"--spring.cloud.task.name=" + TASK_NAME,
|
||||
"--spring.main.web-environment=false",
|
||||
"--spring.cloud.stream.defaultBinder=rabbit",
|
||||
"--spring.cloud.stream.bindings.task-events.destination=test",
|
||||
"foo=" + UUID.randomUUID().toString(), sinkChannelParam };
|
||||
return getCommandLineParams(sinkChannelParam, true);
|
||||
}
|
||||
|
||||
private void testListener(String channelBinding, CountDownLatch latch, Class<?> clazz)
|
||||
throws Exception {
|
||||
private String[] getCommandLineParams(String sinkChannelParam, boolean enableFailJobConfig) {
|
||||
String jobConfig = enableFailJobConfig ?
|
||||
"--spring.cloud.task.test.enable-job-configuration=true" :
|
||||
"--spring.cloud.task.test.enable-fail-job-configuration=true";
|
||||
return new String[]{"--spring.cloud.task.closecontext_enable=false",
|
||||
"--spring.cloud.task.name=" + TASK_NAME,
|
||||
"--spring.main.web-environment=false",
|
||||
"--spring.cloud.stream.defaultBinder=rabbit",
|
||||
"--spring.cloud.stream.bindings.task-events.destination=test",
|
||||
jobConfig,
|
||||
"foo=" + UUID.randomUUID(), sinkChannelParam};
|
||||
}
|
||||
|
||||
private List<Message<byte[]>> testListener(String channelBinding, String bindingName, int numberToRead) {
|
||||
return testListenerForApp(channelBinding, bindingName, numberToRead, BatchEventsApplication.class, true);
|
||||
}
|
||||
|
||||
private List<Message<byte[]>> testListenerSkip(String channelBinding, String bindingName, int numberToRead) {
|
||||
return testListenerForApp(channelBinding, bindingName, numberToRead, BatchSkipEventsApplication.class, false);
|
||||
}
|
||||
|
||||
private List<Message<byte[]>> testListenerForApp(String channelBinding,
|
||||
String bindingName, int numberToRead, Class clazz, boolean enableFailJobConfig) {
|
||||
List<Message<byte[]>> results = new ArrayList<>();
|
||||
|
||||
this.applicationContext = new SpringApplicationBuilder()
|
||||
.sources(this.getConfigurations(clazz, JobConfiguration.class)).build()
|
||||
.run(getCommandLineParams(channelBinding));
|
||||
.sources(TestChannelBinderConfiguration
|
||||
.getCompleteConfiguration(clazz)).web(WebApplicationType.NONE)
|
||||
.build().run(getCommandLineParams(channelBinding, enableFailJobConfig));
|
||||
|
||||
assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
OutputDestination target = this.applicationContext.getBean(OutputDestination.class);
|
||||
|
||||
private void testListenerSkip(String channelBinding, CountDownLatch latch,
|
||||
Class<?> clazz) throws Exception {
|
||||
this.applicationContext = new SpringApplicationBuilder()
|
||||
.sources(this.getConfigurations(clazz, JobSkipConfiguration.class))
|
||||
.build().run(getCommandLineParams(channelBinding));
|
||||
|
||||
assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue();
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/job-execution-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class ListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(JobExecutionEvent execution) {
|
||||
Assertions.assertThat(execution.getJobInstance().getJobName())
|
||||
.isEqualTo("job").as("Job name should be job");
|
||||
jobExecutionLatch.countDown();
|
||||
for (int i = 0; i < numberToRead; i++) {
|
||||
results.add(target.receive(10000, bindingName));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/step-execution-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class StepListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(StepExecutionEvent execution) {
|
||||
if (execution.getStepName().equals("step1")) {
|
||||
stepOneCount++;
|
||||
}
|
||||
if (execution.getStepName().equals("step2")) {
|
||||
stepTwoCount++;
|
||||
}
|
||||
|
||||
stepExecutionLatch.countDown();
|
||||
}
|
||||
@Test
|
||||
public void testItemReadListener() {
|
||||
final String bindingName = "item-read-events-foobar";
|
||||
|
||||
List<Message<byte[]>> result = testListenerSkip(
|
||||
"--spring.cloud.task.batch.events.itemReadEventBindingName=" + bindingName,
|
||||
bindingName, 1);
|
||||
String exceptionMessage = new String(result.get(0).getPayload());
|
||||
assertThat(exceptionMessage).isEqualTo("\"Exception while item was being read\"");
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/item-process-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class ItemProcessListenerBinding {
|
||||
@Test
|
||||
public void testSkipEventListener() {
|
||||
final String SKIPPING_READ_MESSAGE = "\"Skipped when reading.\"";
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(String object) {
|
||||
itemProcessLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/chunk-events-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class ChunkEventsListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(String message) {
|
||||
chunkEventsLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/item-read-events-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class ItemReadEventsListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(Object itemRead) {
|
||||
itemReadEventsLatch.countDown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/skip-events-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class SkipEventsListenerBinding {
|
||||
|
||||
private static final String SKIPPING_READ_MESSAGE = "Skipped when reading.";
|
||||
|
||||
private static final String SKIPPING_WRITE_CONTENT = "-1";
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(String exceptionMessage) {
|
||||
if (exceptionMessage.toString().equals(SKIPPING_READ_MESSAGE)) {
|
||||
final String SKIPPING_WRITE_CONTENT = "\"-1\"";
|
||||
final String bindingName = "skip-event-foobar";
|
||||
List<Message<byte[]>> result = testListenerSkip(
|
||||
"--spring.cloud.task.batch.events.skipEventBindingName=" + bindingName,
|
||||
bindingName, 3);
|
||||
int readSkipCount = 0;
|
||||
int writeSkipCount = 0;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
String exceptionMessage = new String(result.get(i).getPayload());
|
||||
if (exceptionMessage.equals(SKIPPING_READ_MESSAGE)) {
|
||||
readSkipCount++;
|
||||
}
|
||||
if (exceptionMessage.toString().equals(SKIPPING_WRITE_CONTENT)) {
|
||||
if (exceptionMessage.equals(SKIPPING_WRITE_CONTENT)) {
|
||||
writeSkipCount++;
|
||||
}
|
||||
skipEventsLatch.countDown();
|
||||
}
|
||||
|
||||
assertThat(readSkipCount).as("the number of read skip events did not match")
|
||||
.isEqualTo(2);
|
||||
assertThat(writeSkipCount).as("the number of write skip events did not match")
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/item-write-events-sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
@EnableTask
|
||||
public static class ItemWriteEventsListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(String itemWrite) {
|
||||
Assertions.assertThat(itemWrite).startsWith("3 items ")
|
||||
.as("Message should start with '3 items'");
|
||||
Assertions.assertThat(itemWrite).endsWith("written.")
|
||||
.as("Message should end with ' written.'");
|
||||
itemWriteEventsLatch.countDown();
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
@Import(JobConfiguration.class)
|
||||
public static class BatchEventsApplication {
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
@Import(JobSkipConfiguration.class)
|
||||
public static class BatchSkipEventsApplication {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2021 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.
|
||||
@@ -16,78 +16,78 @@
|
||||
|
||||
package org.springframework.cloud.task.listener;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.RabbitMQContainer;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.stream.annotation.EnableBinding;
|
||||
import org.springframework.cloud.stream.annotation.StreamListener;
|
||||
import org.springframework.cloud.stream.binder.rabbit.config.RabbitConfiguration;
|
||||
import org.springframework.cloud.stream.config.BindingServiceConfiguration;
|
||||
import org.springframework.cloud.stream.messaging.Sink;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.stream.binder.test.OutputDestination;
|
||||
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
|
||||
import org.springframework.cloud.task.configuration.EnableTask;
|
||||
import org.springframework.cloud.task.configuration.SimpleTaskAutoConfiguration;
|
||||
import org.springframework.cloud.task.repository.TaskExecution;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* @author Michael Minella
|
||||
* @author Ilayaperumal Gopinathan
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(classes = { TaskEventTests.ListenerBinding.class })
|
||||
public class TaskEventTests {
|
||||
|
||||
private static final String TASK_NAME = "taskEventTest";
|
||||
|
||||
static {
|
||||
GenericContainer rabbitmq = new RabbitMQContainer("rabbitmq:3.8.9")
|
||||
.withExposedPorts(5672);
|
||||
rabbitmq.start();
|
||||
final Integer mappedPort = rabbitmq.getMappedPort(5672);
|
||||
System.setProperty("spring.rabbitmq.test.port", mappedPort.toString());
|
||||
}
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
// Count for two task execution events per task
|
||||
static CountDownLatch latch = new CountDownLatch(2);
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@AfterEach
|
||||
public void tearDown() {
|
||||
if (this.applicationContext != null && this.applicationContext.isActive()) {
|
||||
this.applicationContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskEventListener() throws Exception {
|
||||
ApplicationContextRunner applicationContextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(TaskEventAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
RabbitConfiguration.class,
|
||||
SimpleTaskAutoConfiguration.class,
|
||||
BindingServiceConfiguration.class))
|
||||
.withUserConfiguration(TaskEventsConfiguration.class)
|
||||
.withPropertyValues("--spring.cloud.task.closecontext_enabled=false",
|
||||
"--spring.cloud.task.name=" + TASK_NAME,
|
||||
"--spring.main.web-environment=false",
|
||||
"--spring.cloud.stream.defaultBinder=rabbit",
|
||||
"--spring.cloud.stream.bindings.task-events.destination=test");
|
||||
applicationContextRunner.run((context) -> {
|
||||
assertThat(context.getBean("taskEventListener")).isNotNull();
|
||||
assertThat(
|
||||
context.getBean(TaskEventAutoConfiguration.TaskEventChannels.class))
|
||||
.isNotNull();
|
||||
});
|
||||
assertThat(latch.await(1, TimeUnit.SECONDS)).isTrue();
|
||||
List<Message<byte[]>> result = testListener(
|
||||
"--spring.cloud.task.batch.events.itemWriteEventBindingName=task-events",
|
||||
"task-events", 2);
|
||||
TaskExecution taskExecution = this.objectMapper.readValue(result.get(0).getPayload(),
|
||||
TaskExecution.class);
|
||||
Assertions.assertThat(taskExecution.getTaskName()).isEqualTo(TASK_NAME)
|
||||
.as(String.format("Task name should be '%s'", TASK_NAME));
|
||||
taskExecution = this.objectMapper.readValue(result.get(1).getPayload(),
|
||||
TaskExecution.class);
|
||||
Assertions.assertThat(taskExecution.getTaskName()).isEqualTo(TASK_NAME)
|
||||
.as(String.format("Task name should be '%s'", TASK_NAME));
|
||||
}
|
||||
|
||||
private List<Message<byte[]>> testListener(String channelBinding, String bindingName, int numberToRead) {
|
||||
List<Message<byte[]>> results = new ArrayList<>();
|
||||
this.applicationContext = new SpringApplicationBuilder()
|
||||
.sources(TestChannelBinderConfiguration
|
||||
.getCompleteConfiguration(BatchExecutionEventTests.BatchEventsApplication.class)).web(WebApplicationType.NONE).build()
|
||||
.run(getCommandLineParams(channelBinding));
|
||||
OutputDestination target = this.applicationContext.getBean(OutputDestination.class);
|
||||
for (int i = 0; i < numberToRead; i++) {
|
||||
results.add(target.receive(10000, bindingName));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private String[] getCommandLineParams(String sinkChannelParam) {
|
||||
return new String[]{"--spring.cloud.task.closecontext_enable=false",
|
||||
"--spring.cloud.task.name=" + TASK_NAME,
|
||||
"--spring.main.web-environment=false",
|
||||
"--spring.cloud.stream.defaultBinder=rabbit",
|
||||
"foo=" + UUID.randomUUID(), sinkChannelParam};
|
||||
}
|
||||
|
||||
@EnableTask
|
||||
@@ -95,29 +95,4 @@ public class TaskEventTests {
|
||||
public static class TaskEventsConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@EnableBinding(Sink.class)
|
||||
@PropertySource("classpath:/org/springframework/cloud/task/listener/sink-channel.properties")
|
||||
@EnableAutoConfiguration
|
||||
public static class ListenerBinding {
|
||||
|
||||
@StreamListener(Sink.INPUT)
|
||||
public void receive(TaskExecution execution) {
|
||||
Assertions.assertThat(execution.getTaskName()).isEqualTo(TASK_NAME)
|
||||
.as(String.format("Task name should be '%s'", TASK_NAME));
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandLineRunner commandLineRunner() {
|
||||
return new CommandLineRunner() {
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
System.out.println("Hello World");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user