package notify import ( "context" "errors" "sync" "sync/atomic" "testing" ) func TestSessionIsAliveHandlesUninitializedValue(t *testing.T) { var alive atomic.Value if sessionIsAlive(&alive) { t.Fatal("uninitialized alive should be false") } } func TestSessionMarkStartedUpdatesAliveAndStatus(t *testing.T) { var alive atomic.Value alive.Store(false) status := Status{Alive: false, Reason: "old", Err: errors.New("old")} var mu sync.Mutex sessionMarkStarted(&alive, &mu, &status) gotAlive, _ := alive.Load().(bool) if !gotAlive { t.Fatal("alive not marked true") } if !status.Alive || status.Reason != "" || status.Err != nil { t.Fatalf("unexpected status after start: %+v", status) } } func TestSessionMarkStoppedRunsCleanupAndStop(t *testing.T) { var alive atomic.Value alive.Store(true) status := Status{Alive: true} stopCtx, stopFn := context.WithCancel(context.Background()) defer stopFn() cleanupCalls := 0 boom := errors.New("boom") sessionMarkStopped(&alive, nil, &status, "stopped", boom, stopFn, func() { cleanupCalls++ }, func() { cleanupCalls++ }, ) gotAlive, _ := alive.Load().(bool) if gotAlive { t.Fatal("alive not marked false") } if status.Alive || status.Reason != "stopped" || !errors.Is(status.Err, boom) { t.Fatalf("unexpected status after stop: %+v", status) } if cleanupCalls != 2 { t.Fatalf("cleanupCalls = %d, want 2", cleanupCalls) } select { case <-stopCtx.Done(): default: t.Fatal("stop function was not called") } } func TestSessionStatusValueReturnsCopy(t *testing.T) { status := Status{Alive: true, Reason: "ok"} var mu sync.Mutex snapshot := sessionStatusValue(&mu, &status) status.Reason = "changed" if snapshot.Reason != "ok" { t.Fatalf("snapshot.Reason = %q, want ok", snapshot.Reason) } }