Skip to content

test(ui): the sign-off scenario's drag and key steps retry from fresh geometry until they take, so a late layout can't time them out (#2906) - #2931

Merged
mgradwohl merged 1 commit into
mainfrom
fix/2906-signoff-retry
Oct 25, 2026
Merged

mgradwohl merged 1 commit into
mainfrom
fix/2906-signoff-retry

Conversation

@mgradwohl

Copy link
Copy Markdown
Owner

Description

UiScenarioTest.TheSignOffStepsRunThroughTheWholeShell (tests/App/test_UiScenariosOnDisplay.cpp) fails intermittently on windows-2025 debug, ubuntu-24.04 release and ubuntu-24.04-arm debug, and on every nightly on main since 2026-10-24 (#2927). It reports step not done in time: <step>, and the step varies: column-reordered, column-resized, and locally processes-tree-collapsed.

Cause (test): column-reordered and column-resized each injected one drag, from geometry read once (from/to on the drag's first frame, border/widthBefore on step.frame == 0), and never retried. If that one drag landed while the table was still re-laying out after the step before, or if an OS pointer event moved its press off the header or border, the step waited out its default 240 frames and failed. The other interactive steps already retry every RETRY_FRAMES.

What changes:

  • RetriedDrag: when a drag is released and its effect hasn't shown, another drag starts RETRY_FRAMES later, from the column geometry of that frame: PID/Name DisplayOrder and their visible ClipRect for the reorder, PID's MaxX for the resize. This repeats until the step is done or reaches maxFrames, which is now 600 for both drag steps, as for the other interactive steps. The effect is only checked while no button is held, so a step never ends mid-drag. A reorder that shows up late can't be undone by the next attempt either: the effect is checked before each new attempt starts.
  • dragFrom(): puts the pointer back on the drag's start on every frame up to the press, and on its end with the release. An SDL event queued between two injected positions (a window mouse-leave, a warp's late WM_MOUSEMOVE/MotionNotify) can no longer move the press off target. The backend's events are queued after the ones the driver injected the frame before, so the last position wins.
  • processes-tree-collapsed: each attempt hovers the table on every frame and presses Home, then Down k times, then Left twice, with k growing by one per attempt. Left collapses an expanded parent; on a child it selects the parent, which the second Left collapses. A first row that can't collapse (a root with no children, or one already collapsed) no longer stalls the step. maxFrames is now 600.
  • column-resized: narrows PID instead of widening it once PID is 200 px wide or its border is near the edge of the view (see the repeat finding below).
  • Escape: the press in column-reordered, about and settings-theme-saved is now always released the frame after (tapKeyWhile). Before, it stayed held whenever the menu closed before the release frame. The driver also releases every key and button the scenario uses when a step passes.
  • Failure detail: a failed step now also reports the display size, pointer position, buttons, hovered window and ID, active ID, top popup, and the PID/Name column geometry, e.g. display 1280x800, pointer (603, 187), left down right up, hovered window ##MainWindow/.../ProcessTable_A7EC3B99, hovered id a7ec3b9a, active id a7ec3b9a, popup none; table x 22..1234, PID #1 x 463..600 width 122, Name #0 x 21..463. If a runner still fails, the log shows what the step saw.

Found while reproducing: under --gtest_repeat, each run starts from the table layout the previous run saved to the process's temporary config dir. That layout has PID 40 px wider and PID/Name swapped. Each run of the 20-repeat baseline widened PID until, on the 19th, its right border was past the view (pid 463..1304 in a 1259 px clip), and from then on every run failed at column-resized or column-reordered. CI runs each suite once in a fresh process, so CI never hit this case, but it made local repeat counts meaningless. The resize step now narrows PID when widening has no room, so repeats stay in range.

Product cause: none found. git log 7b630175..origin/main over ProcessesPanel, src/UI, Application.cpp and FramePacing.h:

The failures started when the suite itself landed (#2885) and turned regular once #2925 let the reorder through on Windows CI (it then failed at the next step, column-resized). In the trace from the local failure, the resize press missed because its target was outside the view. On CI the fresh layout leaves room, so the likeliest causes there are a press moved off target by a queued OS pointer event, or a drag that landed before the table settled. Both are covered above.

Closes #2906

PR Size

Small to medium: one test file, about 270 lines added and 70 removed.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Build/CI improvement

Checklist

  • I have read the CONTRIBUTING guidelines
  • My code follows the project's coding standards
  • I have run clang-tidy and addressed any warnings
  • I have run clang-format on my changes
  • I have run pre-commit run --all-files or installed pre-commit hooks
  • I have added tests that prove my fix/feature works
  • All new and existing tests pass
  • I have updated documentation as needed (none needed: test-only change)

Testing

Windows 11, win-debug, TASKSMACK_SYNTHETIC=processes=120,seed=2711 (the suite's ctest environment):

cmake --build --preset win-debug -j 2 --target TaskSmackAppTests
TaskSmackAppTests.exe --gtest_filter=UiScenarioTest.* --gtest_repeat=20
ctest --preset win-debug -j 2
.\tools\clang-tidy.ps1 -Files tests/App/test_UiScenariosOnDisplay.cpp
pre-commit run --files tests/App/test_UiScenariosOnDisplay.cpp
Run Before (origin/main 012b6f2) After
--gtest_repeat=20 19/20 (failed run 19: column-resized) 20/20 (twice)
--gtest_repeat=40 22/40 (from run 19: 14 column-reordered, 4 column-resized; seen twice) 40/40
  • Full ctest --preset win-debug -j 2: 684/684 passed (193 s).
  • A forced failure (resize step maxFrames = 8, not committed) printed the new state line above.
  • clang-tidy (host LLVM 23): nothing left except readability-trailing-comma, which is new in LLVM 23 and also fires on lines this PR doesn't touch, so it isn't in CI's LLVM 22. The new array has the comma anyway.
  • clang-format and pre-commit pass.
  • Linux: not run locally. The ubuntu-24.04 legs run it under Xvfb.

Additional Notes

Test-only. UiScenarioTest still asserts behaviour, not pixels, and each step still starts where the last one left the shell.

🤖 Generated with Claude Code

… geometry until they take, so a late layout can't time them out (#2906)

UiScenarioTest.TheSignOffStepsRunThroughTheWholeShell failed at column-reordered,
column-resized and processes-tree-collapsed on Windows and Linux CI and on every nightly
since 2026-10-24. The two drag steps each injected one drag from geometry read once and
never retried, so a drag that landed while the table was still settling, or whose press
an OS pointer event moved off target, waited out 240 frames and failed.

- RetriedDrag: a drag released without its effect is followed, RETRY_FRAMES later, by
  another from the column geometry of that frame (PID/Name MinX/MaxX/DisplayOrder and
  the visible ClipRect for the reorder, PID's MaxX for the resize), until done or
  maxFrames (now 600, like the other interactive steps). The effect is only checked
  while no button is held, so a step never ends mid-drag.
- dragFrom() puts the pointer back on its start on every frame up to the press, and on
  its end with the release: an SDL event queued between two injected positions (a
  window mouse-leave, a warp's late motion) can't move the press off the header or
  the border.
- processes-tree-collapsed: each attempt hovers the table on every frame and presses
  Home, Down k times, Left, Left, k growing per attempt, so a first row that can't
  collapse (a root leaf, a branch already collapsed) no longer blocks it.
- column-resized narrows PID instead of widening it once it is 200 px or its border
  is near the view's edge. Under --gtest_repeat each run starts from the layout the
  last one saved, so PID grew 40 px a run until its border left the view and every
  later run failed (19th of 20 locally, then 18 of the next 22).
- Escape in column-reordered, about and settings is always released the frame after
  its press (it was left held when the menu closed before the release), and the
  driver releases every scenario key and button when a step passes.
- A failed step now reports the display size, pointer, buttons, hovered window and
  ID, active ID, top popup and the PID/Name column geometry.

No product cause found: #2888 changed only tools/tests, #2920's input redraw grace
doesn't apply while the driver requests FULL_RATE every frame, and #2922 doesn't touch
the Processes table.

Closes #2906

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mgradwohl mgradwohl added this to the v0.10.0 milestone Oct 25, 2026
@mgradwohl mgradwohl added bug Something isn't working ci Refers to issues in the ci workflow testing agent:Windows Owned by the Windows Claude session (bug-fix conveyor) labels Oct 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@mgradwohl
mgradwohl enabled auto-merge (squash) October 25, 2026 13:30
@mgradwohl
mgradwohl merged commit 997c540 into main Oct 25, 2026
31 checks passed
@mgradwohl
mgradwohl deleted the fix/2906-signoff-retry branch October 25, 2026 13:55
mgradwohl added a commit that referenced this pull request Oct 25, 2026
… --gtest_repeat run never opens on the layout the last one saved (#2932) (#2941)

UiScenarioTest and UiLayersOnDisplayTest now derive from
TestSupport::ScratchConfigDirTest (tests/App/ScratchConfigDir.h). SetUp()
makes a new, empty temporary directory and points both
Core::ConfigDirOverride::active() (new setActiveForTesting() seam; what each
Core::Application's PathService reads) and UserConfig
(resetConfigPathForTesting(): config.toml, settings back to defaults) at it.
TearDown() restores both and the settings, then removes the directory;
resetConfigPathForTesting() first waits for a queued or in-flight
background save (#2916), so nothing writes into the directory once it is
gone.

With isolation, #2931's narrowing workaround in the column-resized step is
gone: PID always starts at its default width and is widened 40 px.

Before (workaround disabled, shared config): --gtest_repeat=30 passed runs
1-18, then failed 19, 21, 23, 25, 27 and 29 (PID 826 px and wider, its
right border out of view). After: 30/30.

Fixes #2932

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@mgradwohl mgradwohl mentioned this pull request Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:Windows Owned by the Windows Claude session (bug-fix conveyor) bug Something isn't working ci Refers to issues in the ci workflow testing

Projects

None yet

1 participant