Skip to content

Overnight/test harness 2026 04 20#8

Merged
claudenstein merged 21 commits into
mainfrom
overnight/test-harness-2026-04-20
Apr 29, 2026
Merged

Overnight/test harness 2026 04 20#8
claudenstein merged 21 commits into
mainfrom
overnight/test-harness-2026-04-20

Conversation

@claudenstein

Copy link
Copy Markdown
Owner

No description provided.

Frank Dosk and others added 21 commits April 28, 2026 17:57
Restored the valid-URI Add-button tap with a 500 ms drain
after. The goroutine spawns, calls Eng.AddMagnetURI on a fresh
no-DHT daemon (returns quickly with the torrent added), then
SetTorrentIndexing(false) since shouldIndex defaults true here
(actually true → no SetTorrentIndexing call).

showAddMagnetDialogPrefilled 70.0% → 83.3%; gui pkg 83.5% →
83.8%. -race stable across 5 consecutive runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restored showFilesForSelected to TestDownloadsSelectedActionsHappyPath.
After it builds the filesDialog (spawning the 2 s pollLoop),
we tap the dialog's "Close" button to fire SetOnClosed →
cancel(), and a 300 ms drain lets all goroutines exit before
the test returns.

showFilesForSelected 23.1% → 92.3%; gui pkg 83.8% → 84.6%.
-race stable across 5 consecutive runs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
runCreateTorrent: 60.0% → 93.3% via a tiny-file Root that succeeds
through CreateTorrentFile + AddTorrentMetaInfo (andSeed=true).

runSearch: 61.7% → 87.2% via two new tests that toggle individual
layer checkboxes — local-on hits Index!=nil branch, swarm-on hits
SwarmSearch()!=nil branch. Both daemons are race-clean across 3
consecutive sweeps.

gui pkg total: 85.0% → 85.9%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t-menu happy path

- installShortcuts: cover the dl/sr non-nil arms (Ctrl+N magnet,
  Ctrl+F focus query, Delete-key removeSelected) by populating
  the App with hand-rolled tabs.
- refreshPublisher: cover the throttled error arm by waiting for
  the publisher's startup refreshOnce to set lastRefresh, then
  triggering RefreshNow → ErrTooSoon → fyne.Do(ShowError).
- showAddMagnetDialogPrefilled: cover the !shouldIndex arm by
  unchecking the index checkbox before submit (uri SetTorrentIndexing
  fires).
- rightClickCapture.TappedSecondary: cover ShowPopUpMenuAtPosition
  happy path via window.SetContent so CanvasForObject is non-nil.

gui pkg total: 85.9% → 86.4%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cover newSettingsTab's three button OnTapped closures
(settings.go:47-90) by walking the rendered tab content for
*widget.Button by text and invoking each. With sane pre-populated
entry values the callbacks reach save/applyRateLimits/
applyQueueSettings without hitting validation-error dialogs.

newSettingsTab: 88.0% → 100%. gui pkg total: 86.4% → 86.6%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cover the pauseAction and resumeAction func closures
(downloads.go:265-268) by walking the built menu and invoking
each item.Action directly. With Paused=false the closure path
runs pauseSelected; with Paused=true it runs resumeSelected.

buildContextMenu: 87.3% → 90.9%. gui pkg total: 86.6% → 86.8%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add TestRemoveSelectedConfirmCanceled which taps the "No" button
on the remove-confirm dialog. ok=false trips the early return so
the RemoveTorrent goroutine never spawns — covers the previously
uncovered `if !ok { return }` arm.

removeSelected: 95.5% → 100%. gui pkg total: 86.8% → 86.9%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add TestShowFilesForSelectedEmptyName which constructs a snapshot
with empty Name; the function falls through to
`name = s.InfoHash[:16] + "..."` before delegating to
showFilesDialog (which then short-circuits on missing torrent).

showFilesForSelected: 92.3% → 100%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Introduce newNoSubsystemsTestDaemon helper that sets BloomPath +
ReputationPath to "" so the engine leaves bloom and reputation
tracker uninitialized. KnownGoodBloom() / ReputationTracker()
return nil, exercising the previously-uncovered defensive arms
in confirmHit (search.go:332) and flagHit (search.go:356).

confirmHit: 92.9% → 100%. flagHit: 93.8% → 100%.
gui pkg total: 86.9% → 87.1%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walk the rendered tab content for the "Refresh Now" and
"Unfollow" buttons and tap each. Pre-populate ct.follows with a
row whose lastErr is set so the list update closure's stats-string
err-append arm fires.

buildCompanionTab: 89.7% → 97.4%. gui pkg total: 87.1% → 87.3%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two isolated tests, one per closure: TestSearchTabSubmitCallback
fires queryEntry.OnSubmitted, TestSearchTabButtonCallback fires
searchBtn.OnTapped. Each builds a fresh searchTab with all
layers off so runSearch's orchestrator goroutine completes via
the empty-WaitGroup path; a 1500ms drain lets the spawned
fyne.Do(buildResults) complete before the test returns. Splitting
into two tests avoids a SetText race with a prior runSearch's
in-flight UI work.

newSearchTab: 93.1% → 100%. gui pkg total: 87.3% → 87.5%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After adding a torrent we call Eng.PauseTorrent so the next
TorrentSnapshots returns Status="paused", exercising
status.refresh's `case "paused": paused++` switch arm.

