| package main | |
| import ( | |
| "context" | |
| "fmt" | |
| "sort" | |
| "strings" | |
| "testing" | |
| "time" | |
| "github.com/docker/docker/integration-cli/cli" | |
| "github.com/docker/docker/integration-cli/cli/build" | |
| "github.com/docker/docker/pkg/stringid" | |
| "github.com/docker/go-units" | |
| "gotest.tools/v3/assert" | |
| is "gotest.tools/v3/assert/cmp" | |
| "gotest.tools/v3/icmd" | |
| "gotest.tools/v3/skip" | |
| ) | |
| type DockerCLIPsSuite struct { | |
| ds *DockerSuite | |
| } | |
| func (s *DockerCLIPsSuite) TearDownTest(ctx context.Context, c *testing.T) { | |
| s.ds.TearDownTest(ctx, c) | |
| } | |
| func (s *DockerCLIPsSuite) OnTimeout(c *testing.T) { | |
| s.ds.OnTimeout(c) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersBase(c *testing.T) { | |
| existingContainers := ExistingContainerIDs(c) | |
| firstID := runSleepingContainer(c, "-d") | |
| secondID := runSleepingContainer(c, "-d") | |
| // not long running | |
| out := cli.DockerCmd(c, "run", "-d", "busybox", "true").Stdout() | |
| thirdID := strings.TrimSpace(out) | |
| fourthID := runSleepingContainer(c, "-d") | |
| // make sure the second is running | |
| cli.WaitRun(c, secondID) | |
| // make sure third one is not running | |
| cli.DockerCmd(c, "wait", thirdID) | |
| // make sure the forth is running | |
| cli.WaitRun(c, fourthID) | |
| // all | |
| out = cli.DockerCmd(c, "ps", "-a").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, thirdID, secondID, firstID}), true, fmt.Sprintf("ALL: Container list is not in the correct order: \n%s", out)) | |
| // running | |
| out = cli.DockerCmd(c, "ps").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), []string{fourthID, secondID, firstID}), true, fmt.Sprintf("RUNNING: Container list is not in the correct order: \n%s", out)) | |
| // limit | |
| out = cli.DockerCmd(c, "ps", "-n=2", "-a").Stdout() | |
| expected := []string{fourthID, thirdID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("LIMIT & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-n=2").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("LIMIT: Container list is not in the correct order: \n%s", out)) | |
| // filter since | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-a").Stdout() | |
| expected = []string{fourthID, thirdID, secondID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID).Stdout() | |
| expected = []string{fourthID, secondID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+thirdID).Stdout() | |
| expected = []string{fourthID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out)) | |
| // filter before | |
| out = cli.DockerCmd(c, "ps", "-f", "before="+fourthID, "-a").Stdout() | |
| expected = []string{thirdID, secondID, firstID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("BEFORE filter & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "before="+fourthID).Stdout() | |
| expected = []string{secondID, firstID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("BEFORE filter: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "before="+thirdID).Stdout() | |
| expected = []string{secondID, firstID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out)) | |
| // filter since & before | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a").Stdout() | |
| expected = []string{thirdID, secondID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, BEFORE filter & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID).Stdout() | |
| expected = []string{secondID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, BEFORE filter: Container list is not in the correct order: \n%s", out)) | |
| // filter since & limit | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a").Stdout() | |
| expected = []string{fourthID, thirdID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-n=2").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, LIMIT: Container list is not in the correct order: \n%s", out)) | |
| // filter before & limit | |
| out = cli.DockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a").Stdout() | |
| expected = []string{thirdID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out)) | |
| // filter since & filter before & limit | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a").Stdout() | |
| expected = []string{thirdID} | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out)) | |
| out = cli.DockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1").Stdout() | |
| assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter, BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out)) | |
| } | |
| func assertContainerList(out string, expected []string) bool { | |
| lines := strings.Split(strings.Trim(out, "\n "), "\n") | |
| if len(lines)-1 != len(expected) { | |
| return false | |
| } | |
| containerIDIndex := strings.Index(lines[0], "CONTAINER ID") | |
| for i := 0; i < len(expected); i++ { | |
| foundID := lines[i+1][containerIDIndex : containerIDIndex+12] | |
| if foundID != expected[i][:12] { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersSize(c *testing.T) { | |
| // Problematic on Windows as it doesn't report the size correctly @swernli | |
| testRequires(c, DaemonIsLinux) | |
| cli.DockerCmd(c, "run", "-d", "busybox") | |
| baseOut := cli.DockerCmd(c, "ps", "-s", "-n=1").Stdout() | |
| baseLines := strings.Split(strings.Trim(baseOut, "\n "), "\n") | |
| baseSizeIndex := strings.Index(baseLines[0], "SIZE") | |
| baseFoundsize, _, _ := strings.Cut(baseLines[1][baseSizeIndex:], " ") | |
| baseBytes, err := units.FromHumanSize(baseFoundsize) | |
| assert.NilError(c, err) | |
| const name = "test_size" | |
| cli.DockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo 1 > test") | |
| id := getIDByName(c, name) | |
| var result *icmd.Result | |
| wait := make(chan struct{}) | |
| go func() { | |
| result = icmd.RunCommand(dockerBinary, "ps", "-s", "-n=1") | |
| close(wait) | |
| }() | |
| select { | |
| case <-wait: | |
| case <-time.After(3 * time.Second): | |
| c.Fatalf(`Calling "docker ps -s" timed out!`) | |
| } | |
| result.Assert(c, icmd.Success) | |
| lines := strings.Split(strings.Trim(result.Combined(), "\n "), "\n") | |
| assert.Equal(c, len(lines), 2, "Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines)) | |
| sizeIndex := strings.Index(lines[0], "SIZE") | |
| idIndex := strings.Index(lines[0], "CONTAINER ID") | |
| foundID := lines[1][idIndex : idIndex+12] | |
| assert.Equal(c, foundID, id[:12], fmt.Sprintf("Expected id %s, got %s", id[:12], foundID)) | |
| foundSize, _, _ := strings.Cut(strings.TrimSpace(lines[1][sizeIndex:]), " ") | |
| // With snapshotters the reported usage is the real space occupied on the | |
| // filesystem (also includes metadata), so this new file can actually | |
| // result in a bigger increase depending on the underlying filesystem (on | |
| // ext4 this would be 4096 which is a minimum allocation unit). | |
| if testEnv.UsingSnapshotter() { | |
| newBytes, err := units.FromHumanSize(foundSize) | |
| assert.NilError(c, err) | |
| // Check if size increased by at least 2 bytes. | |
| assert.Check(c, newBytes >= baseBytes+2) | |
| } else { | |
| expectedSize := units.HumanSize(float64(baseBytes + 2)) | |
| assert.Assert(c, strings.Contains(foundSize, expectedSize), "Expected size %q, got %q", expectedSize, foundSize) | |
| } | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterStatus(c *testing.T) { | |
| existingContainers := ExistingContainerIDs(c) | |
| // start exited container | |
| out := cli.DockerCmd(c, "run", "-d", "busybox").Combined() | |
| firstID := strings.TrimSpace(out) | |
| // make sure the exited container is not running | |
| cli.DockerCmd(c, "wait", firstID) | |
| // start running container | |
| out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined() | |
| secondID := strings.TrimSpace(out) | |
| // filter containers by exited | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=exited").Combined() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), firstID) | |
| out = cli.DockerCmd(c, "ps", "-a", "--no-trunc", "-q", "--filter=status=running").Combined() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), secondID) | |
| result := cli.Docker(cli.Args("ps", "-a", "-q", "--filter=status=rubbish"), cli.WithTimeout(time.Second*60)) | |
| result.Assert(c, icmd.Expected{ | |
| ExitCode: 1, | |
| Err: "invalid filter 'status=rubbish'", | |
| }) | |
| // Windows doesn't support pausing of containers | |
| if testEnv.DaemonInfo.OSType != "windows" { | |
| // pause running container | |
| out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined() | |
| pausedID := strings.TrimSpace(out) | |
| cli.DockerCmd(c, "pause", pausedID) | |
| // make sure the container is unpaused to let the daemon stop it properly | |
| defer func() { cli.DockerCmd(c, "unpause", pausedID) }() | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=paused").Combined() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), pausedID) | |
| } | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterHealth(c *testing.T) { | |
| skip.If(c, RuntimeIsWindowsContainerd(), "FIXME. Hang on Windows + containerd combination") | |
| existingContainers := ExistingContainerIDs(c) | |
| // Test legacy no health check | |
| containerID := runSleepingContainer(c, "--name=none_legacy") | |
| cli.WaitRun(c, containerID) | |
| out := cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected id %s, got %s for legacy none filter, output: %q", containerID, containerOut, out)) | |
| // Test no health check specified explicitly | |
| containerID = runSleepingContainer(c, "--name=none", "--no-healthcheck") | |
| cli.WaitRun(c, containerID) | |
| out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected id %s, got %s for none filter, output: %q", containerID, containerOut, out)) | |
| // Test failing health check | |
| out = runSleepingContainer(c, "--name=failing_container", "--health-cmd=exit 1", "--health-interval=1s") | |
| containerID = strings.TrimSpace(out) | |
| waitForHealthStatus(c, "failing_container", "starting", "unhealthy") | |
| out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=unhealthy").Combined() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected containerID %s, got %s for unhealthy filter, output: %q", containerID, containerOut, out)) | |
| // Check passing healthcheck | |
| containerID = runSleepingContainer(c, "--name=passing_container", "--health-cmd=exit 0", "--health-interval=1s") | |
| waitForHealthStatus(c, "passing_container", "starting", "healthy") | |
| out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=healthy").Combined() | |
| containerOut = strings.TrimSpace(RemoveOutputForExistingElements(out, existingContainers)) | |
| assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected containerID %s, got %s for healthy filter, output: %q", containerID, containerOut, out)) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterID(c *testing.T) { | |
| // start container | |
| out := cli.DockerCmd(c, "run", "-d", "busybox").Stdout() | |
| firstID := strings.TrimSpace(out) | |
| // start another container | |
| runSleepingContainer(c) | |
| // filter containers by id | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--filter=id="+firstID).Stdout() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, firstID[:12], fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out)) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterName(c *testing.T) { | |
| // start container | |
| cli.DockerCmd(c, "run", "--name=a_name_to_match", "busybox") | |
| id := getIDByName(c, "a_name_to_match") | |
| // start another container | |
| runSleepingContainer(c, "--name=b_name_to_match") | |
| // filter containers by name | |
| out := cli.DockerCmd(c, "ps", "-a", "-q", "--filter=name=a_name_to_match").Stdout() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, id[:12], fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", id[:12], containerOut, out)) | |
| } | |
| // Test for the ancestor filter for ps. | |
| // There is also the same test but with image:tag@digest in docker_cli_by_digest_test.go | |
| // | |
| // What the test setups : | |
| // - Create 2 image based on busybox using the same repository but different tags | |
| // - Create an image based on the previous image (images_ps_filter_test2) | |
| // - Run containers for each of those image (busybox, images_ps_filter_test1, images_ps_filter_test2) | |
| // - Filter them out :P | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterAncestorImage(c *testing.T) { | |
| existingContainers := ExistingContainerIDs(c) | |
| // Build images | |
| imageName1 := "images_ps_filter_test1" | |
| buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox | |
| LABEL match me 1`)) | |
| imageID1 := getIDByName(c, imageName1) | |
| imageName1Tagged := "images_ps_filter_test1:tag" | |
| buildImageSuccessfully(c, imageName1Tagged, build.WithDockerfile(`FROM busybox | |
| LABEL match me 1 tagged`)) | |
| imageID1Tagged := getIDByName(c, imageName1Tagged) | |
| imageName2 := "images_ps_filter_test2" | |
| buildImageSuccessfully(c, imageName2, build.WithDockerfile(fmt.Sprintf(`FROM %s | |
| LABEL match me 2`, imageName1))) | |
| imageID2 := getIDByName(c, imageName2) | |
| // start containers | |
| cli.DockerCmd(c, "run", "--name=first", "busybox", "echo", "hello") | |
| firstID := getIDByName(c, "first") | |
| // start another container | |
| cli.DockerCmd(c, "run", "--name=second", "busybox", "echo", "hello") | |
| secondID := getIDByName(c, "second") | |
| // start third container | |
| cli.DockerCmd(c, "run", "--name=third", imageName1, "echo", "hello") | |
| thirdID := getIDByName(c, "third") | |
| // start fourth container | |
| cli.DockerCmd(c, "run", "--name=fourth", imageName1Tagged, "echo", "hello") | |
| fourthID := getIDByName(c, "fourth") | |
| // start fifth container | |
| cli.DockerCmd(c, "run", "--name=fifth", imageName2, "echo", "hello") | |
| fifthID := getIDByName(c, "fifth") | |
| filterTestSuite := []struct { | |
| filterName string | |
| expectedIDs []string | |
| }{ | |
| // non existent stuff | |
| {"nonexistent", []string{}}, | |
| {"nonexistent:tag", []string{}}, | |
| // image | |
| {"busybox", []string{firstID, secondID, thirdID, fourthID, fifthID}}, | |
| {imageName1, []string{thirdID, fifthID}}, | |
| {imageName2, []string{fifthID}}, | |
| // image:tag | |
| {fmt.Sprintf("%s:latest", imageName1), []string{thirdID, fifthID}}, | |
| {imageName1Tagged, []string{fourthID}}, | |
| // short-id | |
| {stringid.TruncateID(imageID1), []string{thirdID, fifthID}}, | |
| {stringid.TruncateID(imageID2), []string{fifthID}}, | |
| // full-id | |
| {imageID1, []string{thirdID, fifthID}}, | |
| {imageID1Tagged, []string{fourthID}}, | |
| {imageID2, []string{fifthID}}, | |
| } | |
| var out string | |
| for _, filter := range filterTestSuite { | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+filter.filterName).Stdout() | |
| checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), filter.filterName, filter.expectedIDs) | |
| } | |
| // Multiple ancestor filter | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageName2, "--filter=ancestor="+imageName1Tagged).Stdout() | |
| checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), imageName2+","+imageName1Tagged, []string{fourthID, fifthID}) | |
| } | |
| func checkPsAncestorFilterOutput(c *testing.T, out string, filterName string, expectedIDs []string) { | |
| var actualIDs []string | |
| if out != "" { | |
| actualIDs = strings.Split(out[:len(out)-1], "\n") | |
| } | |
| sort.Strings(actualIDs) | |
| sort.Strings(expectedIDs) | |
| assert.Equal(c, len(actualIDs), len(expectedIDs), fmt.Sprintf("Expected filtered container(s) for %s ancestor filter to be %v:%v, got %v:%v", filterName, len(expectedIDs), expectedIDs, len(actualIDs), actualIDs)) | |
| if len(expectedIDs) > 0 { | |
| same := true | |
| for i := range expectedIDs { | |
| if actualIDs[i] != expectedIDs[i] { | |
| c.Logf("%s, %s", actualIDs[i], expectedIDs[i]) | |
| same = false | |
| break | |
| } | |
| } | |
| assert.Equal(c, same, true, fmt.Sprintf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs)) | |
| } | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterLabel(c *testing.T) { | |
| // start container | |
| cli.DockerCmd(c, "run", "--name=first", "-l", "match=me", "-l", "second=tag", "busybox") | |
| firstID := getIDByName(c, "first") | |
| // start another container | |
| cli.DockerCmd(c, "run", "--name=second", "-l", "match=me too", "busybox") | |
| secondID := getIDByName(c, "second") | |
| // start third container | |
| cli.DockerCmd(c, "run", "--name=third", "-l", "nomatch=me", "busybox") | |
| thirdID := getIDByName(c, "third") | |
| // filter containers by exact match | |
| out := cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me").Stdout() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, firstID, fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)) | |
| // filter containers by two labels | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag").Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, firstID, fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out)) | |
| // filter containers by two labels, but expect not found because of AND behavior | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag-no").Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Equal(c, containerOut, "", fmt.Sprintf("Expected nothing, got %s for exited filter, output: %q", containerOut, out)) | |
| // filter containers by exact key | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match").Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Assert(c, strings.Contains(containerOut, firstID)) | |
| assert.Assert(c, strings.Contains(containerOut, secondID)) | |
| assert.Assert(c, !strings.Contains(containerOut, thirdID)) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterExited(c *testing.T) { | |
| // TODO Flaky on Windows CI [both RS1 and RS5] | |
| // On slower machines the container may not have exited | |
| // yet when we filter below by exit status/exit value. | |
| skip.If(c, DaemonIsWindows(), "FLAKY on Windows, see #20819") | |
| runSleepingContainer(c, "--name=sleep") | |
| firstZero := cli.DockerCmd(c, "run", "-d", "busybox", "true").Stdout() | |
| secondZero := cli.DockerCmd(c, "run", "-d", "busybox", "true").Stdout() | |
| out, _, err := dockerCmdWithError("run", "--name", "nonzero1", "busybox", "false") | |
| assert.Assert(c, err != nil, "Should fail. out: %s", out) | |
| firstNonZero := getIDByName(c, "nonzero1") | |
| out, _, err = dockerCmdWithError("run", "--name", "nonzero2", "busybox", "false") | |
| assert.Assert(c, err != nil, "Should fail. out: %s", out) | |
| secondNonZero := getIDByName(c, "nonzero2") | |
| // filter containers by exited=0 | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0").Stdout() | |
| assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstZero))) | |
| assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondZero))) | |
| assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstNonZero))) | |
| assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondNonZero))) | |
| out = cli.DockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1").Stdout() | |
| assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstNonZero))) | |
| assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondNonZero))) | |
| assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstZero))) | |
| assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondZero))) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsRightTagName(c *testing.T) { | |
| // TODO Investigate further why this fails on Windows to Windows CI | |
| testRequires(c, DaemonIsLinux) | |
| existingContainers := ExistingContainerNames(c) | |
| tag := "asybox:shmatest" | |
| cli.DockerCmd(c, "tag", "busybox", tag) | |
| id1 := runSleepingContainer(c) | |
| id2 := runSleepingContainerInImage(c, tag) | |
| imageID := inspectField(c, "busybox", "Id") | |
| id3 := runSleepingContainerInImage(c, imageID) | |
| out := cli.DockerCmd(c, "ps", "--no-trunc").Stdout() | |
| lines := strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| // skip header | |
| lines = lines[1:] | |
| assert.Equal(c, len(lines), 3, "There should be 3 running container, got %d", len(lines)) | |
| for _, line := range lines { | |
| f := strings.Fields(line) | |
| switch f[0] { | |
| case id1: | |
| assert.Equal(c, f[1], "busybox", fmt.Sprintf("Expected %s tag for id %s, got %s", "busybox", id1, f[1])) | |
| case id2: | |
| assert.Equal(c, f[1], tag, fmt.Sprintf("Expected %s tag for id %s, got %s", tag, id2, f[1])) | |
| case id3: | |
| assert.Equal(c, f[1], imageID, fmt.Sprintf("Expected %s imageID for id %s, got %s", tag, id3, f[1])) | |
| default: | |
| c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3) | |
| } | |
| } | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterCreated(c *testing.T) { | |
| // create a container | |
| out := cli.DockerCmd(c, "create", "busybox").Stdout() | |
| cID := strings.TrimSpace(out) | |
| shortCID := cID[:12] | |
| // Make sure it DOESN'T show up w/o a '-a' for normal 'ps' | |
| out = cli.DockerCmd(c, "ps", "-q").Stdout() | |
| assert.Assert(c, !strings.Contains(out, shortCID), "Should have not seen '%s' in ps output:\n%s", shortCID, out) | |
| // Make sure it DOES show up as 'Created' for 'ps -a' | |
| out = cli.DockerCmd(c, "ps", "-a").Stdout() | |
| hits := 0 | |
| for _, line := range strings.Split(out, "\n") { | |
| if !strings.Contains(line, shortCID) { | |
| continue | |
| } | |
| hits++ | |
| assert.Assert(c, strings.Contains(line, "Created"), "Missing 'Created' on '%s'", line) | |
| } | |
| assert.Equal(c, hits, 1, fmt.Sprintf("Should have seen '%s' in ps -a output once:%d\n%s", shortCID, hits, out)) | |
| // filter containers by 'create' - note, no -a needed | |
| out = cli.DockerCmd(c, "ps", "-q", "-f", "status=created").Stdout() | |
| containerOut := strings.TrimSpace(out) | |
| assert.Assert(c, strings.Contains(containerOut, shortCID), "Should have seen '%s' in ps output:\n%s", shortCID, out) | |
| } | |
| // Test for GitHub issue #12595 | |
| func (s *DockerCLIPsSuite) TestPsImageIDAfterUpdate(c *testing.T) { | |
| // TODO: Investigate why this fails on Windows to Windows CI further. | |
| testRequires(c, DaemonIsLinux) | |
| originalImageName := "busybox:TestPsImageIDAfterUpdate-original" | |
| updatedImageName := "busybox:TestPsImageIDAfterUpdate-updated" | |
| existingContainers := ExistingContainerIDs(c) | |
| icmd.RunCommand(dockerBinary, "tag", "busybox:latest", originalImageName).Assert(c, icmd.Success) | |
| originalImageID := getIDByName(c, originalImageName) | |
| result := icmd.RunCommand(dockerBinary, append([]string{"run", "-d", originalImageName}, sleepCommandForDaemonPlatform()...)...) | |
| result.Assert(c, icmd.Success) | |
| containerID := strings.TrimSpace(result.Combined()) | |
| result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc") | |
| result.Assert(c, icmd.Success) | |
| lines := strings.Split(strings.TrimSpace(result.Combined()), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| // skip header | |
| lines = lines[1:] | |
| assert.Equal(c, len(lines), 1) | |
| for _, line := range lines { | |
| f := strings.Fields(line) | |
| assert.Equal(c, f[1], originalImageName) | |
| } | |
| icmd.RunCommand(dockerBinary, "commit", containerID, updatedImageName).Assert(c, icmd.Success) | |
| icmd.RunCommand(dockerBinary, "tag", updatedImageName, originalImageName).Assert(c, icmd.Success) | |
| result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc") | |
| result.Assert(c, icmd.Success) | |
| lines = strings.Split(strings.TrimSpace(result.Combined()), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| // skip header | |
| lines = lines[1:] | |
| assert.Equal(c, len(lines), 1) | |
| for _, line := range lines { | |
| f := strings.Fields(line) | |
| assert.Equal(c, f[1], originalImageID) | |
| } | |
| } | |
| func (s *DockerCLIPsSuite) TestPsNotShowPortsOfStoppedContainer(c *testing.T) { | |
| testRequires(c, DaemonIsLinux) | |
| cli.DockerCmd(c, "run", "--name=foo", "-d", "-p", "6000:5000", "busybox", "top") | |
| cli.WaitRun(c, "foo") | |
| ports := cli.DockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo").Stdout() | |
| expected := ":6000->5000/tcp" | |
| assert.Assert(c, is.Contains(ports, expected), "Expected: %v, got: %v", expected, ports) | |
| cli.DockerCmd(c, "kill", "foo") | |
| cli.DockerCmd(c, "wait", "foo") | |
| ports = cli.DockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo").Stdout() | |
| assert.Equal(c, ports, "", "Should not got %v", expected) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsShowMounts(c *testing.T) { | |
| existingContainers := ExistingContainerNames(c) | |
| prefix, slash := getPrefixAndSlashFromDaemonPlatform() | |
| mp := prefix + slash + "test" | |
| cli.DockerCmd(c, "volume", "create", "ps-volume-test") | |
| // volume mount containers | |
| runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp) | |
| cli.WaitRun(c, "volume-test-1") | |
| runSleepingContainer(c, "--name=volume-test-2", "--volume", mp) | |
| cli.WaitRun(c, "volume-test-2") | |
| // bind mount container | |
| var bindMountSource string | |
| var bindMountDestination string | |
| if DaemonIsWindows() { | |
| bindMountSource = `c:\` | |
| bindMountDestination = `c:\t` | |
| } else { | |
| bindMountSource = "/tmp" | |
| bindMountDestination = "/t" | |
| } | |
| runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination) | |
| cli.WaitRun(c, "bind-mount-test") | |
| out := cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}").Stdout() | |
| lines := strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| assert.Equal(c, len(lines), 3) | |
| fields := strings.Fields(lines[0]) | |
| assert.Equal(c, len(fields), 2) | |
| assert.Equal(c, fields[0], "bind-mount-test") | |
| assert.Equal(c, fields[1], bindMountSource) | |
| fields = strings.Fields(lines[1]) | |
| assert.Equal(c, len(fields), 2) | |
| anonymousVolumeID := fields[1] | |
| fields = strings.Fields(lines[2]) | |
| assert.Equal(c, fields[1], "ps-volume-test") | |
| // filter by volume name | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test").Stdout() | |
| lines = strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| assert.Equal(c, len(lines), 1) | |
| fields = strings.Fields(lines[0]) | |
| assert.Equal(c, fields[1], "ps-volume-test") | |
| // empty results filtering by unknown volume | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist").Stdout() | |
| assert.Equal(c, len(strings.TrimSpace(out)), 0) | |
| // filter by mount destination | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp).Stdout() | |
| lines = strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| assert.Equal(c, len(lines), 2) | |
| fields = strings.Fields(lines[0]) | |
| assert.Equal(c, fields[1], anonymousVolumeID) | |
| fields = strings.Fields(lines[1]) | |
| assert.Equal(c, fields[1], "ps-volume-test") | |
| // filter by bind mount source | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource).Stdout() | |
| lines = strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| assert.Equal(c, len(lines), 1) | |
| fields = strings.Fields(lines[0]) | |
| assert.Equal(c, len(fields), 2) | |
| assert.Equal(c, fields[0], "bind-mount-test") | |
| assert.Equal(c, fields[1], bindMountSource) | |
| // filter by bind mount destination | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination).Stdout() | |
| lines = strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| assert.Equal(c, len(lines), 1) | |
| fields = strings.Fields(lines[0]) | |
| assert.Equal(c, len(fields), 2) | |
| assert.Equal(c, fields[0], "bind-mount-test") | |
| assert.Equal(c, fields[1], bindMountSource) | |
| // empty results filtering by unknown mount point | |
| out = cli.DockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted").Stdout() | |
| assert.Equal(c, len(strings.TrimSpace(out)), 0) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterNetwork(c *testing.T) { | |
| existing := ExistingContainerIDs(c) | |
| // TODO default network on Windows is not called "bridge", and creating a | |
| // custom network fails on Windows fails with "Error response from daemon: plugin not found") | |
| testRequires(c, DaemonIsLinux) | |
| // create some containers | |
| runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork") | |
| runSleepingContainer(c, "--net=none", "--name=onnonenetwork") | |
| // Filter docker ps on non existing network | |
| out := cli.DockerCmd(c, "ps", "--filter", "network=doesnotexist").Stdout() | |
| containerOut := strings.TrimSpace(out) | |
| lines := strings.Split(containerOut, "\n") | |
| // skip header | |
| lines = lines[1:] | |
| // ps output should have no containers | |
| assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 0) | |
| // Filter docker ps on network bridge | |
| out = cli.DockerCmd(c, "ps", "--filter", "network=bridge").Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| lines = strings.Split(containerOut, "\n") | |
| // skip header | |
| lines = lines[1:] | |
| // ps output should have only one container | |
| assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1) | |
| // Making sure onbridgenetwork is on the output | |
| assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n") | |
| // Filter docker ps on networks bridge and none | |
| out = cli.DockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none").Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| lines = strings.Split(containerOut, "\n") | |
| // skip header | |
| lines = lines[1:] | |
| // ps output should have both the containers | |
| assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 2) | |
| // Making sure onbridgenetwork and onnonenetwork is on the output | |
| assert.Assert(c, strings.Contains(containerOut, "onnonenetwork"), "Missing the container on none network\n") | |
| assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on bridge network\n") | |
| nwID := cli.DockerCmd(c, "network", "inspect", "--format", "{{.ID}}", "bridge").Stdout() | |
| // Filter by network ID | |
| out = cli.DockerCmd(c, "ps", "--filter", "network="+nwID).Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| assert.Assert(c, is.Contains(containerOut, "onbridgenetwork")) | |
| // Filter by partial network ID | |
| partialNwID := nwID[0:4] | |
| out = cli.DockerCmd(c, "ps", "--filter", "network="+partialNwID).Stdout() | |
| containerOut = strings.TrimSpace(out) | |
| lines = strings.Split(containerOut, "\n") | |
| // skip header | |
| lines = lines[1:] | |
| // ps output should have only one container | |
| assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1) | |
| // Making sure onbridgenetwork is on the output | |
| assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n") | |
| } | |
| func (s *DockerCLIPsSuite) TestPsByOrder(c *testing.T) { | |
| container1 := runSleepingContainer(c, "--name", "xyz-abc") | |
| container2 := runSleepingContainer(c, "--name", "xyz-123") | |
| runSleepingContainer(c, "--name", "789-abc") | |
| runSleepingContainer(c, "--name", "789-123") | |
| // Run multiple time should have the same result | |
| out := cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined() | |
| assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1)) | |
| // Run multiple time should have the same result | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined() | |
| assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1)) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsListContainersFilterPorts(c *testing.T) { | |
| testRequires(c, DaemonIsLinux) | |
| existingContainers := ExistingContainerIDs(c) | |
| out := cli.DockerCmd(c, "run", "-d", "--publish=80", "busybox", "top").Stdout() | |
| id1 := strings.TrimSpace(out) | |
| out = cli.DockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top").Stdout() | |
| id2 := strings.TrimSpace(out) | |
| out = cli.DockerCmd(c, "run", "-d", "-p", "1090:90", "busybox", "top").Stdout() | |
| id3 := strings.TrimSpace(out) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q").Stdout() | |
| assert.Assert(c, strings.Contains(strings.TrimSpace(out), id1)) | |
| assert.Assert(c, strings.Contains(strings.TrimSpace(out), id2)) | |
| assert.Assert(c, strings.Contains(strings.TrimSpace(out), id3)) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp").Stdout() | |
| assert.Assert(c, strings.TrimSpace(out) != id1) | |
| assert.Assert(c, strings.TrimSpace(out) != id2) | |
| assert.Assert(c, strings.TrimSpace(out) != id3) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081").Stdout() | |
| assert.Assert(c, strings.TrimSpace(out) != id1) | |
| assert.Assert(c, strings.TrimSpace(out) != id2) | |
| assert.Assert(c, strings.TrimSpace(out) != id3) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81").Stdout() | |
| assert.Assert(c, strings.TrimSpace(out) != id1) | |
| assert.Assert(c, strings.TrimSpace(out) != id2) | |
| assert.Assert(c, strings.TrimSpace(out) != id3) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp").Stdout() | |
| assert.Equal(c, strings.TrimSpace(out), id1) | |
| assert.Assert(c, strings.TrimSpace(out) != id2) | |
| assert.Assert(c, strings.TrimSpace(out) != id3) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=1090").Stdout() | |
| assert.Assert(c, strings.TrimSpace(out) != id1) | |
| assert.Assert(c, strings.TrimSpace(out) != id2) | |
| assert.Equal(c, strings.TrimSpace(out), id3) | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp").Stdout() | |
| out = RemoveOutputForExistingElements(out, existingContainers) | |
| assert.Assert(c, strings.TrimSpace(out) != id1) | |
| assert.Equal(c, strings.TrimSpace(out), id2) | |
| assert.Assert(c, strings.TrimSpace(out) != id3) | |
| } | |
| func (s *DockerCLIPsSuite) TestPsNotShowLinknamesOfDeletedContainer(c *testing.T) { | |
| testRequires(c, DaemonIsLinux) | |
| existingContainers := ExistingContainerNames(c) | |
| cli.DockerCmd(c, "create", "--name=aaa", "busybox", "top") | |
| cli.DockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top") | |
| out := cli.DockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}").Stdout() | |
| lines := strings.Split(strings.TrimSpace(out), "\n") | |
| lines = RemoveLinesForExistingElements(lines, existingContainers) | |
| expected := []string{"bbb", "aaa,bbb/aaa"} | |
| var names []string | |
| names = append(names, lines...) | |
| assert.Assert(c, is.DeepEqual(names, expected), "Expected array with non-truncated names: %v, got: %v", expected, names) | |
| cli.DockerCmd(c, "rm", "bbb") | |
| out = cli.DockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}").Stdout() | |
| out = RemoveOutputForExistingElements(out, existingContainers) | |
| assert.Equal(c, strings.TrimSpace(out), "aaa") | |
| } |