From 0cf8666ec6a8040e3eb2b9650e945cb234b31b1e Mon Sep 17 00:00:00 2001 From: Ziya Suzen Date: Fri, 22 Dec 2023 09:47:34 +0000 Subject: [PATCH] KV get keys should not hang with deleted keys (#293) --- src/NATS.Client.KeyValueStore/NatsKVStore.cs | 5 +- .../GetKeysTest.cs | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 tests/NATS.Client.KeyValueStore.Tests/GetKeysTest.cs diff --git a/src/NATS.Client.KeyValueStore/NatsKVStore.cs b/src/NATS.Client.KeyValueStore/NatsKVStore.cs index 45636b58a..0809ce258 100644 --- a/src/NATS.Client.KeyValueStore/NatsKVStore.cs +++ b/src/NATS.Client.KeyValueStore/NatsKVStore.cs @@ -415,7 +415,7 @@ public async IAsyncEnumerable GetKeysAsync(NatsKVWatchOpts? opts = defau opts = opts with { - IgnoreDeletes = true, + IgnoreDeletes = false, MetaOnly = true, UpdatesOnly = false, }; @@ -427,7 +427,8 @@ public async IAsyncEnumerable GetKeysAsync(NatsKVWatchOpts? opts = defau { while (watcher.Entries.TryRead(out var entry)) { - yield return entry.Key; + if (entry.Operation is NatsKVOperation.Put) + yield return entry.Key; if (entry.Delta == 0) yield break; } diff --git a/tests/NATS.Client.KeyValueStore.Tests/GetKeysTest.cs b/tests/NATS.Client.KeyValueStore.Tests/GetKeysTest.cs new file mode 100644 index 000000000..db4874f4e --- /dev/null +++ b/tests/NATS.Client.KeyValueStore.Tests/GetKeysTest.cs @@ -0,0 +1,48 @@ +using NATS.Client.Core.Tests; + +namespace NATS.Client.KeyValueStore.Tests; + +public class GetKeysTest +{ + [Fact] + public async Task Get_keys_should_not_hang_when_there_are_deleted_keys() + { + const string bucket = "b1"; + var config = new NatsKVConfig(bucket) { History = 10 }; + + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var cancellationToken = cts.Token; + + await using var server = NatsServer.StartJS(); + await using var nats1 = server.CreateClientConnection(); + var js1 = new NatsJSContext(nats1); + var kv1 = new NatsKVContext(js1); + var store1 = await kv1.CreateStoreAsync(config, cancellationToken: cancellationToken); + + await store1.PutAsync("k1", 1, cancellationToken: cancellationToken); + await store1.PutAsync("k2", 2, cancellationToken: cancellationToken); + await store1.PutAsync("k3", 3, cancellationToken: cancellationToken); + + var ks1 = new List(); + await foreach (var k in store1.GetKeysAsync(cancellationToken: cancellationToken)) + { + ks1.Add(k); + } + + ks1.Sort(); + + Assert.Equal(new List { "k1", "k2", "k3" }, ks1); + + await store1.DeleteAsync("k2", cancellationToken: cancellationToken); + + var ks2 = new List(); + await foreach (var k in store1.GetKeysAsync(cancellationToken: cancellationToken)) + { + ks2.Add(k); + } + + ks2.Sort(); + + Assert.Equal(new List { "k1", "k3" }, ks2); + } +}