fix(client): address reconnect toast review feedback
- commit
- 25fad494b7a380cda29328a012f47f15f37ed28e
- author
- brice · · 2026-07-06 01:26 UTC
- parent
- 8a56e91
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +58 -35
M internal/usecase/client/client.go +8 -8
| @@ -209,9 +209,9 @@ func Run(ctx context.Context, dialer ports.Dialer, term ports.Terminal, clk port | |||
| 209 | 209 | } | |
| 210 | 210 | sleepWhileReconnecting := func(d time.Duration) bool { | |
| 211 | 211 | if remote && showingStatus { | |
| 212 | - | return reconnectSleepWithResize(ctx, d, term.ResizeEvents(), redrawRemoteStatus) | |
| 212 | + | return reconnectSleepWithResize(ctx, clk, d, term.ResizeEvents(), redrawRemoteStatus) | |
| 213 | 213 | } | |
| 214 | - | return reconnectSleep(ctx, d) | |
| 214 | + | return reconnectSleep(ctx, clk, d) | |
| 215 | 215 | } | |
| 216 | 216 | ||
| 217 | 217 | for { | |
| @@ -260,23 +260,23 @@ func Run(ctx context.Context, dialer ports.Dialer, term ports.Terminal, clk port | |||
| 260 | 260 | } | |
| 261 | 261 | } | |
| 262 | 262 | ||
| 263 | - | func sleepReconnect(ctx context.Context, d time.Duration) bool { | |
| 264 | - | t := time.NewTimer(d) | |
| 263 | + | func sleepReconnect(ctx context.Context, clk ports.Clock, d time.Duration) bool { | |
| 264 | + | t := clk.NewTimer(d) | |
| 265 | 265 | defer t.Stop() | |
| 266 | 266 | select { | |
| 267 | - | case <-t.C: | |
| 267 | + | case <-t.C(): | |
| 268 | 268 | return true | |
| 269 | 269 | case <-ctx.Done(): | |
| 270 | 270 | return false | |
| 271 | 271 | } | |
| 272 | 272 | } | |
| 273 | 273 | ||
| 274 | - | func sleepReconnectWithResizeEvents(ctx context.Context, d time.Duration, resizeEvents <-chan domain.Size, onResize func(domain.Size)) bool { | |
| 275 | - | t := time.NewTimer(d) | |
| 274 | + | func sleepReconnectWithResizeEvents(ctx context.Context, clk ports.Clock, d time.Duration, resizeEvents <-chan domain.Size, onResize func(domain.Size)) bool { | |
| 275 | + | t := clk.NewTimer(d) | |
| 276 | 276 | defer t.Stop() | |
| 277 | 277 | for { | |
| 278 | 278 | select { | |
| 279 | - | case <-t.C: | |
| 279 | + | case <-t.C(): | |
| 280 | 280 | return true | |
| 281 | 281 | case <-ctx.Done(): | |
| 282 | 282 | return false | |
| @@ -209,9 +209,9 @@ func Run(ctx context.Context, dialer ports.Dialer, term ports.Terminal, clk port | |||||
| 209 | } | 209 | } | ||
| 210 | sleepWhileReconnecting := func(d time.Duration) bool { | 210 | sleepWhileReconnecting := func(d time.Duration) bool { | ||
| 211 | if remote && showingStatus { | 211 | if remote && showingStatus { | ||
| 212 | - | return reconnectSleepWithResize(ctx, d, term.ResizeEvents(), redrawRemoteStatus) | 212 | + | return reconnectSleepWithResize(ctx, clk, d, term.ResizeEvents(), redrawRemoteStatus) |
| 213 | } | 213 | } | ||
| 214 | - | return reconnectSleep(ctx, d) | 214 | + | return reconnectSleep(ctx, clk, d) |
| 215 | } | 215 | } | ||
| 216 | 216 | ||||
| 217 | for { | 217 | for { | ||
| @@ -260,23 +260,23 @@ func Run(ctx context.Context, dialer ports.Dialer, term ports.Terminal, clk port | |||||
| 260 | } | 260 | } | ||
| 261 | } | 261 | } | ||
| 262 | 262 | ||||
| 263 | - | func sleepReconnect(ctx context.Context, d time.Duration) bool { | 263 | + | func sleepReconnect(ctx context.Context, clk ports.Clock, d time.Duration) bool { |
| 264 | - | t := time.NewTimer(d) | 264 | + | t := clk.NewTimer(d) |
| 265 | defer t.Stop() | 265 | defer t.Stop() | ||
| 266 | select { | 266 | select { | ||
| 267 | - | case <-t.C: | 267 | + | case <-t.C(): |
| 268 | return true | 268 | return true | ||
| 269 | case <-ctx.Done(): | 269 | case <-ctx.Done(): | ||
| 270 | return false | 270 | return false | ||
| 271 | } | 271 | } | ||
| 272 | } | 272 | } | ||
| 273 | 273 | ||||
| 274 | - | func sleepReconnectWithResizeEvents(ctx context.Context, d time.Duration, resizeEvents <-chan domain.Size, onResize func(domain.Size)) bool { | 274 | + | func sleepReconnectWithResizeEvents(ctx context.Context, clk ports.Clock, d time.Duration, resizeEvents <-chan domain.Size, onResize func(domain.Size)) bool { |
| 275 | - | t := time.NewTimer(d) | 275 | + | t := clk.NewTimer(d) |
| 276 | defer t.Stop() | 276 | defer t.Stop() | ||
| 277 | for { | 277 | for { | ||
| 278 | select { | 278 | select { | ||
| 279 | - | case <-t.C: | 279 | + | case <-t.C(): |
| 280 | return true | 280 | return true | ||
| 281 | case <-ctx.Done(): | 281 | case <-ctx.Done(): | ||
| 282 | return false | 282 | return false | ||
M internal/usecase/client/reconnect_toast.go +2 -2
| @@ -68,10 +68,10 @@ func writeReconnectToast(out io.Writer, bounds domain.Rect, lines []string) erro | |||
| 68 | 68 | return err | |
| 69 | 69 | } | |
| 70 | 70 | for i, line := range lines { | |
| 71 | - | if _, err := fmt.Fprintf(out, "\x1b[%d;%dH%s", bounds.Y+i+1, bounds.X+1, line); err != nil { | |
| 71 | + | if _, err := fmt.Fprintf(out, "\x1b[%d;%dH\x1b[0m%s", bounds.Y+i+1, bounds.X+1, line); err != nil { | |
| 72 | 72 | return err | |
| 73 | 73 | } | |
| 74 | 74 | } | |
| 75 | - | _, err := io.WriteString(out, "\x1b[u") | |
| 75 | + | _, err := io.WriteString(out, "\x1b[0m\x1b[u") | |
| 76 | 76 | return err | |
| 77 | 77 | } | |
| @@ -68,10 +68,10 @@ func writeReconnectToast(out io.Writer, bounds domain.Rect, lines []string) erro | |||||
| 68 | return err | 68 | return err | ||
| 69 | } | 69 | } | ||
| 70 | for i, line := range lines { | 70 | for i, line := range lines { | ||
| 71 | - | if _, err := fmt.Fprintf(out, "\x1b[%d;%dH%s", bounds.Y+i+1, bounds.X+1, line); err != nil { | 71 | + | if _, err := fmt.Fprintf(out, "\x1b[%d;%dH\x1b[0m%s", bounds.Y+i+1, bounds.X+1, line); err != nil { |
| 72 | return err | 72 | return err | ||
| 73 | } | 73 | } | ||
| 74 | } | 74 | } | ||
| 75 | - | _, err := io.WriteString(out, "\x1b[u") | 75 | + | _, err := io.WriteString(out, "\x1b[0m\x1b[u") |
| 76 | return err | 76 | return err | ||
| 77 | } | 77 | } | ||
M internal/usecase/client/reconnect_toast_test.go +48 -25
| @@ -18,18 +18,28 @@ import ( | |||
| 18 | 18 | "github.com/bnema/vev/pkg/renderer" | |
| 19 | 19 | ) | |
| 20 | 20 | ||
| 21 | - | type reconnectToastClock struct{} | |
| 21 | + | type reconnectToastClock struct { | |
| 22 | + | timer *reconnectToastTimer | |
| 23 | + | created chan struct{} | |
| 24 | + | } | |
| 25 | + | ||
| 26 | + | func newReconnectToastClock() *reconnectToastClock { | |
| 27 | + | return &reconnectToastClock{created: make(chan struct{})} | |
| 28 | + | } | |
| 22 | 29 | ||
| 23 | - | func (reconnectToastClock) Now() time.Time { return time.Now() } | |
| 24 | - | func (reconnectToastClock) NewTimer(d time.Duration) ports.Timer { | |
| 25 | - | return &reconnectToastTimer{t: time.NewTimer(d)} | |
| 30 | + | func (*reconnectToastClock) Now() time.Time { return time.Time{} } | |
| 31 | + | func (c *reconnectToastClock) NewTimer(time.Duration) ports.Timer { | |
| 32 | + | c.timer = &reconnectToastTimer{ch: make(chan time.Time, 1)} | |
| 33 | + | close(c.created) | |
| 34 | + | return c.timer | |
| 26 | 35 | } | |
| 27 | 36 | ||
| 28 | - | type reconnectToastTimer struct{ t *time.Timer } | |
| 37 | + | type reconnectToastTimer struct{ ch chan time.Time } | |
| 29 | 38 | ||
| 30 | - | func (t *reconnectToastTimer) C() <-chan time.Time { return t.t.C } | |
| 31 | - | func (t *reconnectToastTimer) Reset(d time.Duration) bool { return t.t.Reset(d) } | |
| 32 | - | func (t *reconnectToastTimer) Stop() bool { return t.t.Stop() } | |
| 39 | + | func (t *reconnectToastTimer) C() <-chan time.Time { return t.ch } | |
| 40 | + | func (t *reconnectToastTimer) Reset(time.Duration) bool { return true } | |
| 41 | + | func (t *reconnectToastTimer) Stop() bool { return true } | |
| 42 | + | func (t *reconnectToastTimer) fire() { t.ch <- time.Time{} } | |
| 33 | 43 | ||
| 34 | 44 | type reconnectToastDialer struct { | |
| 35 | 45 | trs []ports.Transport | |
| @@ -115,6 +125,7 @@ func TestReconnectToastDrawAndClearHelpers(t *testing.T) { | |||
| 115 | 125 | require.NoError(t, drawReconnectToast(&out, size)) | |
| 116 | 126 | require.Contains(t, out.String(), "┌") | |
| 117 | 127 | require.Contains(t, out.String(), reconnectToastMessage) | |
| 128 | + | require.Contains(t, out.String(), "\x1b[0m") | |
| 118 | 129 | ||
| 119 | 130 | require.NoError(t, clearReconnectToast(&out, size)) | |
| 120 | 131 | bounds := reconnectToastBounds(size) | |
| @@ -140,23 +151,33 @@ func displayWidth(s string) int { | |||
| 140 | 151 | } | |
| 141 | 152 | ||
| 142 | 153 | func TestReconnectSleepWithResizeEventsRedrawsUntilTimerFires(t *testing.T) { | |
| 143 | - | resizeCh := make(chan domain.Size, 1) | |
| 154 | + | clk := newReconnectToastClock() | |
| 155 | + | resizeCh := make(chan domain.Size, 2) | |
| 144 | 156 | resizeCh <- domain.Size{Cols: 100, Rows: 30} | |
| 145 | - | var got domain.Size | |
| 146 | - | ||
| 147 | - | ok := sleepReconnectWithResizeEvents(context.Background(), time.Millisecond, resizeCh, func(size domain.Size) { | |
| 148 | - | got = size | |
| 149 | - | }) | |
| 157 | + | resizeCh <- domain.Size{Cols: 120, Rows: 40} | |
| 158 | + | got := make(chan domain.Size, 2) | |
| 159 | + | done := make(chan bool, 1) | |
| 160 | + | ||
| 161 | + | go func() { | |
| 162 | + | done <- sleepReconnectWithResizeEvents(context.Background(), clk, time.Hour, resizeCh, func(size domain.Size) { | |
| 163 | + | got <- size | |
| 164 | + | }) | |
| 165 | + | }() | |
| 150 | 166 | ||
| 151 | - | require.True(t, ok) | |
| 152 | - | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, got) | |
| 167 | + | <-clk.created | |
| 168 | + | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, <-got) | |
| 169 | + | require.Equal(t, domain.Size{Cols: 120, Rows: 40}, <-got) | |
| 170 | + | clk.timer.fire() | |
| 171 | + | require.True(t, <-done) | |
| 153 | 172 | } | |
| 154 | 173 | ||
| 155 | 174 | func TestRemoteReconnectToastClearsOnSuccessfulReconnect(t *testing.T) { | |
| 156 | 175 | oldSleep := reconnectSleep | |
| 157 | 176 | oldSleepWithResize := reconnectSleepWithResize | |
| 158 | - | reconnectSleep = func(context.Context, time.Duration) bool { return true } | |
| 159 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { return true } | |
| 177 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { return true } | |
| 178 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { | |
| 179 | + | return true | |
| 180 | + | } | |
| 160 | 181 | defer func() { | |
| 161 | 182 | reconnectSleep = oldSleep | |
| 162 | 183 | reconnectSleepWithResize = oldSleepWithResize | |
| @@ -168,7 +189,7 @@ func TestRemoteReconnectToastClearsOnSuccessfulReconnect(t *testing.T) { | |||
| 168 | 189 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonDetach)}}} | |
| 169 | 190 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | |
| 170 | 191 | ||
| 171 | - | err := Run(context.Background(), dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 192 | + | err := Run(context.Background(), dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 172 | 193 | require.NoError(t, err) | |
| 173 | 194 | out := term.out.String() | |
| 174 | 195 | require.Contains(t, out, reconnectToastMessage) | |
| @@ -179,11 +200,11 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||
| 179 | 200 | oldSleep := reconnectSleep | |
| 180 | 201 | oldSleepWithResize := reconnectSleepWithResize | |
| 181 | 202 | ctx, cancel := context.WithCancel(context.Background()) | |
| 182 | - | reconnectSleep = func(context.Context, time.Duration) bool { | |
| 203 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { | |
| 183 | 204 | cancel() | |
| 184 | 205 | return false | |
| 185 | 206 | } | |
| 186 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { | |
| 207 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { | |
| 187 | 208 | cancel() | |
| 188 | 209 | return false | |
| 189 | 210 | } | |
| @@ -197,7 +218,7 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||
| 197 | 218 | tr := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(11)}, {err: io.EOF}}} | |
| 198 | 219 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr}} | |
| 199 | 220 | ||
| 200 | - | err := Run(ctx, dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 221 | + | err := Run(ctx, dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 201 | 222 | require.ErrorIs(t, err, context.Canceled) | |
| 202 | 223 | out := term.out.String() | |
| 203 | 224 | require.Contains(t, out, reconnectToastMessage) | |
| @@ -207,8 +228,10 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||
| 207 | 228 | func TestRemoteReconnectToastClearsOnFinalExit(t *testing.T) { | |
| 208 | 229 | oldSleep := reconnectSleep | |
| 209 | 230 | oldSleepWithResize := reconnectSleepWithResize | |
| 210 | - | reconnectSleep = func(context.Context, time.Duration) bool { return true } | |
| 211 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { return true } | |
| 231 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { return true } | |
| 232 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { | |
| 233 | + | return true | |
| 234 | + | } | |
| 212 | 235 | defer func() { | |
| 213 | 236 | reconnectSleep = oldSleep | |
| 214 | 237 | reconnectSleepWithResize = oldSleepWithResize | |
| @@ -220,7 +243,7 @@ func TestRemoteReconnectToastClearsOnFinalExit(t *testing.T) { | |||
| 220 | 243 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonSessionKilled)}}} | |
| 221 | 244 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | |
| 222 | 245 | ||
| 223 | - | err := Run(context.Background(), dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 246 | + | err := Run(context.Background(), dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | |
| 224 | 247 | var detached *DetachedError | |
| 225 | 248 | require.True(t, errors.As(err, &detached)) | |
| 226 | 249 | out := term.out.String() | |
| @@ -18,18 +18,28 @@ import ( | |||||
| 18 | "github.com/bnema/vev/pkg/renderer" | 18 | "github.com/bnema/vev/pkg/renderer" | ||
| 19 | ) | 19 | ) | ||
| 20 | 20 | ||||
| 21 | - | type reconnectToastClock struct{} | 21 | + | type reconnectToastClock struct { |
| 22 | + | timer *reconnectToastTimer | |||
| 23 | + | created chan struct{} | |||
| 24 | + | } | |||
| 25 | + | ||||
| 26 | + | func newReconnectToastClock() *reconnectToastClock { | |||
| 27 | + | return &reconnectToastClock{created: make(chan struct{})} | |||
| 28 | + | } | |||
| 22 | 29 | ||||
| 23 | - | func (reconnectToastClock) Now() time.Time { return time.Now() } | 30 | + | func (*reconnectToastClock) Now() time.Time { return time.Time{} } |
| 24 | - | func (reconnectToastClock) NewTimer(d time.Duration) ports.Timer { | 31 | + | func (c *reconnectToastClock) NewTimer(time.Duration) ports.Timer { |
| 25 | - | return &reconnectToastTimer{t: time.NewTimer(d)} | 32 | + | c.timer = &reconnectToastTimer{ch: make(chan time.Time, 1)} |
| 33 | + | close(c.created) | |||
| 34 | + | return c.timer | |||
| 26 | } | 35 | } | ||
| 27 | 36 | ||||
| 28 | - | type reconnectToastTimer struct{ t *time.Timer } | 37 | + | type reconnectToastTimer struct{ ch chan time.Time } |
| 29 | 38 | ||||
| 30 | - | func (t *reconnectToastTimer) C() <-chan time.Time { return t.t.C } | 39 | + | func (t *reconnectToastTimer) C() <-chan time.Time { return t.ch } |
| 31 | - | func (t *reconnectToastTimer) Reset(d time.Duration) bool { return t.t.Reset(d) } | 40 | + | func (t *reconnectToastTimer) Reset(time.Duration) bool { return true } |
| 32 | - | func (t *reconnectToastTimer) Stop() bool { return t.t.Stop() } | 41 | + | func (t *reconnectToastTimer) Stop() bool { return true } |
| 42 | + | func (t *reconnectToastTimer) fire() { t.ch <- time.Time{} } | |||
| 33 | 43 | ||||
| 34 | type reconnectToastDialer struct { | 44 | type reconnectToastDialer struct { | ||
| 35 | trs []ports.Transport | 45 | trs []ports.Transport | ||
| @@ -115,6 +125,7 @@ func TestReconnectToastDrawAndClearHelpers(t *testing.T) { | |||||
| 115 | require.NoError(t, drawReconnectToast(&out, size)) | 125 | require.NoError(t, drawReconnectToast(&out, size)) | ||
| 116 | require.Contains(t, out.String(), "┌") | 126 | require.Contains(t, out.String(), "┌") | ||
| 117 | require.Contains(t, out.String(), reconnectToastMessage) | 127 | require.Contains(t, out.String(), reconnectToastMessage) | ||
| 128 | + | require.Contains(t, out.String(), "\x1b[0m") | |||
| 118 | 129 | ||||
| 119 | require.NoError(t, clearReconnectToast(&out, size)) | 130 | require.NoError(t, clearReconnectToast(&out, size)) | ||
| 120 | bounds := reconnectToastBounds(size) | 131 | bounds := reconnectToastBounds(size) | ||
| @@ -140,23 +151,33 @@ func displayWidth(s string) int { | |||||
| 140 | } | 151 | } | ||
| 141 | 152 | ||||
| 142 | func TestReconnectSleepWithResizeEventsRedrawsUntilTimerFires(t *testing.T) { | 153 | func TestReconnectSleepWithResizeEventsRedrawsUntilTimerFires(t *testing.T) { | ||
| 143 | - | resizeCh := make(chan domain.Size, 1) | 154 | + | clk := newReconnectToastClock() |
| 155 | + | resizeCh := make(chan domain.Size, 2) | |||
| 144 | resizeCh <- domain.Size{Cols: 100, Rows: 30} | 156 | resizeCh <- domain.Size{Cols: 100, Rows: 30} | ||
| 145 | - | var got domain.Size | 157 | + | resizeCh <- domain.Size{Cols: 120, Rows: 40} |
| 146 | - | 158 | + | got := make(chan domain.Size, 2) | |
| 147 | - | ok := sleepReconnectWithResizeEvents(context.Background(), time.Millisecond, resizeCh, func(size domain.Size) { | 159 | + | done := make(chan bool, 1) |
| 148 | - | got = size | 160 | + | |
| 149 | - | }) | 161 | + | go func() { |
| 162 | + | done <- sleepReconnectWithResizeEvents(context.Background(), clk, time.Hour, resizeCh, func(size domain.Size) { | |||
| 163 | + | got <- size | |||
| 164 | + | }) | |||
| 165 | + | }() | |||
| 150 | 166 | ||||
| 151 | - | require.True(t, ok) | 167 | + | <-clk.created |
| 152 | - | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, got) | 168 | + | require.Equal(t, domain.Size{Cols: 100, Rows: 30}, <-got) |
| 169 | + | require.Equal(t, domain.Size{Cols: 120, Rows: 40}, <-got) | |||
| 170 | + | clk.timer.fire() | |||
| 171 | + | require.True(t, <-done) | |||
| 153 | } | 172 | } | ||
| 154 | 173 | ||||
| 155 | func TestRemoteReconnectToastClearsOnSuccessfulReconnect(t *testing.T) { | 174 | func TestRemoteReconnectToastClearsOnSuccessfulReconnect(t *testing.T) { | ||
| 156 | oldSleep := reconnectSleep | 175 | oldSleep := reconnectSleep | ||
| 157 | oldSleepWithResize := reconnectSleepWithResize | 176 | oldSleepWithResize := reconnectSleepWithResize | ||
| 158 | - | reconnectSleep = func(context.Context, time.Duration) bool { return true } | 177 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { return true } |
| 159 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { return true } | 178 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { |
| 179 | + | return true | |||
| 180 | + | } | |||
| 160 | defer func() { | 181 | defer func() { | ||
| 161 | reconnectSleep = oldSleep | 182 | reconnectSleep = oldSleep | ||
| 162 | reconnectSleepWithResize = oldSleepWithResize | 183 | reconnectSleepWithResize = oldSleepWithResize | ||
| @@ -168,7 +189,7 @@ func TestRemoteReconnectToastClearsOnSuccessfulReconnect(t *testing.T) { | |||||
| 168 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonDetach)}}} | 189 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonDetach)}}} | ||
| 169 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | 190 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | ||
| 170 | 191 | ||||
| 171 | - | err := Run(context.Background(), dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | 192 | + | err := Run(context.Background(), dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) |
| 172 | require.NoError(t, err) | 193 | require.NoError(t, err) | ||
| 173 | out := term.out.String() | 194 | out := term.out.String() | ||
| 174 | require.Contains(t, out, reconnectToastMessage) | 195 | require.Contains(t, out, reconnectToastMessage) | ||
| @@ -179,11 +200,11 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||||
| 179 | oldSleep := reconnectSleep | 200 | oldSleep := reconnectSleep | ||
| 180 | oldSleepWithResize := reconnectSleepWithResize | 201 | oldSleepWithResize := reconnectSleepWithResize | ||
| 181 | ctx, cancel := context.WithCancel(context.Background()) | 202 | ctx, cancel := context.WithCancel(context.Background()) | ||
| 182 | - | reconnectSleep = func(context.Context, time.Duration) bool { | 203 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { |
| 183 | cancel() | 204 | cancel() | ||
| 184 | return false | 205 | return false | ||
| 185 | } | 206 | } | ||
| 186 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { | 207 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { |
| 187 | cancel() | 208 | cancel() | ||
| 188 | return false | 209 | return false | ||
| 189 | } | 210 | } | ||
| @@ -197,7 +218,7 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||||
| 197 | tr := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(11)}, {err: io.EOF}}} | 218 | tr := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(11)}, {err: io.EOF}}} | ||
| 198 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr}} | 219 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr}} | ||
| 199 | 220 | ||||
| 200 | - | err := Run(ctx, dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | 221 | + | err := Run(ctx, dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) |
| 201 | require.ErrorIs(t, err, context.Canceled) | 222 | require.ErrorIs(t, err, context.Canceled) | ||
| 202 | out := term.out.String() | 223 | out := term.out.String() | ||
| 203 | require.Contains(t, out, reconnectToastMessage) | 224 | require.Contains(t, out, reconnectToastMessage) | ||
| @@ -207,8 +228,10 @@ func TestRemoteReconnectToastClearsOnCancellation(t *testing.T) { | |||||
| 207 | func TestRemoteReconnectToastClearsOnFinalExit(t *testing.T) { | 228 | func TestRemoteReconnectToastClearsOnFinalExit(t *testing.T) { | ||
| 208 | oldSleep := reconnectSleep | 229 | oldSleep := reconnectSleep | ||
| 209 | oldSleepWithResize := reconnectSleepWithResize | 230 | oldSleepWithResize := reconnectSleepWithResize | ||
| 210 | - | reconnectSleep = func(context.Context, time.Duration) bool { return true } | 231 | + | reconnectSleep = func(context.Context, ports.Clock, time.Duration) bool { return true } |
| 211 | - | reconnectSleepWithResize = func(context.Context, time.Duration, <-chan domain.Size, func(domain.Size)) bool { return true } | 232 | + | reconnectSleepWithResize = func(context.Context, ports.Clock, time.Duration, <-chan domain.Size, func(domain.Size)) bool { |
| 233 | + | return true | |||
| 234 | + | } | |||
| 212 | defer func() { | 235 | defer func() { | ||
| 213 | reconnectSleep = oldSleep | 236 | reconnectSleep = oldSleep | ||
| 214 | reconnectSleepWithResize = oldSleepWithResize | 237 | reconnectSleepWithResize = oldSleepWithResize | ||
| @@ -220,7 +243,7 @@ func TestRemoteReconnectToastClearsOnFinalExit(t *testing.T) { | |||||
| 220 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonSessionKilled)}}} | 243 | tr2 := &reconnectToastTransport{recvs: []reconnectToastRecv{{frame: reconnectToastWelcome(22)}, {frame: reconnectToastDetach(ports.ReasonSessionKilled)}}} | ||
| 221 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | 244 | dialer := &reconnectToastDialer{trs: []ports.Transport{tr1, tr2}} | ||
| 222 | 245 | ||||
| 223 | - | err := Run(context.Background(), dialer, term, reconnectToastClock{}, ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) | 246 | + | err := Run(context.Background(), dialer, term, newReconnectToastClock(), ports.IntentAttach, "main", true, nil, slog.New(slog.DiscardHandler)) |
| 224 | var detached *DetachedError | 247 | var detached *DetachedError | ||
| 225 | require.True(t, errors.As(err, &detached)) | 248 | require.True(t, errors.As(err, &detached)) | ||
| 226 | out := term.out.String() | 249 | out := term.out.String() | ||