-
Notifications
You must be signed in to change notification settings - Fork 1
/
rununtil_test.go
172 lines (148 loc) · 4.32 KB
/
rununtil_test.go
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package rununtil_test
import (
"os"
"syscall"
"testing"
"time"
"github.com/mec07/rununtil"
)
func helperSendSignal(t *testing.T, p *os.Process, sent *bool, signal os.Signal, delay time.Duration) {
time.Sleep(delay)
if err := p.Signal(signal); err != nil {
t.Errorf("unexpected error occurred: %v", err)
}
*sent = true
}
func helperMakeFakeRunner(hasBeenShutdown *bool) rununtil.RunnerFunc {
return rununtil.RunnerFunc(func() rununtil.ShutdownFunc {
return rununtil.ShutdownFunc(func() {
*hasBeenShutdown = true
})
})
}
func helperMakeMain(hasBeenKilled *bool) func() {
return func() {
rununtil.AwaitKillSignal(helperMakeFakeRunner(hasBeenKilled))
}
}
func TestRununtilAwaitKillSignal(t *testing.T) {
table := []struct {
name string
signal os.Signal
}{
{
name: "Shutdown from SIGINT",
signal: syscall.SIGINT,
},
{
name: "Shutdown from SIGTERM",
signal: syscall.SIGTERM,
},
}
for _, test := range table {
t.Run(test.name, func(t *testing.T) {
var sentSignal bool
var hasBeenShutdown bool
p, err := os.FindProcess(os.Getpid())
if err != nil {
t.Fatalf("Unexpected error when finding process: %v", err)
}
go helperSendSignal(t, p, &sentSignal, test.signal, 1*time.Millisecond)
rununtil.AwaitKillSignal(helperMakeFakeRunner(&hasBeenShutdown))
if !sentSignal {
t.Fatal("expected signal to have been sent")
}
if !hasBeenShutdown {
t.Fatal("expected the shutdown function to have been called")
}
})
}
}
func TestRununtilAwaitKillSignal_MultipleRunnerFuncs(t *testing.T) {
var hasBeenShutdown1, hasBeenShutdown2, hasBeenShutdown3 bool
var sentSignal bool
p, err := os.FindProcess(os.Getpid())
if err != nil {
t.Fatalf("Unexpected error when finding process: %v", err)
}
go helperSendSignal(t, p, &sentSignal, syscall.SIGINT, time.Millisecond)
rununtil.AwaitKillSignal(
helperMakeFakeRunner(&hasBeenShutdown1),
helperMakeFakeRunner(&hasBeenShutdown2),
helperMakeFakeRunner(&hasBeenShutdown3),
)
if !sentSignal {
t.Fatal("expected signal to have been sent")
}
if !hasBeenShutdown1 {
t.Fatal("expected the shutdown function 1 to have been called")
}
if !hasBeenShutdown2 {
t.Fatal("expected the shutdown function 2 to have been called")
}
if !hasBeenShutdown3 {
t.Fatal("expected the shutdown function 3 to have been called")
}
}
func TestRununtilKilled(t *testing.T) {
var hasBeenKilled bool
cancel := rununtil.Killed(helperMakeMain(&hasBeenKilled))
cancel()
// yield control back to scheduler so that killing can actually happen
time.Sleep(time.Millisecond)
if !hasBeenKilled {
t.Fatal("expected main to have been killed")
}
}
func TestRununtilCancelAll(t *testing.T) {
var hasBeenKilled bool
rununtil.Killed(helperMakeMain(&hasBeenKilled))
// yield control back to scheduler so that the go routines can actually
// start
time.Sleep(time.Millisecond)
rununtil.CancelAll()
// yield control back to scheduler so that killing can actually happen
time.Sleep(time.Millisecond)
if !hasBeenKilled {
t.Fatal("expected main to have been killed")
}
}
func TestRununtilCancelAll_MultipleTimes(t *testing.T) {
var hasBeenKilled bool
for idx := 0; idx < 100; idx++ {
hasBeenKilled = false
rununtil.Killed(helperMakeMain(&hasBeenKilled))
// yield control back to scheduler so that the go routines can actually
// start
time.Sleep(time.Millisecond)
rununtil.CancelAll()
// yield control back to scheduler so that killing can actually happen
time.Sleep(time.Millisecond)
if !hasBeenKilled {
t.Fatal("expected main to have been killed")
}
}
}
func TestRununtilCancelAll_Threadsafe(t *testing.T) {
var hasBeenKilledVec [100]bool
for idx := 0; idx < 100; idx++ {
cancel := rununtil.Killed(helperMakeMain(&hasBeenKilledVec[idx]))
cancel()
rununtil.CancelAll()
}
// yield control back to scheduler so that killing can actually happen
time.Sleep(time.Millisecond)
for idx, hasBeenKilled := range hasBeenKilledVec {
if !hasBeenKilled {
t.Fatalf("expected main to have been killed: %d", idx)
}
}
}
// Annoyingly this test has to be run by itself to actually fail...
// go test -v -run TestKilled_FailsForNonblockingMain
// Fixed test by not actually sending a kill signal anymore --
// it now calls rununtil.CancelAll().
func TestKilled_FailsForNonblockingMain(t *testing.T) {
cancel := rununtil.Killed(func() {})
cancel()
}