Files
DodoSSH/tests
jaap-janandClaude Opus 5 ddf0dd6a2b Stop the transfer tests depending on which thread ran them first
Every test in TransferQueueingTests failed on the Linux runner with "The calling thread
cannot access this object because a different thread owns it", and none of them had
anything to do with the commits in that run. The class drained its rows through
Dispatcher.UIThread.RunJobs(). That dispatcher is process-wide and belongs to whichever
thread touched it first, and xunit runs each test class as its own parallel collection — so
the moment a runner scheduled another class onto that thread ahead of this one, all nine
died inside DispatcherOperation.Execute having asserted nothing about transfers at all. It
passes locally and fails on a machine that schedules differently, which is the whole of why
this took a CI run to find.

TransfersViewModel now takes the poster it marshals through, defaulting to
Dispatcher.UIThread.Post — the seam VaultViewModel's clipboard already is, for the same
reason: a view model that reaches a process-wide UI object directly makes every test of it
depend on a thread it does not choose. No head passes the parameter, so nothing about the
running application changes.

The test supplies a queue of its own and drains it, which is the same shape the dispatcher
gave it. A poster that ran the action inline was tried first and is wrong: the transfer
queue raises Changed from its pump thread as well as from the call that enqueued, so inline
execution has a background thread adding rows to an ObservableCollection while the test
reads it — it passed once and then failed a different test on the next run. Draining keeps
every mutation on the thread doing the asserting, which is the one thing the dispatcher was
providing that was worth keeping.

One test added for the property that broke: queueing is reachable from any thread and must
not care which. The class as a whole guards the seam — remove it and nothing drains, so
every assertion about a row fails.

Verified by reproducing the failure first: a throwaway probe that touched the dispatcher on
one thread and posted and drained on another produced exactly the CI message. Then six
consecutive Release runs of the app suite, all green, plus the layout suite, which builds a
TransfersViewModel of its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 21:43:21 +02:00
..
2026-07-31 10:12:05 +02:00
2026-07-31 10:12:05 +02:00