diff --git a/src/main/java/io/lettuce/core/masterreplica/ReadOnlyCommands.java b/src/main/java/io/lettuce/core/masterreplica/ReadOnlyCommands.java deleted file mode 100644 index 10b2db694f..0000000000 --- a/src/main/java/io/lettuce/core/masterreplica/ReadOnlyCommands.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2020-Present, Redis Ltd. and Contributors - * 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.masterreplica; - -import java.util.Collections; -import java.util.EnumSet; -import java.util.Set; - -import io.lettuce.core.protocol.CommandType; -import io.lettuce.core.protocol.ProtocolKeyword; - -/** - * Contains all command names that are read-only commands. - * - * @author Mark Paluch - */ -class ReadOnlyCommands { - - private static final Set READ_ONLY_COMMANDS = EnumSet.noneOf(CommandType.class); - - static { - for (CommandName commandNames : CommandName.values()) { - READ_ONLY_COMMANDS.add(CommandType.valueOf(commandNames.name())); - } - } - - /** - * @param protocolKeyword must not be {@code null}. - * @return {@code true} if {@link ProtocolKeyword} is a read-only command. - */ - public static boolean isReadOnlyCommand(ProtocolKeyword protocolKeyword) { - return READ_ONLY_COMMANDS.contains(protocolKeyword); - } - - /** - * @return an unmodifiable {@link Set} of {@link CommandType read-only} commands. - */ - public static Set getReadOnlyCommands() { - return Collections.unmodifiableSet(READ_ONLY_COMMANDS); - } - - enum CommandName { - BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL_RO, EVALSHA_RO, EXISTS, FCALL_RO, // - GEODIST, GEOPOS, GEORADIUS_RO, GEORADIUSBYMEMBER_RO, GEOHASH, GET, GETBIT, // - GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HRANDFIELD, HSCAN, HSTRLEN, // - HVALS, INFO, KEYS, LINDEX, LLEN, LPOS, LRANGE, SORT_RO, MGET, PFCOUNT, PTTL, // - RANDOMKEY, SCAN, SCARD, SCRIPT, // - SDIFF, SINTER, SISMEMBER, SMISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // - SUNION, TIME, TTL, TYPE, // - XINFO, XLEN, XPENDING, XRANGE, XREVRANGE, XREAD, // - ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // - ZRANDMEMBER, ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, - } - -} diff --git a/src/main/java/io/lettuce/core/protocol/ReadOnlyCommands.java b/src/main/java/io/lettuce/core/protocol/ReadOnlyCommands.java index a6bfc6333f..d116b0fb48 100644 --- a/src/main/java/io/lettuce/core/protocol/ReadOnlyCommands.java +++ b/src/main/java/io/lettuce/core/protocol/ReadOnlyCommands.java @@ -71,10 +71,10 @@ public static ReadOnlyPredicate asPredicate() { enum CommandName { ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL_RO, EVALSHA_RO, EXISTS, FCALL_RO, // - GEODIST, GEOPOS, GEORADIUS, GEORADIUS_RO, GEORADIUSBYMEMBER, GEORADIUSBYMEMBER_RO, GEOSEARCH, GEOHASH, GET, GETBIT, // + GEODIST, GEOPOS, GEORADIUS_RO, GEORADIUSBYMEMBER_RO, GEOSEARCH, GEOHASH, GET, GETBIT, // GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HRANDFIELD, HSCAN, HSTRLEN, // HVALS, INFO, KEYS, LINDEX, LLEN, LPOS, LRANGE, SORT_RO, MGET, PFCOUNT, PTTL, // - RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, // + RANDOMKEY, SCAN, SCARD, SCRIPT, // SDIFF, SINTER, SISMEMBER, SMISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // SUNION, TIME, TTL, TYPE, // XINFO, XLEN, XPENDING, XRANGE, XREVRANGE, XREAD, // diff --git a/src/test/java/io/lettuce/core/cluster/ClusterReadOnlyCommandsUnitTests.java b/src/test/java/io/lettuce/core/cluster/ClusterReadOnlyCommandsUnitTests.java index b1f6cad9ff..0f7bed34e0 100644 --- a/src/test/java/io/lettuce/core/cluster/ClusterReadOnlyCommandsUnitTests.java +++ b/src/test/java/io/lettuce/core/cluster/ClusterReadOnlyCommandsUnitTests.java @@ -16,7 +16,7 @@ class ClusterReadOnlyCommandsUnitTests { @Test void testCount() { - assertThat(ClusterReadOnlyCommands.getReadOnlyCommands()).hasSize(86); + assertThat(ClusterReadOnlyCommands.getReadOnlyCommands()).hasSize(83); } @Test diff --git a/src/test/java/io/lettuce/core/commands/ReadOnlyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/ReadOnlyCommandIntegrationTests.java new file mode 100644 index 0000000000..a5e4a063ed --- /dev/null +++ b/src/test/java/io/lettuce/core/commands/ReadOnlyCommandIntegrationTests.java @@ -0,0 +1,61 @@ +package io.lettuce.core.commands; + +import io.lettuce.core.TestSupport; +import io.lettuce.core.api.sync.RedisCommands; +import io.lettuce.core.cluster.ClusterReadOnlyCommands; +import io.lettuce.core.cluster.ClusterTestUtil; +import io.lettuce.core.cluster.api.StatefulRedisClusterConnection; +import io.lettuce.core.cluster.api.sync.RedisClusterCommands; +import io.lettuce.core.protocol.CommandType; +import io.lettuce.core.protocol.ProtocolKeyword; +import io.lettuce.core.protocol.ReadOnlyCommands; +import io.lettuce.test.KeyValueStreamingAdapter; +import io.lettuce.test.LettuceExtension; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.inject.Inject; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Thach Le + */ +@ExtendWith(LettuceExtension.class) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +class ReadOnlyCommandIntegrationTests extends TestSupport { + + private final RedisCommands redis; + + @Inject + protected ReadOnlyCommandIntegrationTests(RedisCommands redis) { + this.redis = redis; + } + + @BeforeEach + void setUp() { + redis.flushall(); + } + + @Test + void testReadOnlyCommands() { + for (ProtocolKeyword readOnlyCommand : ClusterReadOnlyCommands.getReadOnlyCommands()) { + assertThat(isCommandReadOnly(readOnlyCommand.name())).isTrue(); + } + } + + private boolean isCommandReadOnly(String commandName) { + List commandInfo = redis.commandInfo(commandName); + if (commandInfo == null || commandInfo.isEmpty()) { + throw new IllegalArgumentException("Command not found: " + commandName); + } + + List flags = (List) commandInfo.get(2); // Index 2 is the flags list + return flags.contains("readonly") && !flags.contains("write"); + } +}