From 63b0a2f662e0d50ff825f8ca095bf1c6cd65289f Mon Sep 17 00:00:00 2001 From: Cosmin Staicu Date: Thu, 16 Jul 2026 18:31:14 +0300 Subject: [PATCH] test(redis): add live e2e guards for StackExchange.Redis internal reflection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two reflection sites reach into StackExchange.Redis private internals and fail silently, so unit tests (which mock the Redis interfaces) cannot detect them degrading — a risk ahead of the upcoming 2.1x and 3.0 upgrades. - Add ProfiledCommandExtensionsIntegrationTests: runs a keyed command against live Redis and asserts GetStatement() carries the key, which only holds when the ProfiledCommand.Message -> Message.CommandAndKey reflection resolves. - Strengthen the existing GetMasterPhysicalConnectionMetrics test to also check the reflected endpoint and a sane AwaitingResponseCount, catching a wrong-but-present field bind, not just a null. Both gated by RUN_REDIS_INTEGRATION_TESTS=1. Verified against live Redis on net8.0 and net10.0 at the current 2.10.1 baseline. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Cosmin Staicu --- ...ofiledCommandExtensionsIntegrationTests.cs | 38 +++++++++++++++++++ .../Redis/RedisConnectorIntegrationTests.cs | 2 + 2 files changed, 40 insertions(+) create mode 100644 tests/UiPath.Caching.Tests/Redis/ProfiledCommandExtensionsIntegrationTests.cs diff --git a/tests/UiPath.Caching.Tests/Redis/ProfiledCommandExtensionsIntegrationTests.cs b/tests/UiPath.Caching.Tests/Redis/ProfiledCommandExtensionsIntegrationTests.cs new file mode 100644 index 0000000..5f902d3 --- /dev/null +++ b/tests/UiPath.Caching.Tests/Redis/ProfiledCommandExtensionsIntegrationTests.cs @@ -0,0 +1,38 @@ +using StackExchange.Redis; +using StackExchange.Redis.Profiling; +using UiPath.Caching.Redis; + +namespace UiPath.Caching.Tests.Redis; + +[Collection("RedisIntegration")] +[Trait("Category", "Integration")] +public class ProfiledCommandExtensionsIntegrationTests(RedisContainerFixture fixture) +{ + [Fact] + public async Task GetStatement_IncludesKey_FromLiveProfiledCommand() + { + Assert.SkipUnless(fixture.Enabled, "Set RUN_REDIS_INTEGRATION_TESTS=1 (Docker required) to run."); + + await using var multiplexer = await ConnectionMultiplexer.ConnectAsync(fixture.ConnectionString); + var database = multiplexer.GetDatabase(); + await database.PingAsync(); + + var session = new ProfilingSession(); + multiplexer.RegisterProfiler(() => session); + + var key = $"profiled-{Guid.NewGuid():N}"; + await database.StringSetAsync(key, "value"); + await database.StringGetAsync(key); + + var commands = session.FinishProfiling().ToList(); + + var keyed = commands.FirstOrDefault(c => + (string.Equals(c.Command, "SET", StringComparison.Ordinal) || string.Equals(c.Command, "GET", StringComparison.Ordinal)) + && c.GetStatement().Contains(key, StringComparison.Ordinal)); + + keyed.Should().NotBeNull(); + keyed!.GetStatement().Should().NotBe(keyed.GetCommandName()); + keyed.GetStatement().Should().StartWith(keyed.Command).And.Contain(key); + keyed.GetTarget().Should().NotBeNullOrEmpty().And.Contain(":"); + } +} diff --git a/tests/UiPath.Caching.Tests/Redis/RedisConnectorIntegrationTests.cs b/tests/UiPath.Caching.Tests/Redis/RedisConnectorIntegrationTests.cs index 3d49518..a0ed080 100644 --- a/tests/UiPath.Caching.Tests/Redis/RedisConnectorIntegrationTests.cs +++ b/tests/UiPath.Caching.Tests/Redis/RedisConnectorIntegrationTests.cs @@ -65,5 +65,7 @@ public async Task GetMasterPhysicalConnectionMetrics_ReturnsData_OnLiveConnectio var metrics = connector.GetMasterPhysicalConnectionMetrics(multiplexer); metrics.Should().NotBeNull(); + metrics!.EndPoint.Should().BeOneOf(multiplexer.GetEndPoints()); + metrics.AwaitingResponseCount.Should().BeGreaterThanOrEqualTo(0); } }