Skip to content

C#: Add RESP2 client to IT. #3833

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion csharp/sources/Valkey.Glide/BaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void Dispose()
}
}

public override string ToString() => $"{GetType().Name} {{ 0x{_clientPointer:X} }}";
public override string ToString() => $"{GetType().Name} {{ 0x{_clientPointer:X} {_clientInfo} }}";

public override int GetHashCode() => (int)_clientPointer;

Expand Down Expand Up @@ -191,6 +191,8 @@ private void FailureCallback(ulong index, IntPtr strPtr, RequestErrorType errTyp
}

~BaseClient() => Dispose();

internal void SetInfo(string info) => _clientInfo = info;
#endregion private methods

#region private fields
Expand All @@ -207,6 +209,7 @@ private void FailureCallback(ulong index, IntPtr strPtr, RequestErrorType errTyp
private IntPtr _clientPointer;
private readonly MessageContainer _messageContainer;
private readonly object _lock = new();
private string _clientInfo = ""; // used to distinguish and identify clients during tests

#endregion private fields

Expand Down
68 changes: 33 additions & 35 deletions csharp/tests/Valkey.Glide.IntegrationTests/ClusterClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@
using gs = Valkey.Glide.GlideString;
namespace Valkey.Glide.IntegrationTests;

public class ClusterClientTests
public class ClusterClientTests(TestConfiguration config)
{
[Fact]
public async Task CustomCommand()
public TestConfiguration Config { get; } = config;

#pragma warning disable xUnit1046 // Avoid using TheoryDataRow arguments that are not serializable
public static IEnumerable<TheoryDataRow<GlideClusterClient, bool>> ClusterClientWithAtomic =>
TestConfiguration.TestClusterClients.SelectMany(r => new TheoryDataRow<GlideClusterClient, bool>[] { new(r.Data, true), new(r.Data, false) });
#pragma warning restore xUnit1046 // Avoid using TheoryDataRow arguments that are not serializable

[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task CustomCommand(GlideClusterClient client)
{
GlideClusterClient client = TestConfiguration.DefaultClusterClient();
// command which returns always a single value
long res = (long)(await client.CustomCommand(["dbsize"])).SingleValue!;
Assert.True(res >= 0);
Expand All @@ -29,10 +36,10 @@ public async Task CustomCommand()
Assert.True((config.SingleValue as Dictionary<gs, object?>)!.Count > 0);
}

[Fact]
public async Task CustomCommandWithRandomRoute()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task CustomCommandWithRandomRoute(GlideClusterClient client)
{
using GlideClusterClient client = TestConfiguration.DefaultClusterClient();
// if a command isn't routed in 100 tries to different nodes, you are a lucker or have a bug
SortedSet<string> ports = [];
foreach (int i in Enumerable.Range(0, 100))
Expand All @@ -54,11 +61,10 @@ public async Task CustomCommandWithRandomRoute()
Assert.Fail($"All 100 commands were sent to: {ports.First()}");
}

[Fact]
public async Task CustomCommandWithSingleNodeRoute()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task CustomCommandWithSingleNodeRoute(GlideClusterClient client)
{
using GlideClusterClient client = TestConfiguration.DefaultClusterClient();

string res = ((await client.CustomCommand(["info", "replication"], new SlotKeyRoute("abc", SlotType.Primary))).SingleValue! as gs)!;
Assert.Contains("role:master", res);

Expand All @@ -75,10 +81,10 @@ public async Task CustomCommandWithSingleNodeRoute()
Assert.Contains("# Replication", res);
}

[Fact]
public async Task CustomCommandWithMultiNodeRoute()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task CustomCommandWithMultiNodeRoute(GlideClusterClient client)
{
using GlideClusterClient client = TestConfiguration.DefaultClusterClient();
_ = await client.Set("abc", "abc");
_ = await client.Set("klm", "klm");
_ = await client.Set("xyz", "xyz");
Expand All @@ -87,21 +93,15 @@ public async Task CustomCommandWithMultiNodeRoute()
Assert.True(res >= 3);
}

[Fact]
public async Task RetryStrategyIsNotSupportedForTransactions()
{
using GlideClusterClient client = TestConfiguration.DefaultClusterClient();
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task RetryStrategyIsNotSupportedForTransactions(GlideClusterClient client)
=> _ = await Assert.ThrowsAsync<RequestException>(async () => _ = await client.Exec(new(true), true, new(retryStrategy: new())));

_ = await Assert.ThrowsAsync<RequestException>(async () => _ = await client.Exec(new(true), true, new(retryStrategy: new())));
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task BatchWithSingleNodeRoute(bool isAtomic)
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(ClusterClientWithAtomic))]
public async Task BatchWithSingleNodeRoute(GlideClusterClient client, bool isAtomic)
{
using GlideClusterClient client = TestConfiguration.DefaultClusterClient();

ClusterBatch batch = new ClusterBatch(isAtomic).Info([Section.REPLICATION]);

object?[]? res = await client.Exec(batch, true, new(route: new SlotKeyRoute("abc", SlotType.Primary)));
Expand All @@ -120,11 +120,10 @@ public async Task BatchWithSingleNodeRoute(bool isAtomic)
Assert.Contains("# Replication", res![0] as gs);
}

[Fact]
public async Task Info()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task Info(GlideClusterClient client)
{
GlideClusterClient client = TestConfiguration.DefaultClusterClient();

Dictionary<string, string> info = await client.Info();
foreach (string nodeInfo in info.Values)
{
Expand All @@ -146,11 +145,10 @@ public async Task Info()
}
}

[Fact]
public async Task InfoWithRoute()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestClusterClients), MemberType = typeof(TestConfiguration))]
public async Task InfoWithRoute(GlideClusterClient client)
{
GlideClusterClient client = TestConfiguration.DefaultClusterClient();

ClusterValue<string> info = await client.Info(Route.Random);
Assert.Multiple([
() => Assert.Contains("# Server", info.SingleValue),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@
using gs = Valkey.Glide.GlideString;
namespace Valkey.Glide.IntegrationTests;

public class StandaloneClientTests
public class StandaloneClientTests(TestConfiguration config)
{
[Fact]
public void CustomCommand()
{
using GlideClient client = TestConfiguration.DefaultStandaloneClient();
public TestConfiguration Config { get; } = config;

[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestStandaloneClients), MemberType = typeof(TestConfiguration))]
public void CustomCommand(GlideClient client) =>
// Assert.Multiple doesn't work with async tasks https://github.com/xunit/xunit/issues/3209
Assert.Multiple(
() => Assert.Equal("PONG", client.CustomCommand(["ping"]).Result!.ToString()),
() => Assert.Equal("piping", client.CustomCommand(["ping", "piping"]).Result!.ToString()),
() => Assert.Contains("# Server", client.CustomCommand(["INFO"]).Result!.ToString())
);
}

[Fact]
public async Task CustomCommandWithBinary()
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestStandaloneClients), MemberType = typeof(TestConfiguration))]
public async Task CustomCommandWithBinary(GlideClient client)
{
using GlideClient client = TestConfiguration.DefaultStandaloneClient();
string key1 = Guid.NewGuid().ToString();
string key2 = Guid.NewGuid().ToString();
string key3 = Guid.NewGuid().ToString();
Expand Down Expand Up @@ -68,13 +68,12 @@ public void CanConnectWithDifferentParameters()
.WithReadFrom(new ConnectionConfiguration.ReadFrom(ConnectionConfiguration.ReadFromStrategy.Primary)).Build());
}

