@@ -15,24 +15,20 @@
|
||||
*/
|
||||
package example.springdata.redis.cluster;
|
||||
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisClusterAvailable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* {@link BasicUsageTests} shows general usage of {@link RedisTemplate} and {@link RedisOperations} in a clustered
|
||||
@@ -40,17 +36,14 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = { AppConfig.class })
|
||||
public class BasicUsageTests {
|
||||
@EnabledOnRedisClusterAvailable(port = 30001)
|
||||
class BasicUsageTests {
|
||||
|
||||
@Autowired RedisTemplate<String, String> template;
|
||||
|
||||
public static @ClassRule RequiresRedisServer redisServerAvailable = RequiresRedisServer.listeningAt("127.0.0.1",
|
||||
30001);
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
template.execute((RedisCallback<String>) connection -> {
|
||||
connection.flushDb();
|
||||
@@ -63,7 +56,7 @@ public class BasicUsageTests {
|
||||
* -> {@code SLOT 5798} served by {@code 127.0.0.1:30002}
|
||||
*/
|
||||
@Test
|
||||
public void singleSlotOperation() {
|
||||
void singleSlotOperation() {
|
||||
|
||||
template.opsForValue().set("name", "rand al'thor"); // slot 5798
|
||||
assertThat(template.opsForValue().get("name")).isEqualTo("rand al'thor");
|
||||
@@ -75,7 +68,7 @@ public class BasicUsageTests {
|
||||
* -> {@code SLOT 14594} served by {@code 127.0.0.1:30003}
|
||||
*/
|
||||
@Test
|
||||
public void multiSlotOperation() {
|
||||
void multiSlotOperation() {
|
||||
|
||||
template.opsForValue().set("name", "matrim cauthon"); // slot 5798
|
||||
template.opsForValue().set("nickname", "prince of the ravens"); // slot 14594
|
||||
@@ -89,7 +82,7 @@ public class BasicUsageTests {
|
||||
* -> {@code SLOT 5798} served by {@code 127.0.0.1:30002}
|
||||
*/
|
||||
@Test
|
||||
public void fixedSlotOperation() {
|
||||
void fixedSlotOperation() {
|
||||
|
||||
template.opsForValue().set("{user}.name", "perrin aybara"); // slot 5474
|
||||
template.opsForValue().set("{user}.nickname", "wolfbrother"); // slot 5474
|
||||
@@ -105,7 +98,7 @@ public class BasicUsageTests {
|
||||
* -> {@code KEY nickname} served by {@code 127.0.0.1:30003}
|
||||
*/
|
||||
@Test
|
||||
public void multiNodeOperation() {
|
||||
void multiNodeOperation() {
|
||||
|
||||
template.opsForValue().set("name", "rand al'thor"); // slot 5798
|
||||
template.opsForValue().set("nickname", "dragon reborn"); // slot 14594
|
||||
|
||||
@@ -17,43 +17,34 @@ package example.springdata.redis.commands;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnCommand;
|
||||
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.data.geo.Circle;
|
||||
import org.springframework.data.geo.Distance;
|
||||
import org.springframework.data.geo.GeoResults;
|
||||
import org.springframework.data.geo.Point;
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit;
|
||||
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
|
||||
import org.springframework.data.redis.core.GeoOperations;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of redis geo-index operations using Template API provided by {@link GeoOperations}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class GeoOperationsTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost().atLeast("3.2");
|
||||
@EnabledOnCommand("GEOADD")
|
||||
class GeoOperationsTests {
|
||||
|
||||
@Autowired RedisOperations<String, String> operations;
|
||||
GeoOperations<String, String> geoOperations;
|
||||
private GeoOperations<String, String> geoOperations;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
@BeforeEach
|
||||
void before() {
|
||||
|
||||
geoOperations = operations.opsForGeo();
|
||||
|
||||
@@ -66,7 +57,7 @@ public class GeoOperationsTests {
|
||||
* Look up points using a geo-index member as reference.
|
||||
*/
|
||||
@Test
|
||||
public void geoRadiusByMember() {
|
||||
void geoRadiusByMember() {
|
||||
|
||||
var byDistance = geoOperations.geoRadiusByMember("Sicily", "Palermo",
|
||||
new Distance(100, DistanceUnit.KILOMETERS));
|
||||
@@ -83,7 +74,7 @@ public class GeoOperationsTests {
|
||||
* Lookup points within a circle around coordinates.
|
||||
*/
|
||||
@Test
|
||||
public void geoRadius() {
|
||||
void geoRadius() {
|
||||
|
||||
var circle = new Circle(new Point(13.583333, 37.316667), //
|
||||
new Distance(100, DistanceUnit.KILOMETERS));
|
||||
@@ -96,7 +87,7 @@ public class GeoOperationsTests {
|
||||
* Calculate the distance between two geo-index members.
|
||||
*/
|
||||
@Test
|
||||
public void geoDistance() {
|
||||
void geoDistance() {
|
||||
|
||||
var distance = geoOperations.geoDist("Sicily", "Catania", "Palermo", DistanceUnit.KILOMETERS);
|
||||
|
||||
@@ -107,7 +98,7 @@ public class GeoOperationsTests {
|
||||
* Return the geo-hash.
|
||||
*/
|
||||
@Test
|
||||
public void geoHash() {
|
||||
void geoHash() {
|
||||
|
||||
var geohashes = geoOperations.geoHash("Sicily", "Catania", "Palermo");
|
||||
|
||||
|
||||
@@ -15,37 +15,29 @@
|
||||
*/
|
||||
package example.springdata.redis.commands;
|
||||
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of operations on redis keys using low level API provided by {@link RedisConnection}.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class KeyOperationsTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
|
||||
@DataRedisTest
|
||||
@EnabledOnRedisAvailable
|
||||
class KeyOperationsTests {
|
||||
|
||||
private static final String PREFIX = KeyOperationsTests.class.getSimpleName();
|
||||
private static final String KEY_PATTERN = PREFIX + "*";
|
||||
@@ -55,8 +47,8 @@ public class KeyOperationsTests {
|
||||
private RedisConnection connection;
|
||||
private RedisSerializer<String> serializer = new StringRedisSerializer();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.connection = connectionFactory.getConnection();
|
||||
}
|
||||
|
||||
@@ -66,7 +58,7 @@ public class KeyOperationsTests {
|
||||
* All keys will be loaded within <strong>one single</strong> operation.
|
||||
*/
|
||||
@Test
|
||||
public void iterateOverKeysMatchingPrefixUsingKeysCommand() {
|
||||
void iterateOverKeysMatchingPrefixUsingKeysCommand() {
|
||||
|
||||
generateRandomKeys(1000);
|
||||
|
||||
@@ -80,7 +72,7 @@ public class KeyOperationsTests {
|
||||
* All keys will be loaded using <strong>multiple</strong> operations.
|
||||
*/
|
||||
@Test
|
||||
public void iterateOverKeysMatchingPrefixUsingScanCommand() {
|
||||
void iterateOverKeysMatchingPrefixUsingScanCommand() {
|
||||
|
||||
generateRandomKeys(1000);
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
package example.springdata.redis.commands;
|
||||
|
||||
import example.springdata.redis.RedisTestConfiguration;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -26,20 +25,17 @@ import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.connection.ReactiveListCommands.PopResult;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnection;
|
||||
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.ReactiveStringCommands.SetCommand;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.data.redis.util.ByteUtils;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of reactive operations on Redis keys using low level API provided by
|
||||
@@ -47,12 +43,9 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = RedisTestConfiguration.class)
|
||||
public class KeyCommandsTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
|
||||
@EnabledOnRedisAvailable
|
||||
class KeyCommandsTests {
|
||||
|
||||
private static final String PREFIX = KeyCommandsTests.class.getSimpleName();
|
||||
private static final String KEY_PATTERN = PREFIX + "*";
|
||||
@@ -62,8 +55,8 @@ public class KeyCommandsTests {
|
||||
private ReactiveRedisConnection connection;
|
||||
private RedisSerializer<String> serializer = new StringRedisSerializer();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.connection = connectionFactory.getReactiveConnection();
|
||||
}
|
||||
|
||||
@@ -73,7 +66,7 @@ public class KeyCommandsTests {
|
||||
* All keys will be loaded within <strong>one single</strong> operation.
|
||||
*/
|
||||
@Test
|
||||
public void iterateOverKeysMatchingPrefixUsingKeysCommand() {
|
||||
void iterateOverKeysMatchingPrefixUsingKeysCommand() {
|
||||
|
||||
generateRandomKeys(50);
|
||||
|
||||
@@ -91,7 +84,7 @@ public class KeyCommandsTests {
|
||||
* Uses {@code RPUSH} to store an item inside a list and {@code BRPOP} <br />
|
||||
*/
|
||||
@Test
|
||||
public void storeToListAndPop() {
|
||||
void storeToListAndPop() {
|
||||
|
||||
var popResult = connection.listCommands()
|
||||
.brPop(Collections.singletonList(ByteBuffer.wrap("list".getBytes())), Duration.ofSeconds(5));
|
||||
|
||||
@@ -18,22 +18,19 @@ package example.springdata.redis.operations;
|
||||
import example.springdata.redis.EmailAddress;
|
||||
import example.springdata.redis.Person;
|
||||
import example.springdata.redis.RedisTestConfiguration;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
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.connection.ReactiveRedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.ReactiveRedisOperations;
|
||||
import org.springframework.data.redis.util.ByteUtils;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of reactive Template API on Redis lists using {@link ReactiveRedisOperations} with Jackson serialization.
|
||||
@@ -41,12 +38,9 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = RedisTestConfiguration.class)
|
||||
public class JacksonJsonTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
|
||||
@EnabledOnRedisAvailable
|
||||
class JacksonJsonTests {
|
||||
|
||||
@Autowired ReactiveRedisOperations<String, Person> typedOperations;
|
||||
|
||||
@@ -60,7 +54,7 @@ public class JacksonJsonTests {
|
||||
* @see RedisTestConfiguration#reactiveJsonPersonRedisTemplate(ReactiveRedisConnectionFactory)
|
||||
*/
|
||||
@Test
|
||||
public void shouldWriteAndReadPerson() {
|
||||
void shouldWriteAndReadPerson() {
|
||||
|
||||
StepVerifier.create(typedOperations.opsForValue().set("homer", new Person("Homer", "Simpson"))) //
|
||||
.expectNext(true) //
|
||||
@@ -70,11 +64,11 @@ public class JacksonJsonTests {
|
||||
.map(ByteUtils::getBytes) //
|
||||
.map(String::new);
|
||||
|
||||
StepVerifier.create(get) //
|
||||
get.as(StepVerifier::create) //
|
||||
.expectNext("{\"firstname\":\"Homer\",\"lastname\":\"Simpson\"}") //
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(typedOperations.opsForValue().get("homer")) //
|
||||
typedOperations.opsForValue().get("homer").as(StepVerifier::create) //
|
||||
.expectNext(new Person("Homer", "Simpson")) //
|
||||
.verifyComplete();
|
||||
}
|
||||
@@ -87,9 +81,10 @@ public class JacksonJsonTests {
|
||||
* @see RedisTestConfiguration#reactiveJsonObjectRedisTemplate(ReactiveRedisConnectionFactory)
|
||||
*/
|
||||
@Test
|
||||
public void shouldWriteAndReadPersonObject() {
|
||||
void shouldWriteAndReadPersonObject() {
|
||||
|
||||
StepVerifier.create(genericOperations.opsForValue().set("homer", new Person("Homer", "Simpson"))) //
|
||||
genericOperations.opsForValue().set("homer", new Person("Homer", "Simpson")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete();
|
||||
|
||||
@@ -97,11 +92,11 @@ public class JacksonJsonTests {
|
||||
.map(ByteUtils::getBytes) //
|
||||
.map(String::new);
|
||||
|
||||
StepVerifier.create(get) //
|
||||
get.as(StepVerifier::create) //
|
||||
.expectNext("{\"_type\":\"example.springdata.redis.Person\",\"firstname\":\"Homer\",\"lastname\":\"Simpson\"}") //
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(genericOperations.opsForValue().get("homer")) //
|
||||
genericOperations.opsForValue().get("homer").as(StepVerifier::create) //
|
||||
.expectNext(new Person("Homer", "Simpson")) //
|
||||
.verifyComplete();
|
||||
}
|
||||
@@ -115,9 +110,10 @@ public class JacksonJsonTests {
|
||||
* @see RedisTestConfiguration#reactiveJsonObjectRedisTemplate(ReactiveRedisConnectionFactory)
|
||||
*/
|
||||
@Test
|
||||
public void shouldWriteAndReadEmailObject() {
|
||||
void shouldWriteAndReadEmailObject() {
|
||||
|
||||
StepVerifier.create(genericOperations.opsForValue().set("mail", new EmailAddress("homer@the-simpsons.com"))) //
|
||||
genericOperations.opsForValue().set("mail", new EmailAddress("homer@the-simpsons.com")) //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(true) //
|
||||
.verifyComplete();
|
||||
|
||||
@@ -125,11 +121,12 @@ public class JacksonJsonTests {
|
||||
.map(ByteUtils::getBytes) //
|
||||
.map(String::new);
|
||||
|
||||
StepVerifier.create(get) //
|
||||
get.as(StepVerifier::create) //
|
||||
.expectNext("{\"_type\":\"example.springdata.redis.EmailAddress\",\"address\":\"homer@the-simpsons.com\"}") //
|
||||
.verifyComplete();
|
||||
|
||||
StepVerifier.create(genericOperations.opsForValue().get("mail")) //
|
||||
genericOperations.opsForValue().get("mail") //
|
||||
.as(StepVerifier::create) //
|
||||
.expectNext(new EmailAddress("homer@the-simpsons.com")) //
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
package example.springdata.redis.operations;
|
||||
|
||||
import example.springdata.redis.RedisTestConfiguration;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -24,15 +24,12 @@ import reactor.test.StepVerifier;
|
||||
import java.time.Duration;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.ReactiveListOperations;
|
||||
import org.springframework.data.redis.core.ReactiveRedisOperations;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of reactive Template API on Redis lists using {@link ReactiveRedisOperations}.
|
||||
@@ -40,17 +37,14 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = RedisTestConfiguration.class)
|
||||
public class ListOperationsTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
|
||||
@EnabledOnRedisAvailable
|
||||
class ListOperationsTests {
|
||||
|
||||
@Autowired ReactiveRedisOperations<String, String> operations;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
@BeforeEach
|
||||
void before() {
|
||||
StepVerifier.create(operations.execute(it -> it.serverCommands().flushDb())).expectNext("OK").verifyComplete();
|
||||
}
|
||||
|
||||
@@ -58,7 +52,7 @@ public class ListOperationsTests {
|
||||
* A simple queue using Redis blocking list commands {@code BLPOP} and {@code LPUSH} to produce the queue message.
|
||||
*/
|
||||
@Test
|
||||
public void shouldPollAndPopulateQueue() {
|
||||
void shouldPollAndPopulateQueue() {
|
||||
|
||||
var queue = "foo";
|
||||
|
||||
|
||||
@@ -18,22 +18,19 @@ package example.springdata.redis.operations;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import example.springdata.redis.RedisTestConfiguration;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
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.ReactiveRedisOperations;
|
||||
import org.springframework.data.redis.core.ReactiveValueOperations;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Show usage of reactive Template API on Redis strings using {@link ReactiveRedisOperations}.
|
||||
@@ -41,17 +38,14 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Slf4j
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(classes = RedisTestConfiguration.class)
|
||||
public class ValueOperationsTests {
|
||||
|
||||
// we only want to run this tests when redis is up an running
|
||||
public static @ClassRule RequiresRedisServer requiresServer = RequiresRedisServer.onLocalhost();
|
||||
@EnabledOnRedisAvailable
|
||||
class ValueOperationsTests {
|
||||
|
||||
@Autowired ReactiveRedisOperations<String, String> operations;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
@BeforeEach
|
||||
void before() {
|
||||
StepVerifier.create(operations.execute(it -> it.serverCommands().flushDb())).expectNext("OK").verifyComplete();
|
||||
}
|
||||
|
||||
@@ -59,7 +53,7 @@ public class ValueOperationsTests {
|
||||
* Implement a simple caching sequence using {@code GET} and {@code SETEX} commands.
|
||||
*/
|
||||
@Test
|
||||
public void shouldCacheValue() {
|
||||
void shouldCacheValue() {
|
||||
|
||||
var cacheKey = "foo";
|
||||
|
||||
|
||||
@@ -17,24 +17,19 @@ package example.springdata.redis.repositories;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import example.springdata.redis.test.util.EmbeddedRedisServer;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import example.springdata.redis.test.condition.EnabledOnRedisAvailable;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.RuleChain;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.geo.Circle;
|
||||
@@ -45,25 +40,15 @@ import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
import org.springframework.data.redis.core.index.GeoIndexed;
|
||||
import org.springframework.data.redis.core.index.Indexed;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class PersonRepositoryTests {
|
||||
|
||||
/**
|
||||
* We need to have a Redis server instance available. <br />
|
||||
* 1) Start/Stop an embedded instance or reuse an already running local installation <br />
|
||||
* 2) Ignore tests if startup failed and no server running locally.
|
||||
*/
|
||||
public static @ClassRule RuleChain rules = RuleChain
|
||||
.outerRule(EmbeddedRedisServer.runningAt(6379).suppressExceptions())
|
||||
.around(RequiresRedisServer.onLocalhost().atLeast("3.2"));
|
||||
@DataRedisTest
|
||||
@EnabledOnRedisAvailable
|
||||
class PersonRepositoryTests {
|
||||
|
||||
/** {@link Charset} for String conversion **/
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
@@ -74,17 +59,17 @@ public class PersonRepositoryTests {
|
||||
/*
|
||||
* Set of test users
|
||||
*/
|
||||
Person eddard = new Person("eddard", "stark", Gender.MALE);
|
||||
Person robb = new Person("robb", "stark", Gender.MALE);
|
||||
Person sansa = new Person("sansa", "stark", Gender.FEMALE);
|
||||
Person arya = new Person("arya", "stark", Gender.FEMALE);
|
||||
Person bran = new Person("bran", "stark", Gender.MALE);
|
||||
Person rickon = new Person("rickon", "stark", Gender.MALE);
|
||||
Person jon = new Person("jon", "snow", Gender.MALE);
|
||||
private Person eddard = new Person("eddard", "stark", Gender.MALE);
|
||||
private Person robb = new Person("robb", "stark", Gender.MALE);
|
||||
private Person sansa = new Person("sansa", "stark", Gender.FEMALE);
|
||||
private Person arya = new Person("arya", "stark", Gender.FEMALE);
|
||||
private Person bran = new Person("bran", "stark", Gender.MALE);
|
||||
private Person rickon = new Person("rickon", "stark", Gender.MALE);
|
||||
private Person jon = new Person("jon", "snow", Gender.MALE);
|
||||
|
||||
@Before
|
||||
@After
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
@AfterEach
|
||||
void setUp() {
|
||||
|
||||
operations.execute((RedisConnection connection) -> {
|
||||
connection.flushDb();
|
||||
@@ -97,7 +82,7 @@ public class PersonRepositoryTests {
|
||||
* Print out the hash structure within Redis.
|
||||
*/
|
||||
@Test
|
||||
public void saveSingleEntity() {
|
||||
void saveSingleEntity() {
|
||||
|
||||
repository.save(eddard);
|
||||
|
||||
@@ -110,7 +95,7 @@ public class PersonRepositoryTests {
|
||||
* Find entity by a single {@link Indexed} property value.
|
||||
*/
|
||||
@Test
|
||||
public void findBySingleProperty() {
|
||||
void findBySingleProperty() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -123,7 +108,7 @@ public class PersonRepositoryTests {
|
||||
* Find entities by multiple {@link Indexed} properties using {@literal AND}.
|
||||
*/
|
||||
@Test
|
||||
public void findByMultipleProperties() {
|
||||
void findByMultipleProperties() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -136,7 +121,7 @@ public class PersonRepositoryTests {
|
||||
* Find entities by multiple {@link Indexed} properties using {@literal OR}.
|
||||
*/
|
||||
@Test
|
||||
public void findByMultiplePropertiesUsingOr() {
|
||||
void findByMultiplePropertiesUsingOr() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -149,7 +134,7 @@ public class PersonRepositoryTests {
|
||||
* Find entities by {@link Example Query by Example}.
|
||||
*/
|
||||
@Test
|
||||
public void findByQueryByExample() {
|
||||
void findByQueryByExample() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -164,7 +149,7 @@ public class PersonRepositoryTests {
|
||||
* Find entities in range defined by {@link Pageable}.
|
||||
*/
|
||||
@Test
|
||||
public void findByReturningPage() {
|
||||
void findByReturningPage() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -183,7 +168,7 @@ public class PersonRepositoryTests {
|
||||
* Find entity by a single {@link Indexed} property on an embedded entity.
|
||||
*/
|
||||
@Test
|
||||
public void findByEmbeddedProperty() {
|
||||
void findByEmbeddedProperty() {
|
||||
|
||||
var winterfell = new Address();
|
||||
winterfell.setCountry("the north");
|
||||
@@ -202,7 +187,7 @@ public class PersonRepositoryTests {
|
||||
* Find entity by a {@link GeoIndexed} property on an embedded entity.
|
||||
*/
|
||||
@Test
|
||||
public void findByGeoLocationProperty() {
|
||||
void findByGeoLocationProperty() {
|
||||
|
||||
var winterfell = new Address();
|
||||
winterfell.setCountry("the north");
|
||||
@@ -236,7 +221,7 @@ public class PersonRepositoryTests {
|
||||
* Print out the hash structure within Redis.
|
||||
*/
|
||||
@Test
|
||||
public void useReferencesToStoreDataToOtherObjects() {
|
||||
void useReferencesToStoreDataToOtherObjects() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
|
||||
@@ -18,16 +18,19 @@ package example.springdata.redis.reactive;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.redis.connection.stream.StreamOffset.*;
|
||||
|
||||
import example.springdata.redis.SensorData;
|
||||
import example.springdata.redis.test.condition.EnabledOnCommand;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import example.springdata.redis.SensorData;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.data.redis.RedisSystemException;
|
||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
||||
import org.springframework.data.redis.connection.stream.ReadOffset;
|
||||
@@ -36,26 +39,22 @@ import org.springframework.data.redis.connection.stream.StreamOffset;
|
||||
import org.springframework.data.redis.core.ReactiveStreamOperations;
|
||||
import org.springframework.data.redis.core.ReactiveStringRedisTemplate;
|
||||
import org.springframework.data.redis.stream.StreamReceiver;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class ReactiveStreamApiTests {
|
||||
|
||||
public static @ClassRule RequiresRedisServer server = RequiresRedisServer.onLocalhost().atLeast("5.0");
|
||||
@DataRedisTest
|
||||
@EnabledOnCommand("XADD")
|
||||
@ImportAutoConfiguration(RedisReactiveAutoConfiguration.class)
|
||||
class ReactiveStreamApiTests {
|
||||
|
||||
@Autowired ReactiveStringRedisTemplate template;
|
||||
@Autowired StreamReceiver<String, MapRecord<String, String, String>> streamReceiver;
|
||||
|
||||
ReactiveStreamOperations<String, String, String> streamOps;
|
||||
private ReactiveStreamOperations<String, String, String> streamOps;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
// clear all
|
||||
template.getConnectionFactory().getReactiveConnection()
|
||||
@@ -67,7 +66,7 @@ public class ReactiveStreamApiTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basics() {
|
||||
void basics() {
|
||||
|
||||
// XADD with fixed id
|
||||
streamOps.add(SensorData.RECORD_1234_0)
|
||||
@@ -111,7 +110,7 @@ public class ReactiveStreamApiTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void continuousRead() {
|
||||
void continuousRead() {
|
||||
|
||||
var messages = streamReceiver.receive(fromStart(SensorData.KEY));
|
||||
|
||||
|
||||
@@ -18,17 +18,16 @@ package example.springdata.redis.sync;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.redis.connection.stream.StreamOffset.*;
|
||||
|
||||
import java.util.List;
|
||||
import example.springdata.redis.SensorData;
|
||||
import example.springdata.redis.test.condition.EnabledOnCommand;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import example.springdata.redis.SensorData;
|
||||
import example.springdata.redis.test.util.RequiresRedisServer;
|
||||
import org.junit.Before;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.data.redis.RedisSystemException;
|
||||
import org.springframework.data.redis.connection.stream.MapRecord;
|
||||
import org.springframework.data.redis.connection.stream.ReadOffset;
|
||||
@@ -37,25 +36,22 @@ import org.springframework.data.redis.connection.stream.StreamOffset;
|
||||
import org.springframework.data.redis.core.StreamOperations;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.stream.StreamMessageListenerContainer;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class SyncStreamApiTests {
|
||||
|
||||
public static @ClassRule RequiresRedisServer server = RequiresRedisServer.onLocalhost().atLeast("5.0");
|
||||
@DataRedisTest
|
||||
@EnabledOnCommand("XADD")
|
||||
class SyncStreamApiTests {
|
||||
|
||||
@Autowired StringRedisTemplate template;
|
||||
@Autowired StreamMessageListenerContainer<String, MapRecord<String, String, String>> messageListenerContainer;
|
||||
|
||||
StreamOperations<String, String, String> streamOps;
|
||||
private StreamOperations<String, String, String> streamOps;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
|
||||
// clear all
|
||||
template.getConnectionFactory().getConnection().flushAll();
|
||||
@@ -64,7 +60,7 @@ public class SyncStreamApiTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basics() {
|
||||
void basics() {
|
||||
|
||||
// XADD with fixed id
|
||||
var fixedId1 = streamOps.add(SensorData.RECORD_1234_0);
|
||||
@@ -97,7 +93,7 @@ public class SyncStreamApiTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void continuousRead() throws InterruptedException {
|
||||
void continuousRead() throws InterruptedException {
|
||||
|
||||
// container autostart is disabled by default
|
||||
if (!messageListenerContainer.isRunning()) {
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* {@code @EnabledOnCommand} is used to signal that the annotated test class or test method is only <em>enabled</em> if
|
||||
* the specified command is available.
|
||||
* <p/>
|
||||
* When applied at the class level, all test methods within that class will be enabled.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@ExtendWith(EnabledOnCommandCondition.class)
|
||||
public @interface EnabledOnCommand {
|
||||
|
||||
String host() default "localhost";
|
||||
|
||||
/**
|
||||
* Redis port number.
|
||||
*/
|
||||
int port() default 6379;
|
||||
|
||||
/**
|
||||
* Name of the Redis command to be available.
|
||||
*/
|
||||
String value();
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import static org.junit.jupiter.api.extension.ConditionEvaluationResult.*;
|
||||
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ExecutionCondition} for {@link EnabledOnCommandCondition @EnabledOnCommand}.
|
||||
*
|
||||
* @see EnabledOnCommandCondition
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class EnabledOnCommandCondition implements ExecutionCondition {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled("@EnabledOnCommand is not present");
|
||||
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(RedisConditions.class);
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
|
||||
var optional = AnnotationUtils.findAnnotation(context.getElement(), EnabledOnCommand.class);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
return ENABLED_BY_DEFAULT;
|
||||
}
|
||||
|
||||
var annotation = optional.get();
|
||||
var command = annotation.value();
|
||||
|
||||
var store = context.getStore(NAMESPACE);
|
||||
var conditions = store.getOrComputeIfAbsent(RedisConditions.class, ignore -> {
|
||||
|
||||
var redisClient = RedisClient.create(LettuceTestClientResources.getSharedClientResources(),
|
||||
RedisURI.create(annotation.host(), annotation.port()));
|
||||
|
||||
var connection = redisClient.connect();
|
||||
var redisConditions = RedisConditions.of(connection);
|
||||
|
||||
connection.close();
|
||||
redisClient.shutdown(Duration.ZERO, Duration.ZERO);
|
||||
return redisConditions;
|
||||
}, RedisConditions.class);
|
||||
|
||||
var hasCommand = conditions.hasCommand(command);
|
||||
return hasCommand ? enabled("Enabled on command " + command)
|
||||
: disabled("Disabled, command " + command + " not available on Redis version " + conditions.getRedisVersion());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* {@code @EnabledOnRedisAvailable} is used to signal that the annotated test class or test method is only
|
||||
* <em>enabled</em> if Redis is running at {@link #port() port}.
|
||||
* <p/>
|
||||
* When applied at the class level, all test methods within that class will be enabled.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@ExtendWith(EnabledOnRedisAvailableCondition.class)
|
||||
public @interface EnabledOnRedisAvailable {
|
||||
|
||||
String host() default "localhost";
|
||||
|
||||
/**
|
||||
* Redis port number.
|
||||
*/
|
||||
int port() default 6379;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import static org.junit.jupiter.api.extension.ConditionEvaluationResult.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ExecutionCondition} for {@link EnabledOnRedisAvailableCondition @EnabledOnRedisAvailable}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @see EnabledOnRedisAvailableCondition
|
||||
*/
|
||||
class EnabledOnRedisAvailableCondition implements ExecutionCondition {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled(
|
||||
"@EnabledOnRedisAvailable is not present");
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
|
||||
var optional = AnnotationUtils.findAnnotation(context.getElement(), EnabledOnRedisAvailable.class);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
return ENABLED_BY_DEFAULT;
|
||||
}
|
||||
|
||||
var annotation = optional.get();
|
||||
|
||||
try (var socket = new Socket()) {
|
||||
socket.connect(new InetSocketAddress(annotation.host(), annotation.port()), 100);
|
||||
|
||||
return enabled(String.format("Connection successful to Redis at %s:%d", annotation.host(), annotation.port()));
|
||||
} catch (IOException e) {
|
||||
return disabled(String.format("Cannot connect to Redis at %s:%d (%s)", annotation.host(), annotation.port(), e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* {@code @EnabledOnRedisClusterAvailable} is used to signal that the annotated test class or test method is only
|
||||
* <em>enabled</em> if Redis Cluster is running.
|
||||
* <p/>
|
||||
* When applied at the class level, all test methods within that class will be enabled.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@ExtendWith(EnabledOnRedisClusterCondition.class)
|
||||
public @interface EnabledOnRedisClusterAvailable {
|
||||
|
||||
String host() default "localhost";
|
||||
|
||||
/**
|
||||
* Redis port number.
|
||||
*/
|
||||
int port();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import static org.junit.jupiter.api.extension.ConditionEvaluationResult.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ExecutionCondition} for {@link EnabledOnRedisClusterCondition @EnabledOnRedisClusterAvailable}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @see EnabledOnRedisClusterCondition
|
||||
*/
|
||||
class EnabledOnRedisClusterCondition implements ExecutionCondition {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled(
|
||||
"@EnabledOnClusterAvailable is not present");
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
|
||||
var optional = AnnotationUtils.findAnnotation(context.getElement(), EnabledOnRedisClusterAvailable.class);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
return ENABLED_BY_DEFAULT;
|
||||
}
|
||||
|
||||
var annotation = optional.get();
|
||||
|
||||
try (var socket = new Socket()) {
|
||||
|
||||
socket.connect(new InetSocketAddress(annotation.host(), annotation.port()), 100);
|
||||
|
||||
return enabled(
|
||||
String.format("Connection successful to Redis Cluster at %s:%d", annotation.host(), annotation.port()));
|
||||
} catch (IOException e) {
|
||||
return disabled(
|
||||
String.format("Cannot connect to Redis Cluster at %s:%d (%s)", annotation.host(), annotation.port(), e));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* {@code @EnabledOnRedisSentinelAvailable} is used to signal that the annotated test class or test method is only
|
||||
* <em>enabled</em> if Redis Sentinel is running.
|
||||
* <p/>
|
||||
* When applied at the class level, all test methods within that class will be enabled.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@ExtendWith(EnabledOnRedisSentinelCondition.class)
|
||||
public @interface EnabledOnRedisSentinelAvailable {
|
||||
|
||||
String host() default "localhost";
|
||||
|
||||
/**
|
||||
* Sentinel port number.
|
||||
*/
|
||||
int value() default 26379;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import static org.junit.jupiter.api.extension.ConditionEvaluationResult.*;
|
||||
|
||||
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
|
||||
import org.junit.jupiter.api.extension.ExecutionCondition;
|
||||
import org.junit.jupiter.api.extension.ExtensionContext;
|
||||
import org.junit.platform.commons.util.AnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ExecutionCondition} for {@link EnabledOnRedisSentinelCondition @EnabledOnRedisSentinelAvailable}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
* @see EnabledOnRedisSentinelCondition
|
||||
*/
|
||||
class EnabledOnRedisSentinelCondition implements ExecutionCondition {
|
||||
|
||||
private static final ConditionEvaluationResult ENABLED_BY_DEFAULT = enabled(
|
||||
"@EnabledOnSentinelAvailable is not present");
|
||||
|
||||
@Override
|
||||
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
|
||||
|
||||
var optional = AnnotationUtils.findAnnotation(context.getElement(), EnabledOnRedisSentinelAvailable.class);
|
||||
|
||||
if (!optional.isPresent()) {
|
||||
return ENABLED_BY_DEFAULT;
|
||||
}
|
||||
|
||||
var annotation = optional.get();
|
||||
|
||||
if (RedisDetector.canConnectToPort(annotation.host(), annotation.value())) {
|
||||
|
||||
return enabled(
|
||||
String.format("Connection successful to Redis Sentinel at %s:%d", annotation.host(), annotation.value()));
|
||||
}
|
||||
|
||||
return disabled(String.format("Cannot connect to Redis Sentinel at %s:%d", annotation.host(), annotation.value()));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import io.lettuce.core.resource.ClientResources;
|
||||
import io.lettuce.core.resource.DefaultClientResources;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Client-Resources suitable for testing. Every time a new {@link LettuceTestClientResources} instance is created, a
|
||||
* {@link Runtime#addShutdownHook(Thread) shutdown hook} is added to close the client resources.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class LettuceTestClientResources {
|
||||
|
||||
private static final ClientResources SHARED_CLIENT_RESOURCES;
|
||||
|
||||
static {
|
||||
|
||||
SHARED_CLIENT_RESOURCES = DefaultClientResources.builder().build();
|
||||
ShutdownQueue.INSTANCE.register(() -> SHARED_CLIENT_RESOURCES.shutdown(0, 0, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
private LettuceTestClientResources() {}
|
||||
|
||||
/**
|
||||
* @return the client resources.
|
||||
*/
|
||||
public static ClientResources getSharedClientResources() {
|
||||
return SHARED_CLIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
import io.lettuce.core.api.sync.RedisCommands;
|
||||
import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
|
||||
import io.lettuce.core.cluster.api.sync.RedisClusterCommands;
|
||||
import io.lettuce.core.models.command.CommandDetail;
|
||||
import io.lettuce.core.models.command.CommandDetailParser;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.data.util.Version;
|
||||
|
||||
/**
|
||||
* Collection of utility methods to test conditions during test execution.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class RedisConditions {
|
||||
|
||||
private final Map<String, Integer> commands;
|
||||
private final Version version;
|
||||
|
||||
private RedisConditions(RedisClusterCommands<String, String> commands) {
|
||||
|
||||
var result = CommandDetailParser.parse(commands.command());
|
||||
|
||||
this.commands = result.stream()
|
||||
.collect(Collectors.toMap(commandDetail -> commandDetail.getName().toUpperCase(), CommandDetail::getArity));
|
||||
|
||||
var info = commands.info("server");
|
||||
|
||||
try {
|
||||
|
||||
var inputStream = new ByteArrayInputStream(info.getBytes());
|
||||
var p = new Properties();
|
||||
p.load(inputStream);
|
||||
|
||||
version = Version.parse(p.getProperty("redis_version"));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link RedisCommands} given {@link StatefulRedisConnection}.
|
||||
*
|
||||
* @param connection must not be {@code null}.
|
||||
* @return
|
||||
*/
|
||||
public static RedisConditions of(StatefulRedisConnection<String, String> connection) {
|
||||
return new RedisConditions(connection.sync());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link RedisCommands} given {@link StatefulRedisClusterConnection}.
|
||||
*
|
||||
* @param connection must not be {@code null}.
|
||||
* @return
|
||||
*/
|
||||
public static RedisConditions of(StatefulRedisClusterConnection<String, String> connection) {
|
||||
return new RedisConditions(connection.sync());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link RedisConditions} given {@link RedisCommands}.
|
||||
*
|
||||
* @param commands must not be {@code null}.
|
||||
* @return
|
||||
*/
|
||||
public static RedisConditions of(RedisClusterCommands<String, String> commands) {
|
||||
return new RedisConditions(commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Redis {@link Version}.
|
||||
*/
|
||||
public Version getRedisVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command
|
||||
* @return {@code true} if the command is present.
|
||||
*/
|
||||
public boolean hasCommand(String command) {
|
||||
return commands.containsKey(command.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param command command name.
|
||||
* @param arity expected arity.
|
||||
* @return {@code true} if the command is present with the given arity.
|
||||
*/
|
||||
public boolean hasCommandArity(String command, int arity) {
|
||||
|
||||
if (!hasCommand(command)) {
|
||||
throw new IllegalStateException("Unknown command: " + command + " in " + commands);
|
||||
}
|
||||
|
||||
return commands.get(command.toUpperCase()) == arity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param versionNumber
|
||||
* @return {@code true} if the version number is met.
|
||||
*/
|
||||
public boolean hasVersionGreaterOrEqualsTo(String versionNumber) {
|
||||
return version.isGreaterThanOrEqualTo(Version.parse(versionNumber));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
|
||||
/**
|
||||
* Utility to detect Redis operation modes.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class RedisDetector {
|
||||
|
||||
public static boolean canConnectToPort(String host, int port) {
|
||||
|
||||
try (var socket = new Socket()) {
|
||||
socket.connect(new InetSocketAddress(host, port), 100);
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020-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.
|
||||
* 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 example.springdata.redis.test.condition;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Shutdown queue allowing ordered resource shutdown (LIFO).
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
enum ShutdownQueue {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
static {
|
||||
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Closeable closeable;
|
||||
while ((closeable = INSTANCE.closeables.pollLast()) != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (Exception o_O) {
|
||||
// ignore
|
||||
o_O.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final LinkedList<Closeable> closeables = new LinkedList<>();
|
||||
|
||||
public static void register(Closeable closeable) {
|
||||
INSTANCE.closeables.add(closeable);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 example.springdata.redis.test.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.rules.ExternalResource;
|
||||
|
||||
import redis.embedded.RedisServer;
|
||||
|
||||
/**
|
||||
* JUnit rule implementation to start and shut down an embedded Redis instance.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class EmbeddedRedisServer extends ExternalResource {
|
||||
|
||||
private static final int DEFAULT_PORT = 6379;
|
||||
private RedisServer server;
|
||||
private int port = DEFAULT_PORT;
|
||||
private boolean suppressExceptions = false;
|
||||
|
||||
public EmbeddedRedisServer() {
|
||||
|
||||
}
|
||||
|
||||
protected EmbeddedRedisServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public static EmbeddedRedisServer runningAt(Integer port) {
|
||||
return new EmbeddedRedisServer(port != null ? port : DEFAULT_PORT);
|
||||
}
|
||||
|
||||
public EmbeddedRedisServer suppressExceptions() {
|
||||
this.suppressExceptions = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.junit.rules.ExternalResource#before()
|
||||
*/
|
||||
@Override
|
||||
protected void before() throws IOException {
|
||||
|
||||
try {
|
||||
|
||||
this.server = new RedisServer(this.port);
|
||||
this.server.start();
|
||||
} catch (Exception e) {
|
||||
if (!suppressExceptions) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.junit.rules.ExternalResource#after()
|
||||
*/
|
||||
@Override
|
||||
protected void after() {
|
||||
|
||||
try {
|
||||
this.server.stop();
|
||||
} catch (Exception e) {
|
||||
if (!suppressExceptions) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017-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.
|
||||
* 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 example.springdata.redis.test.util;
|
||||
|
||||
import io.lettuce.core.resource.ClientResources;
|
||||
import io.lettuce.core.resource.DefaultClientResources;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Utility to keep track of a single {@link ClientResources} instance used from test rules to prevent costly
|
||||
* creation/disposal of threading resources.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ManagedClientResources {
|
||||
|
||||
private static final ManagedClientResources instance = new ManagedClientResources();
|
||||
|
||||
private final AtomicReference<ClientResources> clientResources = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Obtain a managed instance of {@link ClientResources}. Allocates an instance if {@link ManagedClientResources} was
|
||||
* not initialized already.
|
||||
*
|
||||
* @return the {@link ClientResources}.
|
||||
*/
|
||||
static ClientResources getClientResources() {
|
||||
|
||||
var ref = instance.clientResources;
|
||||
|
||||
var clientResources = ref.get();
|
||||
if (clientResources != null) {
|
||||
return clientResources;
|
||||
}
|
||||
|
||||
clientResources = DefaultClientResources.create();
|
||||
|
||||
if (ref.compareAndSet(null, clientResources)) {
|
||||
return clientResources;
|
||||
}
|
||||
|
||||
clientResources.shutdown(0, 0, TimeUnit.SECONDS);
|
||||
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-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.
|
||||
* 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 example.springdata.redis.test.util;
|
||||
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.internal.AssumptionViolatedException;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class RequiresRedisSentinel implements TestRule {
|
||||
|
||||
public enum SentinelsAvailable {
|
||||
ALL_ACTIVE, ONE_ACTIVE, NONE_ACTIVE
|
||||
}
|
||||
|
||||
private static final RedisSentinelConfiguration DEFAULT_SENTINEL_CONFIG = new RedisSentinelConfiguration()
|
||||
.master("mymaster").sentinel("127.0.0.1", 26379).sentinel("127.0.0.1", 26380).sentinel("127.0.0.1", 26381);
|
||||
|
||||
private RedisSentinelConfiguration sentinelConfig;
|
||||
private SentinelsAvailable requiredSentinels;
|
||||
|
||||
protected RequiresRedisSentinel(RedisSentinelConfiguration config) {
|
||||
this.sentinelConfig = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link RequiresRedisSentinel} for given {@link RedisSentinelConfiguration}.
|
||||
*
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
public static RequiresRedisSentinel forConfig(RedisSentinelConfiguration config) {
|
||||
return new RequiresRedisSentinel(config != null ? config : DEFAULT_SENTINEL_CONFIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new {@link RequiresRedisSentinel} using default configuration.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static RequiresRedisSentinel withDefaultConfig() {
|
||||
return new RequiresRedisSentinel(DEFAULT_SENTINEL_CONFIG);
|
||||
}
|
||||
|
||||
public RequiresRedisSentinel sentinelsDisabled() {
|
||||
|
||||
this.requiredSentinels = SentinelsAvailable.NONE_ACTIVE;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies all {@literal Sentinel} nodes are available.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RequiresRedisSentinel allActive() {
|
||||
|
||||
this.requiredSentinels = SentinelsAvailable.ALL_ACTIVE;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies at least one {@literal Sentinel} node is available.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RequiresRedisSentinel oneActive() {
|
||||
|
||||
this.requiredSentinels = SentinelsAvailable.ONE_ACTIVE;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will only check {@link RedisSentinelConfiguration} configuration in case {@link RequiresRedisSentinel} is detected
|
||||
* on test method.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public RequiresRedisSentinel dynamicModeSelection() {
|
||||
this.requiredSentinels = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, org.junit.runner.Description)
|
||||
*/
|
||||
@Override
|
||||
public Statement apply(final Statement base, final Description description) {
|
||||
|
||||
return new Statement() {
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
|
||||
if (description.isTest()) {
|
||||
if (RequiresRedisSentinel.this.requiredSentinels != null) {
|
||||
verify(RequiresRedisSentinel.this.requiredSentinels);
|
||||
}
|
||||
|
||||
} else {
|
||||
verify(RequiresRedisSentinel.this.requiredSentinels);
|
||||
}
|
||||
|
||||
base.evaluate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void verify(SentinelsAvailable verificationMode) {
|
||||
|
||||
var failed = 0;
|
||||
for (var node : sentinelConfig.getSentinels()) {
|
||||
if (!isAvailable(node)) {
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed > 0) {
|
||||
if (SentinelsAvailable.ALL_ACTIVE.equals(verificationMode)) {
|
||||
throw new AssumptionViolatedException(
|
||||
String.format("Expected all Redis Sentinels to respone but %s of %s did not responde", failed,
|
||||
sentinelConfig.getSentinels().size()));
|
||||
}
|
||||
|
||||
if (SentinelsAvailable.ONE_ACTIVE.equals(verificationMode) && sentinelConfig.getSentinels().size() - 1 < failed) {
|
||||
throw new AssumptionViolatedException(
|
||||
"Expected at least one sentinel to respond but it seems all are offline - Game Over!");
|
||||
}
|
||||
}
|
||||
|
||||
if (SentinelsAvailable.NONE_ACTIVE.equals(verificationMode) && failed != sentinelConfig.getSentinels().size()) {
|
||||
throw new AssumptionViolatedException(
|
||||
String.format("Expected to have no sentinels online but found that %s are still alive.",
|
||||
(sentinelConfig.getSentinels().size() - failed)));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAvailable(RedisNode node) {
|
||||
|
||||
var redisClient = RedisClient.create(ManagedClientResources.getClientResources(),
|
||||
RedisURI.create(node.getHost(), node.getPort()));
|
||||
|
||||
try (var connection = redisClient.connect()) {
|
||||
connection.sync().ping();
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
} finally {
|
||||
redisClient.shutdown(Duration.ZERO, Duration.ZERO);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-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.
|
||||
* 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 example.springdata.redis.test.util;
|
||||
|
||||
import io.lettuce.core.RedisClient;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import io.lettuce.core.api.StatefulRedisConnection;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.time.Duration;
|
||||
|
||||
import org.junit.AssumptionViolatedException;
|
||||
import org.junit.rules.ExternalResource;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConverters;
|
||||
import org.springframework.data.util.Version;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of junit rule {@link ExternalResource} to verify Redis (or at least something on the defined host and
|
||||
* port) is up and running. Allows optionally to require a specific Redis version.
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class RequiresRedisServer extends ExternalResource {
|
||||
|
||||
public static final Version NO_VERSION = Version.parse("0.0.0");
|
||||
|
||||
private int timeout = 30;
|
||||
private Version requiredVersion = NO_VERSION;
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
private RequiresRedisServer(String host, int port) {
|
||||
this(host, port, NO_VERSION);
|
||||
}
|
||||
|
||||
private RequiresRedisServer(String host, int port, Version requiredVersion) {
|
||||
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.requiredVersion = requiredVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a Redis instance listening on {@code localhost:6379}.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static RequiresRedisServer onLocalhost() {
|
||||
return new RequiresRedisServer("localhost", 6379);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a Redis instance listening {@code host:port}.
|
||||
*
|
||||
* @param host
|
||||
* @param port
|
||||
* @return
|
||||
*/
|
||||
public static RequiresRedisServer listeningAt(String host, int port) {
|
||||
return new RequiresRedisServer(StringUtils.hasText(host) ? host : "127.0.0.1", port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require a specific Redis version.
|
||||
*
|
||||
* @param version must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public RequiresRedisServer atLeast(String version) {
|
||||
|
||||
Assert.hasText(version, "Version must not be empty!");
|
||||
|
||||
return new RequiresRedisServer(host, port, Version.parse(version));
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.junit.rules.ExternalResource#before()
|
||||
*/
|
||||
@Override
|
||||
protected void before() throws Throwable {
|
||||
|
||||
try (var socket = new Socket()) {
|
||||
socket.setTcpNoDelay(true);
|
||||
socket.setSoLinger(true, 0);
|
||||
socket.connect(new InetSocketAddress(host, port), timeout);
|
||||
} catch (Exception e) {
|
||||
throw new AssumptionViolatedException(String.format("Seems as Redis is not running at %s:%s.", host, port), e);
|
||||
}
|
||||
|
||||
if (NO_VERSION.equals(requiredVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var redisClient = RedisClient.create(ManagedClientResources.getClientResources(),
|
||||
RedisURI.create(host, port));
|
||||
|
||||
try (var connection = redisClient.connect()) {
|
||||
|
||||
var infoServer = connection.sync().info("server");
|
||||
var redisVersion = LettuceConverters.stringToProps().convert(infoServer).getProperty("redis_version");
|
||||
var runningVersion = Version.parse(redisVersion);
|
||||
|
||||
if (runningVersion.isLessThan(requiredVersion)) {
|
||||
throw new AssumptionViolatedException(String
|
||||
.format("This test requires Redis version %s but you run version %s", requiredVersion, runningVersion));
|
||||
}
|
||||
|
||||
} finally {
|
||||
redisClient.shutdown(Duration.ZERO, Duration.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user