Skip to content

Removes dependency on RemoteExecutor in tests#14538

Open
ricardobossan wants to merge 3 commits into
dotnet:mainfrom
ricardobossan:Issue_4500_Remove_RemoteExecutor
Open

Removes dependency on RemoteExecutor in tests#14538
ricardobossan wants to merge 3 commits into
dotnet:mainfrom
ricardobossan:Issue_4500_Remove_RemoteExecutor

Conversation

@ricardobossan
Copy link
Copy Markdown
Member

@ricardobossan ricardobossan commented May 12, 2026

Fixes #4500 (partial; see "Out of scope" below).

Supersedes #12379, which replaced RemoteExecutor.Invoke(...) with Task.Run(...).Wait(). That doesn't work for this set of tests: they mutate irreversible process-wide state (Application.EnableVisualStyles, Application.VisualStyleState, Application.CurrentCulture, Control.CheckForIllegalCrossThreadCalls), so any in-process replacement leaves the mutations behind for whatever runs next. The tests need a host that's isolated by construction.

This PR follows RussKie's suggestion on #4500: move tests that legitimately need an isolated, visual-styles-enabled host into UIIntegrationTests, which already runs serially (eng/xunit.runner.json: parallelizeTestCollections: false, maxParallelThreads: 1) and pre-enables visual styles via ControlTestBase.

Root Cause

The original skip reason on each test ("Crash with AbandonedMutexException. See: https://github.com/dotnet/arcade/issues/5325") blames RemoteExecutor, but arcade#5325 is actually a Coverlet bug (UnloadModule mutex); the winforms repo still consumes the affected coverlet.msbuild variant. RemoteExecutor isn't the bug; it's the side that was easy to remove. These tests need some form of isolation though; EnableVisualStyles is a one-way switch, and VisualStyleState writes broadcast WM_THEMECHANGED to every HWND in the process. UIIntegrationTests already provides that isolation by construction.

Proposed changes

  • Migrate the 17 previously-skipped tests below from src/test/unit/System.Windows.Forms/... to src/test/integration/UIIntegrationTests/.... Each migrated test no longer needs RemoteExecutor and is no longer skipped.
  • Remove the corresponding using Microsoft.DotNet.RemoteExecutor; and orphaned MemberData helpers from the unit-test files. using is preserved in ApplicationTests.cs because two non-skipped tests there still use RemoteExecutor (out of scope for this PR).
  • Net: −616 / +33 lines under src/test/unit/, +672 lines under src/test/integration/UIIntegrationTests/ (six new files).

Migrated tests:

New file (UIIntegrationTests) Migrated tests
Application.ParkingWindowTests.cs ParkingWindow_DoesNotThrowOnGarbageCollecting
Application.StaticStateTests.cs Application_CurrentCulture_Set_GetReturnsExpected, Application_EnableVisualStyles_InvokeBeforeGettingRenderWithVisualStyles_Success, Application_VisualStyleState_Set_ReturnsExpected
CommonDialogTests.cs CommonDialog_ShowDialog_*WithVisualStyles_*
DataGridViewHeaderCellTests.cs MouseLeaveUnsharesRow_InvokeWithDataGridViewMouseDown, OnMouseDown_InvalidRowIndexVisualStyles, OnMouseUp_InvalidRowIndexVisualStyles
ListViewInsertionMarkTests.cs AppearsAfterItem_/Color_/Index_GetInsertMark[WithColor]_Success (unsafe, via LVM_GETINSERTMARK / LVM_GETINSERTMARKCOLOR)
TabPageTests.cs BackColor_GetVisualStyles_ReturnsExpected, BackColor_GetVisualStylesWithParent_ReturnsExpected

