...
1
16
17 package ktesting
18
19 import (
20 "context"
21 "fmt"
22 "time"
23 )
24
25
26
27 func cleanupErr(testName string) error {
28 return canceledError(fmt.Sprintf("test %s is cleaning up", testName))
29 }
30
31 type canceledError string
32
33 func (c canceledError) Error() string { return string(c) }
34
35 func (c canceledError) Is(target error) bool {
36 return target == context.Canceled
37 }
38
39
40
41
42
43 func withTimeout(ctx context.Context, tb TB, timeout time.Duration, timeoutCause string) (context.Context, func(cause string)) {
44 tb.Helper()
45
46 now := time.Now()
47
48 cancelCtx, cancel := context.WithCancelCause(ctx)
49 after := time.NewTimer(timeout)
50 stopCtx, stop := context.WithCancel(ctx)
51 tb.Cleanup(func() {
52 cancel(cleanupErr(tb.Name()))
53 stop()
54 })
55 go func() {
56 select {
57 case <-stopCtx.Done():
58 after.Stop()
59
60
61 case <-after.C:
62 cancel(canceledError(timeoutCause))
63 }
64 }()
65
66
67 deadline := now.Add(timeout)
68 if parentDeadline, ok := ctx.Deadline(); ok {
69 if deadline.After(parentDeadline) {
70 deadline = parentDeadline
71 }
72 }
73
74
75 return deadlineContext{Context: cancelCtx, deadline: deadline}, func(cause string) {
76 var cancelCause error
77 if cause != "" {
78 cancelCause = canceledError(cause)
79 }
80 cancel(cancelCause)
81 }
82 }
83
84 type deadlineContext struct {
85 context.Context
86 deadline time.Time
87 }
88
89 func (d deadlineContext) Deadline() (time.Time, bool) {
90 return d.deadline, true
91 }
92
View as plain text