From 4fd64df100fd873a212fafa6a46d0d599b0d1b5f Mon Sep 17 00:00:00 2001 From: Tihomir Krasimirov Mateev Date: Fri, 29 Mar 2024 09:45:52 +0200 Subject: [PATCH] Added unit tests for most of the pubsub classes that did not have any (#2808) --- .../pubsub/PubSubCommandBuilderUnitTests.java | 127 +++++++++++ ...RedisPubSubAsyncCommandsImplUnitTests.java | 201 ++++++++++++++++++ ...fulRedisPubSubConnectionImplUnitTests.java | 103 +++++++++ 3 files changed, 431 insertions(+) create mode 100644 src/test/java/io/lettuce/core/pubsub/PubSubCommandBuilderUnitTests.java create mode 100644 src/test/java/io/lettuce/core/pubsub/RedisPubSubAsyncCommandsImplUnitTests.java create mode 100644 src/test/java/io/lettuce/core/pubsub/StatefulRedisPubSubConnectionImplUnitTests.java diff --git a/src/test/java/io/lettuce/core/pubsub/PubSubCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/pubsub/PubSubCommandBuilderUnitTests.java new file mode 100644 index 0000000000..59ec37bf42 --- /dev/null +++ b/src/test/java/io/lettuce/core/pubsub/PubSubCommandBuilderUnitTests.java @@ -0,0 +1,127 @@ +package io.lettuce.core.pubsub; + +import io.lettuce.core.codec.RedisCodec; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.output.IntegerOutput; +import io.lettuce.core.output.KeyListOutput; +import io.lettuce.core.output.MapOutput; +import io.lettuce.core.protocol.Command; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static io.lettuce.core.protocol.CommandType.*; +import static org.junit.jupiter.api.Assertions.*; + +class PubSubCommandBuilderUnitTests { + + private PubSubCommandBuilder commandBuilder; + private final RedisCodec codec = StringCodec.UTF8; + + @BeforeEach + void setup() { + this.commandBuilder = new PubSubCommandBuilder<>(codec); + } + + @Test + void publish() { + String channel = "channel"; + String message = "message payload"; + Command command = this.commandBuilder.publish(channel, message); + + assertEquals( PUBLISH, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "key value", command.getArgs().toCommandString()); + assertInstanceOf(IntegerOutput.class, command.getOutput()); + } + + @Test + void pubsubChannels() { + String pattern = "channelPattern"; + Command> command = this.commandBuilder.pubsubChannels(pattern); + + assertEquals( PUBSUB, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "CHANNELS key", command.getArgs().toCommandString()); + assertInstanceOf(KeyListOutput.class, command.getOutput()); + } + + @Test + void pubsubNumsub() { + String pattern = "channelPattern"; + Command> command = this.commandBuilder.pubsubNumsub(pattern); + + assertEquals( PUBSUB, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "NUMSUB key", command.getArgs().toCommandString()); + assertInstanceOf(MapOutput.class, command.getOutput()); + } + + @Test + void pubsubShardChannels() { + String pattern = "channelPattern"; + Command> command = this.commandBuilder.pubsubShardChannels(pattern); + + assertEquals( PUBSUB, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "SHARDCHANNELS key", command.getArgs().toCommandString()); + assertInstanceOf(KeyListOutput.class, command.getOutput()); + } + + @Test + void pubsubShardNumsub() { + String pattern = "channelPattern"; + Command> command = this.commandBuilder.pubsubShardNumsub(pattern); + + assertEquals( PUBSUB, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "SHARDNUMSUB key", command.getArgs().toCommandString()); + assertInstanceOf(MapOutput.class, command.getOutput()); + } + + @Test + void psubscribe() { + String pattern = "channelPattern"; + Command command = this.commandBuilder.psubscribe(pattern); + + assertEquals( PSUBSCRIBE, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "key", command.getArgs().toCommandString()); + assertInstanceOf(PubSubOutput.class, command.getOutput()); + } + + @Test + void punsubscribe() { + String pattern = "channelPattern"; + Command command = this.commandBuilder.punsubscribe(pattern); + + assertEquals( PUNSUBSCRIBE, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "key", command.getArgs().toCommandString()); + assertInstanceOf(PubSubOutput.class, command.getOutput()); + } + + @Test + void subscribe() { + String pattern = "channelPattern"; + Command command = this.commandBuilder.subscribe(pattern); + + assertEquals( SUBSCRIBE, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "key", command.getArgs().toCommandString()); + assertInstanceOf(PubSubOutput.class, command.getOutput()); + } + + @Test + void unsubscribe() { + String pattern = "channelPattern"; + Command command = this.commandBuilder.unsubscribe(pattern); + + assertEquals( UNSUBSCRIBE, command.getType()); + assertInstanceOf(PubSubCommandArgs.class, command.getArgs()); + assertEquals( "key", command.getArgs().toCommandString()); + assertInstanceOf(PubSubOutput.class, command.getOutput()); + } +} diff --git a/src/test/java/io/lettuce/core/pubsub/RedisPubSubAsyncCommandsImplUnitTests.java b/src/test/java/io/lettuce/core/pubsub/RedisPubSubAsyncCommandsImplUnitTests.java new file mode 100644 index 0000000000..a95a73fc4e --- /dev/null +++ b/src/test/java/io/lettuce/core/pubsub/RedisPubSubAsyncCommandsImplUnitTests.java @@ -0,0 +1,201 @@ +package io.lettuce.core.pubsub; + +import io.lettuce.core.codec.RedisCodec; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.output.IntegerOutput; +import io.lettuce.core.output.KeyListOutput; +import io.lettuce.core.output.MapOutput; +import io.lettuce.core.protocol.AsyncCommand; +import io.lettuce.core.protocol.RedisCommand; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import java.util.concurrent.ExecutionException; + +import static io.lettuce.core.protocol.CommandType.*; +import static org.junit.Assert.*; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.mockito.Mockito.*; + +class RedisPubSubAsyncCommandsImplUnitTests { + + private RedisPubSubAsyncCommandsImpl commands; + private StatefulRedisPubSubConnection mockedConnection; + private final RedisCodec codec = StringCodec.UTF8; + + @BeforeEach + void setup() { + mockedConnection = mock(StatefulRedisPubSubConnection.class); + commands = new RedisPubSubAsyncCommandsImpl<>(mockedConnection, codec); + } + + @Test + void psubscribe() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.psubscribe(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PSUBSCRIBE, capturedCommand.getValue().getType()); + assertInstanceOf(PubSubOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void punsubscribe() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.punsubscribe(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUNSUBSCRIBE, capturedCommand.getValue().getType()); + assertInstanceOf(PubSubOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void subscribe() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.subscribe(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( SUBSCRIBE, capturedCommand.getValue().getType()); + assertInstanceOf(PubSubOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void unsubscribe() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.unsubscribe(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( UNSUBSCRIBE, capturedCommand.getValue().getType()); + assertInstanceOf(PubSubOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void publish() throws ExecutionException, InterruptedException { + String channel = "acmeChannel"; + String message = "acmeMessage"; + + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.publish(channel, message).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUBLISH, capturedCommand.getValue().getType()); + assertInstanceOf(IntegerOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "key value", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void pubsubChannels() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.pubsubChannels(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUBSUB, capturedCommand.getValue().getType()); + assertInstanceOf(KeyListOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "CHANNELS key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void pubsubNumsub() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.pubsubNumsub(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUBSUB, capturedCommand.getValue().getType()); + assertInstanceOf(MapOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "NUMSUB key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void pubsubShardChannels() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.pubsubShardChannels(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUBSUB, capturedCommand.getValue().getType()); + assertInstanceOf(KeyListOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "SHARDCHANNELS key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } + + @Test + void pubsubShardNumsub() throws ExecutionException, InterruptedException { + String pattern = "channelPattern"; + + AsyncCommand dispachedMock = mock (AsyncCommand.class); + when(mockedConnection.dispatch((RedisCommand) any())).thenReturn(dispachedMock); + + commands.pubsubShardNumsub(pattern).get(); + + ArgumentCaptor capturedCommand = ArgumentCaptor.forClass(AsyncCommand.class);; + verify(mockedConnection).dispatch(capturedCommand.capture()); + + Assertions.assertEquals( PUBSUB, capturedCommand.getValue().getType()); + assertInstanceOf(MapOutput.class, capturedCommand.getValue().getOutput()); + Assertions.assertEquals( "SHARDNUMSUB key", capturedCommand.getValue().getArgs().toCommandString()); + + assertNotEquals(capturedCommand.getValue(), dispachedMock); + } +} diff --git a/src/test/java/io/lettuce/core/pubsub/StatefulRedisPubSubConnectionImplUnitTests.java b/src/test/java/io/lettuce/core/pubsub/StatefulRedisPubSubConnectionImplUnitTests.java new file mode 100644 index 0000000000..08f6fea6f4 --- /dev/null +++ b/src/test/java/io/lettuce/core/pubsub/StatefulRedisPubSubConnectionImplUnitTests.java @@ -0,0 +1,103 @@ +package io.lettuce.core.pubsub; + +import io.lettuce.core.RedisChannelWriter; +import io.lettuce.core.RedisFuture; +import io.lettuce.core.codec.RedisCodec; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.protocol.AsyncCommand; +import io.lettuce.core.resource.ClientResources; +import io.lettuce.core.tracing.Tracing; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.mockito.Mockito.*; + +import java.time.Duration; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +class StatefulRedisPubSubConnectionImplUnitTests { + + private StatefulRedisPubSubConnectionImpl connection; + + private final RedisCodec codec = StringCodec.UTF8; + private final Duration timeout = Duration.ofSeconds(5); + + PubSubEndpoint mockedEndpoint; + + RedisChannelWriter mockedWriter; + + @BeforeEach + void setup() { + mockedEndpoint = mock(PubSubEndpoint.class); + mockedWriter = mock(RedisChannelWriter.class); + + ClientResources mockedReseources = mock(ClientResources.class); + Tracing mockedTracing = mock(Tracing.class); + when(mockedReseources.tracing()).thenReturn(mockedTracing); + when(mockedTracing.isEnabled()).thenReturn(Boolean.FALSE); + when(mockedWriter.getClientResources()).thenReturn(mockedReseources); + + connection = new StatefulRedisPubSubConnectionImpl(mockedEndpoint, mockedWriter, codec, timeout); + } + + + @Test + void addListener() { + RedisPubSubListener listener = mock(RedisPubSubListener.class); + + connection.addListener(listener); + + verify(mockedEndpoint).addListener(listener); + } + + @Test + void removeListener() { + RedisPubSubListener listener = mock(RedisPubSubListener.class); + + connection.addListener(listener); + connection.removeListener(listener); + + verify(mockedEndpoint).removeListener(listener); + } + + @Test + void removeListenerIgnoreMissingListeners() { + RedisPubSubListener listener = mock(RedisPubSubListener.class); + + connection.removeListener(listener); + + verify(mockedEndpoint).removeListener(listener); + } + + @Test + void resubscribeChannelSubscription() { + when(mockedEndpoint.hasChannelSubscriptions()).thenReturn(true); + when(mockedEndpoint.getChannels()).thenReturn(new HashSet<>(Arrays.asList(new String[] { "channel1", "channel2" }))); + when(mockedEndpoint.hasPatternSubscriptions()).thenReturn(false); + + List> subscriptions = connection.resubscribe(); + RedisFuture commandFuture = subscriptions.get(0); + + assertEquals(1, subscriptions.size()); + assertInstanceOf( AsyncCommand.class, commandFuture); + } + + @Test + void resubscribeChannelAndPatternSubscription() { + when(mockedEndpoint.hasChannelSubscriptions()).thenReturn(true); + when(mockedEndpoint.getChannels()).thenReturn(new HashSet<>(Arrays.asList(new String[] { "channel1", "channel2" }))); + when(mockedEndpoint.hasPatternSubscriptions()).thenReturn(true); + when(mockedEndpoint.getPatterns()).thenReturn(new HashSet<>(Arrays.asList(new String[] { "bcast*", "echo" }))); + + + List> subscriptions = connection.resubscribe(); + + assertEquals(2, subscriptions.size()); + assertInstanceOf( AsyncCommand.class, subscriptions.get(0)); + assertInstanceOf( AsyncCommand.class, subscriptions.get(1)); + } +}