Two intentional deltas from the original tests (both annotated inline):

  1. Application_EnableVisualStyles_InvokeAfterGettingRenderWithVisualStyles_Success is dropped. Its precondition is UseVisualStyles == false followed by a call to EnableVisualStyles(). EnableVisualStyles is a one-way switch, and any test project that has previously enabled visual styles (which UIIntegrationTests does on startup) can never satisfy that precondition again. The behavior under test is documented as "not a recommended scenario"; the original only worked by spawning a fresh process.
  2. Application_CurrentCulture_Set_GetReturnsExpected keeps every managed-side assertion but drops the Assert.Equal(expectedLcid, PInvokeCore.GetThreadLocale()) round-trip. UIIntegrationTests is decorated with [UseDefaultXunitCulture] (via ControlTestBase), and xunit's culture fixture restores the thread locale around test execution. SetThreadLocale also silently no-ops for some LCIDs (notably invariant 0x7F) on STA hosts. The Win32-level round-trip was an implementation detail that only held inside a freshly-spawned RemoteExecutor child; Application.CurrentCulture's documented surface is the managed Thread/CultureInfo pair, which is still verified.

Out of scope (follow-up)

Roughly 17 additional tests carry the same "AbandonedMutexException ... arcade#5325" skip reason but were not in #12379's scope: ~6 more in DataGridViewHeaderCellTests, 1 in ListViewTests, and ~10 in ListViewGroupTests. Per the staggered approach we discussed on the issue, leaving those for a follow-up PR keeps this one reviewable.

Customer Impact

  • None. Test-only change. No product code is touched.

Regression?

  • No.

Risk

  • Minimal. The migration restores test coverage that was previously skipped; if anything regresses it can only surface as test failures (caught by CI before merge), not as customer-facing behavior. UIIntegrationTests already covers the same project surface.

Test methodology

  • Unit tests / Integration tests. Built the solution locally; the migrated tests run green inside UIIntegrationTests. The unit-tests assembly still builds with the using/helper removals applied. No remaining references to the deleted MemberData helpers (CustomLCIDCultureInfo, BackColor_GetVisualStylesWithParent_TestData, MouseLeaveUnsharesRow_WithDataGridViewMouseDown_TestData); grep-verified before deletion.

Test environment(s)

  • 11.0.100-preview.4.26210.111
Microsoft Reviewers: Open in CodeFlow

Supersedes dotnet#12379, which replaced `RemoteExecutor.Invoke(...)` with `Task.Run(...).Wait()`. That doesn't work for this set of tests: they mutate irreversible process-wide state (`Application.EnableVisualStyles`, `Application.VisualStyleState`, `Application.CurrentCulture`, `Control.CheckForIllegalCrossThreadCalls`), so any in-process replacement leaves the mutations behind for whatever runs next. The tests need a host that's isolated by construction.

This PR follows RussKie's suggestion on dotnet#4500: move tests that legitimately need an isolated, visual-styles-enabled host into `UIIntegrationTests`, which already runs serially (`eng/xunit.runner.json`: `parallelizeTestCollections: false`, `maxParallelThreads: 1`) and pre-enables visual styles via `ControlTestBase`.

The original skip reason on each test (`"Crash with AbandonedMutexException. See: https://github.com/dotnet/arcade/issues/5325"`) blames RemoteExecutor, but arcade#5325 is actually a Coverlet bug (`UnloadModule` mutex); the winforms repo still consumes the affected `coverlet.msbuild` variant. RemoteExecutor isn't the bug; it's the side that was easy to remove. These tests need *some* form of isolation though; `EnableVisualStyles` is a one-way switch, and `VisualStyleState` writes broadcast `WM_THEMECHANGED` to every HWND in the process. UIIntegrationTests already provides that isolation by construction.

- Migrate the 17 previously-skipped tests below from `src/test/unit/System.Windows.Forms/...` to `src/test/integration/UIIntegrationTests/...`. Each migrated test no longer needs `RemoteExecutor` and is no longer skipped.
- Remove the corresponding `using Microsoft.DotNet.RemoteExecutor;` and orphaned `MemberData` helpers from the unit-test files. `using` is preserved in `ApplicationTests.cs` because two non-skipped tests there still use `RemoteExecutor` (out of scope for this PR).
- Net: −616 / +33 lines under `src/test/unit/`, +672 lines under `src/test/integration/UIIntegrationTests/` (six new files).

Migrated tests:

