@cryptotaxi247 / kubo / commits / ec96a0b0b

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 +}