1
16
17 package kuberuntime
18
19 import (
20 "sync"
21 "testing"
22 "time"
23
24 v1 "k8s.io/api/core/v1"
25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26 )
27
28 func TestTerminationOrderingSidecarStopAfterMain(t *testing.T) {
29 restartPolicy := v1.ContainerRestartPolicyAlways
30 pod := &v1.Pod{
31 ObjectMeta: metav1.ObjectMeta{
32 UID: "12345678",
33 Name: "bar",
34 Namespace: "new",
35 },
36 Spec: v1.PodSpec{
37 InitContainers: []v1.Container{
38 {
39 Name: "init",
40 Image: "busybox",
41 ImagePullPolicy: v1.PullIfNotPresent,
42 RestartPolicy: &restartPolicy,
43 },
44 },
45 Containers: []v1.Container{
46 {
47 Name: "main",
48 Image: "busybox",
49 ImagePullPolicy: v1.PullIfNotPresent,
50 },
51 },
52 },
53 }
54 to := newTerminationOrdering(pod, getContainerNames(pod))
55
56 var wg sync.WaitGroup
57 wg.Add(1)
58 var sidecarWaitDelay int64
59 var mainWaitDelay int64
60 go func() {
61 sidecarWaitDelay = int64(to.waitForTurn("init", 30))
62 to.containerTerminated("init")
63 wg.Done()
64 }()
65
66 wg.Add(1)
67 go func() {
68 mainWaitDelay = int64(to.waitForTurn("main", 0))
69 time.Sleep(1 * time.Second)
70 to.containerTerminated("main")
71 wg.Done()
72 }()
73 wg.Wait()
74 if sidecarWaitDelay != 1 {
75 t.Errorf("expected sidecar to wait for main container to exit, got delay of %d", sidecarWaitDelay)
76 }
77 if mainWaitDelay != 0 {
78 t.Errorf("expected main container to not wait to exit, got delay of %d", mainWaitDelay)
79 }
80 }
81
82 func TestTerminationOrderingSidecarsInReverseOrder(t *testing.T) {
83 restartPolicy := v1.ContainerRestartPolicyAlways
84 pod := &v1.Pod{
85 ObjectMeta: metav1.ObjectMeta{
86 UID: "12345678",
87 Name: "bar",
88 Namespace: "new",
89 },
90 Spec: v1.PodSpec{
91 InitContainers: []v1.Container{
92 {
93 Name: "sc1",
94 Image: "busybox",
95 ImagePullPolicy: v1.PullIfNotPresent,
96 RestartPolicy: &restartPolicy,
97 },
98 {
99 Name: "sc2",
100 Image: "busybox",
101 ImagePullPolicy: v1.PullIfNotPresent,
102 RestartPolicy: &restartPolicy,
103 },
104 {
105 Name: "sc3",
106 Image: "busybox",
107 ImagePullPolicy: v1.PullIfNotPresent,
108 RestartPolicy: &restartPolicy,
109 },
110 },
111 Containers: []v1.Container{
112 {
113 Name: "main",
114 Image: "busybox",
115 ImagePullPolicy: v1.PullIfNotPresent,
116 },
117 },
118 },
119 }
120 to := newTerminationOrdering(pod, getContainerNames(pod))
121
122 var wg sync.WaitGroup
123 var delays sync.Map
124
125 waitAndExit := func(name string) {
126 delay := int64(to.waitForTurn(name, 30))
127 delays.Store(name, delay)
128 time.Sleep(1 * time.Second)
129 to.containerTerminated(name)
130 wg.Done()
131 }
132 for _, ic := range pod.Spec.InitContainers {
133 wg.Add(1)
134 go waitAndExit(ic.Name)
135 }
136 for _, c := range pod.Spec.Containers {
137 wg.Add(1)
138 go waitAndExit(c.Name)
139 }
140
141
142 wg.Wait()
143
144 getDelay := func(name string) int64 {
145 delay, ok := delays.Load(name)
146 if !ok {
147 t.Errorf("unable to find delay for container %s", name)
148 }
149 return delay.(int64)
150 }
151
152 for _, tc := range []struct {
153 containerName string
154 expectedDelay int64
155 }{
156
157
158 {
159 containerName: "sc1",
160 expectedDelay: 3,
161 },
162
163 {
164 containerName: "sc2",
165 expectedDelay: 2,
166 },
167
168 {
169 containerName: "sc3",
170 expectedDelay: 1,
171 },
172
173 {
174 containerName: "main",
175 expectedDelay: 0,
176 },
177 } {
178 if got := getDelay(tc.containerName); got != tc.expectedDelay {
179 t.Errorf("expected delay for container %s = %d, got %d", tc.containerName, tc.expectedDelay, got)
180 }
181 }
182 }
183
184 func TestTerminationOrderingObeysGrace(t *testing.T) {
185 restartPolicy := v1.ContainerRestartPolicyAlways
186 pod := &v1.Pod{
187 ObjectMeta: metav1.ObjectMeta{
188 UID: "12345678",
189 Name: "bar",
190 Namespace: "new",
191 },
192 Spec: v1.PodSpec{
193 InitContainers: []v1.Container{
194 {
195 Name: "sc1",
196 Image: "busybox",
197 ImagePullPolicy: v1.PullIfNotPresent,
198 RestartPolicy: &restartPolicy,
199 },
200 {
201 Name: "sc2",
202 Image: "busybox",
203 ImagePullPolicy: v1.PullIfNotPresent,
204 RestartPolicy: &restartPolicy,
205 },
206 {
207 Name: "sc3",
208 Image: "busybox",
209 ImagePullPolicy: v1.PullIfNotPresent,
210 RestartPolicy: &restartPolicy,
211 },
212 },
213 Containers: []v1.Container{
214 {
215 Name: "main",
216 Image: "busybox",
217 ImagePullPolicy: v1.PullIfNotPresent,
218 },
219 },
220 },
221 }
222 to := newTerminationOrdering(pod, getContainerNames(pod))
223
224 var wg sync.WaitGroup
225 var delays sync.Map
226
227 waitAndExit := func(name string) {
228
229 delay := int64(to.waitForTurn(name, 2))
230 delays.Store(name, delay)
231 time.Sleep(1 * time.Second)
232 to.containerTerminated(name)
233 wg.Done()
234 }
235 for _, ic := range pod.Spec.InitContainers {
236 wg.Add(1)
237 go waitAndExit(ic.Name)
238 }
239 for _, c := range pod.Spec.Containers {
240 wg.Add(1)
241 go waitAndExit(c.Name)
242 }
243
244
245 wg.Wait()
246
247 getDelay := func(name string) int64 {
248 delay, ok := delays.Load(name)
249 if !ok {
250 t.Errorf("unable to find delay for container %s", name)
251 }
252 return delay.(int64)
253 }
254
255 for _, tc := range []struct {
256 containerName string
257 expectedDelay int64
258 }{
259 {
260 containerName: "sc1",
261
262 expectedDelay: 2,
263 },
264 {
265 containerName: "sc2",
266 expectedDelay: 2,
267 },
268 {
269 containerName: "sc3",
270 expectedDelay: 1,
271 },
272 {
273 containerName: "main",
274 expectedDelay: 0,
275 },
276 } {
277 if got := getDelay(tc.containerName); got != tc.expectedDelay {
278 t.Errorf("expected delay for container %s = %d, got %d", tc.containerName, tc.expectedDelay, got)
279 }
280 }
281 }
282
283 func getContainerNames(p *v1.Pod) []string {
284 var running []string
285 for _, ic := range p.Spec.InitContainers {
286 running = append(running, ic.Name)
287 }
288 for _, c := range p.Spec.Containers {
289 running = append(running, c.Name)
290 }
291 return running
292 }
293
View as plain text