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
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ present (write "none" rather than omitting one):
malformed), the `RoundTripUnitTests` cases (exact bytes), the live tests written-not-run with
`Create(require: RedisFeatures.vX_Y_Z)`, the HLD section 8 scenarios copied and marked
`expected`, and the exact commands:
`dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter "FullyQualifiedName~<Cmd>"`
and, when the analyzer changed, `dotnet test tests/StackExchange.Redis.Build.Tests/StackExchange.Redis.Build.Tests.csproj`.
`dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter-class "*<Cmd>*"`
and, when the analyzer changed, `dotnet test --project tests/StackExchange.Redis.Build.Tests/StackExchange.Redis.Build.Tests.csproj`.
7. **Docs / changelog / public-API files** - `docs/<Feature>.md` + `docs/index.md` yes/no,
`docs/exp/SERxxx.md` yes/no, the `PublicAPI` files, and the note that `docs/ReleaseNotes.md` is
frozen.
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/implement-resp-command/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,6 @@ The in-process managed server (`toys/StackExchange.Redis.Server`) may also need
## Before finishing

- `dotnet build Build.csproj -c Release /p:CI=true` — analyzers + `TreatWarningsAsErrors` must pass (this catches a missing `PublicAPI.Unshipped.txt` entry).
- `dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter "FullyQualifiedName~MyCommand"` — runs your new unit tests without any server.
- `dotnet test tests/StackExchange.Redis.Build.Tests/StackExchange.Redis.Build.Tests.csproj` — if you touched `TransactionAnalyzer`. Also needs no server, and takes seconds.
- `dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter-class "*MyCommand*"` — runs your new unit tests without any server (Microsoft.Testing.Platform filters take fully qualified names, `*` at either end).
- `dotnet test --project tests/StackExchange.Redis.Build.Tests/StackExchange.Redis.Build.Tests.csproj` — if you touched `TransactionAnalyzer`. Also needs no server, and takes seconds.
- Double-check no shipped signature changed (back-compat).
12 changes: 8 additions & 4 deletions .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,19 @@ runs:

- name: StackExchange.Redis.Tests
shell: bash
# Microsoft.Testing.Platform `dotnet test` (selected in global.json); the GitHub Actions reporter is a platform
# extension that is off by default, and the TRX report feeds dorny/test-reporter below (the platform's
# reporter, not xunit's --report-xunit-trx, which truncated the file in 4.0.2)
run: >-
dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj
--no-build
-c Release
-f net10.0
--logger trx
--logger "GitHubActions;summary-include-passed=false;summary-include-skipped=false"
--results-directory ./test-results/
/p:CI=true
--report-trx
--report-github
--report-github-summary-include-passed false
--report-github-summary-include-skipped false

