diff --git a/data/data-redis/README.adoc b/data/data-redis/README.adoc new file mode 100644 index 0000000..581e9df --- /dev/null +++ b/data/data-redis/README.adoc @@ -0,0 +1 @@ +Tests if Data Redis with Lettuce is working. diff --git a/data/data-redis/build.gradle b/data/data-redis/build.gradle new file mode 100644 index 0000000..8c304b4 --- /dev/null +++ b/data/data-redis/build.gradle @@ -0,0 +1,22 @@ +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-data-redis") + + implementation("org.crac:crac:$cracVersion") + implementation(project(":cr-listener")) + + testImplementation("org.springframework.boot:spring-boot-starter-test") + + appTestImplementation(project(":cr-smoke-test-support")) + appTestImplementation("org.awaitility:awaitility:4.2.0") +} + +crSmokeTest { + webApplication = false +} diff --git a/data/data-redis/docker-compose.yml b/data/data-redis/docker-compose.yml new file mode 100644 index 0000000..17115c3 --- /dev/null +++ b/data/data-redis/docker-compose.yml @@ -0,0 +1,6 @@ +version: '3.1' +services: + redis: + image: 'redis:7' + ports: + - '6379' diff --git a/data/data-redis/src/appTest/java/com/example/data/redis/DataRedisApplicationTests.java b/data/data-redis/src/appTest/java/com/example/data/redis/DataRedisApplicationTests.java new file mode 100644 index 0000000..9acfcb1 --- /dev/null +++ b/data/data-redis/src/appTest/java/com/example/data/redis/DataRedisApplicationTests.java @@ -0,0 +1,41 @@ +/* + * 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 + * + * 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 com.example.data.redis; + +import static org.assertj.core.api.Assertions.*; + +import java.time.Duration; + +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; + +/** + * @author Christoph Strobl + */ +@ApplicationTest +public class DataRedisApplicationTests { + + @Test + void connectionTest(AssertableOutput output) { + Awaitility.await().atMost(Duration.ofSeconds(10)).untilAsserted(() -> { + assertThat(output).hasLineMatching("Starting RedisReader: was (initialized|stopped)"); + assertThat(output).hasLineMatching("RedisReader: counting [0-9\\.]+"); + }); + } + +} diff --git a/data/data-redis/src/main/java/com/example/data/redis/DataRedisApplication.java b/data/data-redis/src/main/java/com/example/data/redis/DataRedisApplication.java new file mode 100644 index 0000000..8dc446a --- /dev/null +++ b/data/data-redis/src/main/java/com/example/data/redis/DataRedisApplication.java @@ -0,0 +1,31 @@ +/* + * 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 + * + * 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 com.example.data.redis; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author Christoph Strobl + */ +@SpringBootApplication +public class DataRedisApplication { + + public static void main(String[] args) { + SpringApplication.run(DataRedisApplication.class, args); + } + +} diff --git a/data/data-redis/src/main/java/com/example/data/redis/RedisReader.java b/data/data-redis/src/main/java/com/example/data/redis/RedisReader.java new file mode 100644 index 0000000..a4bccbd --- /dev/null +++ b/data/data-redis/src/main/java/com/example/data/redis/RedisReader.java @@ -0,0 +1,83 @@ +/* + * 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 + * + * 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 com.example.data.redis; + +import java.util.concurrent.atomic.AtomicBoolean; + +import org.springframework.context.SmartLifecycle; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * @author Christoph Strobl + */ +@Component +@EnableScheduling +class RedisReader implements SmartLifecycle { + + static final String STATE_KEY = "component-state"; + static final String COUNTER_KEY = "counter"; + + final StringRedisTemplate redisTemplate; + + final AtomicBoolean running = new AtomicBoolean(false); + + RedisReader(StringRedisTemplate redisTemplate) { + + this.redisTemplate = redisTemplate; + this.redisTemplate.delete(COUNTER_KEY); + this.redisTemplate.opsForValue().set(STATE_KEY, "initialized"); + } + + @Override + public void start() { + + if (running.compareAndSet(false, true)) { + String previousState = getSetState("started"); + System.out.println("Starting RedisReader: was %s".formatted(previousState)); + } + } + + @Scheduled(fixedDelay = 1000) + public void scheduled() { + + if (isRunning()) { + Long value = redisTemplate.opsForValue().increment(COUNTER_KEY); + System.out.println("RedisReader: counting %s".formatted(value)); + } + } + + @Override + public void stop() { + + if (running.compareAndSet(true, false)) { + String previousState = getSetState("stopped"); + System.out.println("Stopping RedisReader: was %s".formatted(previousState)); + } + } + + @Override + public boolean isRunning() { + return running.get(); + } + + String getSetState(String newState) { + return redisTemplate.opsForValue().getAndSet(STATE_KEY, newState); + } + +} diff --git a/data/data-redis/src/main/resources/application.properties b/data/data-redis/src/main/resources/application.properties new file mode 100644 index 0000000..f5867e8 --- /dev/null +++ b/data/data-redis/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.data.redis.host=${REDIS_HOST:localhost} +spring.data.redis.port=${REDIS_PORT_6379:6379} +logging.level.org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory=TRACE diff --git a/data/data-redis/src/test/java/com/example/data/redis/RedisTemplateTest.java b/data/data-redis/src/test/java/com/example/data/redis/RedisTemplateTest.java new file mode 100644 index 0000000..514069b --- /dev/null +++ b/data/data-redis/src/test/java/com/example/data/redis/RedisTemplateTest.java @@ -0,0 +1,36 @@ +/* + * 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 + * + * 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 com.example.data.redis; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.StringRedisTemplate; + +/** + * @author Christoph Strobl + */ +@SpringBootTest +public class RedisTemplateTest { + + @Test + void templateWorks(@Autowired StringRedisTemplate template) { + assertThat(template.getConnectionFactory().getConnection().ping()).isEqualTo("PONG"); + } + +} diff --git a/settings.gradle b/settings.gradle index 12b437b..433092c 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", "integration"].each { group -> +["data", "framework", "integration"].each { group -> file(group).eachDirMatch(~/[a-z].*/) { smokeTest -> include "$group:${smokeTest.name}" }