@@ -22,6 +22,8 @@ import (
2222 "os"
2323 "path/filepath"
2424 "strings"
25+ "sync"
26+ "syscall"
2527 "testing"
2628 "time"
2729
@@ -123,3 +125,67 @@ func TestSandboxRemoveWithoutIPLeakage(t *testing.T) {
123125 t .Logf ("Should not be able to find the pod ip in host-local checkpoint" )
124126 assert .False (t , checkIP (ip ))
125127}
128+
129+ // TestSandboxStopWithNilCNIResult verifies that StopPodSandbox succeeds when
130+ // CNIResult is nil (network setup never completed) even if the network teardown
131+ // itself fails. This exercises the condition in sandbox_stop.go where a nil
132+ // CNIResult causes the teardown error to be logged as a warning instead of
133+ // returned as a hard error.
134+ func TestSandboxStopWithNilCNIResult (t * testing.T ) {
135+ t .Log ("Init PodSandboxConfig with specific label" )
136+ sbName := t .Name ()
137+ labels := map [string ]string {
138+ sbName : "true" ,
139+ }
140+ sbConfig := PodSandboxConfig (sbName , "failpoint" , WithPodLabels (labels ))
141+
142+ t .Log ("Inject CNI failpoint: delay Add (so CNIResult is never set) and fail Del" )
143+ conf := & failpointConf {
144+ // Delay CNI Add for 1 day so network setup never completes and CNIResult stays nil
145+ Add : "1*delay(86400000)" ,
146+ // Make CNI Del fail so teardownPodNetwork returns an error during stop
147+ Del : "1*error(network-teardown-injected-error)" ,
148+ }
149+ injectCNIFailpoint (t , sbConfig , conf )
150+
151+ var wg sync.WaitGroup
152+ wg .Add (1 )
153+
154+ go func () {
155+ defer wg .Done ()
156+ t .Log ("Create a sandbox (will hang on CNI Add)" )
157+ _ , err := runtimeService .RunPodSandbox (sbConfig , failpointRuntimeHandler )
158+ assert .Error (t , err )
159+ }()
160+
161+ t .Log ("Wait for CNI Add to start running" )
162+ assert .NoError (t , ensureCNIAddRunning (t , sbName ), "CNI Add should be running" )
163+
164+ // Kill containerd while CNI Add is in progress so CNIResult is never set
165+ // and no deferred cleanup runs.
166+ t .Log ("Kill containerd with SIGKILL to leave sandbox with nil CNIResult" )
167+ RestartContainerd (t , syscall .SIGKILL )
168+
169+ wg .Wait ()
170+
171+ t .Log ("ListPodSandbox with the specific label" )
172+ l , err := runtimeService .ListPodSandbox (& runtime.PodSandboxFilter {LabelSelector : labels })
173+ require .NoError (t , err )
174+ require .Len (t , l , 1 )
175+
176+ sb := l [0 ]
177+ require .Equal (t , runtime .PodSandboxState_SANDBOX_NOTREADY , sb .State )
178+
179+ t .Log ("Get sandbox info and verify CNIResult is nil" )
180+ _ , info , err := SandboxInfo (sb .Id )
181+ require .NoError (t , err )
182+ require .Nil (t , info .CNIResult , "CNIResult should be nil because CNI setup never completed" )
183+
184+ t .Log ("StopPodSandbox should succeed even though CNI Del fails, because CNIResult is nil" )
185+ err = runtimeService .StopPodSandbox (sb .Id )
186+ assert .NoError (t , err , "StopPodSandbox should not return error when CNIResult is nil" )
187+
188+ t .Log ("RemovePodSandbox should succeed" )
189+ err = runtimeService .RemovePodSandbox (sb .Id )
190+ assert .NoError (t , err )
191+ }
0 commit comments