Skip to content

[Test Optimization] Report sessions where VSTest ran no tests as skipped - #9486

Open
tonyredondo wants to merge 3 commits into
tony/ci-visibility-ipc-cross-runtime-lockfrom
tony/empty-test-sessions
Open

tonyredondo wants to merge 3 commits into
tony/ci-visibility-ipc-cross-runtime-lockfrom
tony/empty-test-sessions

Conversation

@tonyredondo

@tonyredondo tonyredondo commented Oct 21, 2026 •

Copy link
Copy Markdown
Member

Summary of changes

When VSTest runs no tests and the run succeeds, the test session is now reported as skipped:

  • test.status:skip
  • test.skip_reason:No tests were executed
  • test.session.empty_reason:zero_tests

This is what you get from a filter that matches nothing, with dotnet test, dotnet vstest or vstest.console. Sessions that ran tests, and failed sessions, are reported as before. The tag, value and skip reason are the same as in the Go version (DataDog/dd-trace-go#5697) and datadog-ci-rb; dd-trace-js uses the same tag and value.

This is an alternative to #9325. It's stacked on #9335, which fixes the IPC channel this relies on, so please review that one first.

Reason for change

An empty run that exits successfully was reported as pass, so it looked the same as a session whose test events were lost.

Implementation details

  • A new CallTarget integration hooks vstest.console's RunTestsArgumentExecutor+TestRunRequestEventsRegistrar.TestRunRequest_OnRunCompletion, the handler VSTest uses to print "No test matches the given testcase filter". Its signature hasn't changed from vstest 15.9 to today, and it only runs for command-line runs, so IDE (design mode) runs aren't affected. The count comes from VSTest itself, which means it includes tests from frameworks we don't instrument, and a session without test events can't be mistaken for an empty one. An aborted, canceled or failed run, or one without statistics, counts as unknown.
  • vstest.console sends the count to the session it inherited the context from, as a new SessionExecutedTestsMessage on the session's existing IPC channel. That session lives in vstest.console itself (dotnet vstest, vstest.console, and dotnet test on SDK 10 and later) or in the dotnet CLI process (dotnet test on SDK 9 and earlier). Only sessions created by the dotnet test integrations host the IPC server, so manual sessions never get a count.
  • TestSession keeps one small state: nothing reported, every report was zero, or a runner ran tests or couldn't count them. A session that closes as passed with only zero reports closes as skipped. The check runs after the IPC server is disposed, so every report already sent has been read. A runner exception counts as unknown, since CallTarget passes exit code 0 in that case.
  • The count travels over the session's IPC channel, so this needs the CircularChannel fixes in [CI Visibility] Fix message loss and abandoned mutexes in the IPC channel #9335: a new client no longer drops the session's unread messages, the reader reads what was written before it's disposed, and an abandoned mutex no longer leaves the channel locked.
  • The hook finds the session with the same lookup the Coverlet and Microsoft CodeCoverage integrations use. Each of them had a private copy, and DotnetCommon repeated it inline twice, so it now lives once in DotnetCommon.TryGetParentSessionSpanId.

Compared with #9325:

Test coverage

  • EmptyTestSessionTests: zero, non-zero, missing, aborted, canceled and failed runs, going through the real IPC path; zero reports from every runner; a failed session; a runner exception; a session without an IPC server. It mocks ITestOptimization to skip the 5 s agent discovery, so each test takes milliseconds.
  • VSTestEmptySessionTests (integration, existing xUnit sample, real vstest.console): a filter that matches nothing gives a skipped session, and a matching test gives a passed one. With a parent session injected through environment variables, vstest.console sends 0 or 1 to it. Three of the four cases fail if the hook doesn't send the count. These tests skip for net8.0 to net10.0 on Linux and macOS while CI uses the .NET 11 RC SDK, because .NET 11 RC can't share named mutexes with .NET 8-10 (.NET 11 breaks named Mutex interop with every earlier .NET on Linux and macOS dotnet/runtime#134491). The SDK check that MsTestV2DiscoveryTests already had now lives in TestingFrameworkEvpTest so both classes share it. vstest.console runs on the SDK, so the other target frameworks still cover the same code.
  • Manual dotnet test runs with the profiler attached: on SDK 9 the dotnet CLI session received the count and closed as skipped (0) or passed (1), and on SDK 10 the vstest.console session did the same.
  • Local runs on Linux with net8.0: the whole Datadog.Trace.Tests.Ci namespace, the new integration tests, and the Release build of Datadog.Trace with no warnings.

Other details

  • Known gaps:
    • If a solution mixes VSTest and Microsoft.Testing.Platform projects under dotnet test, and the VSTest projects run no tests while the MTP ones run some, the session can be reported as skipped, because MTP projects don't send a count.
    • A count is lost if the session's IPC channel stays full for more than a second, and then another project's zero count could mark the session as skipped. I didn't add a persisted fallback for that; the sender retries a full channel for up to a second.
    • /Tests: runs (RunSpecificTestsArgumentExecutor) aren't hooked and stay passed.
  • Not run locally: Windows, .NET Framework (vstest.console.exe) and macOS.

@tonyredondo
tonyredondo marked this pull request as ready for review October 21, 2026 11:49
@tonyredondo
tonyredondo requested review from a team as code owners October 21, 2026 11:49
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-21T11:52:42.052823Z 701a1b1 Draft marked ready
🔒 Security Review ✅ Completed 2026-10-21T11:54:22.261383Z 701a1b1 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@datadog-datadog-us1-prod datadog-datadog-us1-prod Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits Code Review: FAIL

On Linux ARM64, the pinned .NET 11 RC2 VSTest process cannot share named mutexes with the net8.0–net10.0 integration-test host, causing the parent-session IPC assertions in VSTestEmptySessionTests to time out. The fix is to apply the SDK-aware guard already present in MsTestV2DiscoveryTests.RunDiscoveryScenario to the affected parent-session test inputs.

Open Bits AI session

🤖 Bits Code Review · Commit 701a1b1

@pr-commenter

pr-commenter Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-10-23 16:11:50

Comparing candidate commit 854da7d in PR branch tony/empty-test-sessions with baseline commit 3107870 in branch master.

📊 Benchmarking dashboard

Found 0 performance improvements and 0 performance regressions! Performance is the same for 72 metrics, 0 unstable metrics, 11 known flaky benchmarks, 115 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net6.0

  • unstable execution_time [-84.587ms; -22.412ms] or [-16.757%; -4.440%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net6.0

  • 🟥 throughput [-721.431op/s; -686.197op/s] or [-7.461%; -7.097%]

scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs netcoreapp3.1

  • 🟥 throughput [-425.597op/s; -392.832op/s] or [-6.560%; -6.055%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net6.0

  • unstable execution_time [+29.623ms; +101.873ms] or [+6.574%; +22.607%]

scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest netcoreapp3.1

  • unstable execution_time [-111.774ms; -34.152ms] or [-24.731%; -7.556%]

scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net472

  • unstable execution_time [-66.269ms; +9.522ms] or [-11.465%; +1.647%]
  • unstable throughput [-134.983op/s; -58.450op/s] or [-22.072%; -9.558%]

scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice netcoreapp3.1

  • 🟥 execution_time [+225.744µs; +406.644µs] or [+8.296%; +14.944%]
  • 🟥 throughput [-63.093op/s; -27.893op/s] or [-16.833%; -7.442%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net6.0

  • unstable execution_time [-98.935µs; +1.287µs] or [-16.836%; +0.219%]
  • unstable throughput [-58.357op/s; +192.908op/s] or [-3.219%; +10.642%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark netcoreapp3.1

  • 🟩 allocated_mem [-25.944KB; -25.923KB] or [-9.529%; -9.521%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net6.0

  • unstable execution_time [+4.401µs; +11.175µs] or [+8.587%; +21.800%]
  • 🟥 throughput [-3123.331op/s; -1414.372op/s] or [-15.874%; -7.188%]

scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark netcoreapp3.1

  • unstable execution_time [-2.442µs; +4.658µs] or [-4.466%; +8.518%]

Known flaky benchmarks without significant changes:

  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.ActivityBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_AddEvent_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_GetContext_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_RecordException_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetAttributes_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_SetStatus_Sampled netcoreapp3.1
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net472
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled net6.0
  • scenario:Benchmarks.OpenTelemetry.InstrumentedApi.Trace.TelemetrySpanBenchmark.StartSpan_UpdateName_Sampled netcoreapp3.1
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net472
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild net6.0
  • scenario:Benchmarks.Trace.ActivityBenchmark.StartStopWithChild netcoreapp3.1
  • scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces net472
  • scenario:Benchmarks.Trace.AgentWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleMoreComplexBody netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.AllCycleSimpleBody netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorMoreComplexBody netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net472
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecBodyBenchmark.ObjectExtractorSimpleBody netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net472
  • scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeArgs netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecEncoderBenchmark.EncodeLegacyArgs net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmark netcoreapp3.1
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net472
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack net6.0
  • scenario:Benchmarks.Trace.Asm.AppSecWafBenchmark.RunWafRealisticBenchmarkWithAttack netcoreapp3.1
  • scenario:Benchmarks.Trace.AspNetCoreBenchmark.SendRequest net472
  • scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces net6.0
  • scenario:Benchmarks.Trace.CIVisibilityProtocolWriterBenchmark.WriteAndFlushEnrichedTraces netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSlice net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OptimizedCharSliceWithPool netcoreapp3.1
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net472
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice net6.0
  • scenario:Benchmarks.Trace.CharSliceBenchmark.OriginalCharSlice netcoreapp3.1
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net472
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch net6.0
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearch netcoreapp3.1
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net472
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync net6.0
  • scenario:Benchmarks.Trace.ElasticsearchBenchmark.CallElasticsearchAsync netcoreapp3.1
  • scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net472
  • scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync net6.0
  • scenario:Benchmarks.Trace.GraphQLBenchmark.ExecuteAsync netcoreapp3.1
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog net6.0
  • scenario:Benchmarks.Trace.ILoggerBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatAspectBenchmark net472
  • scenario:Benchmarks.Trace.Iast.StringAspectsBenchmark.StringConcatBenchmark net472
  • scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog net6.0
  • scenario:Benchmarks.Trace.Log4netBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net472
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive net6.0
  • scenario:Benchmarks.Trace.RedisBenchmark.SendReceive netcoreapp3.1
  • scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net472
  • scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog net6.0
  • scenario:Benchmarks.Trace.SerilogBenchmark.EnrichedLog netcoreapp3.1
  • scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net472
  • scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore net6.0
  • scenario:Benchmarks.Trace.SingleSpanAspNetCoreBenchmark.SingleSpanAspNetCore netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope net6.0
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishScope netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan net6.0
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishSpan netcoreapp3.1
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net472
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes net6.0
  • scenario:Benchmarks.Trace.SpanBenchmark.StartFinishTwoScopes netcoreapp3.1
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net472
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin net6.0
  • scenario:Benchmarks.Trace.TraceAnnotationsBenchmark.RunOnMethodBegin netcoreapp3.1

@dd-trace-dotnet-ci-bot

dd-trace-dotnet-ci-bot Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Execution-Time Benchmarks Report ⏱️

Execution-time results for samples comparing This PR (9486) and master.

✅ No regressions detected

📄 View the full report (charts + all metrics) →

@tonyredondo

Copy link
Copy Markdown
Member Author

/azp run consolidated-pipeline

@tonyredondo
tonyredondo force-pushed the tony/empty-test-sessions branch from 50291ff to c28d203 Compare October 23, 2026 10:42
@tonyredondo
tonyredondo changed the base branch from master to tony/ci-visibility-ipc-cross-runtime-lock October 23, 2026 10:42

@datadog-datadog-us1-prod datadog-datadog-us1-prod Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bits Code Review: PASS

More details

Zero-test classification preserves nonzero, unknown, and failed-run outcomes, with IPC drained before the final status decision. Runtime behavior was not exercised because the required .NET 11 RC SDK is unavailable.

Was this helpful? React 👍 or 👎

Open Bits AI session

🤖 Bits Code Review · Commit c28d203

@tonyredondo
tonyredondo force-pushed the tony/ci-visibility-ipc-cross-runtime-lock branch from 1e14acd to bf0693b Compare October 23, 2026 12:05
@tonyredondo
tonyredondo force-pushed the tony/empty-test-sessions branch from c28d203 to dfe06c4 Compare October 23, 2026 12:05
@tonyredondo
tonyredondo force-pushed the tony/ci-visibility-ipc-cross-runtime-lock branch from bf0693b to a84c18a Compare October 23, 2026 13:38
@tonyredondo
tonyredondo force-pushed the tony/empty-test-sessions branch from dfe06c4 to 6eddb0a Compare October 23, 2026 13:38
When a VSTest run succeeds without running any test, the session is now
reported with test.status:skip, test.skip_reason "No tests were executed"
and test.session.empty_reason:zero_tests.

A new integration on vstest.console's run completion handler sends the
executed test count to the session that owns the run over the session
IPC channel, so it works whether vstest.console or the dotnet CLI owns
the session. The session is skipped only when every count it received
is zero; an aborted, canceled or failed run, or a runner exception,
keeps it passed.
… bug

CI runs VSTest from the .NET 11 RC2 SDK, which can't share named mutexes
with .NET 8-10 on Linux (dotnet/runtime#134491). In VSTestEmptySessionTests
vstest.console couldn't write to the parent session's channel on x64 and
ARM64, and on ARM64 the testhost couldn't open the session's channel.

The SDK check moves from MsTestV2DiscoveryTests to TestingFrameworkEvpTest
so both classes share it and it goes away in one place with .NET 11 GA.
vstest.console runs on the SDK whatever the test's target framework, so the
other frameworks still run these tests.
… test integrations

The Coverlet and Microsoft CodeCoverage integrations each had a private
copy of the lookup that extracts the propagated test session from the
environment variables, DotnetCommon repeated it inline twice, and the
VSTest run completion hook added another. They all use
DotnetCommon.TryGetParentSessionSpanId now.
@tonyredondo
tonyredondo force-pushed the tony/ci-visibility-ipc-cross-runtime-lock branch from a84c18a to 94750e5 Compare October 23, 2026 15:16
@tonyredondo
tonyredondo force-pushed the tony/empty-test-sessions branch from 6eddb0a to 854da7d Compare October 23, 2026 15:16

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant