🐛 fix(redis): 修复超过16个数据库无法展示

- 后端改为通过 CONFIG GET databases 动态获取 Redis 数据库数量
- 放宽单机和 Sentinel 模式的 RedisDB 索引限制,支持 db16 及以上
- 前端连接配置和持久化不再裁剪高编号 Redis 数据库
- 连接测试成功后按服务端返回的真实数据库列表展示可选 DB
- 增加 Redis db31 展示、切换、保存和 URI 解析回归测试
Refs #558
This commit is contained in:
Syngnat
2026-06-12 17:22:09 +08:00
parent 70134cd77f
commit 8519748512
12 changed files with 369 additions and 78 deletions

View File

@@ -117,6 +117,7 @@ import {
MongoDiscoverMembers,
TestConnection,
RedisConnect,
RedisGetDatabases,
SelectDatabaseFile,
SelectCertificateFile,
SelectSSHKeyFile,
@@ -141,6 +142,7 @@ const MAX_URI_HOSTS = 32;
const MAX_TIMEOUT_SECONDS = 3600;
const CONNECTION_MODAL_WIDTH = 960;
const CONNECTION_MODAL_BODY_HEIGHT = 620;
const REDIS_DEFAULT_DATABASE_COUNT = 16;
const STEP1_SIDEBAR_DIVIDER_DARK = "rgba(255, 255, 255, 0.16)";
const STEP1_SIDEBAR_DIVIDER_LIGHT = "rgba(0, 0, 0, 0.08)";
const CLICKHOUSE_PROTOCOL_OPTIONS: Array<{
@@ -158,6 +160,62 @@ const OCEANBASE_PROTOCOL_OPTIONS: Array<{
{ value: "mysql", label: "MySQL" },
{ value: "oracle", label: "Oracle" },
];
const normalizeRedisDatabaseIndex = (value: unknown): number | null => {
const parsed = Number(value);
if (!Number.isFinite(parsed) || parsed < 0) return null;
return Math.trunc(parsed);
};
const buildRedisDatabaseList = (...values: unknown[]): number[] => {
const indexes = new Set<number>();
for (let i = 0; i < REDIS_DEFAULT_DATABASE_COUNT; i += 1) {
indexes.add(i);
}
const collect = (value: unknown) => {
if (Array.isArray(value)) {
value.forEach(collect);
return;
}
const index = normalizeRedisDatabaseIndex(value);
if (index !== null) {
indexes.add(index);
}
};
values.forEach(collect);
return Array.from(indexes).sort((a, b) => a - b);
};
const extractRedisDatabaseList = (value: unknown): number[] => {
if (!Array.isArray(value)) return [];
const indexes = new Set<number>();
value.forEach((row: any) => {
const index = normalizeRedisDatabaseIndex(row?.index ?? row?.Index);
if (index !== null) {
indexes.add(index);
}
});
const result = Array.from(indexes).sort((a, b) => a - b);
return result.length > 0 ? result : buildRedisDatabaseList();
};
const normalizeRedisDatabaseSelection = (
value: unknown,
supportedDbs: number[],
): number[] | undefined => {
if (!Array.isArray(value)) return undefined;
const supported = new Set(supportedDbs);
const selected = Array.from(
new Set(
value
.map(normalizeRedisDatabaseIndex)
.filter((index): index is number => index !== null)
.filter((index) => supported.size === 0 || supported.has(index)),
),
).sort((a, b) => a - b);
return selected.length > 0 ? selected : undefined;
};
const normalizeClickHouseProtocolValue = (
value: unknown,
): ClickHouseProtocolChoice => {
@@ -290,7 +348,7 @@ const ConnectionModal: React.FC<{
} | null>(null);
const [testErrorLogOpen, setTestErrorLogOpen] = useState(false);
const [dbList, setDbList] = useState<string[]>([]);
const [redisDbList, setRedisDbList] = useState<number[]>([]); // Redis databases 0-15
const [redisDbList, setRedisDbList] = useState<number[]>([]);
const [mongoMembers, setMongoMembers] = useState<MongoMemberInfo[]>([]);
const [discoveringMembers, setDiscoveringMembers] = useState(false);
const [uriFeedback, setUriFeedback] = useState<{
@@ -728,19 +786,17 @@ const ConnectionModal: React.FC<{
) {
form.setFieldValue("port", 6379);
}
const supportedDbs = Array.from({ length: 16 }, (_, i) => i);
const supportedDbs = buildRedisDatabaseList(
form.getFieldValue("redisDB"),
form.getFieldValue("includeRedisDatabases"),
);
setRedisDbList(supportedDbs);
const selectedDbsRaw = form.getFieldValue("includeRedisDatabases");
const selectedDbs = Array.isArray(selectedDbsRaw)
? selectedDbsRaw.map((entry: any) => Number(entry))
: [];
const validDbs = selectedDbs
.filter((entry: number) => Number.isFinite(entry))
.map((entry: number) => Math.trunc(entry))
.filter((entry: number) => supportedDbs.includes(entry));
form.setFieldValue(
"includeRedisDatabases",
validDbs.length > 0 ? validDbs : undefined,
normalizeRedisDatabaseSelection(
form.getFieldValue("includeRedisDatabases"),
supportedDbs,
),
);
}
if (fieldName === "proxyType") {
@@ -2472,7 +2528,12 @@ const ConnectionModal: React.FC<{
}
// 如果是 Redis 编辑模式,设置已保存的 Redis 数据库列表
if (configType === "redis") {
setRedisDbList(Array.from({ length: 16 }, (_, i) => i));
setRedisDbList(
buildRedisDatabaseList(
config.redisDB,
initialValues.includeRedisDatabases,
),
);
}
} else {
// Create mode: Start at step 1
@@ -2878,7 +2939,32 @@ const ConnectionModal: React.FC<{
void message.destroy("connection-test-failure");
setTestResult({ type: "success", message: res.message });
if (isRedisType) {
setRedisDbList(Array.from({ length: 16 }, (_, i) => i));
const dbRes = await withClientTimeout(
RedisGetDatabases(config as any),
rpcTimeoutMs,
`连接成功但拉取 Redis 数据库列表超时(>${timeoutSeconds} 秒)`,
);
if (dbRes.success) {
const supportedDbs = extractRedisDatabaseList(dbRes.data);
setRedisDbList(supportedDbs);
form.setFieldValue(
"includeRedisDatabases",
normalizeRedisDatabaseSelection(
form.getFieldValue("includeRedisDatabases"),
supportedDbs,
),
);
} else {
setRedisDbList(
buildRedisDatabaseList(
config.redisDB,
form.getFieldValue("includeRedisDatabases"),
),
);
message.warning(
`连接成功,但获取 Redis 数据库列表失败:${normalizeConnectionSecretErrorMessage(dbRes.message, "未知错误")}`,
);
}
} else if (!isJVMType) {
// Other databases: fetch database list
const dbRes = await withClientTimeout(
@@ -3419,7 +3505,7 @@ const ConnectionModal: React.FC<{
connectionParams: normalizedConnectionParams,
timeout: Number(mergedValues.timeout || 30),
redisDB: Number.isFinite(Number(mergedValues.redisDB))
? Math.max(0, Math.min(15, Math.trunc(Number(mergedValues.redisDB))))
? Math.max(0, Math.trunc(Number(mergedValues.redisDB)))
: 0,
redisSentinelMaster: redisSentinelMaster,
redisSentinelUser: redisSentinelUser,
@@ -5957,19 +6043,17 @@ const ConnectionModal: React.FC<{
) {
form.setFieldValue("port", 6379);
}
const supportedDbs = Array.from({ length: 16 }, (_, i) => i);
const supportedDbs = buildRedisDatabaseList(
form.getFieldValue("redisDB"),
form.getFieldValue("includeRedisDatabases"),
);
setRedisDbList(supportedDbs);
const selectedDbsRaw = form.getFieldValue("includeRedisDatabases");
const selectedDbs = Array.isArray(selectedDbsRaw)
? selectedDbsRaw.map((entry: any) => Number(entry))
: [];
const validDbs = selectedDbs
.filter((entry: number) => Number.isFinite(entry))
.map((entry: number) => Math.trunc(entry))
.filter((entry: number) => supportedDbs.includes(entry));
form.setFieldValue(
"includeRedisDatabases",
validDbs.length > 0 ? validDbs : undefined,
normalizeRedisDatabaseSelection(
form.getFieldValue("includeRedisDatabases"),
supportedDbs,
),
);
}
if (

View File

@@ -224,7 +224,7 @@ const ConnectionModalRedisSections: React.FC<ConnectionModalRedisSectionsProps>
>
<Select
mode="multiple"
placeholder="选择显示的数据库 (0-15)"
placeholder="选择显示的数据库"
allowClear
>
{redisDbList.map((db) => (

View File

@@ -398,6 +398,30 @@ describe('store appearance persistence', () => {
expect(config?.port).toBe(9030);
});
it('preserves Redis database indexes above the default 16 databases', async () => {
const { useStore } = await importStore();
useStore.getState().replaceConnections([
{
id: 'redis-32',
name: 'Redis 32 DBs',
includeRedisDatabases: [0, 15, 16, 31, -1, 31],
config: {
id: 'redis-32',
type: 'redis',
host: 'redis.local',
port: 6379,
user: '',
redisDB: 31,
},
},
]);
const saved = useStore.getState().connections[0];
expect(saved?.config.redisDB).toBe(31);
expect(saved?.includeRedisDatabases).toEqual([0, 15, 16, 31]);
});
it('keeps InterSystems IRIS saved connections as independent datasource type', async () => {
const { useStore } = await importStore();

View File

@@ -122,6 +122,7 @@ const MAX_PERSISTED_SQL_LOG_LENGTH = 100 * 1024;
const MAX_PERSISTED_SQL_LOG_MESSAGE_LENGTH = 2 * 1024;
const DEFAULT_CONNECTION_TYPE = "mysql";
const DEFAULT_JVM_PORT = 9010;
const MAX_REDIS_DATABASE_INDEX = Number.MAX_SAFE_INTEGER;
const DEFAULT_GLOBAL_PROXY: GlobalProxyConfig = {
enabled: false,
type: "socks5",
@@ -781,7 +782,12 @@ const sanitizeConnectionConfig = (value: unknown): ConnectionConfig => {
};
if (type === "redis") {
safeConfig.redisDB = normalizeIntegerInRange(raw.redisDB, 0, 0, 15);
safeConfig.redisDB = normalizeIntegerInRange(
raw.redisDB,
0,
0,
MAX_REDIS_DATABASE_INDEX,
);
safeConfig.redisSentinelMaster = toTrimmedString(raw.redisSentinelMaster);
safeConfig.redisSentinelUser = toTrimmedString(raw.redisSentinelUser);
safeConfig.redisSentinelPassword = savePassword
@@ -857,7 +863,7 @@ const sanitizeSavedConnection = (
const includeRedisDatabases = sanitizeNumberArray(
raw.includeRedisDatabases,
0,
15,
MAX_REDIS_DATABASE_INDEX,
);
return {

View File

@@ -297,7 +297,7 @@ export interface ConnectionConfig {
dsn?: string;
connectionParams?: string;
timeout?: number;
redisDB?: number; // Redis database index (0-15)
redisDB?: number; // Redis database index
uri?: string; // Connection URI for copy/paste
clickHouseProtocol?: "auto" | "http" | "native"; // ClickHouse connection protocol override
oceanBaseProtocol?: "mysql" | "oracle"; // OceanBase tenant compatibility protocol
@@ -342,7 +342,7 @@ export interface SavedConnection {
hasOpaqueURI?: boolean;
hasOpaqueDSN?: boolean;
includeDatabases?: string[];
includeRedisDatabases?: number[]; // Redis databases to show (0-15)
includeRedisDatabases?: number[]; // Redis databases to show
iconType?: string; // 自定义图标类型(如 'mysql','postgres'),不填则取 config.type
iconColor?: string; // 自定义图标颜色(十六进制),不填则取类型默认色
}

View File

@@ -79,7 +79,7 @@ describe('redisConnectionUri', () => {
redisSentinelMaster: 'mymaster',
redisSentinelUser: 'ops',
redisSentinelPassword: 'sentinel-pass',
redisDB: 0,
redisDB: 99,
});
});
});

View File

@@ -250,9 +250,8 @@ const appendRedisSSLPathParamsForUri = (
const normalizeRedisDB = (value: unknown): number => {
const parsed = Number(value);
return Number.isFinite(parsed) && parsed >= 0 && parsed <= 15
? Math.trunc(parsed)
: 0;
if (!Number.isFinite(parsed) || parsed < 0) return 0;
return Math.trunc(parsed);
};
const normalizeRedisTopology = (value: unknown): RedisTopology => {

View File

@@ -28,7 +28,7 @@ func normalizeRunConfig(config connection.ConnectionConfig, dbName string) conne
runConfig.Database = name
case "redis":
runConfig.Database = name
if idx, err := strconv.Atoi(name); err == nil && idx >= 0 && idx <= 15 {
if idx, err := strconv.Atoi(name); err == nil && idx >= 0 {
runConfig.RedisDB = idx
}
default:

View File

@@ -229,6 +229,19 @@ func TestNormalizeRunConfig_IRISUsesNamespaceFromTree(t *testing.T) {
}
}
func TestNormalizeRunConfig_RedisAllowsDatabaseIndexAboveDefault(t *testing.T) {
t.Parallel()
runConfig := normalizeRunConfig(connection.ConnectionConfig{
Type: "redis",
RedisDB: 0,
}, "31")
if runConfig.Database != "31" || runConfig.RedisDB != 31 {
t.Fatalf("expected Redis db31 from tree, got database=%q redisDB=%d", runConfig.Database, runConfig.RedisDB)
}
}
func TestNormalizeSchemaAndTable_IRISDoesNotTreatNamespaceAsSchema(t *testing.T) {
t.Parallel()

View File

@@ -12,7 +12,7 @@ type RedisValue struct {
// RedisDBInfo represents information about a Redis database
type RedisDBInfo struct {
Index int `json:"index"` // Database index (single: 0-15, cluster: logical 0-15)
Index int `json:"index"` // Database index (single/sentinel: server configured range, cluster: logical 0-15)
Keys int64 `json:"keys"` // Number of keys in this database
}

View File

@@ -37,6 +37,8 @@ type RedisClientImpl struct {
}
const (
redisDefaultDatabaseCount = 16
redisClusterLogicalDBCount = 16
redisScanDefaultTargetCount int64 = 2000
redisScanMaxTargetCount int64 = 10000
redisScanMinStepCount int64 = 200
@@ -263,10 +265,9 @@ func (r *RedisClientImpl) Connect(config connection.ConnectionConfig) error {
config.Password = sanitizeRedisPassword(config.Password)
config.RedisSentinelPassword = sanitizeRedisPassword(config.RedisSentinelPassword)
r.config = config
if r.config.RedisDB < 0 || r.config.RedisDB > 15 {
if r.config.RedisDB < 0 {
r.config.RedisDB = 0
}
r.currentDB = r.config.RedisDB
r.forwarder = nil
r.client = nil
r.singleClient = nil
@@ -282,6 +283,10 @@ func (r *RedisClientImpl) Connect(config connection.ConnectionConfig) error {
topology := strings.ToLower(strings.TrimSpace(config.Topology))
isSentinel := topology == "sentinel"
r.isCluster = !isSentinel && (topology == "cluster" || len(seedAddrs) > 1)
if r.isCluster && r.config.RedisDB >= redisClusterLogicalDBCount {
r.config.RedisDB = 0
}
r.currentDB = r.config.RedisDB
if (r.isCluster || isSentinel) && config.UseSSH {
return fmt.Errorf("Redis %s模式暂不支持 SSH 隧道,请关闭 SSH 后重试", redisTopologyDisplayName(topology))
@@ -1349,8 +1354,8 @@ func (r *RedisClientImpl) ExecuteCommand(args []string) (interface{}, error) {
if err != nil {
return nil, fmt.Errorf("无效数据库索引: %s", args[1])
}
if index < 0 || index > 15 {
return nil, fmt.Errorf("数据库索引必须在 0-15 之间")
if index < 0 || index >= redisClusterLogicalDBCount {
return nil, fmt.Errorf("数据库索引必须在 0-%d 之间", redisClusterLogicalDBCount-1)
}
r.currentDB = index
r.config.RedisDB = index
@@ -1496,6 +1501,67 @@ func (r *RedisClientImpl) GetServerInfo() (map[string]string, error) {
return result, nil
}
func parseRedisKeyspaceDatabaseKeys(info string) map[int]int64 {
dbMap := make(map[int]int64)
lines := strings.Split(info, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "db") {
// Format: db0:keys=123,expires=0,avg_ttl=0
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
dbIndex, err := strconv.Atoi(strings.TrimPrefix(parts[0], "db"))
if err != nil {
continue
}
kvPairs := strings.Split(parts[1], ",")
for _, kv := range kvPairs {
if strings.HasPrefix(kv, "keys=") {
keys, _ := strconv.ParseInt(strings.TrimPrefix(kv, "keys="), 10, 64)
dbMap[dbIndex] = keys
break
}
}
}
}
return dbMap
}
func parseRedisConfiguredDatabaseCount(config map[string]string) (int, bool) {
for key, value := range config {
if !strings.EqualFold(strings.TrimSpace(key), "databases") {
continue
}
count, err := strconv.Atoi(strings.TrimSpace(value))
if err == nil && count > 0 {
return count, true
}
}
return 0, false
}
func (r *RedisClientImpl) resolveRedisDatabaseCount(ctx context.Context, dbMap map[int]int64) int {
count := redisDefaultDatabaseCount
if r.currentDB >= count {
count = r.currentDB + 1
}
for index := range dbMap {
if index >= count {
count = index + 1
}
}
config, err := r.client.ConfigGet(ctx, "databases").Result()
if err != nil {
return count
}
if configured, ok := parseRedisConfiguredDatabaseCount(config); ok && configured > count {
count = configured
}
return count
}
// GetDatabases returns information about all databases
func (r *RedisClientImpl) GetDatabases() ([]RedisDBInfo, error) {
if r.client == nil {
@@ -1521,8 +1587,8 @@ func (r *RedisClientImpl) GetDatabases() ([]RedisDBInfo, error) {
logger.Warnf("Redis 集群获取 key 数量失败,回退为 0: %v", err)
totalKeys = 0
}
result := make([]RedisDBInfo, 16)
for i := 0; i < 16; i++ {
result := make([]RedisDBInfo, redisClusterLogicalDBCount)
for i := 0; i < redisClusterLogicalDBCount; i++ {
result[i] = RedisDBInfo{Index: i, Keys: 0}
}
result[0].Keys = totalKeys
@@ -1535,36 +1601,10 @@ func (r *RedisClientImpl) GetDatabases() ([]RedisDBInfo, error) {
return nil, err
}
// Parse keyspace info
dbMap := make(map[int]int64)
lines := strings.Split(info, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "db") {
// Format: db0:keys=123,expires=0,avg_ttl=0
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
dbIndex, err := strconv.Atoi(strings.TrimPrefix(parts[0], "db"))
if err != nil {
continue
}
// Parse keys count
kvPairs := strings.Split(parts[1], ",")
for _, kv := range kvPairs {
if strings.HasPrefix(kv, "keys=") {
keys, _ := strconv.ParseInt(strings.TrimPrefix(kv, "keys="), 10, 64)
dbMap[dbIndex] = keys
break
}
}
}
}
// Return all 16 databases (0-15)
result := make([]RedisDBInfo, 16)
for i := 0; i < 16; i++ {
dbMap := parseRedisKeyspaceDatabaseKeys(info)
databaseCount := r.resolveRedisDatabaseCount(ctx, dbMap)
result := make([]RedisDBInfo, databaseCount)
for i := 0; i < databaseCount; i++ {
result[i] = RedisDBInfo{
Index: i,
Keys: dbMap[i], // Will be 0 if not in map
@@ -1581,16 +1621,16 @@ func (r *RedisClientImpl) SelectDB(index int) error {
}
if r.isCluster {
if index < 0 || index > 15 {
return fmt.Errorf("数据库索引必须在 0-15 之间")
if index < 0 || index >= redisClusterLogicalDBCount {
return fmt.Errorf("数据库索引必须在 0-%d 之间", redisClusterLogicalDBCount-1)
}
r.currentDB = index
r.config.RedisDB = index
return nil
}
if index < 0 || index > 15 {
return fmt.Errorf("数据库索引必须在 0-15 之间")
if index < 0 {
return fmt.Errorf("数据库索引必须大于等于 0")
}
nextConfig := r.config

View File

@@ -2,17 +2,101 @@ package redis
import (
"GoNavi-Wails/internal/connection"
"bufio"
"encoding/json"
"errors"
"fmt"
"io"
"math"
"math/big"
"net"
"sort"
"strconv"
"strings"
"testing"
goredis "github.com/redis/go-redis/v9"
)
func startRedisProtocolTestServer(t *testing.T, handler func([]string) string) string {
t.Helper()
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("listen redis test server failed: %v", err)
}
t.Cleanup(func() {
_ = listener.Close()
})
go func() {
for {
conn, err := listener.Accept()
if err != nil {
return
}
go func() {
defer conn.Close()
reader := bufio.NewReader(conn)
for {
args, err := readRedisProtocolArray(reader)
if err != nil {
return
}
response := handler(args)
if response == "" {
response = "+OK\r\n"
}
if _, err := conn.Write([]byte(response)); err != nil {
return
}
}
}()
}
}()
return listener.Addr().String()
}
func readRedisProtocolArray(reader *bufio.Reader) ([]string, error) {
line, err := reader.ReadString('\n')
if err != nil {
return nil, err
}
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, "*") {
return nil, fmt.Errorf("expected array, got %q", line)
}
count, err := strconv.Atoi(strings.TrimPrefix(line, "*"))
if err != nil {
return nil, err
}
args := make([]string, 0, count)
for i := 0; i < count; i++ {
bulkHeader, err := reader.ReadString('\n')
if err != nil {
return nil, err
}
bulkHeader = strings.TrimSpace(bulkHeader)
if !strings.HasPrefix(bulkHeader, "$") {
return nil, fmt.Errorf("expected bulk string, got %q", bulkHeader)
}
size, err := strconv.Atoi(strings.TrimPrefix(bulkHeader, "$"))
if err != nil {
return nil, err
}
buf := make([]byte, size+2)
if _, err := io.ReadFull(reader, buf); err != nil {
return nil, err
}
args = append(args, string(buf[:size]))
}
return args, nil
}
func redisBulkString(value string) string {
return fmt.Sprintf("$%d\r\n%s\r\n", len(value), value)
}
// 回归保护HGETALL 在 RESP3 下返回 map[interface{}]interface{}go-redis v9 默认 RESP3
// 这种类型 encoding/json 无法序列化,原值穿透到 Wails RPC 会让 Windows 进程退出(用户感知闪退)。
// formatCommandResult 必须把 map 平展成交错 [k1, v1, k2, v2, ...] array前端按 array 渲染。
@@ -277,6 +361,47 @@ func TestRedisClusterKeepsSSHValidation(t *testing.T) {
}
}
func TestRedisGetDatabasesUsesConfiguredDatabaseCountAboveDefault(t *testing.T) {
keyspaceInfo := "# Keyspace\r\ndb0:keys=1,expires=0,avg_ttl=0\r\ndb31:keys=2,expires=0,avg_ttl=0\r\n"
addr := startRedisProtocolTestServer(t, func(args []string) string {
command := strings.ToUpper(strings.TrimSpace(args[0]))
switch command {
case "HELLO":
return "-ERR unknown command 'HELLO'\r\n"
case "CLIENT":
return "-ERR unknown subcommand\r\n"
case "CONFIG":
if len(args) >= 3 && strings.EqualFold(args[1], "GET") && strings.EqualFold(args[2], "databases") {
return "*2\r\n$9\r\ndatabases\r\n$2\r\n32\r\n"
}
case "INFO":
return redisBulkString(keyspaceInfo)
}
return "+OK\r\n"
})
rawClient := goredis.NewClient(&goredis.Options{
Addr: addr,
Protocol: 2,
})
client := &RedisClientImpl{
client: rawClient,
singleClient: rawClient,
}
defer client.Close()
dbs, err := client.GetDatabases()
if err != nil {
t.Fatalf("GetDatabases returned error: %v", err)
}
if len(dbs) != 32 {
t.Fatalf("expected 32 redis databases, got %d (%#v)", len(dbs), dbs)
}
if dbs[31].Index != 31 || dbs[31].Keys != 2 {
t.Fatalf("expected db31 with 2 keys, got %#v", dbs[31])
}
}
func TestRedisSelectDBReconnectsWithSentinelConfig(t *testing.T) {
oldConnect := redisDBSwitchConnect
defer func() {
@@ -317,12 +442,12 @@ func TestRedisSelectDBReconnectsWithSentinelConfig(t *testing.T) {
}
defer client.Close()
if err := client.SelectDB(6); err != nil {
if err := client.SelectDB(31); err != nil {
t.Fatalf("SelectDB returned error: %v", err)
}
if captured.RedisDB != 6 || client.currentDB != 6 {
t.Fatalf("expected RedisDB/currentDB=6, captured=%d current=%d", captured.RedisDB, client.currentDB)
if captured.RedisDB != 31 || client.currentDB != 31 {
t.Fatalf("expected RedisDB/currentDB=31, captured=%d current=%d", captured.RedisDB, client.currentDB)
}
if captured.Topology != "sentinel" {
t.Fatalf("expected sentinel topology to be preserved, got %q", captured.Topology)