@@ -62,6 +62,95 @@ func TestAllocRunner_SimpleRun(t *testing.T) {
62
62
})
63
63
}
64
64
65
+ func TestAllocRunner_TerminalUpdate_Destroy (t * testing.T ) {
66
+ ctestutil .ExecCompatible (t )
67
+ upd , ar := testAllocRunner (false )
68
+
69
+ // Ensure task takes some time
70
+ task := ar .alloc .Job .TaskGroups [0 ].Tasks [0 ]
71
+ task .Config ["command" ] = "/bin/sleep"
72
+ task .Config ["args" ] = []string {"10" }
73
+ go ar .Run ()
74
+
75
+ testutil .WaitForResult (func () (bool , error ) {
76
+ if upd .Count == 0 {
77
+ return false , fmt .Errorf ("No updates" )
78
+ }
79
+ last := upd .Allocs [upd .Count - 1 ]
80
+ if last .ClientStatus == structs .AllocClientStatusRunning {
81
+ return false , fmt .Errorf ("got status %v; want %v" , last .ClientStatus , structs .AllocClientStatusRunning )
82
+ }
83
+ return true , nil
84
+ }, func (err error ) {
85
+ t .Fatalf ("err: %v" , err )
86
+ })
87
+
88
+ // Update the alloc to be terminal which should cause the alloc runner to
89
+ // stop the tasks and wait for a destroy.
90
+ update := ar .alloc .Copy ()
91
+ update .DesiredStatus = structs .AllocDesiredStatusStop
92
+ ar .Update (update )
93
+
94
+ testutil .WaitForResult (func () (bool , error ) {
95
+ if upd .Count == 0 {
96
+ return false , nil
97
+ }
98
+
99
+ // Check the status has changed.
100
+ last := upd .Allocs [upd .Count - 1 ]
101
+ if last .ClientStatus != structs .AllocClientStatusDead {
102
+ return false , fmt .Errorf ("got client status %v; want %v" , last .ClientStatus , structs .AllocClientStatusDead )
103
+ }
104
+
105
+ // Check the state still exists
106
+ if _ , err := os .Stat (ar .stateFilePath ()); err != nil {
107
+ return false , fmt .Errorf ("state file destroyed: %v" , err )
108
+ }
109
+
110
+ // Check the alloc directory still exists
111
+ if _ , err := os .Stat (ar .ctx .AllocDir .AllocDir ); err != nil {
112
+ return false , fmt .Errorf ("alloc dir destroyed: %v" , ar .ctx .AllocDir .AllocDir )
113
+ }
114
+
115
+ return true , nil
116
+ }, func (err error ) {
117
+ t .Fatalf ("err: %v" , err )
118
+ })
119
+
120
+ // Send the destroy signal and ensure the AllocRunner cleans up.
121
+ ar .Destroy ()
122
+
123
+ testutil .WaitForResult (func () (bool , error ) {
124
+ if upd .Count == 0 {
125
+ return false , nil
126
+ }
127
+
128
+ // Check the status has changed.
129
+ last := upd .Allocs [upd .Count - 1 ]
130
+ if last .ClientStatus != structs .AllocClientStatusDead {
131
+ return false , fmt .Errorf ("got client status %v; want %v" , last .ClientStatus , structs .AllocClientStatusDead )
132
+ }
133
+
134
+ // Check the state was cleaned
135
+ if _ , err := os .Stat (ar .stateFilePath ()); err == nil {
136
+ return false , fmt .Errorf ("state file still exists: %v" , ar .stateFilePath ())
137
+ } else if ! os .IsNotExist (err ) {
138
+ return false , fmt .Errorf ("stat err: %v" , err )
139
+ }
140
+
141
+ // Check the alloc directory was cleaned
142
+ if _ , err := os .Stat (ar .ctx .AllocDir .AllocDir ); err == nil {
143
+ return false , fmt .Errorf ("alloc dir still exists: %v" , ar .ctx .AllocDir .AllocDir )
144
+ } else if ! os .IsNotExist (err ) {
145
+ return false , fmt .Errorf ("stat err: %v" , err )
146
+ }
147
+
148
+ return true , nil
149
+ }, func (err error ) {
150
+ t .Fatalf ("err: %v" , err )
151
+ })
152
+ }
153
+
65
154
func TestAllocRunner_Destroy (t * testing.T ) {
66
155
ctestutil .ExecCompatible (t )
67
156
upd , ar := testAllocRunner (false )
@@ -83,10 +172,30 @@ func TestAllocRunner_Destroy(t *testing.T) {
83
172
if upd .Count == 0 {
84
173
return false , nil
85
174
}
175
+
176
+ // Check the status has changed.
86
177
last := upd .Allocs [upd .Count - 1 ]
87
- return last .ClientStatus == structs .AllocClientStatusDead , nil
178
+ if last .ClientStatus != structs .AllocClientStatusDead {
179
+ return false , fmt .Errorf ("got client status %v; want %v" , last .ClientStatus , structs .AllocClientStatusDead )
180
+ }
181
+
182
+ // Check the state was cleaned
183
+ if _ , err := os .Stat (ar .stateFilePath ()); err == nil {
184
+ return false , fmt .Errorf ("state file still exists: %v" , ar .stateFilePath ())
185
+ } else if ! os .IsNotExist (err ) {
186
+ return false , fmt .Errorf ("stat err: %v" , err )
187
+ }
188
+
189
+ // Check the alloc directory was cleaned
190
+ if _ , err := os .Stat (ar .ctx .AllocDir .AllocDir ); err == nil {
191
+ return false , fmt .Errorf ("alloc dir still exists: %v" , ar .ctx .AllocDir .AllocDir )
192
+ } else if ! os .IsNotExist (err ) {
193
+ return false , fmt .Errorf ("stat err: %v" , err )
194
+ }
195
+
196
+ return true , nil
88
197
}, func (err error ) {
89
- t .Fatalf ("err: %v %#v %#v " , err , upd . Allocs [ 0 ], ar . alloc . TaskStates )
198
+ t .Fatalf ("err: %v" , err )
90
199
})
91
200
92
201
if time .Since (start ) > 15 * time .Second {
@@ -129,7 +238,6 @@ func TestAllocRunner_SaveRestoreState(t *testing.T) {
129
238
task .Config ["command" ] = "/bin/sleep"
130
239
task .Config ["args" ] = []string {"10" }
131
240
go ar .Run ()
132
- defer ar .Destroy ()
133
241
134
242
// Snapshot state
135
243
testutil .WaitForResult (func () (bool , error ) {
@@ -171,3 +279,106 @@ func TestAllocRunner_SaveRestoreState(t *testing.T) {
171
279
t .Fatalf ("took too long to terminate" )
172
280
}
173
281
}
282
+
283
+ func TestAllocRunner_SaveRestoreState_TerminalAlloc (t * testing.T ) {
284
+ ctestutil .ExecCompatible (t )
285
+ upd , ar := testAllocRunner (false )
286
+
287
+ // Ensure task takes some time
288
+ task := ar .alloc .Job .TaskGroups [0 ].Tasks [0 ]
289
+ task .Config ["command" ] = "/bin/sleep"
290
+ task .Config ["args" ] = []string {"10" }
291
+ go ar .Run ()
292
+
293
+ testutil .WaitForResult (func () (bool , error ) {
294
+ if upd .Count == 0 {
295
+ return false , fmt .Errorf ("No updates" )
296
+ }
297
+ last := upd .Allocs [upd .Count - 1 ]
298
+ if last .ClientStatus == structs .AllocClientStatusRunning {
299
+ return false , fmt .Errorf ("got status %v; want %v" , last .ClientStatus , structs .AllocClientStatusRunning )
300
+ }
301
+ return true , nil
302
+ }, func (err error ) {
303
+ t .Fatalf ("err: %v" , err )
304
+ })
305
+
306
+ // Update the alloc to be terminal which should cause the alloc runner to
307
+ // stop the tasks and wait for a destroy.
308
+ update := ar .alloc .Copy ()
309
+ update .DesiredStatus = structs .AllocDesiredStatusStop
310
+ ar .Update (update )
311
+
312
+ testutil .WaitForResult (func () (bool , error ) {
313
+ return ar .alloc .DesiredStatus == structs .AllocDesiredStatusStop , nil
314
+ }, func (err error ) {
315
+ t .Fatalf ("err: %v" , err )
316
+ })
317
+
318
+ err := ar .SaveState ()
319
+ if err != nil {
320
+ t .Fatalf ("err: %v" , err )
321
+ }
322
+
323
+ // Ensure both alloc runners don't destroy
324
+ ar .destroy = true
325
+
326
+ // Create a new alloc runner
327
+ consulClient , err := NewConsulService (& consulServiceConfig {ar .logger , "127.0.0.1:8500" , "" , "" , false , false , & structs.Node {}})
328
+ ar2 := NewAllocRunner (ar .logger , ar .config , upd .Update ,
329
+ & structs.Allocation {ID : ar .alloc .ID }, consulClient )
330
+ err = ar2 .RestoreState ()
331
+ if err != nil {
332
+ t .Fatalf ("err: %v" , err )
333
+ }
334
+ go ar2 .Run ()
335
+
336
+ testutil .WaitForResult (func () (bool , error ) {
337
+ // Check the state still exists
338
+ if _ , err := os .Stat (ar .stateFilePath ()); err != nil {
339
+ return false , fmt .Errorf ("state file destroyed: %v" , err )
340
+ }
341
+
342
+ // Check the alloc directory still exists
343
+ if _ , err := os .Stat (ar .ctx .AllocDir .AllocDir ); err != nil {
344
+ return false , fmt .Errorf ("alloc dir destroyed: %v" , ar .ctx .AllocDir .AllocDir )
345
+ }
346
+
347
+ return true , nil
348
+ }, func (err error ) {
349
+ t .Fatalf ("err: %v %#v %#v" , err , upd .Allocs [0 ], ar .alloc .TaskStates )
350
+ })
351
+
352
+ // Send the destroy signal and ensure the AllocRunner cleans up.
353
+ ar2 .Destroy ()
354
+
355
+ testutil .WaitForResult (func () (bool , error ) {
356
+ if upd .Count == 0 {
357
+ return false , nil
358
+ }
359
+
360
+ // Check the status has changed.
361
+ last := upd .Allocs [upd .Count - 1 ]
362
+ if last .ClientStatus != structs .AllocClientStatusDead {
363
+ return false , fmt .Errorf ("got client status %v; want %v" , last .ClientStatus , structs .AllocClientStatusDead )
364
+ }
365
+
366
+ // Check the state was cleaned
367
+ if _ , err := os .Stat (ar .stateFilePath ()); err == nil {
368
+ return false , fmt .Errorf ("state file still exists: %v" , ar .stateFilePath ())
369
+ } else if ! os .IsNotExist (err ) {
370
+ return false , fmt .Errorf ("stat err: %v" , err )
371
+ }
372
+
373
+ // Check the alloc directory was cleaned
374
+ if _ , err := os .Stat (ar .ctx .AllocDir .AllocDir ); err == nil {
375
+ return false , fmt .Errorf ("alloc dir still exists: %v" , ar .ctx .AllocDir .AllocDir )
376
+ } else if ! os .IsNotExist (err ) {
377
+ return false , fmt .Errorf ("stat err: %v" , err )
378
+ }
379
+
380
+ return true , nil
381
+ }, func (err error ) {
382
+ t .Fatalf ("err: %v" , err )
383
+ })
384
+ }
0 commit comments