Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions tests/StackExchange.Redis.Tests/BacklogTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,12 @@ public async Task TotalOutstandingIncludesBacklogQueue()
Log("Test: Checking reconnected");
Assert.True(conn.IsConnected);

// lastPing completing proves the backlog drained, not that every connection is idle: the reconnect's own
// handshake traffic (and the subscription connection's) can still be awaiting replies at this instant,
// and TotalOutstanding counts those too (seen on CI as 7 and 1); so wait for quiescence rather than assert it
Log("Test: awaiting quiescence");
await UntilConditionAsync(TimeSpan.FromSeconds(5), () => conn.GetCounters().TotalOutstanding == 0).ForAwait();

Log("Test: asserting reconnected counters");
var reconnectedServerCounters = server.GetCounters();
var reconnectedConnCounters = conn.GetCounters();
Expand Down
41 changes: 23 additions & 18 deletions tests/StackExchange.Redis.Tests/HashFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ namespace StackExchange.Redis.Tests;
[RunPerProtocol]
public class HashFieldTests(ITestOutputHelper output, SharedConnectionFixture fixture) : TestBase(output, fixture)
{
// absolute expiries (the DateTime overloads) are computed against the client clock and read back against the
// server's; on the Windows CI runner the server lives in WSL, whose clock can sit a few ms off the host's, and
// the TTL then lands just above the nominal 2h (seen: 7200001ms). Relative (TimeSpan) expiries use one clock only
private const double ClockSkewToleranceMs = 1000;

private readonly DateTime nextCentury = new DateTime(2101, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private readonly TimeSpan oneYearInMs = TimeSpan.FromMilliseconds(31536000000);

Expand Down Expand Up @@ -319,7 +324,7 @@ public void HashFieldGetAndSetExpiry()
fieldResult = db.HashFieldGetAndSetExpiry(hashKey, "f1", DateTime.Now.AddMinutes(120));
Assert.Equal(1, fieldResult);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing persist
fieldResult = db.HashFieldGetAndSetExpiry(hashKey, "f1", persist: true);
Expand All @@ -340,8 +345,8 @@ public void HashFieldGetAndSetExpiry()
fieldResults = db.HashFieldGetAndSetExpiry(hashKey, fields, DateTime.Now.AddMinutes(120));
Assert.Equal(values, fieldResults);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with persist
fieldResults = db.HashFieldGetAndSetExpiry(hashKey, fields, persist: true);
Expand Down Expand Up @@ -369,7 +374,7 @@ public async Task HashFieldGetAndSetExpiryAsync()
fieldResult = await db.HashFieldGetAndSetExpiryAsync(hashKey, "f1", DateTime.Now.AddMinutes(120));
Assert.Equal(1, fieldResult);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing persist
fieldResult = await db.HashFieldGetAndSetExpiryAsync(hashKey, "f1", persist: true);
Expand All @@ -390,8 +395,8 @@ public async Task HashFieldGetAndSetExpiryAsync()
fieldResults = await db.HashFieldGetAndSetExpiryAsync(hashKey, fields, DateTime.Now.AddMinutes(120));
Assert.Equal(values, fieldResults);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with persist
fieldResults = await db.HashFieldGetAndSetExpiryAsync(hashKey, fields, persist: true);
Expand All @@ -417,13 +422,13 @@ public void HashFieldSetAndSetExpiry()
result = db.HashFieldSetAndSetExpiry(hashKey, "f1", 1, DateTime.Now.AddMinutes(120));
Assert.Equal(1, result);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing with keepttl
result = db.HashFieldSetAndSetExpiry(hashKey, "f1", 1, keepTtl: true);
Assert.Equal(1, result);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with timespan
result = db.HashFieldSetAndSetExpiry(hashKey, entries, TimeSpan.FromHours(1));
Expand All @@ -436,15 +441,15 @@ public void HashFieldSetAndSetExpiry()
result = db.HashFieldSetAndSetExpiry(hashKey, entries, DateTime.Now.AddMinutes(120));
Assert.Equal(1, result);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with keepttl
result = db.HashFieldSetAndSetExpiry(hashKey, entries, keepTtl: true);
Assert.Equal(1, result);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing with ExpireWhen.Exists
db.KeyDelete(hashKey);
Expand Down Expand Up @@ -481,13 +486,13 @@ public async Task HashFieldSetAndSetExpiryAsync()
result = await db.HashFieldSetAndSetExpiryAsync(hashKey, "f1", 1, DateTime.Now.AddMinutes(120));
Assert.Equal(1, result);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing with keepttl
result = await db.HashFieldSetAndSetExpiryAsync(hashKey, "f1", 1, keepTtl: true);
Assert.Equal(1, result);
fieldTtl = db.HashFieldGetTimeToLive(hashKey, new RedisValue[] { "f1" })[0];
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtl, TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with timespan
result = await db.HashFieldSetAndSetExpiryAsync(hashKey, entries, TimeSpan.FromHours(1));
Expand All @@ -500,15 +505,15 @@ public async Task HashFieldSetAndSetExpiryAsync()
result = await db.HashFieldSetAndSetExpiryAsync(hashKey, entries, DateTime.Now.AddMinutes(120));
Assert.Equal(1, result);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing multiple fields with keepttl
result = await db.HashFieldSetAndSetExpiryAsync(hashKey, entries, keepTtl: true);
Assert.Equal(1, result);
fieldTtls = db.HashFieldGetTimeToLive(hashKey, fields);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds);
Assert.InRange(fieldTtls[0], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);
Assert.InRange(fieldTtls[1], TimeSpan.FromMinutes(119).TotalMilliseconds, TimeSpan.FromHours(2).TotalMilliseconds + ClockSkewToleranceMs);

// testing with ExpireWhen.Exists
db.KeyDelete(hashKey);
Expand Down
Loading