test(daemon): repair vacuous session-isolation assertion; drop dead seq bump
TestNotifyRoutesToSessionClientOnly compared against a client from a second, unrelated Daemon fixture, so the isolation check passed regardless of whether session-scoped routing actually fanned out. Build the second session/client on the same daemon (matching TestNotifyGlobalFansOutToAttachedClients) so the assertion exercises real routing. Also drop the dead noticeSeq bump and seq stamp in showToast's prepend branch: retainToastTimerLocked immediately re-bumps and re-stamps seq before the timer arms, making the first assignment misleading dead code.
- commit
- 04dc9834000f628b527cceed1c88ccb2a22e5e20
- author
- brice · · 2026-07-20 12:35 UTC
- parent
- 57a5dbb
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +11 -5
M internal/usecase/daemon/notify.go +1 -2
| @@ -229,8 +229,7 @@ func (d *Daemon) showToast(ac *attachedClient, n domain.Notification) { | |||
| 229 | 229 | return | |
| 230 | 230 | } | |
| 231 | 231 | ||
| 232 | - | rt.noticeSeq++ | |
| 233 | - | toast := noticeToast{n: n, seq: rt.noticeSeq} | |
| 232 | + | toast := noticeToast{n: n} | |
| 234 | 233 | rt.noticeToasts = append([]noticeToast{toast}, rt.noticeToasts...) | |
| 235 | 234 | if len(rt.noticeToasts) > maxVisibleToasts { | |
| 236 | 235 | for i := maxVisibleToasts; i < len(rt.noticeToasts); i++ { | |
| @@ -229,8 +229,7 @@ func (d *Daemon) showToast(ac *attachedClient, n domain.Notification) { | |||||
| 229 | return | 229 | return | ||
| 230 | } | 230 | } | ||
| 231 | 231 | ||||
| 232 | - | rt.noticeSeq++ | 232 | + | toast := noticeToast{n: n} |
| 233 | - | toast := noticeToast{n: n, seq: rt.noticeSeq} | |||
| 234 | rt.noticeToasts = append([]noticeToast{toast}, rt.noticeToasts...) | 233 | rt.noticeToasts = append([]noticeToast{toast}, rt.noticeToasts...) | ||
| 235 | if len(rt.noticeToasts) > maxVisibleToasts { | 234 | if len(rt.noticeToasts) > maxVisibleToasts { | ||
| 236 | for i := maxVisibleToasts; i < len(rt.noticeToasts); i++ { | 235 | for i := maxVisibleToasts; i < len(rt.noticeToasts); i++ { | ||
M internal/usecase/daemon/notify_test.go +10 -3
| @@ -367,14 +367,21 @@ func TestReportErrorNonBenignIsNeverDropped(t *testing.T) { | |||
| 367 | 367 | ||
| 368 | 368 | func TestNotifyRoutesToSessionClientOnly(t *testing.T) { | |
| 369 | 369 | d, sess, ac, _ := newNoticeFixture(t, newNoticeClock()) | |
| 370 | - | _, _, otherAC, _ := newNoticeFixture(t, newNoticeClock()) | |
| 370 | + | ||
| 371 | + | other := &attachedClient{output: newOutputStateStream(), size: domain.Size{Cols: 80, Rows: 24}} | |
| 372 | + | other.initOverlays() | |
| 373 | + | sess2 := &session{id: "manual-2", name: "other", ctx: sess.ctx, cancel: func() {}, client: other} | |
| 374 | + | other.setSession(sess2) | |
| 375 | + | d.mu.Lock() | |
| 376 | + | d.sessions[sess2.id] = sess2 | |
| 377 | + | d.mu.Unlock() | |
| 371 | 378 | ||
| 372 | 379 | d.notify(sess, domain.NoticeInfo, domain.NoticeClipboard, "copied", nil) | |
| 373 | 380 | ||
| 374 | 381 | toasts := awaitToastCount(t, ac, 1) | |
| 375 | 382 | require.Equal(t, sess.id, toasts[0].SessionID) | |
| 376 | - | otherToasts, _ := visibleToasts(otherAC) | |
| 377 | - | require.Empty(t, otherToasts, "another daemon's client must be untouched") | |
| 383 | + | otherToasts, _ := visibleToasts(other) | |
| 384 | + | require.Empty(t, otherToasts, "another session's client must be untouched by session-scoped notices") | |
| 378 | 385 | } | |
| 379 | 386 | ||
| 380 | 387 | func TestNotifySessionWithoutClientRecordsHistoryOnly(t *testing.T) { | |
| @@ -367,14 +367,21 @@ func TestReportErrorNonBenignIsNeverDropped(t *testing.T) { | |||||
| 367 | 367 | ||||
| 368 | func TestNotifyRoutesToSessionClientOnly(t *testing.T) { | 368 | func TestNotifyRoutesToSessionClientOnly(t *testing.T) { | ||
| 369 | d, sess, ac, _ := newNoticeFixture(t, newNoticeClock()) | 369 | d, sess, ac, _ := newNoticeFixture(t, newNoticeClock()) | ||
| 370 | - | _, _, otherAC, _ := newNoticeFixture(t, newNoticeClock()) | 370 | + | |
| 371 | + | other := &attachedClient{output: newOutputStateStream(), size: domain.Size{Cols: 80, Rows: 24}} | |||
| 372 | + | other.initOverlays() | |||
| 373 | + | sess2 := &session{id: "manual-2", name: "other", ctx: sess.ctx, cancel: func() {}, client: other} | |||
| 374 | + | other.setSession(sess2) | |||
| 375 | + | d.mu.Lock() | |||
| 376 | + | d.sessions[sess2.id] = sess2 | |||
| 377 | + | d.mu.Unlock() | |||
| 371 | 378 | ||||
| 372 | d.notify(sess, domain.NoticeInfo, domain.NoticeClipboard, "copied", nil) | 379 | d.notify(sess, domain.NoticeInfo, domain.NoticeClipboard, "copied", nil) | ||
| 373 | 380 | ||||
| 374 | toasts := awaitToastCount(t, ac, 1) | 381 | toasts := awaitToastCount(t, ac, 1) | ||
| 375 | require.Equal(t, sess.id, toasts[0].SessionID) | 382 | require.Equal(t, sess.id, toasts[0].SessionID) | ||
| 376 | - | otherToasts, _ := visibleToasts(otherAC) | 383 | + | otherToasts, _ := visibleToasts(other) |
| 377 | - | require.Empty(t, otherToasts, "another daemon's client must be untouched") | 384 | + | require.Empty(t, otherToasts, "another session's client must be untouched by session-scoped notices") |
| 378 | } | 385 | } | ||
| 379 | 386 | ||||
| 380 | func TestNotifySessionWithoutClientRecordsHistoryOnly(t *testing.T) { | 387 | func TestNotifySessionWithoutClientRecordsHistoryOnly(t *testing.T) { | ||