@@ -6,6 +6,7 @@ package cri_containerd
66import (
77 "context"
88 "testing"
9+ "time"
910
1011 runtime "k8s.io/cri-api/pkg/apis/runtime/v1alpha2"
1112)
@@ -170,3 +171,78 @@ func Test_StopContainer_ReusePod_LCOW(t *testing.T) {
170171 containerID = createContainer (t , client , ctx , request )
171172 runContainerLifetime (t , client , ctx , containerID )
172173}
174+
175+ // This test runs a container with an image that waits for sigterm and then
176+ // prints for loop counter down from 60 till the container is stopped with
177+ // a timeout of 15 seconds. This is done to mimic graceful termination
178+ // behavior and to ensure that the containers are killed only after 15 second
179+ // timeout specified via the stop container command.
180+ func Test_GracefulTermination (t * testing.T ) {
181+ for name , tc := range map [string ]struct {
182+ features []string
183+ runtimeHandler string
184+ image string
185+ }{
186+ "WCOWProcessNanoserver" : {
187+ features : []string {featureWCOWProcess },
188+ runtimeHandler : wcowProcessRuntimeHandler ,
189+ image : gracefulTerminationNanoserver ,
190+ },
191+ "WCOWProcessServercore" : {
192+ features : []string {featureWCOWProcess },
193+ runtimeHandler : wcowProcessRuntimeHandler ,
194+ image : gracefulTerminationServercore ,
195+ },
196+ "WCOWHypervisorNanoserver" : {
197+ features : []string {featureWCOWHypervisor },
198+ runtimeHandler : wcowHypervisorRuntimeHandler ,
199+ image : gracefulTerminationNanoserver ,
200+ },
201+ "WCOWHypervisorServercore" : {
202+ features : []string {featureWCOWHypervisor },
203+ runtimeHandler : wcowHypervisorRuntimeHandler ,
204+ image : gracefulTerminationServercore ,
205+ },
206+ } {
207+ t .Run (name , func (t * testing.T ) {
208+ requireFeatures (t , tc .features ... )
209+ pullRequiredImages (t , []string {tc .image })
210+ client := newTestRuntimeClient (t )
211+ ctx , cancel := context .WithCancel (context .Background ())
212+ defer cancel ()
213+ sandboxRequest := getRunPodSandboxRequest (t , tc .runtimeHandler )
214+ podID := runPodSandbox (t , client , ctx , sandboxRequest )
215+ defer removePodSandbox (t , client , ctx , podID )
216+ defer stopPodSandbox (t , client , ctx , podID )
217+ request := & runtime.CreateContainerRequest {
218+ PodSandboxId : podID ,
219+ Config : & runtime.ContainerConfig {
220+ Metadata : & runtime.ContainerMetadata {},
221+ Image : & runtime.ImageSpec {
222+ Image : tc .image ,
223+ },
224+ },
225+ SandboxConfig : sandboxRequest .Config ,
226+ }
227+ containerID := createContainer (t , client , ctx , request )
228+ defer removeContainer (t , client , ctx , containerID )
229+
230+ startContainer (t , client , ctx , containerID )
231+ // Wait few seconds for the container to be completely initialized
232+ time .Sleep (5 * time .Second )
233+ assertContainerState (t , client , ctx , containerID , runtime .ContainerState_CONTAINER_RUNNING )
234+
235+ startTimeOfContainer := time .Now ()
236+ // stop container with timeout of 15 seconds
237+ stopContainerWithTimeout (t , client , ctx , containerID , 15 )
238+ assertContainerState (t , client , ctx , containerID , runtime .ContainerState_CONTAINER_EXITED )
239+ // get time elapsed before and after container stop command was issued
240+ elapsedTime := time .Since (startTimeOfContainer )
241+ // Ensure that the container has stopped after approx 15 seconds.
242+ // We are giving it a buffer of +/- 1 second
243+ if elapsedTime < 14 * time .Second || elapsedTime > 16 * time .Second {
244+ t .Fatalf ("Container did not shutdown gracefully \n " )
245+ }
246+ })
247+ }
248+ }
0 commit comments