Skip to content

More powerful virtual test server for unit tests#3022

Open
mgravell wants to merge 6 commits intomainfrom
marc/test-server
Open

More powerful virtual test server for unit tests#3022
mgravell wants to merge 6 commits intomainfrom
marc/test-server

Conversation

@mgravell
Copy link
Collaborator

@mgravell mgravell commented Feb 26, 2026

Part of #3018, and planned for use with active:active (geo-redundancy) and "hitless" (server maintenance events)

The idea here is to put in place much stronger test infrastructure to allow us to simulate complex server environments as pure unit tests. This builds on top of the toy server; obviously it needs to also be tested against real infrastructure, but that infrastructure is much more complicated to setup and maintain - this is much more workable for unit test scenarios and maintaining core functionality.

Most of the code here is in the "test" and "toys" area; in the core "src" area, I have:

  • allowed ServerSelectionStrategy to work with a null muxer (using basic defaults)
  • allowed the "-MOVED to self" logic recently added for Valkey cluster to also work for standalone reconnects
  • added an internal convenience SlotRange.IsSingleSlot accessor

This works by:

  • the toy server is now able to emulate an entire group of nodes; at the moment this is horizontal (cluster), but it could also at a later date be vertical (replication); this includes support for cluster nodes and cluster slots
  • the toy server can be hosted directly in a unit test and connected to the client via the tunnel API, bypassing complications like socket exhaustion
  • utility methods allow simulation of server-side operations; at the moment this is key migrations, but in future this could include "push" notifications, etc

This concept can (and will) also be extended to support:

  • connection instability
  • connection latency
  • command latency
  • multi-geo clusters (probably with the addition of a "polytunnel")

Example is in MovedUnitTests, but basically:

using var server = new InProcessTestServer(log) { ServerType = ServerType.Cluster };
var secondNode = server.AddEmptyNode();
...
config.Endpoints.Add(server.DefaultEndpoint); // the endpoint is configurable but is only theoretical
config.Tunnel = server.Tunnel; // this is how we connect the muxer to the toy server
...
await db.StringSetAsync(key, "value");
var value = await db.StringGetAsync(key);
Assert.Equal("value", (string?)value);
...
server.Migrate(key, secondNode); // reconfigures the internal slot map
...
value = await db.StringGetAsync(key);
Assert.Equal("value", (string?)value);

We can see in the logs output:

Creating in-process server: StackExchange.Redis.Tests.InProcessTestServer
Client intercepted, endpoint 127.0.0.1:6380 (Interactive) mapped to Cluster node 127.0.0.1:6380 (empty)
Client intercepted, endpoint 127.0.0.1:6379 (Interactive) mapped to Cluster node 127.0.0.1:6379 (all keys)
Client 2 being redirected: 15004 to 127.0.0.1:6380 (15004)
Server shutting down...

The two "Client intercepted" entries are from the tunnel stepping in to avoid socket IO; initially :6379 has all the data (the default position) and :6380 has nothing. The "Client 2 being redirect" means we sent a -MOVED, but the test passed after following the redirect to the new virtual location.

Note that currently slot migrations are atomic in the Migrate method; there is no 5-step migration process.

@mgravell mgravell changed the title Marc/test server More powerful virtual test server for unit tests Feb 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant