diff --git a/specerror/runtime.go b/specerror/runtime.go index 383aea63..5b4abbe1 100644 --- a/specerror/runtime.go +++ b/specerror/runtime.go @@ -86,14 +86,16 @@ const ( KillSignalImplement // DeleteWithoutIDGenError represents "`delete` operation MUST generate an error if it is not provided the container ID." DeleteWithoutIDGenError - // DeleteNonStopHaveNoEffect represents "Attempting to `delete` a container that is not `stopped` MUST have no effect on the container." + // DeleteNonStopHaveNoEffect represents "Attempting to `delete` a container that is neither `created` nor `stopped` MUST have no effect on the container." DeleteNonStopHaveNoEffect - // DeleteNonStopGenError represents "Attempting to `delete` a container that is not `stopped` MUST generate an error." + // DeleteNonStopGenError represents "Attempting to `delete` a container that is neither `created` nor `stopped` MUST generate an error." DeleteNonStopGenError // DeleteResImplement represents "Deleting a container MUST delete the resources that were created during the `create` step." DeleteResImplement // DeleteOnlyCreatedRes represents "Note that resources associated with the container, but not created by this container, MUST NOT be deleted." DeleteOnlyCreatedRes + // DeleteCreatedNoEffectOrDelete represents "Attempting to `delete` a container that is `created` MAY either have no effect on the container and generate an error, or terminate the container process and then delete the container." + DeleteCreatedNoEffectOrDelete ) var ( @@ -176,4 +178,5 @@ func init() { register(DeleteNonStopGenError, rfc2119.Must, deleteRef) register(DeleteResImplement, rfc2119.Must, deleteRef) register(DeleteOnlyCreatedRes, rfc2119.Must, deleteRef) + register(DeleteCreatedNoEffectOrDelete, rfc2119.May, deleteRef) } diff --git a/validation/delete/delete.go b/validation/delete/delete.go index 76d59c98..23cbd818 100644 --- a/validation/delete/delete.go +++ b/validation/delete/delete.go @@ -43,15 +43,18 @@ func main() { errExpected bool // set true to check whether 'delete' takes effect and just check if 'delete' DOES NOT take effect effectCheck bool - err error + // set true if 'delete' may either fail and have no effect, or succeed and delete the container + mayDelete bool + err error }{ // Note: the nil config test case should run first since we are re-using the bundle // delete without id - {nil, "", util.LifecycleActionNone, false, false, specerror.NewError(specerror.DeleteWithoutIDGenError, fmt.Errorf("`delete` operation MUST generate an error if it is not provided the container ID"), rspecs.Version)}, + {nil, "", util.LifecycleActionNone, false, false, false, specerror.NewError(specerror.DeleteWithoutIDGenError, fmt.Errorf("`delete` operation MUST generate an error if it is not provided the container ID"), rspecs.Version)}, // delete a created container - {stoppedConfig, containerID, util.LifecycleActionCreate, false, true, specerror.NewError(specerror.DeleteNonStopGenError, fmt.Errorf("attempting to `delete` a container that is not `stopped` MUST generate an error"), rspecs.Version)}, + // TODO: bump runtime-spec to v1.3.1 once it's out (for the reference). + {stoppedConfig, containerID, util.LifecycleActionCreate, false, false, true, specerror.NewError(specerror.DeleteCreatedNoEffectOrDelete, fmt.Errorf("attempting to `delete` a container that is `created` MAY either have no effect on the container and generate an error, or terminate the container process and then delete the container"), rspecs.Version)}, // delete a running container - {runningConfig, containerID, util.LifecycleActionCreate | util.LifecycleActionStart, false, true, specerror.NewError(specerror.DeleteNonStopGenError, fmt.Errorf("attempting to `delete` a container that is not `stopped` MUST generate an error"), rspecs.Version)}, + {runningConfig, containerID, util.LifecycleActionCreate | util.LifecycleActionStart, false, true, false, specerror.NewError(specerror.DeleteNonStopGenError, fmt.Errorf("attempting to `delete` a container that is neither `created` nor `stopped` MUST generate an error"), rspecs.Version)}, } for _, c := range cases { @@ -70,14 +73,25 @@ func main() { testRuntime.SetID(c.id) util.WaitingForStatus(testRuntime, util.LifecycleStatusCreated|util.LifecycleStatusStopped, time.Second*10, time.Second*1) deletedErr := testRuntime.Delete() - util.SpecErrorOK(t, (deletedErr == nil) == c.errExpected, c.err, deletedErr) + if c.mayDelete { + if deletedErr == nil { + // waiting for the error of State, just in case the delete operation takes time + util.WaitingForStatus(testRuntime, util.LifecycleActionNone, time.Second*3, time.Second/2) + } + _, err = testRuntime.State() + // either 'delete' failed and the container is still there, + // or 'delete' succeeded and the container is gone + util.SpecErrorOK(t, (deletedErr == nil) == (err != nil), c.err, deletedErr) + } else { + util.SpecErrorOK(t, (deletedErr == nil) == c.errExpected, c.err, deletedErr) + } if c.effectCheck { // waiting for the error of State, just in case the delete operation takes time util.WaitingForStatus(testRuntime, util.LifecycleActionNone, time.Second*3, time.Second/2) _, err = testRuntime.State() // err == nil means the 'delete' operation does NOT take effect - util.SpecErrorOK(t, err == nil, specerror.NewError(specerror.DeleteNonStopHaveNoEffect, fmt.Errorf("attempting to `delete` a container that is not `stopped` MUST have no effect on the container"), rspecs.Version), err) + util.SpecErrorOK(t, err == nil, specerror.NewError(specerror.DeleteNonStopHaveNoEffect, fmt.Errorf("attempting to `delete` a container that is neither `created` nor `stopped` MUST have no effect on the container"), rspecs.Version), err) } // created and but deleted