util: fractional context
Juan Batiz-Benet committed
Dec 20, 2014 at 22:28 UTC
ec96a0b0b5d0f78d00aeacf35eb7ccbe128bdd3d
2 files changed
+159
util/ctx/fracctx.go
new
+22
@@ -0,0 +1,22 @@
1
+package ctxutil
2
+
3
+import (
4
+ "time"
5
+
6
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7
+)
8
+
9
+func WithDeadlineFraction(ctx context.Context, fraction float64) (context.Context, context.CancelFunc) {
10
+ d, found := ctx.Deadline()
11
+ if !found { // no deadline
12
+ return context.WithCancel(ctx)
13
+ }
14
+
15
+ left := d.Sub(time.Now())
16
+ if left < 0 { // already passed...
17
+ return context.WithCancel(ctx)
18
+ }
19
+
20
+ left = time.Duration(float64(left) * fraction)
21
+ return context.WithTimeout(ctx, left)
22
+}
util/ctx/fracctx_test.go
new
+137
@@ -0,0 +1,137 @@
1
+package ctxutil
2
+
3
+import (
4
+ "testing"
5
+ "time"
6
+
7
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8
+)
9
+
10
+// this test is on the context tool itself, not our stuff. it's for sanity on ours.
11
+func TestDeadline(t *testing.T) {
12
+ ctx, _ := context.WithTimeout(context.Background(), 5*time.Millisecond)
13
+
14
+ select {
15
+ case <-ctx.Done():
16
+ t.Fatal("ended too early")
17
+ default:
18
+ }
19
+
20
+ <-time.After(6 * time.Millisecond)
21
+
22
+ select {
23
+ case <-ctx.Done():
24
+ default:
25
+ t.Fatal("ended too late")
26
+ }
27
+}
28
+
29
+func TestDeadlineFractionForever(t *testing.T) {
30
+
31
+ ctx, _ := WithDeadlineFraction(context.Background(), 0.5)
32
+
33
+ _, found := ctx.Deadline()
34
+ if found {
35
+ t.Fatal("should last forever")
36
+ }
37
+}
38
+
39
+func TestDeadlineFractionHalf(t *testing.T) {
40
+
41
+ ctx1, _ := context.WithTimeout(context.Background(), 10*time.Millisecond)
42
+ ctx2, _ := WithDeadlineFraction(ctx1, 0.5)
43
+
44
+ select {
45
+ case <-ctx1.Done():
46
+ t.Fatal("ctx1 ended too early")
47
+ case <-ctx2.Done():
48
+ t.Fatal("ctx2 ended too early")
49
+ default:
50
+ }
51
+
52
+ <-time.After(2 * time.Millisecond)
53
+
54
+ select {
55
+ case <-ctx1.Done():
56
+ t.Fatal("ctx1 ended too early")
57
+ case <-ctx2.Done():
58
+ t.Fatal("ctx2 ended too early")
59
+ default:
60
+ }
61
+
62
+ <-time.After(4 * time.Millisecond)
63
+
64
+ select {
65
+ case <-ctx1.Done():
66
+ t.Fatal("ctx1 ended too early")
67
+ case <-ctx2.Done():
68
+ default:
69
+ t.Fatal("ctx2 ended too late")
70
+ }
71
+
72
+ <-time.After(6 * time.Millisecond)
73
+
74
+ select {
75
+ case <-ctx1.Done():
76
+ default:
77
+ t.Fatal("ctx1 ended too late")
78
+ }
79
+
80
+}
81
+
82
+func TestDeadlineFractionCancel(t *testing.T) {
83
+
84
+ ctx1, cancel1 := context.WithTimeout(context.Background(), 10*time.Millisecond)
85
+ ctx2, cancel2 := WithDeadlineFraction(ctx1, 0.5)
86
+
87
+ select {
88
+ case <-ctx1.Done():
89
+ t.Fatal("ctx1 ended too early")
90
+ case <-ctx2.Done():
91
+ t.Fatal("ctx2 ended too early")
92
+ default:
93
+ }
94
+
95
+ cancel2()
96
+
97
+ select {
98
+ case <-ctx1.Done():
99
+ t.Fatal("ctx1 should NOT be cancelled")
100
+ case <-ctx2.Done():
101
+ default:
102
+ t.Fatal("ctx2 should be cancelled")
103
+ }
104
+
105
+ cancel1()
106
+
107
+ select {
108
+ case <-ctx1.Done():
109
+ case <-ctx2.Done():
110
+ default:
111
+ t.Fatal("ctx1 should be cancelled")
112
+ }
113
+
114
+}
115
+
116
+func TestDeadlineFractionObeysParent(t *testing.T) {
117
+
118
+ ctx1, cancel1 := context.WithTimeout(context.Background(), 10*time.Millisecond)
119
+ ctx2, _ := WithDeadlineFraction(ctx1, 0.5)
120
+
121
+ select {
122
+ case <-ctx1.Done():
123
+ t.Fatal("ctx1 ended too early")
124
+ case <-ctx2.Done():
125
+ t.Fatal("ctx2 ended too early")
126
+ default:
127
+ }
128
+
129
+ cancel1()
130
+
131
+ select {
132
+ case <-ctx2.Done():
133
+ default:
134
+ t.Fatal("ctx2 should be cancelled")
135
+ }
136
+
137
+}