1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
// Detach returns a context that keeps all the values of its parent context
// but detaches from the cancellation and error handling.
func Detach(ctx context.Context) context.Context { return detachedContext{ctx} }
type detachedContext struct{ parent context.Context }
func (v detachedContext) Deadline() (time.Time, bool) { return time.Time{}, false }
func (v detachedContext) Done() <-chan struct{} { return nil }
func (v detachedContext) Err() error { return nil }
func (v detachedContext) Value(key interface{}) interface{} { return v.parent.Value(key) }
func TestDetach(t *testing.T) {
type ctxKey string
var key = ctxKey("key")
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
ctx = context.WithValue(ctx, key, "value")
dctx := Detach(ctx)
// Detached context has the same values.
got, ok := dctx.Value(key).(string)
if !ok || got != "value" {
t.Errorf("Value: got (%v, %t), want 'value', true", got, ok)
}
// Detached context doesn't time out.
time.Sleep(500 * time.Millisecond)
if err := ctx.Err(); err != context.DeadlineExceeded {
t.Fatalf("original context Err: got %v, want DeadlineExceeded", err)
}
if err := dctx.Err(); err != nil {
t.Errorf("detached context Err: got %v, want nil", err)
}
}
|