Files
moby/daemon/delete_test.go
Sebastiaan van Stijn 83510a26b3 api/types: move backend types to daemon/server
The "backend" types in API were designed to decouple the API server
implementation from the daemon, or other parts of the code that
back the API server. This would allow the daemon to evolve (e.g.
functionality moved to different subsystems) without that impacting
the API server's implementation.

Now that the API server is no longer part of the API package (module),
there is no benefit to having it in the API module. The API server
may evolve (and require changes in the backend), which has no direct
relation with the API module (types, responses); the backend definition
is, however, coupled to the API server implementation.

It's worth noting that, while "technically" possible to use the API
server package, and implement an alternative backend implementation,
this has never been a prime objective. The backend definition was
never considered "stable", and we don't expect external users to
(attempt) to use it as such.

This patch moves the backend types to the daemon/server package,
so that they can evolve with the daemon and API server implementation
without that impacting the API module (which we intend to be stable,
following SemVer).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-07-28 00:03:04 +02:00

99 lines
2.8 KiB
Go

package daemon
import (
"fmt"
"os"
"testing"
"time"
cerrdefs "github.com/containerd/errdefs"
"github.com/docker/docker/daemon/container"
"github.com/docker/docker/daemon/server/backend"
containertypes "github.com/moby/moby/api/types/container"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func newDaemonWithTmpRoot(t *testing.T) (*Daemon, func()) {
tmp, err := os.MkdirTemp("", "docker-daemon-unix-test-")
assert.NilError(t, err)
d := &Daemon{
repository: tmp,
root: tmp,
}
d.containers = container.NewMemoryStore()
return d, func() { os.RemoveAll(tmp) }
}
func newContainerWithState(state *container.State) *container.Container {
return &container.Container{
ID: "test",
State: state,
Config: &containertypes.Config{},
}
}
// TestContainerDelete tests that a useful error message and instructions is
// given when attempting to remove a container (#30842)
func TestContainerDelete(t *testing.T) {
tests := []struct {
doc string
errMsg string
initContainer func() *container.Container
}{
{
doc: "paused container",
errMsg: "container is paused and must be unpaused first",
initContainer: func() *container.Container {
return newContainerWithState(&container.State{Paused: true, Running: true})
},
},
{
doc: "restarting container",
errMsg: "container is restarting: stop the container before removing or force remove",
initContainer: func() *container.Container {
c := newContainerWithState(container.NewState())
c.SetRunning(nil, nil, time.Now())
c.SetRestarting(&container.ExitStatus{})
return c
},
},
{
doc: "running container",
errMsg: "container is running: stop the container before removing or force remove",
initContainer: func() *container.Container {
return newContainerWithState(&container.State{Running: true})
},
},
}
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
c := tc.initContainer()
d, cleanup := newDaemonWithTmpRoot(t)
defer cleanup()
d.containers.Add(c.ID, c)
err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: false})
assert.Check(t, is.ErrorType(err, cerrdefs.IsConflict))
assert.Check(t, is.ErrorContains(err, tc.errMsg))
})
}
}
func TestContainerDoubleDelete(t *testing.T) {
c := newContainerWithState(container.NewState())
// Mark the container as having a delete in progress
c.SetRemovalInProgress()
d, cleanup := newDaemonWithTmpRoot(t)
defer cleanup()
d.containers.Add(c.ID, c)
// Try to remove the container when its state is removalInProgress.
// It should return an error indicating it is under removal progress.
err := d.ContainerRm(c.ID, &backend.ContainerRmConfig{ForceRemove: true})
assert.Check(t, is.ErrorContains(err, fmt.Sprintf("removal of container %s is already in progress", c.ID)))
}