Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
test(re): make RE integration expectations version/cluster robust
- TimeSeries rules: hash-tag src/dest key pairs so multi-key TS.CREATERULE/
  DELETERULE co-locate on one slot, avoiding CROSSSLOT before the intended
  key-existence error on a clustered Redis Enterprise DB.
- Search DropIndex: accept both module wordings ("no such index" and
  "index not found") instead of gating on an unreliable server version.
- JSON DEBUG MEMORY: assert a positive size rather than a magic >20 byte
  threshold that newer modules no longer satisfy.
- Search SpellCheck: use index-scoped size assertion (AssertIndexSize) to
  match the async sibling and avoid a whole-DB DBSIZE race on the shared
  cluster connection.
  • Loading branch information
kiryazovi-redis committed Jul 1, 2026
commit 312a120bbeb4ef245c9a489e7d52051216b0217d
6 changes: 4 additions & 2 deletions tests/NRedisStack.Tests/Json/JsonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,8 @@ public void Memory(string endpointId)

commands.Set(key, "$", new { a = "hello", b = new { a = "world" } });
var res = commands.DebugMemory(key);
Assert.True(res > 20);
// Newer JSON modules report a smaller size; only assert a real positive size.
Assert.True(res > 0);
res = commands.DebugMemory("non-existent key");
Assert.Equal(0, res);
}
Expand All @@ -1088,7 +1089,8 @@ public async Task MemoryAsync(string endpointId)

await commands.SetAsync(key, "$", new { a = "hello", b = new { a = "world" } });
var res = await commands.DebugMemoryAsync(key);
Assert.True(res > 20);
// Newer JSON modules report a smaller size; only assert a real positive size.
Assert.True(res > 0);
res = await commands.DebugMemoryAsync("non-existent key");
Assert.Equal(0, res);
}
Expand Down
16 changes: 11 additions & 5 deletions tests/NRedisStack.Tests/Search/SearchTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1669,8 +1669,11 @@ public void TestDropIndex(string endpointId)

Assert.NotNull(ex);
Assert.IsType<RedisServerException>(ex);
var fault = EndpointsFixture.IsAtLeast(ServerVersion.Redis_8_8) ? "index not found" : "no such index";
Assert.Contains(fault, ex.Message, StringComparison.OrdinalIgnoreCase);
// Accept both module wordings: older "no such index", newer "index not found".
Assert.True(
ex.Message.Contains("no such index", StringComparison.OrdinalIgnoreCase)
|| ex.Message.Contains("index not found", StringComparison.OrdinalIgnoreCase),
ex.Message);
}

private int DatabaseSize(IDatabase db) => DatabaseSize(db, out _);
Expand Down Expand Up @@ -1734,8 +1737,11 @@ public async Task TestDropIndexAsync(string endpointId)

Assert.NotNull(ex);
Assert.IsType<RedisServerException>(ex);
var fault = EndpointsFixture.IsAtLeast(ServerVersion.Redis_8_8) ? "index not found" : "no such index";
Assert.Contains(fault, ex.Message, StringComparison.OrdinalIgnoreCase);
// Accept both module wordings: older "no such index", newer "index not found".
Assert.True(
ex.Message.Contains("no such index", StringComparison.OrdinalIgnoreCase)
|| ex.Message.Contains("index not found", StringComparison.OrdinalIgnoreCase),
ex.Message);
}

[Theory]
Expand Down Expand Up @@ -2850,7 +2856,7 @@ public void TestBasicSpellCheck(string endpointId)
db.HashSet("doc1", [new("name", "name2"), new("body", "body2")]);
db.HashSet("doc1", [new("name", "name2"), new("body", "name2")]);

AssertDatabaseSize(db, 1);
AssertIndexSize(ft, index, 1);
var reply = ft.SpellCheck(index, "name");
Assert.Single(reply.Keys);
Assert.Equal("name", reply.Keys.First());
Expand Down
56 changes: 29 additions & 27 deletions tests/NRedisStack.Tests/TimeSeries/TestAPI/TestRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,24 @@ namespace NRedisStack.Tests.TimeSeries.TestAPI;

