...
1
2
3
4 package interrupt_handler_test
5
6 import (
7 "syscall"
8 "time"
9
10 . "github.com/onsi/ginkgo/v2"
11 "github.com/onsi/ginkgo/v2/internal/interrupt_handler"
12 "github.com/onsi/ginkgo/v2/internal/parallel_support"
13 . "github.com/onsi/ginkgo/v2/internal/test_helpers"
14 . "github.com/onsi/gomega"
15 )
16
17 var _ = Describe("InterruptHandler", func() {
18 var trigger func()
19 var interruptHandler *interrupt_handler.InterruptHandler
20 BeforeEach(func() {
21 trigger = func() {
22 syscall.Kill(syscall.Getpid(), syscall.SIGUSR2)
23 }
24 })
25
26 Describe("Signal interrupts", func() {
27 BeforeEach(func() {
28 interruptHandler = interrupt_handler.NewInterruptHandler(nil, syscall.SIGUSR2)
29 DeferCleanup(interruptHandler.Stop)
30 }, OncePerOrdered)
31
32 It("starts off uninterrupted", func() {
33 status := interruptHandler.Status()
34 Ω(status.Interrupted()).Should(BeFalse())
35 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseInvalid))
36 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelUninterrupted))
37 Consistently(status.Channel).ShouldNot(BeClosed())
38 })
39
40 When("interrupted repeatedly", Ordered, func() {
41 var status interrupt_handler.InterruptStatus
42 BeforeAll(func() {
43 status = interruptHandler.Status()
44 Ω(status.Interrupted()).Should(BeFalse())
45 })
46
47 Specify("when first interrupted, it closes the channel and goes to the next Cleanup and Report level", func() {
48 trigger()
49 Eventually(status.Channel).Should(BeClosed())
50
51 status = interruptHandler.Status()
52 Ω(status.Interrupted()).Should(BeTrue())
53 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
54 Ω(status.Message()).Should(Equal("Interrupted by User"))
55 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelCleanupAndReport))
56 Ω(status.ShouldIncludeProgressReport()).Should(BeTrue())
57 })
58
59 Specify("when interrupted a second time, it closes the next channel and goes to the Report Only level", func() {
60 trigger()
61 Eventually(status.Channel).Should(BeClosed())
62
63 status = interruptHandler.Status()
64 Ω(status.Interrupted()).Should(BeTrue())
65 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
66 Ω(status.Message()).Should(Equal("Interrupted by User"))
67 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelReportOnly))
68 Ω(status.ShouldIncludeProgressReport()).Should(BeTrue())
69 })
70
71 Specify("when interrupted a third time, it closes the next channel and goes to the Bail-Out level", func() {
72 trigger()
73 Eventually(status.Channel).Should(BeClosed())
74
75 status = interruptHandler.Status()
76 Ω(status.Interrupted()).Should(BeTrue())
77 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
78 Ω(status.Message()).Should(Equal("Interrupted by User"))
79 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelBailOut))
80 Ω(status.ShouldIncludeProgressReport()).Should(BeTrue())
81 })
82
83 Specify("when interrupted again and again, it no longer interrupts once the last level has been reached", func() {
84 trigger()
85 Consistently(status.Channel).ShouldNot(BeClosed())
86 trigger()
87 Consistently(status.Channel).ShouldNot(BeClosed())
88
89 status = interruptHandler.Status()
90 Ω(status.Interrupted()).Should(BeTrue())
91 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
92 Ω(status.Message()).Should(Equal("Interrupted by User"))
93 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelBailOut))
94 Ω(status.ShouldIncludeProgressReport()).Should(BeTrue())
95 })
96 })
97 })
98
99 Describe("Interrupting when another Ginkgo process has aborted", func() {
100 var client parallel_support.Client
101 BeforeEach(func() {
102 _, client, _ = SetUpServerAndClient(2)
103 interruptHandler = interrupt_handler.NewInterruptHandler(client, syscall.SIGUSR2)
104 DeferCleanup(interruptHandler.Stop)
105 })
106
107 It("interrupts when the server is told to abort", func() {
108 status := interruptHandler.Status()
109 Consistently(status.Channel).ShouldNot(BeClosed())
110
111 client.PostAbort()
112
113 Eventually(status.Channel).Should(BeClosed())
114 })
115
116 It("notes the correct cause and returns an interrupt message that does not include a progress report", func() {
117 status := interruptHandler.Status()
118 Ω(status.Interrupted()).Should(BeFalse())
119
120 client.PostAbort()
121 Eventually(status.Channel).Should(BeClosed())
122
123 status = interruptHandler.Status()
124 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseAbortByOtherProcess))
125 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelCleanupAndReport))
126 Ω(status.Interrupted()).Should(BeTrue())
127 Ω(status.Message()).Should(Equal("Interrupted by Other Ginkgo Process"))
128 Ω(status.ShouldIncludeProgressReport()).Should(BeFalse())
129 })
130
131 It("does not retrigger on subsequent aborts", func() {
132 status := interruptHandler.Status()
133 Ω(status.Interrupted()).Should(BeFalse())
134
135 client.PostAbort()
136 Eventually(status.Channel).Should(BeClosed())
137
138 status = interruptHandler.Status()
139 client.PostAbort()
140 Consistently(status.Channel, interrupt_handler.ABORT_POLLING_INTERVAL+100*time.Millisecond).ShouldNot(BeClosed())
141
142 status = interruptHandler.Status()
143 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseAbortByOtherProcess))
144 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelCleanupAndReport))
145 })
146
147 It("does not trigger if the suite has already been interrupted", func() {
148 status := interruptHandler.Status()
149 Ω(status.Interrupted()).Should(BeFalse())
150
151 trigger()
152 Eventually(status.Channel).Should(BeClosed())
153
154 status = interruptHandler.Status()
155 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
156 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelCleanupAndReport))
157
158 status = interruptHandler.Status()
159 client.PostAbort()
160 Consistently(status.Channel, interrupt_handler.ABORT_POLLING_INTERVAL+100*time.Millisecond).ShouldNot(BeClosed())
161
162 status = interruptHandler.Status()
163 Ω(status.Cause).Should(Equal(interrupt_handler.InterruptCauseSignal))
164 Ω(status.Level).Should(Equal(interrupt_handler.InterruptLevelCleanupAndReport))
165 })
166
167 It("doesn't just rely on the ABORT_POLLING_INTERVAL timer to report that the interrupt has happened", func() {
168 client.PostAbort()
169 Ω(interruptHandler.Status().Cause).Should(Equal(interrupt_handler.InterruptCauseAbortByOtherProcess))
170 }, MustPassRepeatedly(10))
171 })
172 })
173
View as plain text