- uses: dorny/test-reporter@v3
continue-on-error: true
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,10 @@ jobs:
run: |
$exitCode = 0
foreach ($tfm in @("net10.0", "net481")) {
dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj --no-build -c Release -f $tfm --logger trx --logger GitHubActions --results-directory ./test-results/ /p:CI=true
# Microsoft.Testing.Platform `dotnet test` (selected in global.json); the GitHub Actions reporter is a platform
# extension that is off by default, and the TRX report feeds dorny/test-reporter below (the platform's
# reporter, not xunit's --report-xunit-trx, which truncated the file in 4.0.2)
dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj --no-build -c Release -f $tfm --results-directory ./test-results/ --report-trx --report-github --report-github-summary-include-passed false --report-github-summary-include-skipped false
if ($LASTEXITCODE -ne 0) {
$exitCode = $LASTEXITCODE
}
Expand Down
12 changes: 8 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ StackExchange.Redis — a high-performance .NET client for RESP servers (Redis,
- `toys/` — runnable samples and an in-process RESP server (`StackExchange.Redis.Server`, used by tests as a managed fake server), Kestrel-hosted server, console tools.
- `docs/` — published documentation site source (markdown). `docs/ReleaseNotes.md` is the changelog (frozen at 3.0 — from v3 onward release notes live in GitHub Releases).

`Build.csproj` is a `Microsoft.Build.Traversal` project that references everything under `eng/src/tests/toys` — build/test/pack it to act on the whole repo. `StackExchange.Redis.slnx` is the IDE solution (XML SLNX format, not classic `.sln`).
`Build.csproj` is a `Microsoft.Build.Traversal` project that references everything under `eng/src/tests/toys` — build/pack it to act on the whole repo. `StackExchange.Redis.slnx` is the IDE solution (XML SLNX format, not classic `.sln`); it is also what `dotnet test --solution` runs, because tests use the Microsoft.Testing.Platform runner (selected in `global.json`), which cannot see a traversal project on the .NET 10 SDK.

## Build, test, pack

Expand All @@ -30,10 +30,14 @@ pwsh ./build.ps1 -StartServers
docker compose --file tests/RedisConfigs/docker-compose.yml up -d --wait

# Run the main test suite against one target framework (fastest inner loop)
dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -c Release -f net10.0
dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -c Release -f net10.0

# Run a single test class / method (xUnit v3 + Microsoft.Testing.Platform)
dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter "FullyQualifiedName~ClassName.MethodName"
# Run a single test class / method (xUnit v3 on Microsoft.Testing.Platform; names are fully qualified, '*' allowed at either end)
dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter-class StackExchange.Redis.Tests.ClassName
dotnet test --project tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -f net10.0 --filter-method StackExchange.Redis.Tests.ClassName.MethodName

# Every test project at once (what build.ps1 does)
dotnet test --solution StackExchange.Redis.slnx -c Release --no-build

# Pack the library
dotnet pack src/StackExchange.Redis/StackExchange.Redis.csproj --no-build -c Release /p:Packing=true
Expand Down
9 changes: 4 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.9.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="5.6.0" />
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
<PackageVersion Include="Microsoft.Testing.Platform" Version="2.1.0" />
<PackageVersion Include="Microsoft.Testing.Platform" Version="2.5.1" />
<!-- the platform's own TRX reporter (the report-trx switch); xunit's own report-xunit-trx truncated a 400KB report in 4.0.2 -->
<PackageVersion Include="Microsoft.Testing.Extensions.TrxReport" Version="2.5.1" />
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.10.94" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="NSubstitute" Version="6.2.0" />
Expand All @@ -55,9 +56,7 @@
<PackageVersion Include="System.Reflection.Metadata" Version="10.0.13" />
<!-- For binding redirect testing, main package gets this transitively -->
<PackageVersion Include="System.Runtime.Caching" Version="10.0.13" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.v3.runner.console" Version="3.2.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="xunit.v3" Version="4.0.2" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions StackExchange.Redis.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<Project Path="tests/RedisConfigs/RedisConfigs.csproj" />
<Project Path="tests/RESPite.Tests/RESPite.Tests.csproj" />
<Project Path="tests/StackExchange.Redis.Benchmarks/StackExchange.Redis.Benchmarks.csproj" />
<Project Path="tests/StackExchange.Redis.Build.Tests/StackExchange.Redis.Build.Tests.csproj" />
<Project Path="tests/StackExchange.Redis.FaultInjector.Tests/StackExchange.Redis.FaultInjector.Tests.csproj" />
<Project Path="tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj" />
</Folder>
Expand Down
8 changes: 5 additions & 3 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ if ($RunTests) {
& .\RedisConfigs\start-all.cmd
Write-Host "Servers Started." -ForegroundColor "Green"
}
Write-Host "Running tests: Build.csproj traversal (all frameworks)" -ForegroundColor "Magenta"
Write-Host "Running tests: StackExchange.Redis.slnx (all test projects)" -ForegroundColor "Magenta"
if ($NetCoreOnlyTests) {
dotnet test ".\Build.csproj" -c Release -f net8.0 --no-build --logger trx
# net10.0, not net8.0: the analyzer and fault-injector test projects only target net10.0, and the
# Microsoft.Testing.Platform runner fails a project that lacks the requested framework rather than skipping it
dotnet test --solution ".\StackExchange.Redis.slnx" -c Release -f net10.0 --no-build --report-trx
} else {
dotnet test ".\Build.csproj" -c Release --no-build --logger trx
dotnet test --solution ".\StackExchange.Redis.slnx" -c Release --no-build --report-trx
}
if ($LastExitCode -ne 0) {
Write-Host "Error with tests, aborting build." -Foreground "Red"
Expand Down
3 changes: 3 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
{
"sdk": {
"allowPrerelease": false
},
"test": {
"runner": "Microsoft.Testing.Platform"
}
}
7 changes: 4 additions & 3 deletions tests/RESPite.Tests/RESPite.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
<IsPackable>false</IsPackable>
<SignAssembly>true</SignAssembly>
<OutputType>Exe</OutputType>
<!-- xunit.v3 4.x runs on Microsoft.Testing.Platform; global.json selects that runner for `dotnet test`, so the
VSTest adapter packages (Microsoft.NET.Test.Sdk, xunit.runner.visualstudio) are no longer referenced -->
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="System.IO.Pipelines" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.v3.runner.console" PrivateAssets="all" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="all" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<OutputType>Exe</OutputType>
<!-- xunit.v3 4.x runs on Microsoft.Testing.Platform; global.json selects that runner for `dotnet test`, so the
VSTest adapter packages (Microsoft.NET.Test.Sdk, xunit.runner.visualstudio) are no longer referenced -->
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<Nullable>enable</Nullable>
<!-- the analyzer test harness needs a newer Roslyn than the shipped analyzer targets; see
Directory.Packages.props. Testing at the shipped floor is not achievable, and is accepted. -->
Expand All @@ -25,9 +28,8 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" />
<PackageReference Include="System.Security.Cryptography.Pkcs" /> <!-- audit: see Directory.Packages.props -->
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="all" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" />
<PackageReference Include="Microsoft.Testing.Platform" />
</ItemGroup>
</Project>
5 changes: 3 additions & 2 deletions tests/StackExchange.Redis.FaultInjector.Tests/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Xunit;
using Xunit.Sdk;
using Xunit.v3;

// One cluster, one injector, and scenarios that mutate *cluster* state - node exclusions, maintenance mode,
// endpoint policies. Running classes in parallel therefore breaks two ways at once: they interfere semantically
Expand All @@ -8,4 +9,4 @@
//
// So this tier is strictly serial. It costs wall-clock - the scenarios are minutes each - and buys results that
// mean something.
[assembly: CollectionBehavior(DisableTestParallelization = true)]
[assembly: Parallelization(Mode = ParallelMode.None)]
2 changes: 1 addition & 1 deletion tests/StackExchange.Redis.FaultInjector.Tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ docker compose up -d # 10-15 minutes for the cluster to come

export SER_FI_CONFIG_DIR=$PWD # or FI_CONSOLE_CONFIG_DIR, which is also honoured
export E2E_SCENARIO_TESTS=true # explicit opt-in: these create and delete databases
dotnet test tests/StackExchange.Redis.FaultInjector.Tests
dotnet test --project tests/StackExchange.Redis.FaultInjector.Tests/StackExchange.Redis.FaultInjector.Tests.csproj
```

**Point it at the *current* environment.** A stale directory passes every check we make: the credentials are
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
<DebugType>full</DebugType>
<Nullable>enable</Nullable>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<!-- xunit.v3 4.x runs on Microsoft.Testing.Platform; global.json selects that runner for `dotnet test`, so the
VSTest adapter packages (Microsoft.NET.Test.Sdk, xunit.runner.visualstudio) are no longer referenced -->
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\StackExchange.Redis\StackExchange.Redis.csproj" />
<PackageReference Include="GitHubActionsTestLogger" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Microsoft.Testing.Platform" />
<PackageReference Include="xunit.v3" />
<PackageReference Include="xunit.v3.runner.console" PrivateAssets="all" />
<PackageReference Include="xunit.runner.visualstudio" PrivateAssets="all" />
<PackageReference Include="Microsoft.Testing.Extensions.TrxReport" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion tests/StackExchange.Redis.Tests/BatchWriteFailureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public async Task EveryBatchCommandCompletesAfterMidBatchWriteFailure(bool queue
{
Assert.Fail("hung: " + string.Join(", ", all.Select((t, i) => $"cmd{i}={t.Status}")));
}
// individual faults are inspected below
// individual faults are inspected below; the combined task's own exception is never read, so mark it seen
_ = everything.Exception;

for (int i = 0; i < all.Length; i++)
{
Expand Down
4 changes: 2 additions & 2 deletions tests/StackExchange.Redis.Tests/Helpers/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ public override ValueTask<IReadOnlyCollection<IXunitTestCase>> Discover(ITestFra

public class TheoryDiscoverer : Xunit.v3.TheoryDiscoverer
{
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute, ITheoryDataRow dataRow, object?[] testMethodArguments)
=> base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, testMethodArguments).ExpandAsync();
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute, ITheoryDataRow dataRow, object?[] testMethodArguments, string? index)
=> base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, testMethodArguments, index).ExpandAsync();

protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute)
=> base.CreateTestCasesForTheory(discoveryOptions, testMethod, theoryAttribute).ExpandAsync();
Expand Down
8 changes: 5 additions & 3 deletions tests/StackExchange.Redis.Tests/Helpers/TcpForwarder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,11 @@ private async Task PumpAsync(TcpClient client)
// the buffer size is spelled out because the two-argument (stream, token) overload does not
// exist on .NET Framework, which the test project still targets
const int BufferSize = 4096;
await Task.WhenAny(
near.CopyToAsync(far, BufferSize, _cts.Token),
far.CopyToAsync(near, BufferSize, _cts.Token)).ForAwait();
var inbound = near.CopyToAsync(far, BufferSize, _cts.Token);
var outbound = far.CopyToAsync(near, BufferSize, _cts.Token);
await Task.WhenAny(inbound, outbound).ForAwait();
// the other direction fails when the sockets go away below; nobody awaits it, so observe it here
_ = Task.WhenAll(inbound, outbound).ContinueWith(static t => _ = t.Exception, TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
catch
{
Expand Down
9 changes: 8 additions & 1 deletion tests/StackExchange.Redis.Tests/InProcessTestServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,14 @@ public ConfigurationOptions GetClientConfig(bool withPubSub = true, bool default

public override void Log(string message)
{
_log?.WriteLine(message);
// the server's own background work (write loops, delayed closes after MOVING) can outlive the test that
// created it; xunit v3 throws on output with no active test, and from a fire-and-forget task that only
// surfaces as an unobserved exception at the end of the run
try
{
_log?.WriteLine(message);
}
catch (InvalidOperationException) { }
base.Log(message);
}

Expand Down
Loading
Loading