| New file (UIIntegrationTests) | Migrated tests |
|---|---|
| `Application.ParkingWindowTests.cs` | `ParkingWindow_DoesNotThrowOnGarbageCollecting` |
| `Application.StaticStateTests.cs` | `Application_CurrentCulture_Set_GetReturnsExpected`, `Application_EnableVisualStyles_InvokeBeforeGettingRenderWithVisualStyles_Success`, `Application_VisualStyleState_Set_ReturnsExpected` |
| `CommonDialogTests.cs` | 3× `CommonDialog_ShowDialog_*WithVisualStyles_*` |
| `DataGridViewHeaderCellTests.cs` | `MouseLeaveUnsharesRow_InvokeWithDataGridViewMouseDown`, `OnMouseDown_InvalidRowIndexVisualStyles`, `OnMouseUp_InvalidRowIndexVisualStyles` |
| `ListViewInsertionMarkTests.cs` | 5× `AppearsAfterItem_/Color_/Index_GetInsertMark[WithColor]_Success` (unsafe, via `LVM_GETINSERTMARK` / `LVM_GETINSERTMARKCOLOR`) |
| `TabPageTests.cs` | `BackColor_GetVisualStyles_ReturnsExpected`, `BackColor_GetVisualStylesWithParent_ReturnsExpected` |

Two intentional deltas from the original tests (both annotated inline):

1. `Application_EnableVisualStyles_InvokeAfterGettingRenderWithVisualStyles_Success` is **dropped**. Its precondition is `UseVisualStyles == false` followed by a call to `EnableVisualStyles()`. `EnableVisualStyles` is a one-way switch, and any test project that has previously enabled visual styles (which UIIntegrationTests does on startup) can never satisfy that precondition again. The behavior under test is documented as "not a recommended scenario"; the original only worked by spawning a fresh process.
2. `Application_CurrentCulture_Set_GetReturnsExpected` keeps every managed-side assertion but **drops the `Assert.Equal(expectedLcid, PInvokeCore.GetThreadLocale())` round-trip**. UIIntegrationTests is decorated with `[UseDefaultXunitCulture]` (via `ControlTestBase`), and xunit's culture fixture restores the thread locale around test execution. `SetThreadLocale` also silently no-ops for some LCIDs (notably invariant `0x7F`) on STA hosts. The Win32-level round-trip was an implementation detail that only held inside a freshly-spawned RemoteExecutor child; `Application.CurrentCulture`'s documented surface is the managed `Thread`/`CultureInfo` pair, which is still verified.

Roughly 17 additional tests carry the same `"AbandonedMutexException ... arcade#5325"` skip reason but were not in dotnet#12379's scope: ~6 more in `DataGridViewHeaderCellTests`, 1 in `ListViewTests`, and ~10 in `ListViewGroupTests`. Per the staggered approach we discussed on the issue, leaving those for a follow-up PR keeps this one reviewable.

- None. Test-only change. No product code is touched.

- No.

- Minimal. The migration restores test coverage that was previously skipped; if anything regresses it can only surface as test failures (caught by CI before merge), not as customer-facing behavior. UIIntegrationTests already covers the same project surface.

- Unit tests / Integration tests. Built the solution locally; the migrated tests run green inside `UIIntegrationTests`. The unit-tests assembly still builds with the using/helper removals applied. No remaining references to the deleted `MemberData` helpers (`CustomLCIDCultureInfo`, `BackColor_GetVisualStylesWithParent_TestData`, `MouseLeaveUnsharesRow_WithDataGridViewMouseDown_TestData`); grep-verified before deletion.

- 11.0.100-preview.4.26210.111
@ricardobossan ricardobossan self-assigned this May 12, 2026
@ricardobossan ricardobossan requested a review from a team as a code owner May 12, 2026 15:12
@ricardobossan ricardobossan added the waiting-review This item is waiting on review by one or more members of team label May 12, 2026
@KlausLoeffelmann
Copy link
Copy Markdown
Member

@ricardobossan - can you check why the tests fail?

@ricardobossan ricardobossan marked this pull request as draft May 13, 2026 00:31
@ricardobossan
Copy link
Copy Markdown
Member Author

Drafting until feedback is handled.

@ricardobossan ricardobossan marked this pull request as ready for review May 13, 2026 00:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-test coverage waiting-review This item is waiting on review by one or more members of team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove dependency on RemoteExecutor in tests

2 participants