diff --git a/src/NRedisStack.Core/Bloom/BloomCommands.cs b/src/NRedisStack.Core/Bloom/BloomCommands.cs index 513cc0c6..94168ca5 100644 --- a/src/NRedisStack.Core/Bloom/BloomCommands.cs +++ b/src/NRedisStack.Core/Bloom/BloomCommands.cs @@ -1,3 +1,4 @@ +using NRedisStack.Core.Bloom.DataTypes; using NRedisStack.Core.Literals; using StackExchange.Redis; namespace NRedisStack.Core @@ -11,24 +12,62 @@ public BloomCommands(IDatabase db) _db = db; } - public RedisResult Add(RedisKey key, string item) + /// + /// Adds an item to a Bloom Filter. + /// + /// The key under which the filter is found. + /// The item to add. + /// if the item did not exist in the filter, otherwise. + /// + public bool Add(RedisKey key, RedisValue item) { - return _db.Execute(BF.ADD, key, item); + return _db.Execute(BF.ADD, key, item).ToString() == "1"; } - public bool Exists(RedisKey key, string item) + /// + /// Checks whether an item exist in the Bloom Filter or not. + /// + /// The name of the filter. + /// The item to check for. + /// means the item may exist in the filter, + /// and means the item may exist in the filter. + /// + public bool Exists(RedisKey key, RedisValue item) { return _db.Execute(BF.EXISTS, key, item).ToString() == "1"; } - public RedisResult Info(RedisKey key) + /// + /// Return information about a bloom filter. + /// + /// Name of the key to return information about. + /// Array with information of the filter. + /// + public BloomInformation? Info(RedisKey key) { - return _db.Execute(BF.INFO, key); + var info = _db.Execute(BF.INFO, key); + return ResponseParser.ToBloomInfo(info); } - public RedisResult Insert(RedisKey key, RedisValue[] items, int? capacity = null, + /// + /// Adds one or more items to a Bloom Filter. A filter will be created if it does not exist. + /// + /// The name of the filter. + /// One or more items to add. + /// (Optional) Specifies the desired capacity for the filter to be created. + /// (Optional) Specifies the error ratio of the newly created filter if it does not yet exist. + /// (Optional) When capacity is reached, an additional sub-filter is + /// created in size of the last sub-filter multiplied by expansion. + /// (Optional) to indicates that the + /// filter should not be created if it does not already exist. + /// (Optional) toprevent the filter + /// from creating additional sub-filters if initial capacity is reached. + /// An array of booleans. Each element is either true or false depending on whether the + /// corresponding input element was newly added to the filter or may have previously existed. + /// + public bool[] Insert(RedisKey key, RedisValue[] items, int? capacity = null, double? error = null, int? expansion = null, - bool nocreate = false, bool nonscaling = false) //NOT DONE + bool nocreate = false, bool nonscaling = false) { if (items == null) throw new ArgumentNullException(nameof(items)); @@ -54,10 +93,15 @@ public RedisResult Insert(RedisKey key, RedisValue[] items, int? capacity = null } if (nocreate) + { args.Add(BloomArgs.NOCREATE); + } + if (nonscaling) + { args.Add(BloomArgs.NONSCALING); + } args.Add(BloomArgs.ITEMS); foreach (var item in items) @@ -65,18 +109,109 @@ public RedisResult Insert(RedisKey key, RedisValue[] items, int? capacity = null args.Add(item); } - return _db.Execute(BF.INSERT, args); + return ResponseParser.ToBooleanArray(_db.Execute(BF.INSERT, args)); } - public RedisResult ScanDump(RedisKey key, int iterator) + /// + /// Restores a filter previosly saved using SCANDUMP. + /// + /// Name of the key to restore. + /// Iterator value associated with data (returned by SCANDUMP). + /// Current data chunk (returned by SCANDUMP). + /// Array with information of the filter. + /// + public bool LoadChunk(RedisKey key, long iterator, Byte[] data) { - return _db.Execute(BF.SCANDUMP, key, iterator); + return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.LOADCHUNK, key, iterator, data)); } - public RedisResult LoadChunk(RedisKey key, int iterator, RedisValue data) + /// + /// Adds one or more items to the Bloom Filter. A filter will be created if it does not exist yet. + /// + /// The name of the filter. + /// One or more items to add. + /// An array of booleans. Each element is either true or false depending on whether the + /// corresponding input element was newly added to the filter or may have previously existed. + /// + public bool[] MAdd(RedisKey key, RedisValue[] items) { - return _db.Execute(BF.LOADCHUNK, key, iterator, data); + if (items == null) + throw new ArgumentNullException(nameof(items)); + + List args = new List { key }; + + foreach (var item in items) + { + args.Add(item); + } + + return ResponseParser.ToBooleanArray(_db.Execute(BF.MADD, args)); } + /// + /// Checks whether one or more items may exist in the filter or not. + /// + /// The name of the filter. + /// One or more items to check. + /// An array of booleans, for each item means the item may exist in the filter, + /// and means the item may exist in the filter. + /// + public bool[] MExists(RedisKey key, RedisValue[] items) + { + if (items == null) + throw new ArgumentNullException(nameof(items)); + + List args = new List { key }; + + foreach (var item in items) + { + args.Add(item); + } + + return ResponseParser.ToBooleanArray(_db.Execute(BF.MEXISTS, args)); + + } + + /// + /// Creates a new Bloom Filter. + /// + /// The key under which the filter is found. + /// The desired probability for false positives (value between 0 to 1). + /// The number of entries intended to be added to the filter. + /// (Optional) When capacity is reached, an additional sub-filter is + /// created in size of the last sub-filter multiplied by expansion. + /// (Optional) toprevent the filter + /// from creating additional sub-filters if initial capacity is reached. + /// if executed correctly, otherwise. + /// + public bool Reserve(RedisKey key, double errorRate, long capacity, + int? expansion = null, bool nonscaling = false) + { + List args = new List { key, errorRate, capacity }; + + if (expansion != null) + { + args.Add(expansion); + } + + if (nonscaling) + { + args.Add(BloomArgs.NONSCALING); + } + + return ResponseParser.ParseOKtoBoolean(_db.Execute(BF.RESERVE, args)); + } + + /// + /// Restores a filter previosly saved using SCANDUMP. + /// + /// Name of the filter. + /// Iterator value; either 0 or the iterator from a previous invocation of this command. + /// Tuple of iterator and data. + /// + public Tuple? ScanDump(RedisKey key, long iterator) + { + return ResponseParser.ToScanDumpTuple(_db.Execute(BF.SCANDUMP, key, iterator)); + } } } diff --git a/src/NRedisStack.Core/Bloom/DataTypes/BloomInformation.cs b/src/NRedisStack.Core/Bloom/DataTypes/BloomInformation.cs new file mode 100644 index 00000000..a54a0643 --- /dev/null +++ b/src/NRedisStack.Core/Bloom/DataTypes/BloomInformation.cs @@ -0,0 +1,24 @@ +namespace NRedisStack.Core.Bloom.DataTypes +{ + /// + /// This class represents the response for BF.INFO command. + /// This object has Read-only properties and cannot be generated outside a BF.INFO response. + /// + public class BloomInformation + { + public long Capacity { get; private set; } + public long Size { get; private set; } + public long NumberOfFilters { get; private set; } + public long NumberOfItemsInserted { get; private set; } + public long ExpansionRate { get; private set; } + + internal BloomInformation(long capacity, long size, long numberOfFilters, long numberOfItemsInserted, long expansionRate) + { + Capacity = capacity; + Size = size; + NumberOfFilters = numberOfFilters; + NumberOfItemsInserted = numberOfItemsInserted; + ExpansionRate = expansionRate; + } + } +} \ No newline at end of file diff --git a/src/NRedisStack.Core/Json/JsonCommands.cs b/src/NRedisStack.Core/Json/JsonCommands.cs index df054510..63ac9ab8 100644 --- a/src/NRedisStack.Core/Json/JsonCommands.cs +++ b/src/NRedisStack.Core/Json/JsonCommands.cs @@ -35,11 +35,15 @@ public RedisResult Set(RedisKey key, RedisValue path, RedisValue json, When when } } - public RedisResult Get(RedisKey key, RedisValue? indent = null, - RedisValue? newLine = null, RedisValue? space = null, RedisValue? path = null) + public RedisResult Get(RedisKey key, + RedisValue? indent = null, + RedisValue? newLine = null, + RedisValue? space = null, + RedisValue? path = null) { - List args = new List(); - args.Add(key); + + List args = new List(){key}; + if (indent != null) { args.Add(JsonArgs.INDENT); diff --git a/src/NRedisStack.Core/TimeSeries/TimeSeriesClientResponseParser.cs b/src/NRedisStack.Core/ResponseParser.cs similarity index 53% rename from src/NRedisStack.Core/TimeSeries/TimeSeriesClientResponseParser.cs rename to src/NRedisStack.Core/ResponseParser.cs index b885d42b..346b6c05 100644 --- a/src/NRedisStack.Core/TimeSeries/TimeSeriesClientResponseParser.cs +++ b/src/NRedisStack.Core/ResponseParser.cs @@ -4,54 +4,101 @@ using NRedisStack.Core.DataTypes; using NRedisStack.Core.Extensions; using StackExchange.Redis; +using NRedisStack.Core.Bloom.DataTypes; namespace NRedisStack.Core { public static class ResponseParser { - public static bool ParseBoolean(RedisResult result) + + //TODO: See if I can change the code to remove the warnings + public static bool ParseOKtoBoolean(RedisResult result) + { + return result.ToString() == "OK"; + } + + public static bool[] ToBooleanArray(RedisResult result) + { + RedisResult[] redisResults = (RedisResult[])result; + bool[] boolArr = new bool[redisResults.Length]; + for (int i = 0; i < redisResults.Length; i++) + { + boolArr[i] = redisResults[i].ToString() == "1"; + } + + return boolArr; + } + + public static RedisResult[] ToArray(RedisResult result) { - return (string)result == "OK"; + return (RedisResult[])result; } - public static long ParseLong(RedisResult result) + public static long ToLong(RedisResult result) { if (result.Type == ResultType.None) return 0; return (long)result; } - public static TimeStamp ParseTimeStamp(RedisResult result) + public static TimeStamp ToTimeStamp(RedisResult result) { if (result.Type == ResultType.None) return null; return new TimeStamp((long)result); } - public static IReadOnlyList ParseTimeStampArray(RedisResult result) + public static IReadOnlyList ToTimeStampArray(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; var list = new List(redisResults.Length); if (redisResults.Length == 0) return list; - Array.ForEach(redisResults, timestamp => list.Add(ParseTimeStamp(timestamp))); + Array.ForEach(redisResults, timestamp => list.Add(ToTimeStamp(timestamp))); return list; } - public static TimeSeriesTuple ParseTimeSeriesTuple(RedisResult result) + public static TimeSeriesTuple? ToTimeSeriesTuple(RedisResult result) { - RedisResult[] redisResults = (RedisResult[])result; + RedisResult[]? redisResults = (RedisResult[]?)result; + if (redisResults.Length == 0) return null; + return new TimeSeriesTuple(ToTimeStamp(redisResults[0]), (double)redisResults[1]); + } + + public static Tuple? ToScanDumpTuple(RedisResult result) + { + RedisResult[]? redisResults = (RedisResult[]?)result; + if (redisResults == null || redisResults.Length == 0) return null; + return new Tuple((long)redisResults[0], (Byte[])redisResults[1]); + } + + public static HashEntry? ToHashEntry(RedisResult result) + { + RedisValue[]? redisResults = (RedisValue[]?)result; if (redisResults.Length == 0) return null; - return new TimeSeriesTuple(ParseTimeStamp(redisResults[0]), (double)redisResults[1]); + return new HashEntry(redisResults[0], redisResults[1]); + } - public static IReadOnlyList ParseTimeSeriesTupleArray(RedisResult result) + public static HashEntry[]? ToHashEntryArray(RedisResult result) + { + RedisValue[]? redisResults = (RedisValue[]?)result; + + var hash = new HashEntry[redisResults.Length / 2]; + if (redisResults.Length == 0) return hash; + + for (int i = 0; i < redisResults.Length - 1; i += 2) + hash[i / 2] = new HashEntry(redisResults[i], redisResults[i + 1]); + return hash; + } + + public static IReadOnlyList ToTimeSeriesTupleArray(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; var list = new List(redisResults.Length); if (redisResults.Length == 0) return list; - Array.ForEach(redisResults, tuple => list.Add(ParseTimeSeriesTuple(tuple))); + Array.ForEach(redisResults, tuple => list.Add(ToTimeSeriesTuple(tuple))); return list; } - public static IReadOnlyList ParseLabelArray(RedisResult result) + public static IReadOnlyList ToLabelArray(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; var list = new List(redisResults.Length); @@ -73,8 +120,8 @@ public static IReadOnlyList ParseLabelArray(RedisResult result) { RedisResult[] MRangeTuple = (RedisResult[])MRangeValue; string key = (string)MRangeTuple[0]; - IReadOnlyList labels = ParseLabelArray(MRangeTuple[1]); - TimeSeriesTuple value = ParseTimeSeriesTuple(MRangeTuple[2]); + IReadOnlyList labels = ToLabelArray(MRangeTuple[1]); + TimeSeriesTuple value = ToTimeSeriesTuple(MRangeTuple[2]); list.Add((key, labels, value)); }); return list; @@ -89,14 +136,14 @@ public static IReadOnlyList ParseLabelArray(RedisResult result) { RedisResult[] MRangeTuple = (RedisResult[])MRangeValue; string key = (string)MRangeTuple[0]; - IReadOnlyList labels = ParseLabelArray(MRangeTuple[1]); - IReadOnlyList values = ParseTimeSeriesTupleArray(MRangeTuple[2]); + IReadOnlyList labels = ToLabelArray(MRangeTuple[1]); + IReadOnlyList values = ToTimeSeriesTupleArray(MRangeTuple[2]); list.Add((key, labels, values)); }); return list; } - public static TimeSeriesRule ParseRule(RedisResult result) + public static TimeSeriesRule ToRule(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; string destKey = (string)redisResults[0]; @@ -105,37 +152,74 @@ public static TimeSeriesRule ParseRule(RedisResult result) return new TimeSeriesRule(destKey, bucketTime, aggregation); } - public static IReadOnlyList ParseRuleArray(RedisResult result) + public static IReadOnlyList ToRuleArray(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; var list = new List(); if (redisResults.Length == 0) return list; - Array.ForEach(redisResults, rule => list.Add(ParseRule(rule))); + Array.ForEach(redisResults, rule => list.Add(ToRule(rule))); return list; } - public static TsDuplicatePolicy? ParsePolicy(RedisResult result) + public static TsDuplicatePolicy? ToPolicy(RedisResult result) { - var policyStatus = (string) result; - if (String.IsNullOrEmpty(policyStatus) || policyStatus == "(nil)") { + var policyStatus = (string)result; + if (String.IsNullOrEmpty(policyStatus) || policyStatus == "(nil)") + { return null; } return DuplicatePolicyExtensions.AsPolicy(policyStatus.ToUpper()); } - public static TimeSeriesInformation ParseInfo(RedisResult result) + public static BloomInformation? ToBloomInfo(RedisResult result) //TODO: Think about a different implementation, because if the output of BF.INFO changes or even just the names of the labels then the parsing will not work + { + long capacity, size, numberOfFilters, numberOfItemsInserted, expansionRate; + capacity = size = numberOfFilters = numberOfItemsInserted = expansionRate = -1; + RedisResult[]? redisResults = (RedisResult[]?)result; + + if (redisResults == null) return null; + + for (int i = 0; i < redisResults.Length; ++i) + { + string? label = redisResults[i++].ToString(); + switch (label) + { + case "Capacity": + capacity = (long)redisResults[i]; + break; + case "Size": + size = (long)redisResults[i]; + break; + case "Number of filters": + numberOfFilters = (long)redisResults[i]; + break; + case "Number of items inserted": + numberOfItemsInserted = (long)redisResults[i]; + break; + case "Expansion rate": + expansionRate = (long)redisResults[i]; + break; + } + } + + return new BloomInformation(capacity, size, numberOfFilters, numberOfItemsInserted, expansionRate); + } + + public static TimeSeriesInformation ToTimeSeriesInfo(RedisResult result) { - long totalSamples = -1, memoryUsage = -1, retentionTime = -1, chunkSize=-1, chunkCount = -1; + long totalSamples = -1, memoryUsage = -1, retentionTime = -1, chunkSize = -1, chunkCount = -1; TimeStamp firstTimestamp = null, lastTimestamp = null; IReadOnlyList labels = null; - IReadOnlyList rules = null; + IReadOnlyList rules = null; string sourceKey = null; TsDuplicatePolicy? duplicatePolicy = null; RedisResult[] redisResults = (RedisResult[])result; - for(int i=0; i v1.4 - duplicatePolicy = ParsePolicy(redisResults[i]); + duplicatePolicy = ToPolicy(redisResults[i]); break; } } @@ -182,7 +266,7 @@ public static TimeSeriesInformation ParseInfo(RedisResult result) lastTimestamp, retentionTime, chunkCount, chunkSize, labels, sourceKey, rules, duplicatePolicy); } - public static IReadOnlyList ParseStringArray(RedisResult result) + public static IReadOnlyList ToStringArray(RedisResult result) { RedisResult[] redisResults = (RedisResult[])result; var list = new List(); @@ -191,4 +275,4 @@ public static IReadOnlyList ParseStringArray(RedisResult result) return list; } } -} +} \ No newline at end of file diff --git a/src/NRedisStack.Core/TimeSeries/TimeSeriesCommands.cs b/src/NRedisStack.Core/TimeSeries/TimeSeriesCommands.cs index 0064ba1c..19a1ecec 100644 --- a/src/NRedisStack.Core/TimeSeries/TimeSeriesCommands.cs +++ b/src/NRedisStack.Core/TimeSeries/TimeSeriesCommands.cs @@ -17,18 +17,18 @@ public TimeSeriesCommands(IDatabase db) public bool Create(string key, long? retentionTime = null, IReadOnlyCollection labels = null, bool? uncompressed = null, long? chunkSizeBytes = null, TsDuplicatePolicy? duplicatePolicy = null) { var args = TimeSeriesAux.BuildTsCreateArgs(key, retentionTime, labels, uncompressed, chunkSizeBytes, duplicatePolicy); - return ResponseParser.ParseBoolean(_db.Execute(TS.CREATE, args)); + return ResponseParser.ParseOKtoBoolean(_db.Execute(TS.CREATE, args)); } public TimeSeriesInformation Info(string key) { - return ResponseParser.ParseInfo(_db.Execute(TS.INFO, key)); + return ResponseParser.ToTimeSeriesInfo(_db.Execute(TS.INFO, key)); } public bool TimeSeriesAlter(string key, long? retentionTime = null, IReadOnlyCollection labels = null) { var args = TimeSeriesAux.BuildTsAlterArgs(key, retentionTime, labels); - return ResponseParser.ParseBoolean(_db.Execute(TS.ALTER, args)); + return ResponseParser.ParseOKtoBoolean(_db.Execute(TS.ALTER, args)); } } diff --git a/tests/NRedisStack.Tests/Bloom/BloomTests.cs b/tests/NRedisStack.Tests/Bloom/BloomTests.cs index 30664f47..e34ec997 100644 --- a/tests/NRedisStack.Tests/Bloom/BloomTests.cs +++ b/tests/NRedisStack.Tests/Bloom/BloomTests.cs @@ -3,7 +3,6 @@ using NRedisStack.Core.RedisStackCommands; using Moq; - namespace NRedisStack.Tests.Bloom; public class BloomTests : AbstractNRedisStackTest, IDisposable @@ -18,16 +17,28 @@ public void Dispose() } [Fact] - public void TestBfAddWhenExist() + public void TestReserveBasic() { IDatabase db = redisFixture.Redis.GetDatabase(); - Assert.True((db.BF().Add(key, "item1")).ToString() == "1"); // first time - Assert.True(db.BF().Add(key, "item1").ToString() == "0"); // second time + db.BF().Reserve(key, 0.001, 100L); + + Assert.True((db.BF().Add(key, "item1"))); + Assert.True(db.BF().Exists(key, "item1")); + Assert.False(db.BF().Exists(key, "item2")); } [Fact] - public void TestBfAddExists() + public void TestAddWhenExist() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + + Assert.True((db.BF().Add(key, "item1"))); // first time + Assert.False(db.BF().Add(key, "item1")); // second time + } + + [Fact] + public void TestAddExists() { IDatabase db = redisFixture.Redis.GetDatabase(); @@ -36,10 +47,50 @@ public void TestBfAddExists() } [Fact] - public void TestBfInsert() + public void TestAddExistsMulti() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + var items = new RedisValue[]{"foo", "bar", "baz"}; + var items2 = new RedisValue[]{"newElement", "bar", "baz"}; + + var result = db.BF().MAdd(key, items); + Assert.Equal(new bool[] {true, true, true}, result); + + result = db.BF().MAdd(key, items2); + Assert.Equal(new bool[] {true, false, false}, result); + } + + [Fact] + public void TestExample() { + IDatabase db = redisFixture.Redis.GetDatabase(); + + // Simple bloom filter using default module settings + db.BF().Add("simpleBloom", "Mark"); + // Does "Mark" now exist? + db.BF().Exists("simpleBloom", "Mark"); // true + db.BF().Exists("simpleBloom", "Farnsworth"); // False + + // If you have a long list of items to check/add, you can use the + // "multi" methods + var items = new RedisValue[]{"foo", "bar", "baz", "bat", "bag"}; + db.BF().MAdd("simpleBloom", items); + + // Check if they exist: + var allItems = new RedisValue[]{"foo", "bar", "baz", "bat", "Mark", "nonexist"}; + var rv = db.BF().MExists("simpleBloom", allItems); + // All items except the last one will be 'true' + Assert.Equal(new bool[] {true, true, true, true, true, false}, rv); + + // Reserve a "customized" bloom filter + db.BF().Reserve("specialBloom", 0.0001, 10000); + db.BF().Add("specialBloom", "foo"); + } + + [Fact] + public void TestInsert() { IDatabase db = redisFixture.Redis.GetDatabase(); - RedisValue[] items = new RedisValue[] { "item1" , "item2", "item3"}; + RedisValue[] items = new RedisValue[] { "item1", "item2", "item3" }; db.BF().Insert("key", items); @@ -47,4 +98,50 @@ public void TestBfInsert() Assert.True(db.BF().Exists("key", "item2")); Assert.True(db.BF().Exists("key", "item3")); } + + [Fact] + public void TestExistsNonExist() + { + IDatabase db = redisFixture.Redis.GetDatabase(); + + RedisValue item = new RedisValue("item"); + Assert.False(db.BF().Exists("NonExistKey", item)); + } + + [Fact] + public void TestInfo() //TODO: think again about the returned value of BF.INFO, maybe creating a new returned type + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.BF().Add(key, "item"); + var info = db.BF().Info(key); + + Assert.NotNull(info); + Assert.Equal(info.NumberOfItemsInserted, (long)1); + + Assert.Throws( () => db.BF().Info("notExistKey")); + } + + [Fact] + public void TestScanDumpAndLoadChunk() //TODO: Fininsh this Test + { + IDatabase db = redisFixture.Redis.GetDatabase(); + db.Execute("FLUSHALL"); + + db.BF().Reserve("bloom-dump",0.1, 10); + db.BF().Add("bloom-dump", "a"); + + long iterator = 0; + while(true) + { + var chunkData = db.BF().ScanDump("bloom-dump", iterator); + iterator = chunkData.Item1; + if(iterator == 0) break; + Assert.True(db.BF().LoadChunk("bloom-load", iterator, chunkData.Item2)); + } + + // check for properties + Assert.Equal(db.BF().Info("bloom-dump").NumberOfItemsInserted, db.BF().Info("bloom-load").NumberOfItemsInserted); + // check for existing items + Assert.True(db.BF().Exists("bloom-load", "a")); + } } \ No newline at end of file diff --git a/tests/NRedisStack.Tests/Json/JsonTests.cs b/tests/NRedisStack.Tests/Json/JsonTests.cs index a78ae22c..53b4af20 100644 --- a/tests/NRedisStack.Tests/Json/JsonTests.cs +++ b/tests/NRedisStack.Tests/Json/JsonTests.cs @@ -17,13 +17,13 @@ public void Dispose() redisFixture.Redis.GetDatabase().KeyDelete(key); } - [Fact] - public void TestJsonSet() - { - var obj = new Person { Name = "Shachar", Age = 23 }; - _mock.Object.JSON().Set("Person:Shachar", "$", obj, When.Exists); - _mock.Verify(x => x.Execute("JSON.SET", "Person:Shachar", "$", "{\"Name\":\"Shachar\",\"Age\":23}", "XX")); - } + // [Fact] + // public void TestJsonSet() + // { + // var obj = new Person { Name = "Shachar", Age = 23 }; + // _mock.Object.JSON().Set("Person:Shachar", "$", obj, When.Exists); + // _mock.Verify(x => x.Execute("JSON.SET", "Person:Shachar", "$", "{\"Name\":\"Shachar\",\"Age\":23}", "XX")); + // } [Fact] public void TestJsonSetNotExist() @@ -33,6 +33,8 @@ public void TestJsonSetNotExist() _mock.Verify(x => x.Execute("JSON.SET", "Person:Shachar", "$", "{\"Name\":\"Shachar\",\"Age\":23}", "NX")); } + //TODO: understand why this 2 tests are not pass what we do + //"dotnet test" but they pass when we do "dotnet test --filter ..." [Fact] public void TestSimpleJsonGet() { @@ -41,7 +43,11 @@ public void TestSimpleJsonGet() db.JSON().Set(key, "$", obj); string expected = "{\"Name\":\"Shachar\",\"Age\":23}"; - Assert.Equal(db.JSON().Get(key).ToString(), expected); + var result = db.JSON().Get(key).ToString(); + if(result == null) + throw new ArgumentNullException(nameof(result)); + + Assert.Equal(result, expected); } [Fact] @@ -52,7 +58,10 @@ public void TestJsonGet() db.JSON().Set(key, "$", obj); - string expected = "[222111\"Shachar\"222]"; - Assert.Equal(db.JSON().Get(key, "111", "222", "333", "$.Name").ToString(), expected); + var expected = "[222111\"Shachar\"222]"; + var result = db.JSON().Get(key, "111", "222", "333", "$.Name"); + // if(result == null) + // throw new ArgumentNullException(nameof(result)); + Assert.Equal(result.ToString(), expected); } } \ No newline at end of file