diff --git a/cr-smoke-test-support/src/main/java/org/springframework/cr/smoketest/support/junit/AwaitApplication.java b/cr-smoke-test-support/src/main/java/org/springframework/cr/smoketest/support/junit/AwaitApplication.java index 95fa8a4..cb79f11 100644 --- a/cr-smoke-test-support/src/main/java/org/springframework/cr/smoketest/support/junit/AwaitApplication.java +++ b/cr-smoke-test-support/src/main/java/org/springframework/cr/smoketest/support/junit/AwaitApplication.java @@ -38,6 +38,9 @@ class AwaitApplication implements BeforeAllCallback { private final Pattern APPLICATION_STARTED = Pattern .compile("Started [A-Za-z0-9]+ in [0-9\\.]+ seconds \\(process running for [0-9\\.]+\\)"); + private final Pattern APPLICATION_RE_STARTED = Pattern + .compile("Spring-managed lifecycle restart completed in [0-9\\.]+ ms"); + private final Pattern WEB_SERVER_STARTED = Pattern.compile(" started on port"); @Override @@ -51,7 +54,8 @@ class AwaitApplication implements BeforeAllCallback { // TODO Either change logging of // DefaultLifecycleProcessor.CracResourceAdapter.afterRestore to INFO or // add INFO logging on restore on Spring Boot side - if (this.APPLICATION_STARTED.matcher(line).find() || this.WEB_SERVER_STARTED.matcher(line).find()) { + if (this.APPLICATION_STARTED.matcher(line).find() || this.WEB_SERVER_STARTED.matcher(line).find() + || this.APPLICATION_RE_STARTED.matcher(line).find()) { return; } } diff --git a/integration/integration-basic/README.adoc b/integration/integration-basic/README.adoc new file mode 100644 index 0000000..80dfeda --- /dev/null +++ b/integration/integration-basic/README.adoc @@ -0,0 +1,3 @@ +Tests if a basic Spring Integration pipeline is working. + + diff --git a/integration/integration-basic/build.gradle b/integration/integration-basic/build.gradle new file mode 100644 index 0000000..46d840f --- /dev/null +++ b/integration/integration-basic/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "java" + id "org.springframework.boot" + id "org.springframework.cr.smoke-test" +} + +dependencies { + implementation(platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)) + implementation("org.springframework.boot:spring-boot-starter-integration") + implementation("org.springframework.integration:spring-integration-file") + + implementation("org.crac:crac:$cracVersion") + implementation(project(":cr-listener")) + + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("org.springframework.integration:spring-integration-test") + + appTestImplementation(project(":cr-smoke-test-support")) + appTestImplementation("org.awaitility:awaitility:4.2.0") +} diff --git a/integration/integration-basic/src/appTest/java/com/example/si/FileCopySpringIntegrationApplicationTest.java b/integration/integration-basic/src/appTest/java/com/example/si/FileCopySpringIntegrationApplicationTest.java new file mode 100644 index 0000000..ceae197 --- /dev/null +++ b/integration/integration-basic/src/appTest/java/com/example/si/FileCopySpringIntegrationApplicationTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2023 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 com.example.si; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.UUID; + +import org.awaitility.Awaitility; +import org.junit.jupiter.api.Test; + +import org.springframework.cr.smoketest.support.assertj.AssertableOutput; +import org.springframework.cr.smoketest.support.junit.ApplicationTest; +import org.springframework.util.StreamUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +@ApplicationTest +public class FileCopySpringIntegrationApplicationTest { + + @Test + void connectionTest(AssertableOutput output) { + + String fileName = "test-" + UUID.randomUUID() + ".txt"; + String sourceFilePath = tempFolder("source_dir") + File.separator + fileName; + String destFilePath = tempFolder("dest_dir") + File.separator + fileName; + + writeFile("Hello World", sourceFilePath); + + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { + assertThat(new File(destFilePath)).exists(); + assertThat(output).hasLineContaining("Source File Payload:" + sourceFilePath); + }); + } + + private static String tempFolder(String suffix) { + String tmpDirsLocation = System.getProperty("java.io.tmpdir"); + return tmpDirsLocation + suffix; + } + + private static void writeFile(String fileBody, String filePath) { + try { + StreamUtils.copy(fileBody, StandardCharsets.UTF_8, new FileOutputStream(filePath)); + } + catch (IOException e) { + throw new RuntimeException("Failed to copy test file to source directory", e); + } + } + +} \ No newline at end of file diff --git a/integration/integration-basic/src/main/java/com/example/si/FileCopySpringIntegrationApplication.java b/integration/integration-basic/src/main/java/com/example/si/FileCopySpringIntegrationApplication.java new file mode 100644 index 0000000..a2650e3 --- /dev/null +++ b/integration/integration-basic/src/main/java/com/example/si/FileCopySpringIntegrationApplication.java @@ -0,0 +1,96 @@ +/* + * Copyright 2023 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 com.example.si; + +import java.io.File; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.integration.annotation.InboundChannelAdapter; +import org.springframework.integration.annotation.Poller; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.annotation.Transformer; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.config.EnableIntegration; +import org.springframework.integration.core.MessageSource; +import org.springframework.integration.file.FileReadingMessageSource; +import org.springframework.integration.file.FileWritingMessageHandler; +import org.springframework.integration.file.filters.SimplePatternFileListFilter; +import org.springframework.integration.file.support.FileExistsMode; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; + +@SpringBootApplication +@EnableIntegration +public class FileCopySpringIntegrationApplication { + + private final Log logger = LogFactory.getLog(getClass()); + + public static final String INPUT_DIR = tempFolder("source_dir"); + + public static final String OUTPUT_DIR = tempFolder("dest_dir"); + + public String FILE_PATTERN = "*.txt"; + + public static void main(String[] args) { + SpringApplication.run(FileCopySpringIntegrationApplication.class, args); + } + + @Bean + public MessageChannel fileChannel() { + return new DirectChannel(); + } + + @Bean + public MessageChannel transformedFileChannel() { + return new DirectChannel(); + } + + @Transformer(inputChannel = "fileChannel", outputChannel = "transformedFileChannel") + public String transform(String payload) { + // System.out.println("Source File Payload:" + payload); + logger.info("Source File Payload:" + payload); + return payload; + } + + @Bean + @InboundChannelAdapter(channel = "fileChannel", poller = @Poller(fixedDelay = "1000")) + public MessageSource fileReadingMessageSource() { + FileReadingMessageSource sourceReader = new FileReadingMessageSource(); + sourceReader.setDirectory(new File(INPUT_DIR)); + sourceReader.setFilter(new SimplePatternFileListFilter(FILE_PATTERN)); + return sourceReader; + } + + @Bean + @ServiceActivator(inputChannel = "transformedFileChannel") + public MessageHandler fileWritingMessageHandler() { + FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(OUTPUT_DIR)); + handler.setFileExistsMode(FileExistsMode.REPLACE); + handler.setExpectReply(false); + return handler; + } + + private static String tempFolder(String suffix) { + String tmpDirsLocation = System.getProperty("java.io.tmpdir"); + return tmpDirsLocation + suffix; + } + +} diff --git a/integration/integration-basic/src/main/resources/application.properties b/integration/integration-basic/src/main/resources/application.properties new file mode 100644 index 0000000..e69de29 diff --git a/settings.gradle b/settings.gradle index d0a4937..12b437b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -27,7 +27,7 @@ rootProject.name="spring-checkpoint-restore-smoke-tests" include "cr-smoke-test-support" include "cr-listener" -["framework"].each { group -> +["framework", "integration"].each { group -> file(group).eachDirMatch(~/[a-z].*/) { smokeTest -> include "$group:${smokeTest.name}" }