Upgrade to Jedis 5.0

Adapt to API changes in the Jedis 5.0 driver.
Fix bzPopMaxShouldWorkCorrectly() and bzPopMinShouldWorkCorrectly() tests in JedisClusterConnectionTests.

Jedis 5.0 changed the bzpopmax and bzpopmin Redis commands to no longer return an empty (Array)List internally when evaluating and popping from an empty sorted set. A NullPointerException will be thrown if either bzpopmax or bzpopmin commands are executd on an empty Redis sorted set in Jedis 5.0 (vs. Jedis 4.x):

Closes #2612
Original pull request: #2716
This commit is contained in:
John Blum
2023-06-15 19:17:35 -07:00
committed by Christoph Strobl
parent d63fd19519
commit 2075633809
14 changed files with 256 additions and 142 deletions

View File

@@ -2279,7 +2279,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
@EnabledOnCommand("BZPOPMIN")
public void bzPopMinShouldWorkCorrectly() {
assertThat(clusterConnection.bZPopMin(KEY_1_BYTES, 10, TimeUnit.MILLISECONDS)).isNull();
assertThat(clusterConnection.zSetCommands().zCard(KEY_1_BYTES)).isZero();
nativeConnection.zadd(KEY_1_BYTES, 10D, VALUE_1_BYTES);
nativeConnection.zadd(KEY_1_BYTES, 20D, VALUE_2_BYTES);
@@ -2306,7 +2306,7 @@ public class JedisClusterConnectionTests implements ClusterConnectionTests {
@EnabledOnCommand("BZPOPMAX")
public void bzPopMaxShouldWorkCorrectly() {
assertThat(clusterConnection.bZPopMax(KEY_1_BYTES, 10, TimeUnit.MILLISECONDS)).isNull();
assertThat(clusterConnection.zSetCommands().zCard(KEY_1_BYTES)).isZero();
nativeConnection.zadd(KEY_1_BYTES, 10D, VALUE_1_BYTES);
nativeConnection.zadd(KEY_1_BYTES, 20D, VALUE_2_BYTES);

View File

@@ -165,7 +165,7 @@ class JedisConnectionUnitTests {
connection.scan(ScanOptions.NONE);
verify(jedisSpy, never()).quit();
verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531, GH-2006
@@ -177,7 +177,7 @@ class JedisConnectionUnitTests {
Cursor<byte[]> cursor = connection.scan(ScanOptions.NONE);
cursor.close();
verify(jedisSpy, times(1)).quit();
verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -188,7 +188,7 @@ class JedisConnectionUnitTests {
connection.sScan("foo".getBytes(), ScanOptions.NONE);
verify(jedisSpy, never()).quit();
verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -200,7 +200,7 @@ class JedisConnectionUnitTests {
Cursor<byte[]> cursor = connection.sScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
verify(jedisSpy, times(1)).quit();
verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -211,7 +211,7 @@ class JedisConnectionUnitTests {
connection.zScan("foo".getBytes(), ScanOptions.NONE);
verify(jedisSpy, never()).quit();
verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -223,7 +223,7 @@ class JedisConnectionUnitTests {
Cursor<Tuple> cursor = connection.zScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
verify(jedisSpy, times(1)).quit();
verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-531
@@ -234,7 +234,7 @@ class JedisConnectionUnitTests {
connection.hScan("foo".getBytes(), ScanOptions.NONE);
verify(jedisSpy, never()).quit();
verify(jedisSpy, never()).disconnect();
}
@Test // DATAREDIS-531
@@ -246,7 +246,7 @@ class JedisConnectionUnitTests {
Cursor<Entry<byte[], byte[]>> cursor = connection.hScan("foo".getBytes(), ScanOptions.NONE);
cursor.close();
verify(jedisSpy, times(1)).quit();
verify(jedisSpy, times(1)).disconnect();
}
@Test // DATAREDIS-714

View File

@@ -16,7 +16,15 @@
package org.springframework.data.redis.connection.jedis;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.params.GetExParams;
import redis.clients.jedis.params.SetParams;
@@ -35,12 +43,15 @@ import org.springframework.data.redis.connection.RedisServer;
import org.springframework.data.redis.connection.RedisStringCommands.SetOption;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.core.types.RedisClientInfo;
import org.springframework.lang.Nullable;
import org.springframework.test.util.ReflectionTestUtils;
/**
* Unit tests for {@link JedisConverters}.
*
* @author Christoph Strobl
* @author Mark Paluch
* @author John Blum
*/
class JedisConvertersUnitTests {
@@ -212,15 +223,31 @@ class JedisConvertersUnitTests {
@Test // GH-2050
void convertsExpirationToSetPXAT() {
assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS)))
.extracting(SetParams::toString).isEqualTo(SetParams.setParams().pxAt(10).toString());
SetParams mockSetParams = mock(SetParams.class);
doReturn(mockSetParams).when(mockSetParams).pxAt(anyLong());
Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS);
assertThat(JedisConverters.toSetCommandExPxArgument(expiration, mockSetParams)).isNotNull();
verify(mockSetParams, times(1)).pxAt(eq(10L));
verifyNoMoreInteractions(mockSetParams);
}
@Test // GH-2050
void convertsExpirationToSetEXAT() {
assertThat(JedisConverters.toSetCommandExPxArgument(Expiration.unixTimestamp(1, TimeUnit.MINUTES)))
.extracting(SetParams::toString).isEqualTo(SetParams.setParams().exAt(60).toString());
SetParams mockSetParams = mock(SetParams.class);
doReturn(mockSetParams).when(mockSetParams).exAt(anyLong());
Expiration expiration = Expiration.unixTimestamp(1, TimeUnit.MINUTES);
assertThat(JedisConverters.toSetCommandExPxArgument(expiration, mockSetParams)).isNotNull();
verify(mockSetParams, times(1)).exAt(eq(60L));
verifyNoMoreInteractions(mockSetParams);
}
@Test // DATAREDIS-316, DATAREDIS-749
@@ -241,43 +268,91 @@ class JedisConvertersUnitTests {
@Test // GH-2050
void convertsExpirationToGetExEX() {
assertThat(JedisConverters.toGetExParams(Expiration.seconds(10))).extracting(GetExParams::toString)
.isEqualTo(new GetExParams().ex(10).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).ex(anyLong());
Expiration expiration = Expiration.seconds(10);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).ex(eq(10L));
verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationWithTimeUnitToGetExEX() {
assertThat(JedisConverters.toGetExParams(Expiration.from(1, TimeUnit.MINUTES))).extracting(GetExParams::toString)
.isEqualTo(new GetExParams().ex(60).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).ex(anyLong());
Expiration expiration = Expiration.from(1, TimeUnit.MINUTES);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).ex(eq(60L)); // seconds
verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExPEX() {
assertThat(JedisConverters.toGetExParams(Expiration.milliseconds(10))).extracting(GetExParams::toString)
.isEqualTo(new GetExParams().px(10).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).px(anyLong());
Expiration expiration = Expiration.milliseconds(10L);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).px(eq(10L));
verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExEXAT() {
assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.SECONDS)))
.extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(10).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).exAt(anyLong());
Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.SECONDS);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).exAt(eq(10L));
verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationWithTimeUnitToGetExEXAT() {
assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(1, TimeUnit.MINUTES)))
.extracting(GetExParams::toString).isEqualTo(new GetExParams().exAt(60).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).exAt(anyLong());
Expiration expiration = Expiration.unixTimestamp(1, TimeUnit.MINUTES);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).exAt(eq(60L));
verifyNoMoreInteractions(mockGetExParams);
}
@Test // GH-2050
void convertsExpirationToGetExPXAT() {
assertThat(JedisConverters.toGetExParams(Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS)))
.extracting(GetExParams::toString).isEqualTo(new GetExParams().pxAt(10).toString());
GetExParams mockGetExParams = mock(GetExParams.class);
doReturn(mockGetExParams).when(mockGetExParams).pxAt(anyLong());
Expiration expiration = Expiration.unixTimestamp(10, TimeUnit.MILLISECONDS);
assertThat(JedisConverters.toGetExParams(expiration, mockGetExParams)).isNotNull();
verify(mockGetExParams, times(1)).pxAt(eq(10L));
verifyNoMoreInteractions(mockGetExParams);
}
private void verifyRedisServerInfo(RedisServer server, Map<String, String> values) {
@@ -289,18 +364,22 @@ class JedisConvertersUnitTests {
private static String toString(SetParams setParams) {
StringBuilder builder = new StringBuilder();
StringBuilder stringBuilder = new StringBuilder();
for (byte[] parameter : setParams.getByteParams()) {
stringBuilder.append(toString((Protocol.Keyword) ReflectionTestUtils.getField(setParams, "existance")));
stringBuilder.append(toString((Protocol.Keyword) ReflectionTestUtils.getField(setParams, "expiration")));
if (builder.length() != 0) {
builder.append(' ');
}
Long expirationValue = (Long) ReflectionTestUtils.getField(setParams, "expirationValue");
builder.append(new String(parameter));
if (expirationValue != null) {
stringBuilder.append(" ").append(expirationValue);
}
return builder.toString();
return stringBuilder.toString().trim();
}
private static String toString(@Nullable Enum<?> value) {
return value != null ? value.name().toLowerCase() : "";
}
private Map<String, String> getRedisServerInfoMap(String name, int port) {