status.refresh: 92.8% → 93.8%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TestLayerDPublisherRefreshKeepsItemFresh's post-refresh sanity
query had a 5s context budget. Under -race the loopback DHT
traversal can take longer than that, occasionally tripping
"post-refresh lookup empty: asked=3 responded=0 hits=0" even
though the publisher refresh ticker did fire correctly. The
test deadline outside this query is already 12s, so absorbing
a few more seconds for a single Lookup.Query is straightforward.

Stable across 3 consecutive -race runs after the bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walk a context menu built from a queued snapshot and invoke the
"Stop indexing"/"Start indexing", "Move to top of queue", and
"Move to bottom of queue" actions. Each closure spawns an
engine goroutine that no-ops on the missing torrent; a 200 ms
drain bounds them.

Skip "Files..." and "Remove" since their callbacks open dialogs
whose font-cache rendering races other tests under -race.

buildContextMenu: 90.9% → 96.4%. gui pkg total: 87.5% → 87.8%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
buildAndSign's `if len(ihBytes) != 20 { return error }` guard
is unreachable through readRecords (it gates jr.IH at 40 chars
first), but it's still a load-bearing safety check for any
future caller that bypasses readRecords. Add a direct unit
test that passes a 38-char hex (decodes to 19 bytes) and
asserts the error message.

buildAndSign: 91.7% → 95.8%. cmd/swartznet: 97.9% → 98.0%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refactor files_dialog.pollLoop to extract its tick body into a
new tickRefresh method. Then cover both directly:
- TestFilesDialogTickRefreshErr / TestFilesDialogTickRefreshSuccess
  drive tickRefresh's missing-torrent and present-torrent paths.
- TestFilesDialogPollLoopTickFires runs the goroutine for 2.3s
  so the 2-second ticker fires once, hitting `case <-tick.C:
  fd.tickRefresh()`.

files_dialog.pollLoop: 35.7% → 100%, tickRefresh: 100% (new).
gui pkg total: 87.8% → 88.5%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two new tests:
- TestBuildContextMenuFilesActionWithRealTorrent: real torrent
  added so showFilesForSelected → showFilesDialog reaches its
  build path; we tap the dialog's Close button to drain the
  spawned 2s pollLoop.
- TestBuildContextMenuRemoveActionTapsNo: invokes the Remove
  closure → confirm dialog → tap "No" so the goroutine never
  spawns.

buildContextMenu: 96.4% → 100%. gui pkg total: 88.5% → 88.6%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Run buildStatusTab.pollLoop and buildCompanionTab.pollLoop in
background goroutines for 4.3 seconds — past their 4-second
ticker interval — so the case <-tick.C arm fires once. Then
cancel ctx and drain. Both refresh paths fyne.Do label
updates; race-clean across the full gui suite.

status.pollLoop: 85.7% → 100%, companion.pollLoop: 85.7% → 100%.
gui pkg total: 88.6% → 88.8%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A real torrent in the engine makes setAllPriorities's
SetFilePriority calls succeed → no err-dialog rendering, no
font-cache race. Tap each bulk button via the overlay walker.

files_dialog.build: 86.0% → 89.5%. gui pkg total: 88.8% → 88.9%.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror autofillName's pattern for the Output path: when the user
picks a root via Choose File/Folder or types into the Root entry,
populate "<root>.torrent" into outEntry. Only overwrite when the
field is empty or still matches the previous auto-fill so a
hand-edited path survives re-browsing.

Eliminates the "Output path required" error users hit on Create
after picking a root but before picking an output — a needless
UX papercut visible in the user's recent screenshot.

Update TestCreateTorrentDialogConfirmArms to clear outEntry
before submitting the empty-output variant, since the dialog
now populates it on its own.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three-case test against the autofill closure:
- Fresh dialog → typing into Root populates Output as
  "<root>.torrent".
- User-edited Output is preserved across subsequent Root
  edits.
- Trailing slash on Root (folder mode) is stripped before the
  ".torrent" suffix so /a/b/ → /a/b.torrent rather than
  /a/b/.torrent.
@claudenstein
claudenstein merged commit 9a23f87 into main Apr 29, 2026
1 check failed
claudenstein pushed a commit that referenced this pull request Jul 19, 2026
Closes the round-4 adversarial backlog; each fix has a regression test that
fails when the fix is neutralized. All touched packages race-clean.

- #10 companion: put the new BEP-46 pointer BEFORE dropping the old seed, so a
  failed put keeps the still-advertised infohash fetchable.
- #7 dhtindex: TOCTOU between off-lock aggregate Refresh and a concurrent
  Retract — added a gen counter + post-distribute re-check so a retracted tree
  isn't left published for a full refresh interval.
- #9 indexer/httpapi/daemon: a malformed query string is now a typed
  ErrBadQuery → HTTP 400 (client fault), not 500; classified at the daemon
  seam via a LocalBadRequest flag (httpapi imports no indexer types).
- #5 companion: publisher GeneratedAt is now strictly monotonic across content
  changes, so a backward wall-clock step no longer trips the follower's replay
  guard and drops legitimate new content.
- #11 companion: an Unfollow racing an in-flight Sync no longer resurrects the
  dedup maps — per-publisher Forget epoch, re-checked under lock in commitDedup.
- #4 engine: persistAdd runs after Add releases e.mu; a racing RemoveTorrent
  could be resurrected — updateGuarded(abort) + Handle.isRemoved() make the
  create happens-before-correct (RemoveTorrent closes h.removed before its
  lock-guarded remove); persistSeedAdd DataPath refinement → updateExisting.
- #8 swarmsearch: initiator/responder txid collision deferred with a fix sketch
  (needs a wire direction bit + the unwired StartSync path) — see DECISIONS T3-8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant