diff --git a/pom.xml b/pom.xml
index 31554944e2..c4c21f2d29 100644
--- a/pom.xml
+++ b/pom.xml
@@ -531,6 +531,21 @@
test
+
+
+
+ org.testcontainers
+ testcontainers
+ 1.20.1
+ test
+
+
+ org.testcontainers
+ junit-jupiter
+ 1.20.1
+ test
+
+
diff --git a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
index 0e5871d8cb..74abb1d73b 100644
--- a/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
+++ b/src/main/java/io/lettuce/core/RedisJsonCommandBuilder.java
@@ -255,9 +255,7 @@ Command jsonSet(K key, JsonPath jsonPath, JsonValue value, J
CommandArgs args = new CommandArgs<>(codec).addKey(key);
- if (jsonPath != null && !jsonPath.isRootPath()) {
- args.add(jsonPath.toString());
- }
+ args.add(jsonPath.toString());
args.add(value.asByteBuffer().array());
diff --git a/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java b/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java
index 52bba199ad..eb9ecdc6c2 100644
--- a/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/RedisContainerIntegrationTests.java
@@ -3,52 +3,65 @@
* All rights reserved.
*
* Licensed under the MIT License.
- *
- * This file contains contributions from third-party contributors
- * 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 io.lettuce.core;
-import io.lettuce.core.api.StatefulRedisConnection;
-import io.lettuce.core.api.async.RedisAsyncCommands;
+import io.lettuce.core.api.sync.RedisCommands;
+import io.lettuce.core.json.JsonPath;
+import io.lettuce.core.json.JsonValue;
+import io.lettuce.core.json.arguments.JsonSetArgs;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
-import java.time.Duration;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+@Testcontainers
public class RedisContainerIntegrationTests {
- // TODO use https://java.testcontainers.org/supported_docker_environment/
- protected static RedisAsyncCommands redis;
+ @Container
+ public GenericContainer redisContainer = new GenericContainer(image).withExposedPorts(6379).withReuse(true);;
+
+ private static DockerImageName image = DockerImageName.parse("redis/redis-stack:latest");
+
+ private static RedisClient client;
+
+ protected static RedisCommands redis;
+
+ @BeforeEach
+ public void prepare() throws IOException {
+ if (!redisContainer.isRunning()) {
+ redisContainer.start();
+ }
+
+ String address = redisContainer.getHost();
+ Integer port = redisContainer.getFirstMappedPort();
+ RedisURI redisURI = RedisURI.Builder.redis(address).withPort(port).build();
+
+ client = RedisClient.create(redisURI);
+ redis = client.connect().sync();
+
+ redis.flushall();
- protected static RedisClient redisClient;
+ Path path = Paths.get("src/test/resources/bike-inventory.json");
+ String read = String.join("", Files.readAllLines(path));
+ JsonValue value = redis.getJsonParser().createJsonValue(read);
- @BeforeAll
- static void setup() {
- RedisURI redisURI = RedisURI.Builder.redis("").withPort(19897)
- .withPassword("").withTimeout(Duration.ofSeconds(30)).build();
- redisClient = RedisClient.create(redisURI);
- StatefulRedisConnection connect = redisClient.connect();
- redis = connect.async();
+ redis.jsonSet("bikes:inventory", JsonPath.ROOT_PATH, value, JsonSetArgs.Builder.none());
}
@AfterAll
static void teardown() {
- if (redis != null)
- redis.getStatefulConnection().close();
- if (redisClient != null)
- redisClient.shutdown();
+ if (client != null) {
+ client.shutdown();
+ }
}
}
diff --git a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
index 3e0c4b9333..3aced7c4c0 100644
--- a/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
+++ b/src/test/java/io/lettuce/core/json/RedisJsonIntegrationTests.java
@@ -3,26 +3,12 @@
* All rights reserved.
*
* Licensed under the MIT License.
- *
- * This file contains contributions from third-party contributors
- * 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 io.lettuce.core.json;
import io.lettuce.core.RedisContainerIntegrationTests;
import io.lettuce.core.json.arguments.JsonGetArgs;
-import io.lettuce.core.json.arguments.JsonRangeArgs;
import io.lettuce.core.json.arguments.JsonSetArgs;
import org.junit.jupiter.api.Test;
@@ -44,23 +30,17 @@ void jsonArrappend() throws ExecutionException, InterruptedException {
JsonParser parser = redis.getJsonParser();
JsonValue element = parser.createJsonValue("\"{id:bike6}\"");
- List appendedElements = redis.jsonArrappend(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element).get();
+ List appendedElements = redis.jsonArrappend(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element);
assertThat(appendedElements).hasSize(1);
- assertThat(appendedElements.get(0)).isEqualTo(5);
-
- // Cleanup
-
- List> poppedJson = redis.jsonArrpop(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, -1).get();
- assertThat(poppedJson).hasSize(1);
- assertThat(poppedJson.get(0).toValue()).isEqualTo("\"{id:bike6}\"");
+ assertThat(appendedElements.get(0)).isEqualTo(4);
}
@Test
void jsonArrindex() throws ExecutionException, InterruptedException {
JsonParser parser = redis.getJsonParser();
- JsonValue element = parser.createJsonValue("\"{id:bike6}\"");
+ JsonValue element = parser.createJsonValue("\"id\": \"bike:2\"");
- List arrayIndex = redis.jsonArrindex(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element, null).get();
+ List arrayIndex = redis.jsonArrindex(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, element, null);
assertThat(arrayIndex).isNotNull();
assertThat(arrayIndex.get(0).longValue()).isEqualTo(3L);
}
@@ -72,18 +52,17 @@ void jsonArrinsert() {
@Test
void jsonArrlen() throws ExecutionException, InterruptedException {
- List poppedJson = redis.jsonArrlen(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH).get();
+ List poppedJson = redis.jsonArrlen(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH);
assertThat(poppedJson).hasSize(1);
- assertThat(poppedJson.get(0).longValue()).isEqualTo(5);
+ assertThat(poppedJson.get(0).longValue()).isEqualTo(3);
}
@Test
void jsonArrpop() throws ExecutionException, InterruptedException {
- List> poppedJson = redis.jsonArrpop(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, -1).get();
+ List> poppedJson = redis.jsonArrpop(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, -1);
assertThat(poppedJson).hasSize(1);
- assertThat(poppedJson.get(0).toValue()).isEqualTo("\"{id:bike6}\"");
-
- throw new RuntimeException("Missing cleanup");
+ assertThat(poppedJson.get(0).toValue()).contains(
+ "{\"id\":\"bike:3\",\"model\":\"Weywot\",\"description\":\"This bike gives kids aged six years and old");
}
@Test
@@ -101,7 +80,7 @@ void jsonGet() throws ExecutionException, InterruptedException {
JsonPath path = JsonPath.of("$..mountain_bikes[0:2].model");
// Verify codec parsing
- List> value = redis.jsonGet(BIKES_INVENTORY, JsonGetArgs.Builder.none(), path).get();
+ List> value = redis.jsonGet(BIKES_INVENTORY, JsonGetArgs.Builder.none(), path);
assertThat(value).hasSize(1);
assertThat(value.get(0).toValue()).isEqualTo("[\"Phoebe\",\"Quaoar\"]");
@@ -127,9 +106,9 @@ void jsonMerge() throws ExecutionException, InterruptedException {
void jsonMGet() throws ExecutionException, InterruptedException {
JsonPath path = JsonPath.of("$..model");
- List> value = redis.jsonMGet(path, BIKES_INVENTORY).get();
+ List> value = redis.jsonMGet(path, BIKES_INVENTORY);
assertThat(value).hasSize(1);
- assertThat(value.get(0).toValue()).isEqualTo("[\"Phoebe\",\"Quaoar\",\"Weywot\",\"Salacia\",\"Mimas\"]");
+ assertThat(value.get(0).toValue()).isEqualTo("[\"Phoebe\",\"Quaoar\",\"Weywot\"]");
}
@Test
@@ -141,13 +120,9 @@ void jsonMset() throws ExecutionException, InterruptedException {
void jsonNumincrby() throws ExecutionException, InterruptedException {
JsonPath path = JsonPath.of("$..mountain_bikes[0:1].price");
- List value = redis.jsonNumincrby(BIKES_INVENTORY, path, 5L).get();
- assertThat(value).hasSize(1);
- assertThat(value.get(0).longValue()).isEqualTo(1930L);
-
- value = redis.jsonNumincrby(BIKES_INVENTORY, path, -5L).get();
+ List value = redis.jsonNumincrby(BIKES_INVENTORY, path, 5L);
assertThat(value).hasSize(1);
- assertThat(value.get(0).longValue()).isEqualTo(1925L);
+ assertThat(value.get(0).longValue()).isEqualTo(1933L);
}
@Test
@@ -182,7 +157,7 @@ void jsonSet() throws ExecutionException, InterruptedException {
JsonSetArgs args = JsonSetArgs.Builder.none();
- String result = redis.jsonSet(BIKES_INVENTORY, JsonPath.of(COMMUTER_BIKES), bikeRecord, args).get();
+ String result = redis.jsonSet(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH, bikeRecord, args);
assertThat(result).isEqualTo("OK");
}
@@ -203,15 +178,15 @@ void jsonToggle() throws ExecutionException, InterruptedException {
@Test
void jsonDel() throws ExecutionException, InterruptedException {
- JsonPath path = JsonPath.of("$..mountain_bikes[3:4]");
+ JsonPath path = JsonPath.of("$..mountain_bikes[2:3]");
- Long value = redis.jsonDel(BIKES_INVENTORY, path).get();
+ Long value = redis.jsonDel(BIKES_INVENTORY, path);
assertThat(value).isEqualTo(1);
}
@Test
void jsonType() throws ExecutionException, InterruptedException {
- String jsonType = redis.jsonType(BIKES_INVENTORY, JsonPath.of(COMMUTER_BIKES)).get().get(0);
+ String jsonType = redis.jsonType(BIKES_INVENTORY, MOUNTAIN_BIKES_PATH).get(0);
assertThat(jsonType).isEqualTo("array");
}
diff --git a/src/test/resources/bike-inventory.json b/src/test/resources/bike-inventory.json
new file mode 100644
index 0000000000..303f7a5b5f
--- /dev/null
+++ b/src/test/resources/bike-inventory.json
@@ -0,0 +1,44 @@
+{
+ "inventory": {
+ "mountain_bikes": [
+ {
+ "id": "bike:1",
+ "model": "Phoebe",
+ "description": "This is a mid-travel trail slayer that is a fantastic daily driver or one bike quiver. The Shimano Claris 8-speed groupset gives plenty of gear range to tackle hills and there's room for mudguards and a rack too. This is the bike for the rider who wants trail manners with low fuss ownership.",
+ "price": 1928,
+ "specs": {
+ "material": "carbon",
+ "weight": 13.1
+ },
+ "colors": [
+ "black",
+ "silver"
+ ]
+ },
+ {
+ "id": "bike:2",
+ "model": "Quaoar",
+ "description": "Redesigned for the 2020 model year, this bike impressed our testers and is the best all-around trail bike we've ever tested. The Shimano gear system effectively does away with an external cassette, so is super low maintenance in terms of wear and tear. All in all it's an impressive package for the price, making it very competitive.",
+ "price": 2072,
+ "specs": {
+ "material": "aluminium",
+ "weight": 7.9
+ },
+ "colors": [
+ "black",
+ "white"
+ ]
+ },
+ {
+ "id": "bike:3",
+ "model": "Weywot",
+ "description": "This bike gives kids aged six years and older a durable and uberlight mountain bike for their first experience on tracks and easy cruising through forests and fields. A set of powerful Shimano hydraulic disc brakes provide ample stopping ability. If you're after a budget option, this is one of the best bikes you could get.",
+ "price": 3264,
+ "specs": {
+ "material": "alloy",
+ "weight": 13.8
+ }
+ }
+ ]
+ }
+}