[Fact]
[Theory(DisableDiscoveryEnumeration = true)]
[MemberData(nameof(Config.TestStandaloneClients), MemberType = typeof(TestConfiguration))]
// Verify that client can handle complex return types, not just strings
// TODO: remove this test once we add tests with these commands
public async Task CustomCommandWithDifferentReturnTypes()
public async Task CustomCommandWithDifferentReturnTypes(GlideClient client)
{
using GlideClient client = TestConfiguration.DefaultStandaloneClient();

string key1 = Guid.NewGuid().ToString();
Assert.Equal(2, (long)(await client.CustomCommand(["hset", key1, "f1", "v1", "f2", "v2"]))!);
Assert.Equal(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,51 @@ public static TheoryData<BaseClient> TestClients
{
if (field.Count == 0)
{
field = [(BaseClient)DefaultStandaloneClientWithExtraTimeout(), (BaseClient)DefaultClusterClientWithExtraTimeout()];
field = [.. TestStandaloneClients.Select(d => (BaseClient)d.Data), .. TestClusterClients.Select(d => (BaseClient)d.Data)];
}
return field;
}

private set;
} = [];

public static TheoryData<GlideClient> TestStandaloneClients
{
get
{
if (field.Count == 0)
{
GlideClient resp2client = GlideClient.CreateClient(
DefaultClientConfig().WithRequestTimeout(1000).WithProtocolVersion(Protocol.RESP2).Build()
).GetAwaiter().GetResult();
resp2client.SetInfo("RESP2");
GlideClient resp3client = GlideClient.CreateClient(
DefaultClientConfig().WithRequestTimeout(1000).WithProtocolVersion(Protocol.RESP3).Build()
).GetAwaiter().GetResult();
resp3client.SetInfo("RESP3");
field = [resp2client, resp3client];
}
return field;
}

private set;
} = [];

public static TheoryData<GlideClusterClient> TestClusterClients
{
get
{
if (field.Count == 0)
{
GlideClusterClient resp2client = GlideClusterClient.CreateClient(
DefaultClusterClientConfig().WithRequestTimeout(1000).WithProtocolVersion(Protocol.RESP2).Build()
).GetAwaiter().GetResult();
resp2client.SetInfo("RESP2");
GlideClusterClient resp3client = GlideClusterClient.CreateClient(
DefaultClusterClientConfig().WithRequestTimeout(1000).WithProtocolVersion(Protocol.RESP3).Build()
).GetAwaiter().GetResult();
resp3client.SetInfo("RESP3");
field = [resp2client, resp3client];
}
return field;
}
Expand All @@ -57,6 +101,8 @@ public static void ResetTestClients()
data.Data.Dispose();
}
TestClients = [];
TestClusterClients = [];
TestStandaloneClients = [];
}

public TestConfiguration()
Expand Down
Loading