diff --git a/AGENTS.md b/AGENTS.md index 35454df3..42493b4f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -33,9 +33,8 @@ Common commands: - `task test:integration` (integration tests only) - Filter tests: - - By class: `--filter "FullyQualifiedName~ClassName"` - - By method: `--filter "FullyQualifiedName~MethodName"` - - By display name pattern: `--filter "DisplayName~Pattern"` + - By class: `task test:unit filter=MyTestClass` + - By method: `task test:integration filter=MyMethodName` - Coverage and reports (preferred via Task): - `task coverage`, `task coverage:unit`, `task coverage:integration` diff --git a/DEVELOPER.md b/DEVELOPER.md index acb31eb4..42bd3241 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -196,8 +196,12 @@ In Windows, run from following commands from the appropriate Visual Studio Comma task test # Run specific test suites - task test:unit # Unit tests only - task test:integration # Integration tests only + task test:unit + task test:integration + + # Run specific test classes or methods + task test:unit filter=MyTestClass + task test:integration filter=MyMethodName # Run tests with coverage and generate reports task coverage # All tests with coverage diff --git a/Taskfile.yml b/Taskfile.yml index 7c28ea13..eeb6cd56 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,9 +7,15 @@ vars: UNIT_TEST_PROJECT: tests/Valkey.Glide.UnitTests/Valkey.Glide.UnitTests.csproj INTEGRATION_TEST_PROJECT: tests/Valkey.Glide.IntegrationTests/Valkey.Glide.IntegrationTests.csproj - # Build options + # Build the solution or a specific target. + # Usage: `task build target=lib` TARGET: '{{.target | default "all"}}' - TARGET_PATH: '{{if eq .TARGET "lib"}}sources/Valkey.Glide/{{end}}' + BUILD_TARGET: '{{if eq .TARGET "lib"}}sources/Valkey.Glide/{{end}}' + + # Filter tests by class or method name. + # Usage: `task test:unit filter=MyTestClass` + FILTER: '{{.filter | default ""}}' + TEST_FILTER: "{{if .FILTER}}--filter FullyQualifiedName~{{.FILTER}}{{end}}" tasks: clean: @@ -31,13 +37,19 @@ tasks: desc: Run unit tests only deps: [clean] cmds: - - dotnet test {{.UNIT_TEST_PROJECT}} --configuration Release --verbosity normal + - dotnet test {{.UNIT_TEST_PROJECT}} + --configuration Release + --verbosity normal + {{.TEST_FILTER}} test:integration: desc: Run integration tests only deps: [clean] cmds: - - dotnet test {{.INTEGRATION_TEST_PROJECT}} --configuration Release --verbosity normal + - dotnet test {{.INTEGRATION_TEST_PROJECT}} + --configuration Release + --verbosity normal + {{.TEST_FILTER}} test:coverage:unit: desc: Run unit tests with coverage collection @@ -146,7 +158,7 @@ tasks: build: desc: Build the solution - cmd: dotnet build {{.TARGET_PATH}} --configuration Release + cmd: dotnet build {{.BUILD_TARGET}} --configuration Release test: desc: Build and run all tests diff --git a/sources/Valkey.Glide/Abstract/ValkeyServer.cs b/sources/Valkey.Glide/Abstract/ValkeyServer.cs index 9c3fada0..4d009d68 100644 --- a/sources/Valkey.Glide/Abstract/ValkeyServer.cs +++ b/sources/Valkey.Glide/Abstract/ValkeyServer.cs @@ -163,13 +163,13 @@ public async Task LolwutAsync(CommandFlags flags = CommandFlags.None) public async Task ScriptExistsAsync(string script, CommandFlags flags = CommandFlags.None) { + GuardClauses.ThrowIfCommandFlags(flags); + if (string.IsNullOrEmpty(script)) { throw new ArgumentException("Script cannot be null or empty", nameof(script)); } - GuardClauses.ThrowIfCommandFlags(flags); - // Calculate SHA1 hash of the script using Script scriptObj = new(script); string hash = scriptObj.Hash; @@ -181,13 +181,13 @@ public async Task ScriptExistsAsync(string script, CommandFlags flags = Co public async Task ScriptExistsAsync(byte[] sha1, CommandFlags flags = CommandFlags.None) { + GuardClauses.ThrowIfCommandFlags(flags); + if (sha1 == null || sha1.Length == 0) { throw new ArgumentException("SHA1 hash cannot be null or empty", nameof(sha1)); } - GuardClauses.ThrowIfCommandFlags(flags); - // Convert byte array to hex string string hash = BitConverter.ToString(sha1).Replace("-", "").ToLowerInvariant(); @@ -198,13 +198,13 @@ public async Task ScriptExistsAsync(byte[] sha1, CommandFlags flags = Comm public async Task ScriptLoadAsync(string script, CommandFlags flags = CommandFlags.None) { + GuardClauses.ThrowIfCommandFlags(flags); + if (string.IsNullOrEmpty(script)) { throw new ArgumentException("Script cannot be null or empty", nameof(script)); } - GuardClauses.ThrowIfCommandFlags(flags); - // Use custom command to call SCRIPT LOAD ValkeyResult result = await ExecuteAsync("SCRIPT", ["LOAD", script], flags); string? hashString = (string?)result; @@ -220,13 +220,13 @@ public async Task ScriptLoadAsync(string script, CommandFlags flags = Co public async Task ScriptLoadAsync(LuaScript script, CommandFlags flags = CommandFlags.None) { + GuardClauses.ThrowIfCommandFlags(flags); + if (script == null) { throw new ArgumentNullException(nameof(script)); } - GuardClauses.ThrowIfCommandFlags(flags); - // Load the executable script byte[] hash = await ScriptLoadAsync(script.ExecutableScript, flags); return new LoadedLuaScript(script, hash, script.ExecutableScript); diff --git a/tests/Valkey.Glide.IntegrationTests/ClientSideCacheTests.cs b/tests/Valkey.Glide.IntegrationTests/ClientSideCacheTests.cs index b8120f74..be4c60b6 100644 --- a/tests/Valkey.Glide.IntegrationTests/ClientSideCacheTests.cs +++ b/tests/Valkey.Glide.IntegrationTests/ClientSideCacheTests.cs @@ -11,31 +11,10 @@ public class ClientSideCacheTests { #region Helpers - private static async Task CreateStandaloneClientWithCache(ClientSideCacheConfig cache) - { - var config = TestConfiguration.DefaultClientConfig() - .WithClientSideCache(cache) - .Build(); - return await GlideClient.CreateClient(config); - } - - private static async Task CreateClusterClientWithCache(ClientSideCacheConfig cache) - { - var config = TestConfiguration.DefaultClusterClientConfig() - .WithClientSideCache(cache) - .Build(); - return await GlideClusterClient.CreateClient(config); - } - private static async Task CreateClientWithCache(ClientSideCacheConfig cache, bool clusterMode) - { - if (clusterMode) - { - return await CreateClusterClientWithCache(cache); - } - - return await CreateStandaloneClientWithCache(cache); - } + => clusterMode + ? await GlideClusterClient.CreateClient(TestConfiguration.DefaultClusterClientConfig().WithClientSideCache(cache).Build()) + : await GlideClient.CreateClient(TestConfiguration.DefaultClientConfig().WithClientSideCache(cache).Build()); #endregion @@ -112,11 +91,11 @@ public async Task WithoutMetrics_MetricCallsFail(bool clusterMode) Assert.Equal("value", value.ToString()); // Metrics that require EnableMetrics should fail - _ = await Assert.ThrowsAsync(() => client.GetCacheHitRateAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheMissRateAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheEvictionsAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheExpirationsAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheTotalLookupsAsync()); + _ = await Assert.ThrowsAsync(client.GetCacheHitRateAsync); + _ = await Assert.ThrowsAsync(client.GetCacheMissRateAsync); + _ = await Assert.ThrowsAsync(client.GetCacheEvictionsAsync); + _ = await Assert.ThrowsAsync(client.GetCacheExpirationsAsync); + _ = await Assert.ThrowsAsync(client.GetCacheTotalLookupsAsync); // Entry count should still work (doesn't require metrics) long entryCount = await client.GetCacheEntryCountAsync(); @@ -132,12 +111,12 @@ public async Task WithoutMetrics_MetricCallsFail(bool clusterMode) public async Task NoCacheConfigured_AllMetricsFail(BaseClient client) { // Without cache configured, all metric calls should fail - _ = await Assert.ThrowsAsync(() => client.GetCacheHitRateAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheMissRateAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheEntryCountAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheEvictionsAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheExpirationsAsync()); - _ = await Assert.ThrowsAsync(() => client.GetCacheTotalLookupsAsync()); + _ = await Assert.ThrowsAsync(client.GetCacheHitRateAsync); + _ = await Assert.ThrowsAsync(client.GetCacheMissRateAsync); + _ = await Assert.ThrowsAsync(client.GetCacheEntryCountAsync); + _ = await Assert.ThrowsAsync(client.GetCacheEvictionsAsync); + _ = await Assert.ThrowsAsync(client.GetCacheExpirationsAsync); + _ = await Assert.ThrowsAsync(client.GetCacheTotalLookupsAsync); } #endregion @@ -273,9 +252,8 @@ public async Task EvictionPolicyLRU(bool clusterMode) Assert.Equal(largeValue, value.ToString()); } - // Verify 2 evictions occurred - long evictions = await client.GetCacheEvictionsAsync(); - Assert.Equal(2, evictions); + // Verify at least 2 evictions occurred (possibly more due to internal overhead) + Assert.True(await client.GetCacheEvictionsAsync() >= 2); // Verify cache is working (hit rate > 0) double hitRate = await client.GetCacheHitRateAsync(); @@ -356,9 +334,8 @@ public async Task EvictionPolicyLFU(bool clusterMode) entryCount = await client.GetCacheEntryCountAsync(); Assert.Equal(3, entryCount); - // Verify 1 eviction occurred - long evictions = await client.GetCacheEvictionsAsync(); - Assert.Equal(1, evictions); + // Verify at least 1 eviction occurred (possibly more due to internal overhead) + Assert.True(await client.GetCacheEvictionsAsync() >= 1); // Check that key1 (highest frequency) is still cached double oldHitRate = await client.GetCacheHitRateAsync(); diff --git a/tests/Valkey.Glide.IntegrationTests/ServerModules/FtInfoTests.cs b/tests/Valkey.Glide.IntegrationTests/ServerModules/FtInfoTests.cs index fff4ae90..95557df3 100644 --- a/tests/Valkey.Glide.IntegrationTests/ServerModules/FtInfoTests.cs +++ b/tests/Valkey.Glide.IntegrationTests/ServerModules/FtInfoTests.cs @@ -101,8 +101,9 @@ public async Task InfoLocalAsync_TextFieldAttributes(BaseClient client) await SkipUtils.IfSearchModuleNotLoaded(client); var index = Guid.NewGuid().ToString(); + var prefix = $"{index}:"; var field = new Ft.CreateTextField("$.title", "title") { NoStem = true, WithSuffixTrie = false }; - await Ft.CreateAsync(client, index, field); + await Ft.CreateAsync(client, index, field, new Ft.CreateOptions { Prefixes = [prefix] }); var info = await Ft.InfoLocalAsync(client, index); var attr = Assert.IsType(Assert.Single(info.Attributes)); @@ -122,8 +123,9 @@ public async Task InfoLocalAsync_TagFieldAttributes(BaseClient client) await SkipUtils.IfSearchModuleNotLoaded(client); var index = Guid.NewGuid().ToString(); + var prefix = $"{index}:"; var field = new Ft.CreateTagField("category") { Separator = '|', CaseSensitive = true }; - await Ft.CreateAsync(client, index, field); + await Ft.CreateAsync(client, index, field, new Ft.CreateOptions { Prefixes = [prefix] }); var info = await Ft.InfoLocalAsync(client, index); var attr = Assert.IsType(Assert.Single(info.Attributes)); @@ -144,8 +146,9 @@ public async Task InfoLocalAsync_NumericFieldAttributes(BaseClient client) await SkipUtils.IfSearchModuleNotLoaded(client); var index = Guid.NewGuid().ToString(); + var prefix = $"{index}:"; var field = new Ft.CreateNumericField("price"); - await Ft.CreateAsync(client, index, field); + await Ft.CreateAsync(client, index, field, new Ft.CreateOptions { Prefixes = [prefix] }); var info = await Ft.InfoLocalAsync(client, index); var attr = Assert.IsType(Assert.Single(info.Attributes)); @@ -162,13 +165,14 @@ public async Task InfoLocalAsync_VectorFieldFlatAttributes(BaseClient client) await SkipUtils.IfSearchModuleNotLoaded(client); var index = Guid.NewGuid().ToString(); + var prefix = $"{index}:"; var field = new Ft.CreateVectorFieldFlat { Identifier = "embedding", Dimensions = 128, DistanceMetric = Ft.DistanceMetric.Cosine, }; - await Ft.CreateAsync(client, index, field); + await Ft.CreateAsync(client, index, field, new Ft.CreateOptions { Prefixes = [prefix] }); var info = await Ft.InfoLocalAsync(client, index); var attr = Assert.IsType(Assert.Single(info.Attributes)); @@ -190,6 +194,7 @@ public async Task InfoLocalAsync_VectorFieldHnswAttributes(BaseClient client) await SkipUtils.IfSearchModuleNotLoaded(client); var index = Guid.NewGuid().ToString(); + var prefix = $"{index}:"; var field = new Ft.CreateVectorFieldHnsw { Identifier = "vec", @@ -199,7 +204,7 @@ public async Task InfoLocalAsync_VectorFieldHnswAttributes(BaseClient client) VectorsExaminedOnConstruction = 200, VectorsExaminedOnRuntime = 10, }; - await Ft.CreateAsync(client, index, field); + await Ft.CreateAsync(client, index, field, new Ft.CreateOptions { Prefixes = [prefix] }); var info = await Ft.InfoLocalAsync(client, index); var attr = Assert.IsType(Assert.Single(info.Attributes)); diff --git a/tests/Valkey.Glide.IntegrationTests/StackExchange/CommandFlagsTests.cs b/tests/Valkey.Glide.IntegrationTests/StackExchange/CommandFlagsTests.cs index bf8c3828..d745404b 100644 --- a/tests/Valkey.Glide.IntegrationTests/StackExchange/CommandFlagsTests.cs +++ b/tests/Valkey.Glide.IntegrationTests/StackExchange/CommandFlagsTests.cs @@ -423,7 +423,7 @@ public async Task HashFieldGetAndSetExpiryAsync_MultiField_ThrowsOnCommandFlags( _ = await Assert.ThrowsAsync( () => db.HashFieldGetAndSetExpiryAsync("key", [], flags: UnsupportedFlag)); _ = await Assert.ThrowsAsync( - () => db.HashFieldGetAndSetExpiryAsync("key", [], flags: UnsupportedFlag)); + () => db.HashFieldGetAndSetExpiryAsync("key", [], DateTime.MinValue, UnsupportedFlag)); } [Theory(DisableDiscoveryEnumeration = true)] @@ -443,7 +443,7 @@ public async Task HashFieldSetAndSetExpiryAsync_MultiField_ThrowsOnCommandFlags( _ = await Assert.ThrowsAsync( () => db.HashFieldSetAndSetExpiryAsync("key", [], flags: UnsupportedFlag)); _ = await Assert.ThrowsAsync( - () => db.HashFieldSetAndSetExpiryAsync("key", [], flags: UnsupportedFlag)); + () => db.HashFieldSetAndSetExpiryAsync("key", [], DateTime.MinValue, flags: UnsupportedFlag)); } #endregion @@ -1041,6 +1041,203 @@ public async Task StringSetRangeAsync_ThrowsOnCommandFlags(IDatabaseAsync db) => _ = await Assert.ThrowsAsync( () => db.StringSetRangeAsync("key", 0, "value", UnsupportedFlag)); + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StringSetAsync_WithExpiry_ThrowsOnCommandFlags(IDatabaseAsync db) + { + _ = await Assert.ThrowsAsync( + () => db.StringSetAsync("key", "value", TimeSpan.Zero, false, When.Always, UnsupportedFlag)); + _ = await Assert.ThrowsAsync( + () => db.StringSetAsync("key", "value", TimeSpan.Zero, When.Always, UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StringSetAndGetAsync_WithExpiry_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StringSetAndGetAsync("key", "value", TimeSpan.Zero, When.Always, UnsupportedFlag)); + + #endregion + #region Stream Commands + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamAddAsync_SingleField_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamAddAsync("key", "field", "value", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamAddAsync_MultiField_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamAddAsync("key", [], flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamReadAsync_SingleKey_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamReadAsync("key", "0-0", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamReadAsync_MultiKey_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamReadAsync([], flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamRangeAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamRangeAsync("key", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamReadGroupAsync_SingleKey_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamReadGroupAsync("key", "group", "consumer", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamReadGroupAsync_WithClaimMinIdleTime_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamReadGroupAsync("key", "group", "consumer", null, null, false, TimeSpan.Zero, UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamReadGroupAsync_MultiKey_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamReadGroupAsync([], "group", "consumer", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamLengthAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamLengthAsync("key", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamDeleteAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamDeleteAsync("key", [], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamCreateConsumerGroupAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + { + _ = await Assert.ThrowsAsync( + () => db.StreamCreateConsumerGroupAsync("key", "group", flags: UnsupportedFlag)); + _ = await Assert.ThrowsAsync( + () => db.StreamCreateConsumerGroupAsync("key", "group", null, true, 0L, UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamDeleteConsumerGroupAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamDeleteConsumerGroupAsync("key", "group", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamCreateConsumerAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamCreateConsumerAsync("key", "group", "consumer", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamDeleteConsumerAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamDeleteConsumerAsync("key", "group", "consumer", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamConsumerGroupSetPositionAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + { + _ = await Assert.ThrowsAsync( + () => db.StreamConsumerGroupSetPositionAsync("key", "group", "0-0", UnsupportedFlag)); + _ = await Assert.ThrowsAsync( + () => db.StreamConsumerGroupSetPositionAsync("key", "group", "0-0", 0L, UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamAcknowledgeAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + { + _ = await Assert.ThrowsAsync( + () => db.StreamAcknowledgeAsync("key", "group", "0-0", UnsupportedFlag)); + _ = await Assert.ThrowsAsync( + () => db.StreamAcknowledgeAsync("key", "group", [], UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamPendingAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamPendingAsync("key", "group", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamPendingMessagesAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamPendingMessagesAsync("key", "group", 10, "consumer", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamClaimAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamClaimAsync("key", "group", "consumer", 0, [], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamClaimIdsOnlyAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamClaimIdsOnlyAsync("key", "group", "consumer", 0, [], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamAutoClaimAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamAutoClaimAsync("key", "group", "consumer", 0, "0-0", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamAutoClaimIdsOnlyAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamAutoClaimIdsOnlyAsync("key", "group", "consumer", 0, "0-0", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamTrimAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + { + _ = await Assert.ThrowsAsync( + () => db.StreamTrimAsync("key", 100, false, UnsupportedFlag)); + _ = await Assert.ThrowsAsync( + () => db.StreamTrimAsync("key", 100L, false, null, StreamTrimMode.KeepReferences, UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamTrimByMinIdAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamTrimByMinIdAsync("key", "0-0", flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamInfoAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamInfoAsync("key", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamGroupInfoAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamGroupInfoAsync("key", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task StreamConsumerInfoAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.StreamConsumerInfoAsync("key", "group", UnsupportedFlag)); + #endregion #region Server Management Commands @@ -1092,5 +1289,199 @@ public async Task IServer_FlushAllDatabasesAsync_UnsupportedFlags_Throws(IServer => _ = await Assert.ThrowsAsync( () => server.FlushAllDatabasesAsync(UnsupportedFlag)); + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ExecuteAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ExecuteAsync("PING", [], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_InfoRawAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.InfoRawAsync(flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_InfoAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.InfoAsync(flags: UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_PingAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.PingAsync("hello", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_EchoAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.EchoAsync("hello", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ConfigRewriteAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ConfigRewriteAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_DatabaseSizeAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.DatabaseSizeAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ClientGetNameAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ClientGetNameAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ClientIdAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ClientIdAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ScriptExistsAsync_String_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ScriptExistsAsync("return 1", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ScriptExistsAsync_ByteArray_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ScriptExistsAsync([], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ScriptLoadAsync_String_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ScriptLoadAsync("return 1", UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ScriptLoadAsync_LuaScript_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ScriptLoadAsync(LuaScript.Prepare("return 1"), UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_ScriptFlushAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + () => server.ScriptFlushAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestServers), MemberType = typeof(TestConfiguration))] + public async Task IServer_KeysAsync_UnsupportedFlags_Throws(IServer server) + => _ = await Assert.ThrowsAsync( + async () => { await foreach (var _ in server.KeysAsync(flags: UnsupportedFlag)) { } }); + + #endregion + #region IDatabaseAsync Commands + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task ExecuteAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.ExecuteAsync("PING", null, UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task PingAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.PingAsync(UnsupportedFlag)); + + #endregion + #region Transaction Commands + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task WatchAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.WatchAsync([], UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task UnwatchAsync_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.UnwatchAsync(UnsupportedFlag)); + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestDatabases), MemberType = typeof(TestConfiguration))] + public async Task UnwatchAsync_WithRoute_ThrowsOnCommandFlags(IDatabaseAsync db) + => _ = await Assert.ThrowsAsync( + () => db.UnwatchAsync(Route.Random, UnsupportedFlag)); + + #endregion + #region Subscriber Commands + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestStandaloneConnections), MemberType = typeof(TestConfiguration))] + public async Task ISubscriber_PublishAsync_ThrowsOnCommandFlags(ConnectionMultiplexer connection) + { + var subscriber = connection.GetSubscriber(); + _ = await Assert.ThrowsAsync( + () => subscriber.PublishAsync( + ValkeyChannel.Literal("test-channel"), + "hello", + UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestStandaloneConnections), MemberType = typeof(TestConfiguration))] + public async Task ISubscriber_SubscribeAsync_WithHandler_ThrowsOnCommandFlags(ConnectionMultiplexer connection) + { + var subscriber = connection.GetSubscriber(); + _ = await Assert.ThrowsAsync( + () => subscriber.SubscribeAsync( + ValkeyChannel.Literal("test-channel"), + (_, _) => { }, + UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestStandaloneConnections), MemberType = typeof(TestConfiguration))] + public async Task ISubscriber_SubscribeAsync_Queue_ThrowsOnCommandFlags(ConnectionMultiplexer connection) + { + var subscriber = connection.GetSubscriber(); + _ = await Assert.ThrowsAsync( + () => subscriber.SubscribeAsync( + ValkeyChannel.Literal("test-channel"), + UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestStandaloneConnections), MemberType = typeof(TestConfiguration))] + public async Task ISubscriber_UnsubscribeAsync_ThrowsOnCommandFlags(ConnectionMultiplexer connection) + { + var subscriber = connection.GetSubscriber(); + _ = await Assert.ThrowsAsync( + () => subscriber.UnsubscribeAsync( + ValkeyChannel.Literal("test-channel"), + null, + UnsupportedFlag)); + } + + [Theory(DisableDiscoveryEnumeration = true)] + [MemberData(nameof(TestConfiguration.TestStandaloneConnections), MemberType = typeof(TestConfiguration))] + public async Task ISubscriber_UnsubscribeAllAsync_ThrowsOnCommandFlags(ConnectionMultiplexer connection) + { + var subscriber = connection.GetSubscriber(); + _ = await Assert.ThrowsAsync( + () => subscriber.UnsubscribeAllAsync(UnsupportedFlag)); + } + + [Fact] + public async Task ChannelMessageQueue_UnsubscribeAsync_ThrowsOnCommandFlags() + { + var subscriber = TestConfiguration.DefaultCompatibleConnection().GetSubscriber(); + var queue = await subscriber.SubscribeAsync(ValkeyChannel.Literal(Guid.NewGuid().ToString())); + _ = await Assert.ThrowsAsync( + () => queue.UnsubscribeAsync(UnsupportedFlag)); + } + #endregion }