| 330 | } |
| 331 | |
| 332 | func (e *outExpecter) doMatchWithDeadline(ctx context.Context, name string, fn func(*bufio.Reader) error) error { |
| 333 | e.t.Helper() |
| 334 | |
| 335 | // A timeout is mandatory, caller can decide by passing a context |
| 336 | // that times out. |
| 337 | if _, ok := ctx.Deadline(); !ok { |
| 338 | timeout := testutil.WaitMedium |
| 339 | e.logf("%s ctx has no deadline, using %s", name, timeout) |
| 340 | var cancel context.CancelFunc |
| 341 | //nolint:gocritic // Rule guard doesn't detect that we're using testutil.Wait*. |
| 342 | ctx, cancel = context.WithTimeout(ctx, timeout) |
| 343 | defer cancel() |
| 344 | } |
| 345 | |
| 346 | match := make(chan error, 1) |
| 347 | go func() { |
| 348 | defer close(match) |
| 349 | match <- fn(e.runeReader) |
| 350 | }() |
| 351 | select { |
| 352 | case err := <-match: |
| 353 | return err |
| 354 | case <-ctx.Done(): |
| 355 | // Ensure goroutine is cleaned up before test exit, do not call |
| 356 | // (*outExpecter).close here to let the caller decide. |
| 357 | _ = e.out.Close() |
| 358 | <-match |
| 359 | |
| 360 | return xerrors.Errorf("match deadline exceeded: %w", ctx.Err()) |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | func (e *outExpecter) logf(format string, args ...interface{}) { |
| 365 | e.t.Helper() |