| package daemon | |
| import ( | |
| "context" | |
| "os" | |
| "path/filepath" | |
| "testing" | |
| "github.com/docker/docker/api/types" | |
| containertypes "github.com/docker/docker/api/types/container" | |
| "github.com/docker/docker/api/types/filters" | |
| "github.com/docker/docker/container" | |
| "github.com/docker/docker/image" | |
| "github.com/google/uuid" | |
| "github.com/opencontainers/go-digest" | |
| "gotest.tools/v3/assert" | |
| is "gotest.tools/v3/assert/cmp" | |
| ) | |
| var root string | |
| func TestMain(m *testing.M) { | |
| var err error | |
| root, err = os.MkdirTemp("", "docker-container-test-") | |
| if err != nil { | |
| panic(err) | |
| } | |
| defer os.RemoveAll(root) | |
| os.Exit(m.Run()) | |
| } | |
| // This sets up a container with a name so that name filters | |
| // work against it. It takes in a pointer to Daemon so that | |
| // minor operations are not repeated by the caller | |
| func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *container.Container { | |
| t.Helper() | |
| var ( | |
| id = uuid.New().String() | |
| computedImageID = image.ID(digest.FromString(id)) | |
| cRoot = filepath.Join(root, id) | |
| ) | |
| if err := os.MkdirAll(cRoot, 0o755); err != nil { | |
| t.Fatal(err) | |
| } | |
| c := container.NewBaseContainer(id, cRoot) | |
| // these are for passing includeContainerInList | |
| if name[0] != '/' { | |
| name = "/" + name | |
| } | |
| c.Name = name | |
| c.Running = true | |
| c.HostConfig = &containertypes.HostConfig{} | |
| // these are for passing the refreshImage reducer | |
| c.ImageID = computedImageID | |
| c.Config = &containertypes.Config{ | |
| Image: computedImageID.String(), | |
| } | |
| // this is done here to avoid requiring these | |
| // operations n x number of containers in the | |
| // calling function | |
| daemon.containersReplica.Save(c) | |
| daemon.reserveName(id, name) | |
| return c | |
| } | |
| func containerListContainsName(containers []*types.Container, name string) bool { | |
| for _, ctr := range containers { | |
| for _, containerName := range ctr.Names { | |
| if containerName == name { | |
| return true | |
| } | |
| } | |
| } | |
| return false | |
| } | |
| func TestListInvalidFilter(t *testing.T) { | |
| db, err := container.NewViewDB() | |
| assert.Assert(t, err == nil) | |
| d := &Daemon{ | |
| containersReplica: db, | |
| } | |
| _, err = d.Containers(context.Background(), &containertypes.ListOptions{ | |
| Filters: filters.NewArgs(filters.Arg("invalid", "foo")), | |
| }) | |
| assert.Assert(t, is.Error(err, "invalid filter 'invalid'")) | |
| } | |
| func TestNameFilter(t *testing.T) { | |
| db, err := container.NewViewDB() | |
| assert.Assert(t, err == nil) | |
| d := &Daemon{ | |
| containersReplica: db, | |
| } | |
| var ( | |
| one = setupContainerWithName(t, "a1", d) | |
| two = setupContainerWithName(t, "a2", d) | |
| three = setupContainerWithName(t, "b1", d) | |
| ) | |
| // moby/moby #37453 - ^ regex not working due to prefix slash | |
| // not being stripped | |
| containerList, err := d.Containers(context.Background(), &containertypes.ListOptions{ | |
| Filters: filters.NewArgs(filters.Arg("name", "^a")), | |
| }) | |
| assert.NilError(t, err) | |
| assert.Assert(t, is.Len(containerList, 2)) | |
| assert.Assert(t, containerListContainsName(containerList, one.Name)) | |
| assert.Assert(t, containerListContainsName(containerList, two.Name)) | |
| // Same as above but with slash prefix should produce the same result | |
| containerListWithPrefix, err := d.Containers(context.Background(), &containertypes.ListOptions{ | |
| Filters: filters.NewArgs(filters.Arg("name", "^/a")), | |
| }) | |
| assert.NilError(t, err) | |
| assert.Assert(t, is.Len(containerListWithPrefix, 2)) | |
| assert.Assert(t, containerListContainsName(containerListWithPrefix, one.Name)) | |
| assert.Assert(t, containerListContainsName(containerListWithPrefix, two.Name)) | |
| // Same as above but make sure it works for exact names | |
| containerList, err = d.Containers(context.Background(), &containertypes.ListOptions{ | |
| Filters: filters.NewArgs(filters.Arg("name", "b1")), | |
| }) | |
| assert.NilError(t, err) | |
| assert.Assert(t, is.Len(containerList, 1)) | |
| assert.Assert(t, containerListContainsName(containerList, three.Name)) | |
| // Same as above but with slash prefix should produce the same result | |
| containerListWithPrefix, err = d.Containers(context.Background(), &containertypes.ListOptions{ | |
| Filters: filters.NewArgs(filters.Arg("name", "/b1")), | |
| }) | |
| assert.NilError(t, err) | |
| assert.Assert(t, is.Len(containerListWithPrefix, 1)) | |
| assert.Assert(t, containerListContainsName(containerListWithPrefix, three.Name)) | |
| } |