public class TestRules(EndpointsFixture endpointsFixture) : AbstractNRedisStackTest(endpointsFixture), IDisposable
{
private readonly string srcKey = "RULES_TEST_SRC";
// Hash-tag ({rules}) so src/dest co-locate on one slot; otherwise a clustered
// Redis Enterprise DB returns CROSSSLOT before the intended key-existence error.
private readonly string srcKey = "{rules}RULES_TEST_SRC";

private readonly Dictionary<TsAggregation, string> destKeys = new()
{
{ TsAggregation.Avg, "RULES_DEST_" + TsAggregation.Avg },
{ TsAggregation.Count, "RULES_DEST_" + TsAggregation.Count },
{ TsAggregation.First, "RULES_DEST_" + TsAggregation.First },
{ TsAggregation.Last, "RULES_DEST_" + TsAggregation.Last },
{ TsAggregation.Max, "RULES_DEST_" + TsAggregation.Max },
{ TsAggregation.Min, "RULES_DEST_" + TsAggregation.Min },
{ TsAggregation.Range, "RULES_DEST_" + TsAggregation.Range },
{ TsAggregation.StdP, "RULES_DEST_" + TsAggregation.StdP },
{ TsAggregation.StdS, "RULES_DEST_" + TsAggregation.StdS },
{ TsAggregation.Sum, "RULES_DEST_" + TsAggregation.Sum },
{ TsAggregation.VarP, "RULES_DEST_" + TsAggregation.VarP },
{ TsAggregation.VarS, "RULES_DEST_" + TsAggregation.VarS }
{ TsAggregation.Avg, "{rules}RULES_DEST_" + TsAggregation.Avg },
{ TsAggregation.Count, "{rules}RULES_DEST_" + TsAggregation.Count },
{ TsAggregation.First, "{rules}RULES_DEST_" + TsAggregation.First },
{ TsAggregation.Last, "{rules}RULES_DEST_" + TsAggregation.Last },
{ TsAggregation.Max, "{rules}RULES_DEST_" + TsAggregation.Max },
{ TsAggregation.Min, "{rules}RULES_DEST_" + TsAggregation.Min },
{ TsAggregation.Range, "{rules}RULES_DEST_" + TsAggregation.Range },
{ TsAggregation.StdP, "{rules}RULES_DEST_" + TsAggregation.StdP },
{ TsAggregation.StdS, "{rules}RULES_DEST_" + TsAggregation.StdS },
{ TsAggregation.Sum, "{rules}RULES_DEST_" + TsAggregation.Sum },
{ TsAggregation.VarP, "{rules}RULES_DEST_" + TsAggregation.VarP },
{ TsAggregation.VarS, "{rules}RULES_DEST_" + TsAggregation.VarS }
};

[SkipIfRedisTheory(Is.Enterprise)]
Expand Down Expand Up @@ -66,7 +68,7 @@ public void TestNonExistingSrc()
{
IDatabase db = GetCleanDatabase();
var ts = db.TS();
string destKey = "RULES_DEST_" + TsAggregation.Avg;
string destKey = "{rules}RULES_DEST_" + TsAggregation.Avg;
ts.Create(destKey);
TimeSeriesRule rule = new(destKey, 50, TsAggregation.Avg);
var ex = Assert.Throws<RedisServerException>(() => ts.CreateRule(srcKey, rule));
Expand All @@ -80,7 +82,7 @@ public void TestNonExisitingDestinaion()
{
IDatabase db = GetCleanDatabase();
var ts = db.TS();
string destKey = "RULES_DEST_" + TsAggregation.Avg;
string destKey = "{rules}RULES_DEST_" + TsAggregation.Avg;
ts.Create(srcKey);
TimeSeriesRule rule = new(destKey, 50, TsAggregation.Avg);
var ex = Assert.Throws<RedisServerException>(() => ts.CreateRule(srcKey, rule));
Expand All @@ -95,21 +97,21 @@ public void TestAlignTimestamp(string endpointId)
{
IDatabase db = GetCleanDatabase(endpointId);
var ts = db.TS();
ts.Create("ts1");
ts.Create("ts2");
ts.Create("ts3");
ts.Create("{align}ts1");
ts.Create("{align}ts2");
ts.Create("{align}ts3");

TimeSeriesRule rule1 = new("ts2", 10, TsAggregation.Count);
ts.CreateRule("ts1", rule1, 0);
TimeSeriesRule rule1 = new("{align}ts2", 10, TsAggregation.Count);
ts.CreateRule("{align}ts1", rule1, 0);

TimeSeriesRule rule2 = new("ts3", 10, TsAggregation.Count);
ts.CreateRule("ts1", rule2, 1);
TimeSeriesRule rule2 = new("{align}ts3", 10, TsAggregation.Count);
ts.CreateRule("{align}ts1", rule2, 1);

ts.Add("ts1", 1, 1);
ts.Add("ts1", 10, 3);
ts.Add("ts1", 21, 7);
ts.Add("{align}ts1", 1, 1);
ts.Add("{align}ts1", 10, 3);
ts.Add("{align}ts1", 21, 7);

Assert.Equal(2, ts.Range("ts2", "-", "+", aggregation: TsAggregation.Count, timeBucket: 10).Count);
Assert.Single(ts.Range("ts3", "-", "+", aggregation: TsAggregation.Count, timeBucket: 10));
Assert.Equal(2, ts.Range("{align}ts2", "-", "+", aggregation: TsAggregation.Count, timeBucket: 10).Count);
Assert.Single(ts.Range("{align}ts3", "-", "+", aggregation: TsAggregation.Count, timeBucket: 10));
}
}