@@ -30,7 +30,7 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
3030 counter , err := telemetry .GetCounter (noop .NewMeterProvider ().Meter ("github.com/e2b-dev/infra/packages/api/internal/orchestrator/evictor" ), telemetry .ApiEvictorFsOnlyAutoPause )
3131 require .NoError (t , err )
3232
33- runOn := func (autoPause , autoPauseFilesystemOnly bool , fcVersion string ) sandbox.RemoveOpts {
33+ runOn := func (state sandbox. State , autoPause , autoPauseFilesystemOnly bool , fcVersion string ) sandbox.RemoveOpts {
3434 var got sandbox.RemoveOpts
3535 called := false
3636 e := & Evictor {
@@ -52,6 +52,8 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
5252 e .evictSandbox (t .Context (), sandbox.Sandbox {
5353 SandboxID : "sbx" ,
5454 TeamID : uuid .New (),
55+ ExecutionID : "exec-1" ,
56+ State : state ,
5557 AutoPause : autoPause ,
5658 AutoPauseFilesystemOnly : autoPauseFilesystemOnly ,
5759 FirecrackerVersion : fcVersion ,
@@ -63,7 +65,7 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
6365 return got
6466 }
6567 run := func (autoPause , autoPauseFilesystemOnly bool ) sandbox.RemoveOpts {
66- return runOn (autoPause , autoPauseFilesystemOnly , "v1.14-0.2.0" )
68+ return runOn (sandbox . StateRunning , autoPause , autoPauseFilesystemOnly , "v1.14-0.2.0" )
6769 }
6870
6971 t .Run ("kill carries timeout reason" , func (t * testing.T ) {
@@ -76,6 +78,13 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
7678 assert .Equal (t , sandbox .KillReasonTimeout , got .Reason )
7779 })
7880
81+ t .Run ("removal is pinned to the scanned execution" , func (t * testing.T ) {
82+ t .Parallel ()
83+
84+ assert .Equal (t , "exec-1" , run (false , false ).ExpectExecutionID )
85+ assert .Equal (t , "exec-1" , run (true , false ).ExpectExecutionID )
86+ })
87+
7988 t .Run ("kill ignores the auto-pause snapshot kind" , func (t * testing.T ) {
8089 t .Parallel ()
8190
@@ -120,7 +129,7 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
120129 t .Run ("filesystem-only auto-pause is honored on a legacy release" , func (t * testing.T ) {
121130 t .Parallel ()
122131
123- got := runOn (true , true , "v1.14.1_431f1fc" )
132+ got := runOn (sandbox . StateRunning , true , true , "v1.14.1_431f1fc" )
124133
125134 assert .Equal (t , sandbox .StateActionPause , got .Action )
126135 assert .True (t , got .FilesystemOnly )
@@ -129,9 +138,88 @@ func TestEvictSandbox_ReasonByAction(t *testing.T) {
129138 t .Run ("filesystem-only auto-pause is honored on an unparsable version" , func (t * testing.T ) {
130139 t .Parallel ()
131140
132- got := runOn (true , true , "" )
141+ got := runOn (sandbox . StateRunning , true , true , "" )
133142
134143 assert .Equal (t , sandbox .StateActionPause , got .Action )
135144 assert .True (t , got .FilesystemOnly )
136145 })
146+
147+ t .Run ("auto-pause leftover in killing is killed not paused" , func (t * testing.T ) {
148+ t .Parallel ()
149+
150+ got := runOn (sandbox .StateKilling , true , true , "v1.14-0.2.0" )
151+
152+ assert .Equal (t , sandbox .StateActionKill , got .Action )
153+ assert .True (t , got .Eviction )
154+ assert .Equal (t , sandbox .KillReasonTimeout , got .Reason )
155+ assert .False (t , got .FilesystemOnly )
156+ })
157+
158+ t .Run ("auto-pause leftover that can still pause is paused" , func (t * testing.T ) {
159+ t .Parallel ()
160+
161+ for _ , state := range []sandbox.State {sandbox .StatePausing , sandbox .StateSnapshotting } {
162+ t .Run (string (state ), func (t * testing.T ) {
163+ t .Parallel ()
164+
165+ got := runOn (state , true , true , "v1.14-0.2.0" )
166+
167+ assert .Equal (t , sandbox .StateActionPause , got .Action )
168+ assert .True (t , got .FilesystemOnly )
169+ })
170+ }
171+ })
172+ }
173+
174+ func TestCanTake (t * testing.T ) {
175+ t .Parallel ()
176+
177+ assert .True (t , canTake (sandbox .StateRunning , sandbox .StateActionPause ))
178+ assert .True (t , canTake (sandbox .StatePausing , sandbox .StateActionPause ))
179+ assert .True (t , canTake (sandbox .StateSnapshotting , sandbox .StateActionPause ))
180+ assert .False (t , canTake (sandbox .StateKilling , sandbox .StateActionPause ))
181+ assert .True (t , canTake (sandbox .StateKilling , sandbox .StateActionKill ))
182+ }
183+
184+ func TestIsStaleDecision (t * testing.T ) {
185+ t .Parallel ()
186+
187+ t .Run ("state moved since the scan" , func (t * testing.T ) {
188+ t .Parallel ()
189+
190+ err := & sandbox.InvalidStateTransitionError {
191+ CurrentState : sandbox .StateKilling ,
192+ TargetState : sandbox .StatePausing ,
193+ }
194+ assert .True (t , isStaleDecision (err , sandbox .StateRunning ))
195+ assert .True (t , isKnownEvictionError (err , sandbox .StateRunning ))
196+ })
197+
198+ t .Run ("refusal from the scanned state stays a failure" , func (t * testing.T ) {
199+ t .Parallel ()
200+
201+ // An unknown state is refused from the same state it was scanned in.
202+ // Nothing moved; the record is broken.
203+ err := & sandbox.InvalidStateTransitionError {
204+ CurrentState : "" ,
205+ TargetState : sandbox .StateKilling ,
206+ }
207+ assert .False (t , isStaleDecision (err , "" ))
208+ assert .False (t , isKnownEvictionError (err , "" ))
209+ })
210+
211+ t .Run ("other errors are not stale decisions" , func (t * testing.T ) {
212+ t .Parallel ()
213+
214+ assert .False (t , isStaleDecision (sandbox .ErrNotFound , sandbox .StateRunning ))
215+ })
216+ }
217+
218+ func TestIsGone (t * testing.T ) {
219+ t .Parallel ()
220+
221+ assert .True (t , isGone (sandbox .ErrNotFound ))
222+ assert .True (t , isGone (sandbox .ErrExecutionMismatch ))
223+ assert .True (t , isKnownEvictionError (sandbox .ErrExecutionMismatch , sandbox .StateRunning ))
224+ assert .False (t , isGone (sandbox .ErrEvictionNotNeeded ))
137225}
0 commit comments