github.com/moby/docker@v26.1.3+incompatible/daemon/delete_test.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 8 "github.com/docker/docker/api/types/backend" 9 containertypes "github.com/docker/docker/api/types/container" 10 "github.com/docker/docker/container" 11 "github.com/docker/docker/errdefs" 12 "gotest.tools/v3/assert" 13 is "gotest.tools/v3/assert/cmp" 14 ) 15 16 func newDaemonWithTmpRoot(t *testing.T) (*Daemon, func()) { 17 tmp, err := os.MkdirTemp("", "docker-daemon-unix-test-") 18 assert.NilError(t, err) 19 d := &Daemon{ 20 repository: tmp, 21 root: tmp, 22 } 23 d.containers = container.NewMemoryStore() 24 return d, func() { os.RemoveAll(tmp) } 25 } 26 27 func newContainerWithState(state *container.State) *container.Container { 28 return &container.Container{ 29 ID: "test", 30 State: state, 31 Config: &containertypes.Config{}, 32 } 33 } 34 35 // TestContainerDelete tests that a useful error message and instructions is 36 // given when attempting to remove a container (#30842) 37 func TestContainerDelete(t *testing.T) { 38 tests := []struct { 39 doc string 40 errMsg string 41 initContainer func() *container.Container 42 }{ 43 { 44 doc: "paused container", 45 errMsg: "container is paused and must be unpaused first", 46 initContainer: func() *container.Container { 47 return newContainerWithState(&container.State{Paused: true, Running: true}) 48 }, 49 }, 50 { 51 doc: "restarting container", 52 errMsg: "container is restarting: stop the container before removing or force remove", 53 initContainer: func() *container.Container { 54 c := newContainerWithState(container.NewState()) 55 c.SetRunning(nil, nil, true) 56 c.SetRestarting(&container.ExitStatus{}) 57 return c 58 }, 59 }, 60 { 61 doc: "running container", 62 errMsg: "container is running: stop the container before removing or force remove", 63 initContainer: func() *container.Container { 64 return newContainerWithState(&container.State{Running: true}) 65 }, 66 }, 67 } 68 69 for _, tc := range tests { 70 tc := tc 71 t.Run(tc.doc, func(t *testing.T) { 72 c := tc.initContainer() 73 d, cleanup := newDaemonWithTmpRoot(t) 74 defer cleanup() 75 d.containers.Add(c.ID, c) 76 77 err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: false}) 78 assert.Check(t, is.ErrorType(err, errdefs.IsConflict)) 79 assert.Check(t, is.ErrorContains(err, tc.errMsg)) 80 }) 81 } 82 } 83 84 func TestContainerDoubleDelete(t *testing.T) { 85 c := newContainerWithState(container.NewState()) 86 87 // Mark the container as having a delete in progress 88 c.SetRemovalInProgress() 89 90 d, cleanup := newDaemonWithTmpRoot(t) 91 defer cleanup() 92 d.containers.Add(c.ID, c) 93 94 // Try to remove the container when its state is removalInProgress. 95 // It should return an error indicating it is under removal progress. 96 err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: true}) 97 assert.Check(t, is.ErrorContains(err, fmt.Sprintf("removal of container %s is already in progress", c.ID))) 98 }