1
2
3
4
5
6
7
8
9
10
11
12
13
14 package bpm
15
16 import (
17 "context"
18 "math/rand"
19 "testing"
20 "time"
21
22 . "github.com/onsi/ginkgo"
23 . "github.com/onsi/gomega"
24 "github.com/shirou/gopsutil/process"
25 "sigs.k8s.io/controller-runtime/pkg/envtest"
26 )
27
28 func TestBpm(t *testing.T) {
29 RegisterFailHandler(Fail)
30
31 RunSpecsWithDefaultAndCustomReporters(t,
32 "Background Process Manager Suite",
33 []Reporter{envtest.NewlineReporter{}})
34 }
35
36 func RandomeIdentifier() string {
37 var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
38
39 s := make([]rune, 10)
40 for i := range s {
41 s[i] = letters[rand.Intn(len(letters))]
42 }
43 return string(s)
44 }
45
46 func WaitProcess(m *BackgroundProcessManager, cmd *ManagedProcess, exceedTime time.Duration) {
47 pid := cmd.Process.Pid
48 procState, err := process.NewProcess(int32(pid))
49 Expect(err).To(BeNil())
50 ct, err := procState.CreateTime()
51 Expect(err).To(BeNil())
52 pair := ProcessPair{
53 Pid: pid,
54 CreateTime: ct,
55 }
56 channel, ok := m.deathSig.Load(pair)
57 Expect(ok).To(BeTrue())
58 deathChannel := channel.(chan bool)
59
60 timeExceed := false
61 select {
62 case <-deathChannel:
63 case <-time.Tick(exceedTime):
64 timeExceed = true
65 }
66 Expect(timeExceed).To(BeFalse())
67 }
68
69 var _ = Describe("background process manager", func() {
70 m := NewBackgroundProcessManager()
71
72 Context("normally exited process", func() {
73 It("should work", func() {
74 cmd := DefaultProcessBuilder("sleep", "2").Build()
75 err := m.StartProcess(cmd)
76 Expect(err).To(BeNil())
77
78 WaitProcess(&m, cmd, time.Second*5)
79 })
80
81 It("processes with the same identifier", func() {
82 identifier := RandomeIdentifier()
83
84 cmd := DefaultProcessBuilder("sleep", "2").
85 SetIdentifier(identifier).
86 Build()
87 err := m.StartProcess(cmd)
88 Expect(err).To(BeNil())
89
90 startTime := time.Now()
91 cmd2 := DefaultProcessBuilder("sleep", "2").
92 SetIdentifier(identifier).
93 Build()
94 err = m.StartProcess(cmd2)
95 costedTime := time.Since(startTime)
96 Expect(err).To(BeNil())
97 Expect(costedTime.Seconds()).Should(BeNumerically(">", 1.9))
98
99 _, err = process.NewProcess(int32(cmd.Process.Pid))
100 Expect(err).NotTo(BeNil())
101
102 WaitProcess(&m, cmd2, time.Second*5)
103 })
104 })
105
106 Context("kill process", func() {
107 It("should work", func() {
108 cmd := DefaultProcessBuilder("sleep", "2").Build()
109 err := m.StartProcess(cmd)
110 Expect(err).To(BeNil())
111
112 pid := cmd.Process.Pid
113 procState, err := process.NewProcess(int32(pid))
114 Expect(err).To(BeNil())
115 ct, err := procState.CreateTime()
116 Expect(err).To(BeNil())
117
118 err = m.KillBackgroundProcess(context.Background(), pid, ct)
119 Expect(err).To(BeNil())
120
121 procState, err = process.NewProcess(int32(pid))
122 Expect(err).NotTo(BeNil())
123 })
124
125 It("process with the same identifier", func() {
126 identifier := RandomeIdentifier()
127
128 cmd := DefaultProcessBuilder("sleep", "2").
129 SetIdentifier(identifier).
130 Build()
131 err := m.StartProcess(cmd)
132 Expect(err).To(BeNil())
133
134 pid := cmd.Process.Pid
135 procState, err := process.NewProcess(int32(pid))
136 Expect(err).To(BeNil())
137 ct, err := procState.CreateTime()
138 Expect(err).To(BeNil())
139
140 cmd2 := DefaultProcessBuilder("sleep", "2").
141 SetIdentifier(identifier).
142 Build()
143
144 go func() {
145 time.Sleep(time.Second)
146
147 err = m.KillBackgroundProcess(context.Background(), pid, ct)
148 Expect(err).To(BeNil())
149 }()
150
151 startTime := time.Now()
152 err = m.StartProcess(cmd2)
153 costedTime := time.Since(startTime)
154 Expect(err).To(BeNil())
155 Expect(costedTime.Seconds()).Should(And(BeNumerically("<", 2), BeNumerically(">", 1)))
156
157 pid2 := cmd2.Process.Pid
158 procState2, err := process.NewProcess(int32(pid2))
159 Expect(err).To(BeNil())
160 ct2, err := procState2.CreateTime()
161 Expect(err).To(BeNil())
162
163 err = m.KillBackgroundProcess(context.Background(), pid2, ct2)
164 Expect(err).To(BeNil())
165 })
166 })
167 })
168