Skip to content

Commit 4e4e30d

Browse files
committed
- change the test-server to support multi-DB operations
- update the client to use the product-variant info to allow multi-DB operations on Valkey - unit test with the toy-server
1 parent bc95598 commit 4e4e30d

5 files changed

Lines changed: 213 additions & 51 deletions

File tree

src/StackExchange.Redis/ServerEndPoint.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,12 @@ public RedisServer GetRedisServer(object? asyncState)
9191
/// This is memoized because it's accessed on hot paths inside the write lock.
9292
/// </remarks>
9393
public bool SupportsDatabases =>
94-
supportsDatabases ??= serverType == ServerType.Standalone && Multiplexer.CommandMap.IsAvailable(RedisCommand.SELECT);
94+
supportsDatabases ??= serverType switch
95+
{
96+
ServerType.Standalone => true,
97+
ServerType.Cluster => _productVariant is ProductVariant.Valkey,
98+
_ => false,
99+
} && Multiplexer.CommandMap.IsAvailable(RedisCommand.SELECT);
95100

96101
public int Databases
97102
{
@@ -1140,6 +1145,7 @@ internal void SetProductVariant(ProductVariant variant, string productVersion)
11401145
{
11411146
_productVariant = variant;
11421147
_productVersion = productVersion;
1148+
ClearMemoized(); // variant impacts multi-DB rules for cluster
11431149
}
11441150

11451151
internal ProductVariant GetProductVariant(out string productVersion)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Xunit;
4+
5+
namespace StackExchange.Redis.Tests;
6+
7+
[RunPerProtocol]
8+
public class InProcessDatabaseUnitTests(ITestOutputHelper output)
9+
{
10+
[Fact]
11+
public async Task DatabasesAreIsolatedAndCanBeFlushed()
12+
{
13+
using var server = new InProcessTestServer(output);
14+
await using var conn = await server.ConnectAsync();
15+
16+
var admin = conn.GetServer(conn.GetEndPoints()[0]);
17+
var key = (RedisKey)Guid.NewGuid().ToString("n");
18+
var db0 = conn.GetDatabase(0);
19+
var db1 = conn.GetDatabase(1);
20+
21+
db0.KeyDelete(key, CommandFlags.FireAndForget);
22+
db1.KeyDelete(key, CommandFlags.FireAndForget);
23+
db0.StringSet(key, "a");
24+
db1.StringSet(key, "b");
25+
26+
Assert.Equal("a", db0.StringGet(key));
27+
Assert.Equal("b", db1.StringGet(key));
28+
Assert.Equal(1, admin.DatabaseSize(0));
29+
Assert.Equal(1, admin.DatabaseSize(1));
30+
31+
admin.FlushDatabase(0);
32+
Assert.True(db0.StringGet(key).IsNull);
33+
Assert.Equal("b", db1.StringGet(key));
34+
35+
admin.FlushAllDatabases();
36+
Assert.True(db1.StringGet(key).IsNull);
37+
Assert.Equal(0, admin.DatabaseSize(0));
38+
Assert.Equal(0, admin.DatabaseSize(1));
39+
}
40+
}

tests/StackExchange.Redis.Tests/ProductVariantUnitTests.cs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class ProductVariantUnitTests(ITestOutputHelper log)
1414
public async Task DetectProductVariant(ProductVariant variant)
1515
{
1616
using var serverObj = new ProductServer(variant, log);
17-
using var conn = await serverObj.ConnectAsync();
17+
using var conn = await serverObj.ConnectAsync(withPubSub: false);
1818
var serverApi = conn.GetServer(conn.GetEndPoints().First());
1919
serverApi.Ping();
2020
var reportedProduct = serverApi.GetProductVariant(out var reportedVersion);
@@ -30,14 +30,64 @@ public async Task DetectProductVariant(ProductVariant variant)
3030
}
3131
}
3232

33-
private sealed class ProductServer(ProductVariant variant, ITestOutputHelper log) : InProcessTestServer(log)
33+
[Theory]
34+
[InlineData(ProductVariant.Redis, ServerType.Standalone, true)]
35+
[InlineData(ProductVariant.Redis, ServerType.Cluster, false)]
36+
[InlineData(ProductVariant.Garnet, ServerType.Standalone, true)]
37+
[InlineData(ProductVariant.Garnet, ServerType.Cluster, false)]
38+
[InlineData(ProductVariant.Valkey, ServerType.Standalone, true)]
39+
[InlineData(ProductVariant.Valkey, ServerType.Cluster, true)]
40+
public async Task MultiDbSupportMatchesProductVariantAndServerType(ProductVariant variant, ServerType serverType, bool supportsMultiDb)
41+
{
42+
using var serverObj = new ProductServer(variant, log, serverType);
43+
await using var conn = await serverObj.ConnectAsync(withPubSub: false);
44+
45+
var serverApi = conn.GetServer(conn.GetEndPoints().First());
46+
await serverApi.PingAsync();
47+
Assert.Equal(serverType, serverApi.ServerType);
48+
Assert.Equal(variant, serverApi.GetProductVariant(out _));
49+
50+
RedisKey key = $"multidb:{variant}:{serverType}";
51+
const string db0Value = "db0";
52+
const string db1Value = "db1";
53+
var db0 = conn.GetDatabase(0);
54+
55+
var db1 = conn.GetDatabase(1);
56+
57+
await db0.StringSetAsync(key, db0Value);
58+
59+
if (supportsMultiDb)
60+
{
61+
await db1.StringSetAsync(key, db1Value);
62+
Assert.Equal(db0Value, (string?)await db0.StringGetAsync(key));
63+
Assert.Equal(db1Value, (string?)await db1.StringGetAsync(key));
64+
}
65+
else
66+
{
67+
var ex = await Assert.ThrowsAsync<RedisConnectionException>(() => db1.StringSetAsync(key, db1Value));
68+
var inner = Assert.IsType<RedisCommandException>(ex.InnerException);
69+
Assert.Contains("cannot switch to database: 1", inner.Message);
70+
Assert.Equal(db0Value, (string?)await db0.StringGetAsync(key));
71+
}
72+
}
73+
74+
private sealed class ProductServer : InProcessTestServer
3475
{
76+
private readonly ProductVariant _variant;
77+
78+
public ProductServer(ProductVariant variant, ITestOutputHelper log, ServerType serverType = ServerType.Standalone)
79+
: base(log)
80+
{
81+
_variant = variant;
82+
ServerType = serverType;
83+
}
84+
3585
protected override void Info(StringBuilder sb, string section)
3686
{
3787
base.Info(sb, section);
3888
if (section is "Server")
3989
{
40-
switch (variant)
90+
switch (_variant)
4191
{
4292
case ProductVariant.Garnet:
4393
sb.AppendLine("garnet_version:1.2.3-preview4");
@@ -49,5 +99,18 @@ protected override void Info(StringBuilder sb, string section)
4999
}
50100
}
51101
}
102+
103+
protected override bool SupportMultiDb(out string err)
104+
{
105+
switch (_variant)
106+
{
107+
case ProductVariant.Valkey:
108+
// support multiple databases even on cluster
109+
err = "";
110+
return true;
111+
default:
112+
return base.SupportMultiDb(out err);
113+
}
114+
}
52115
}
53116
}

0 commit comments

Comments
 (0)