Skip to content

Commit 163a0b6

Browse files
committed
Add/fix tests
Signed-off-by: Alex Rehnby-Martin <alex.rehnby-martin@improving.com>
1 parent 5137a62 commit 163a0b6

File tree

3 files changed

+170
-7
lines changed

3 files changed

+170
-7
lines changed

sources/Valkey.Glide/BaseClient.GenericCommands.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ public async Task<ValkeyValue[]> SortAsync(ValkeyKey key, long skip = 0, long ta
170170
return await Command(Request.SortAsync(key, skip, take, order, sortType, by, get));
171171
}
172172

173+
public async Task<long> SortAndStoreAsync(ValkeyKey destination, ValkeyKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, ValkeyValue by = default, ValkeyValue[]? get = null, CommandFlags flags = CommandFlags.None)
174+
{
175+
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");
176+
return await Command(Request.SortAndStoreAsync(destination, key, skip, take, order, sortType, by, get));
177+
}
178+
173179
public async Task<long> WaitAsync(long numreplicas, long timeout, CommandFlags flags = CommandFlags.None)
174180
{
175181
Utils.Requires<NotImplementedException>(flags == CommandFlags.None, "Command flags are not supported by GLIDE");

sources/Valkey.Glide/Internals/Request.GenericCommands.cs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,49 @@ public static Cmd<object[], ValkeyValue[]> SortAsync(ValkeyKey key, long skip =
265265
args.Add(Constants.AlphaKeyword);
266266
}
267267

268-
return new(RequestType.Sort, [.. args], false, response => response?.Cast<GlideString>().Select(item => (ValkeyValue)item).ToArray() ?? []);
268+
return new(RequestType.SortReadOnly, [.. args], false, response => response?.Cast<GlideString>().Select(item => (ValkeyValue)item).ToArray() ?? []);
269+
}
270+
271+
public static Cmd<long, long> SortAndStoreAsync(ValkeyKey destination, ValkeyKey key, long skip = 0, long take = -1, Order order = Order.Ascending, SortType sortType = SortType.Numeric, ValkeyValue by = default, ValkeyValue[]? get = null)
272+
{
273+
List<GlideString> args = [key.ToGlideString()];
274+
275+
if (!by.IsNull)
276+
{
277+
args.Add(Constants.ByKeyword);
278+
args.Add(by.ToGlideString());
279+
}
280+
281+
if (skip != 0 || take != -1)
282+
{
283+
args.Add(Constants.LimitKeyword);
284+
args.Add(skip.ToGlideString());
285+
args.Add(take.ToGlideString());
286+
}
287+
288+
if (get != null)
289+
{
290+
foreach (var pattern in get)
291+
{
292+
args.Add(Constants.GetKeyword);
293+
args.Add(pattern.ToGlideString());
294+
}
295+
}
296+
297+
if (order == Order.Descending)
298+
{
299+
args.Add(Constants.DescKeyword);
300+
}
301+
302+
if (sortType == SortType.Alphabetic)
303+
{
304+
args.Add(Constants.AlphaKeyword);
305+
}
306+
307+
args.Add(Constants.StoreKeyword);
308+
args.Add(destination.ToGlideString());
309+
310+
return Simple<long>(RequestType.Sort, [.. args]);
269311
}
270312

271313
public static Cmd<bool, bool> KeyMoveAsync(ValkeyKey key, int database)

tests/Valkey.Glide.IntegrationTests/GenericCommandTests.cs

Lines changed: 121 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,8 @@ public async Task TestKeysAsync_Scan(GlideClient client)
567567
Assert.Empty(keys);
568568
}
569569

570+
571+
570572
[Theory(DisableDiscoveryEnumeration = true)]
571573
[MemberData(nameof(Config.TestClients), MemberType = typeof(TestConfiguration))]
572574
public async Task TestSort(BaseClient client)
@@ -612,6 +614,54 @@ public async Task TestSort(BaseClient client)
612614
}
613615
}
614616

617+
[Theory(DisableDiscoveryEnumeration = true)]
618+
[MemberData(nameof(Config.TestClients), MemberType = typeof(TestConfiguration))]
619+
public async Task TestSortAndStore(BaseClient client)
620+
{
621+
string sourceKey = "{prefix}-" + Guid.NewGuid().ToString();
622+
string destKey = "{prefix}-" + Guid.NewGuid().ToString();
623+
624+
// Test basic sort and store
625+
await client.ListLeftPushAsync(sourceKey, ["3", "1", "2"]);
626+
long count = await client.SortAndStoreAsync(destKey, sourceKey);
627+
Assert.Equal(3, count);
628+
629+
// Verify destination contains sorted values
630+
ValkeyValue[] result = await client.ListRangeAsync(destKey);
631+
Assert.Equal(["1", "2", "3"], result.Select(v => v.ToString()).ToArray());
632+
633+
// Test with descending order
634+
string destKey2 = "{prefix}-" + Guid.NewGuid().ToString();
635+
count = await client.SortAndStoreAsync(destKey2, sourceKey, order: Order.Descending);
636+
Assert.Equal(3, count);
637+
result = await client.ListRangeAsync(destKey2);
638+
Assert.Equal(["3", "2", "1"], result.Select(v => v.ToString()).ToArray());
639+
640+
// Test with limit
641+
string destKey3 = "{prefix}-" + Guid.NewGuid().ToString();
642+
count = await client.SortAndStoreAsync(destKey3, sourceKey, skip: 1, take: 1);
643+
Assert.Equal(1, count);
644+
result = await client.ListRangeAsync(destKey3);
645+
Assert.Single(result);
646+
Assert.Equal("2", result[0].ToString());
647+
648+
// Test alphabetic sort
649+
string alphaKey = "{prefix}-" + Guid.NewGuid().ToString();
650+
string alphaDestKey = "{prefix}-" + Guid.NewGuid().ToString();
651+
await client.ListLeftPushAsync(alphaKey, ["b", "a", "c"]);
652+
count = await client.SortAndStoreAsync(alphaDestKey, alphaKey, sortType: SortType.Alphabetic);
653+
Assert.Equal(3, count);
654+
result = await client.ListRangeAsync(alphaDestKey);
655+
Assert.Equal(["a", "b", "c"], result.Select(v => v.ToString()).ToArray());
656+
657+
// Test overwriting existing destination
658+
await client.StringSetAsync(destKey, "existing_value");
659+
count = await client.SortAndStoreAsync(destKey, sourceKey);
660+
Assert.Equal(3, count);
661+
// Destination should now be a list, not a string
662+
Assert.Equal(ValkeyType.List, await client.KeyTypeAsync(destKey));
663+
}
664+
615665
[Theory(DisableDiscoveryEnumeration = true)]
616666
[MemberData(nameof(Config.TestClients), MemberType = typeof(TestConfiguration))]
617667
public async Task TestWait(BaseClient client)
@@ -622,18 +672,83 @@ public async Task TestWait(BaseClient client)
622672
// Set a key to create a write operation
623673
await client.StringSetAsync(key, value);
624674

675+
// Test WAIT with different expected behavior for cluster vs standalone
676+
long replicaCount = await client.WaitAsync(1, 1000);
677+
if (client is GlideClusterClient)
678+
{
679+
Assert.True(replicaCount >= 1); // Cluster mode
680+
}
681+
else
682+
{
683+
Assert.True(replicaCount >= 0); // Standalone mode
684+
}
685+
625686
// Test WAIT with 0 replicas (should return immediately)
626-
long replicaCount = await client.WaitAsync(0, 1000);
687+
replicaCount = await client.WaitAsync(0, 1000);
627688
Assert.True(replicaCount >= 0);
628689

629690
// Test WAIT with timeout 0 (should return immediately)
630691
replicaCount = await client.WaitAsync(1, 0);
631692
Assert.True(replicaCount >= 0);
693+
}
632694

633-
// Test WAIT with reasonable parameters
634-
// In a single-node setup, this should return 0 replicas
635-
replicaCount = await client.WaitAsync(1, 100);
636-
Assert.True(replicaCount >= 0);
695+
[Theory(DisableDiscoveryEnumeration = true)]
696+
[MemberData(nameof(Config.TestClients), MemberType = typeof(TestConfiguration))]
697+
public async Task TestWait_NegativeTimeout(BaseClient client)
698+
{
699+
// Test negative timeout should throw exception
700+
var exception = await Assert.ThrowsAsync<Errors.RequestException>(
701+
() => client.WaitAsync(1, -1));
702+
Assert.Contains("Timeout cannot be negative", exception.Message, StringComparison.OrdinalIgnoreCase);
703+
}
704+
705+
[Theory(DisableDiscoveryEnumeration = true)]
706+
[MemberData(nameof(Config.TestStandaloneClients), MemberType = typeof(TestConfiguration))]
707+
public async Task TestSortAndStore_WithPatterns(GlideClient client)
708+
{
709+
// Test with BY and GET patterns (only for standalone clients)
710+
string userKey = "{prefix}-" + Guid.NewGuid().ToString();
711+
string destKey = "{prefix}-" + Guid.NewGuid().ToString();
712+
713+
// Set up test data
714+
await client.HashSetAsync("user:1", [new HashEntry("age", "30"), new HashEntry("name", "Alice")]);
715+
await client.HashSetAsync("user:2", [new HashEntry("age", "25"), new HashEntry("name", "Bob")]);
716+
await client.ListLeftPushAsync(userKey, ["2", "1"]);
717+
718+
// Test with BY pattern
719+
long count = await client.SortAndStoreAsync(destKey, userKey, by: "user:*->age");
720+
Assert.Equal(2, count);
721+
ValkeyValue[] result = await client.ListRangeAsync(destKey);
722+
Assert.Equal(["2", "1"], result.Select(v => v.ToString()).ToArray());
723+
724+
// Test with GET pattern
725+
string destKey2 = "{prefix}-" + Guid.NewGuid().ToString();
726+
count = await client.SortAndStoreAsync(destKey2, userKey, by: "user:*->age", get: ["user:*->name"]);
727+
Assert.Equal(2, count);
728+
result = await client.ListRangeAsync(destKey2);
729+
Assert.Equal(["Bob", "Alice"], result.Select(v => v.ToString()).ToArray());
730+
}
731+
732+
[Theory(DisableDiscoveryEnumeration = true)]
733+
[MemberData(nameof(Config.TestStandaloneClients), MemberType = typeof(TestConfiguration))]
734+
public async Task TestKeysAsync_LargeDataset(GlideClient client)
735+
{
736+
string prefix = Guid.NewGuid().ToString();
737+
738+
var tasks = Enumerable.Range(0, 25000).Select(i =>
739+
client.StringSetAsync($"{prefix}:key{i}", $"value{i}"));
740+
await Task.WhenAll(tasks);
741+
742+
int count = 0;
743+
await foreach (var key in client.KeysAsync(pattern: $"{prefix}:*"))
744+
{
745+
count++;
746+
}
747+
Assert.Equal(25000, count);
748+
749+
var sampleKeys = Enumerable.Range(0, 100).Select(i => (ValkeyKey)$"{prefix}:key{i}").ToArray();
750+
long sampleCount = await client.KeyExistsAsync(sampleKeys);
751+
Assert.Equal(100L, sampleCount);
637752
}
638753

639-
}
754+
}

0 commit comments

Comments
 (0)