github.com/docker/engine@v22.0.0-20211208180946-d456264580cf+incompatible/integration-cli/docker_cli_ps_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"strconv"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/docker/docker/api/types/versions"
    12  	"github.com/docker/docker/integration-cli/cli"
    13  	"github.com/docker/docker/integration-cli/cli/build"
    14  	"github.com/docker/docker/pkg/stringid"
    15  	"gotest.tools/v3/assert"
    16  	is "gotest.tools/v3/assert/cmp"
    17  	"gotest.tools/v3/icmd"
    18  	"gotest.tools/v3/skip"
    19  )
    20  
    21  func (s *DockerSuite) TestPsListContainersBase(c *testing.T) {
    22  	existingContainers := ExistingContainerIDs(c)
    23  
    24  	out := runSleepingContainer(c, "-d")
    25  	firstID := strings.TrimSpace(out)
    26  
    27  	out = runSleepingContainer(c, "-d")
    28  	secondID := strings.TrimSpace(out)
    29  
    30  	// not long running
    31  	out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
    32  	thirdID := strings.TrimSpace(out)
    33  
    34  	out = runSleepingContainer(c, "-d")
    35  	fourthID := strings.TrimSpace(out)
    36  
    37  	// make sure the second is running
    38  	assert.Assert(c, waitRun(secondID) == nil)
    39  
    40  	// make sure third one is not running
    41  	dockerCmd(c, "wait", thirdID)
    42  
    43  	// make sure the forth is running
    44  	assert.Assert(c, waitRun(fourthID) == nil)
    45  
    46  	// all
    47  	out, _ = dockerCmd(c, "ps", "-a")
    48  	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))
    49  
    50  	// running
    51  	out, _ = dockerCmd(c, "ps")
    52  	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))
    53  
    54  	// limit
    55  	out, _ = dockerCmd(c, "ps", "-n=2", "-a")
    56  	expected := []string{fourthID, thirdID}
    57  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("LIMIT & ALL: Container list is not in the correct order: \n%s", out))
    58  
    59  	out, _ = dockerCmd(c, "ps", "-n=2")
    60  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("LIMIT: Container list is not in the correct order: \n%s", out))
    61  
    62  	// filter since
    63  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-a")
    64  	expected = []string{fourthID, thirdID, secondID}
    65  	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))
    66  
    67  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
    68  	expected = []string{fourthID, secondID}
    69  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out))
    70  
    71  	out, _ = dockerCmd(c, "ps", "-f", "since="+thirdID)
    72  	expected = []string{fourthID}
    73  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out))
    74  
    75  	// filter before
    76  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
    77  	expected = []string{thirdID, secondID, firstID}
    78  	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))
    79  
    80  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
    81  	expected = []string{secondID, firstID}
    82  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("BEFORE filter: Container list is not in the correct order: \n%s", out))
    83  
    84  	out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID)
    85  	expected = []string{secondID, firstID}
    86  	assert.Equal(c, assertContainerList(RemoveOutputForExistingElements(out, existingContainers), expected), true, fmt.Sprintf("SINCE filter: Container list is not in the correct order: \n%s", out))
    87  
    88  	// filter since & before
    89  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a")
    90  	expected = []string{thirdID, secondID}
    91  	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))
    92  
    93  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
    94  	expected = []string{secondID}
    95  	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))
    96  
    97  	// filter since & limit
    98  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
    99  	expected = []string{fourthID, thirdID}
   100  
   101  	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))
   102  
   103  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
   104  	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))
   105  
   106  	// filter before & limit
   107  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
   108  	expected = []string{thirdID}
   109  	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))
   110  
   111  	out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
   112  	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))
   113  
   114  	// filter since & filter before & limit
   115  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a")
   116  	expected = []string{thirdID}
   117  	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))
   118  
   119  	out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
   120  	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))
   121  
   122  }
   123  
   124  func assertContainerList(out string, expected []string) bool {
   125  	lines := strings.Split(strings.Trim(out, "\n "), "\n")
   126  
   127  	if len(lines)-1 != len(expected) {
   128  		return false
   129  	}
   130  
   131  	containerIDIndex := strings.Index(lines[0], "CONTAINER ID")
   132  	for i := 0; i < len(expected); i++ {
   133  		foundID := lines[i+1][containerIDIndex : containerIDIndex+12]
   134  		if foundID != expected[i][:12] {
   135  			return false
   136  		}
   137  	}
   138  
   139  	return true
   140  }
   141  
   142  func (s *DockerSuite) TestPsListContainersSize(c *testing.T) {
   143  	// Problematic on Windows as it doesn't report the size correctly @swernli
   144  	testRequires(c, DaemonIsLinux)
   145  	dockerCmd(c, "run", "-d", "busybox")
   146  
   147  	baseOut, _ := dockerCmd(c, "ps", "-s", "-n=1")
   148  	baseLines := strings.Split(strings.Trim(baseOut, "\n "), "\n")
   149  	baseSizeIndex := strings.Index(baseLines[0], "SIZE")
   150  	baseFoundsize := baseLines[1][baseSizeIndex:]
   151  	baseBytes, err := strconv.Atoi(strings.Split(baseFoundsize, "B")[0])
   152  	assert.NilError(c, err)
   153  
   154  	name := "test_size"
   155  	dockerCmd(c, "run", "--name", name, "busybox", "sh", "-c", "echo 1 > test")
   156  	id := getIDByName(c, name)
   157  
   158  	var result *icmd.Result
   159  
   160  	wait := make(chan struct{})
   161  	go func() {
   162  		result = icmd.RunCommand(dockerBinary, "ps", "-s", "-n=1")
   163  		close(wait)
   164  	}()
   165  	select {
   166  	case <-wait:
   167  	case <-time.After(3 * time.Second):
   168  		c.Fatalf("Calling \"docker ps -s\" timed out!")
   169  	}
   170  	result.Assert(c, icmd.Success)
   171  	lines := strings.Split(strings.Trim(result.Combined(), "\n "), "\n")
   172  	assert.Equal(c, len(lines), 2, "Expected 2 lines for 'ps -s -n=1' output, got %d", len(lines))
   173  	sizeIndex := strings.Index(lines[0], "SIZE")
   174  	idIndex := strings.Index(lines[0], "CONTAINER ID")
   175  	foundID := lines[1][idIndex : idIndex+12]
   176  	assert.Equal(c, foundID, id[:12], fmt.Sprintf("Expected id %s, got %s", id[:12], foundID))
   177  	expectedSize := fmt.Sprintf("%dB", 2+baseBytes)
   178  	foundSize := lines[1][sizeIndex:]
   179  	assert.Assert(c, strings.Contains(foundSize, expectedSize), "Expected size %q, got %q", expectedSize, foundSize)
   180  }
   181  
   182  func (s *DockerSuite) TestPsListContainersFilterStatus(c *testing.T) {
   183  	existingContainers := ExistingContainerIDs(c)
   184  
   185  	// start exited container
   186  	out := cli.DockerCmd(c, "run", "-d", "busybox").Combined()
   187  	firstID := strings.TrimSpace(out)
   188  
   189  	// make sure the exited container is not running
   190  	cli.DockerCmd(c, "wait", firstID)
   191  
   192  	// start running container
   193  	out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
   194  	secondID := strings.TrimSpace(out)
   195  
   196  	// filter containers by exited
   197  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=exited").Combined()
   198  	containerOut := strings.TrimSpace(out)
   199  	assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), firstID)
   200  
   201  	out = cli.DockerCmd(c, "ps", "-a", "--no-trunc", "-q", "--filter=status=running").Combined()
   202  	containerOut = strings.TrimSpace(out)
   203  	assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), secondID)
   204  
   205  	result := cli.Docker(cli.Args("ps", "-a", "-q", "--filter=status=rubbish"), cli.WithTimeout(time.Second*60))
   206  	err := "Invalid filter 'status=rubbish'"
   207  	if versions.LessThan(testEnv.DaemonAPIVersion(), "1.32") {
   208  		err = "Unrecognised filter value for status: rubbish"
   209  	}
   210  	result.Assert(c, icmd.Expected{
   211  		ExitCode: 1,
   212  		Err:      err,
   213  	})
   214  	// Windows doesn't support pausing of containers
   215  	if testEnv.OSType != "windows" {
   216  		// pause running container
   217  		out = cli.DockerCmd(c, "run", "-itd", "busybox").Combined()
   218  		pausedID := strings.TrimSpace(out)
   219  		cli.DockerCmd(c, "pause", pausedID)
   220  		// make sure the container is unpaused to let the daemon stop it properly
   221  		defer func() { cli.DockerCmd(c, "unpause", pausedID) }()
   222  
   223  		out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "--filter=status=paused").Combined()
   224  		containerOut = strings.TrimSpace(out)
   225  		assert.Equal(c, RemoveOutputForExistingElements(containerOut, existingContainers), pausedID)
   226  	}
   227  }
   228  
   229  func (s *DockerSuite) TestPsListContainersFilterHealth(c *testing.T) {
   230  	skip.If(c, RuntimeIsWindowsContainerd(), "FIXME. Hang on Windows + containerd combination")
   231  	existingContainers := ExistingContainerIDs(c)
   232  	// Test legacy no health check
   233  	out := runSleepingContainer(c, "--name=none_legacy")
   234  	containerID := strings.TrimSpace(out)
   235  
   236  	cli.WaitRun(c, containerID)
   237  
   238  	out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
   239  	containerOut := strings.TrimSpace(out)
   240  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected id %s, got %s for legacy none filter, output: %q", containerID, containerOut, out))
   241  
   242  	// Test no health check specified explicitly
   243  	out = runSleepingContainer(c, "--name=none", "--no-healthcheck")
   244  	containerID = strings.TrimSpace(out)
   245  
   246  	cli.WaitRun(c, containerID)
   247  
   248  	out = cli.DockerCmd(c, "ps", "-q", "-l", "--no-trunc", "--filter=health=none").Combined()
   249  	containerOut = strings.TrimSpace(out)
   250  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected id %s, got %s for none filter, output: %q", containerID, containerOut, out))
   251  
   252  	// Test failing health check
   253  	out = runSleepingContainer(c, "--name=failing_container", "--health-cmd=exit 1", "--health-interval=1s")
   254  	containerID = strings.TrimSpace(out)
   255  
   256  	waitForHealthStatus(c, "failing_container", "starting", "unhealthy")
   257  
   258  	out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=unhealthy").Combined()
   259  	containerOut = strings.TrimSpace(out)
   260  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected containerID %s, got %s for unhealthy filter, output: %q", containerID, containerOut, out))
   261  
   262  	// Check passing healthcheck
   263  	out = runSleepingContainer(c, "--name=passing_container", "--health-cmd=exit 0", "--health-interval=1s")
   264  	containerID = strings.TrimSpace(out)
   265  
   266  	waitForHealthStatus(c, "passing_container", "starting", "healthy")
   267  
   268  	out = cli.DockerCmd(c, "ps", "-q", "--no-trunc", "--filter=health=healthy").Combined()
   269  	containerOut = strings.TrimSpace(RemoveOutputForExistingElements(out, existingContainers))
   270  	assert.Equal(c, containerOut, containerID, fmt.Sprintf("Expected containerID %s, got %s for healthy filter, output: %q", containerID, containerOut, out))
   271  }
   272  
   273  func (s *DockerSuite) TestPsListContainersFilterID(c *testing.T) {
   274  	// start container
   275  	out, _ := dockerCmd(c, "run", "-d", "busybox")
   276  	firstID := strings.TrimSpace(out)
   277  
   278  	// start another container
   279  	runSleepingContainer(c)
   280  
   281  	// filter containers by id
   282  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--filter=id="+firstID)
   283  	containerOut := strings.TrimSpace(out)
   284  	assert.Equal(c, containerOut, firstID[:12], fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID[:12], containerOut, out))
   285  }
   286  
   287  func (s *DockerSuite) TestPsListContainersFilterName(c *testing.T) {
   288  	// start container
   289  	dockerCmd(c, "run", "--name=a_name_to_match", "busybox")
   290  	id := getIDByName(c, "a_name_to_match")
   291  
   292  	// start another container
   293  	runSleepingContainer(c, "--name=b_name_to_match")
   294  
   295  	// filter containers by name
   296  	out, _ := dockerCmd(c, "ps", "-a", "-q", "--filter=name=a_name_to_match")
   297  	containerOut := strings.TrimSpace(out)
   298  	assert.Equal(c, containerOut, id[:12], fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", id[:12], containerOut, out))
   299  }
   300  
   301  // Test for the ancestor filter for ps.
   302  // There is also the same test but with image:tag@digest in docker_cli_by_digest_test.go
   303  //
   304  // What the test setups :
   305  // - Create 2 image based on busybox using the same repository but different tags
   306  // - Create an image based on the previous image (images_ps_filter_test2)
   307  // - Run containers for each of those image (busybox, images_ps_filter_test1, images_ps_filter_test2)
   308  // - Filter them out :P
   309  func (s *DockerSuite) TestPsListContainersFilterAncestorImage(c *testing.T) {
   310  	existingContainers := ExistingContainerIDs(c)
   311  
   312  	// Build images
   313  	imageName1 := "images_ps_filter_test1"
   314  	buildImageSuccessfully(c, imageName1, build.WithDockerfile(`FROM busybox
   315  		 LABEL match me 1`))
   316  	imageID1 := getIDByName(c, imageName1)
   317  
   318  	imageName1Tagged := "images_ps_filter_test1:tag"
   319  	buildImageSuccessfully(c, imageName1Tagged, build.WithDockerfile(`FROM busybox
   320  		 LABEL match me 1 tagged`))
   321  	imageID1Tagged := getIDByName(c, imageName1Tagged)
   322  
   323  	imageName2 := "images_ps_filter_test2"
   324  	buildImageSuccessfully(c, imageName2, build.WithDockerfile(fmt.Sprintf(`FROM %s
   325  		 LABEL match me 2`, imageName1)))
   326  	imageID2 := getIDByName(c, imageName2)
   327  
   328  	// start containers
   329  	dockerCmd(c, "run", "--name=first", "busybox", "echo", "hello")
   330  	firstID := getIDByName(c, "first")
   331  
   332  	// start another container
   333  	dockerCmd(c, "run", "--name=second", "busybox", "echo", "hello")
   334  	secondID := getIDByName(c, "second")
   335  
   336  	// start third container
   337  	dockerCmd(c, "run", "--name=third", imageName1, "echo", "hello")
   338  	thirdID := getIDByName(c, "third")
   339  
   340  	// start fourth container
   341  	dockerCmd(c, "run", "--name=fourth", imageName1Tagged, "echo", "hello")
   342  	fourthID := getIDByName(c, "fourth")
   343  
   344  	// start fifth container
   345  	dockerCmd(c, "run", "--name=fifth", imageName2, "echo", "hello")
   346  	fifthID := getIDByName(c, "fifth")
   347  
   348  	var filterTestSuite = []struct {
   349  		filterName  string
   350  		expectedIDs []string
   351  	}{
   352  		// non existent stuff
   353  		{"nonexistent", []string{}},
   354  		{"nonexistent:tag", []string{}},
   355  		// image
   356  		{"busybox", []string{firstID, secondID, thirdID, fourthID, fifthID}},
   357  		{imageName1, []string{thirdID, fifthID}},
   358  		{imageName2, []string{fifthID}},
   359  		// image:tag
   360  		{fmt.Sprintf("%s:latest", imageName1), []string{thirdID, fifthID}},
   361  		{imageName1Tagged, []string{fourthID}},
   362  		// short-id
   363  		{stringid.TruncateID(imageID1), []string{thirdID, fifthID}},
   364  		{stringid.TruncateID(imageID2), []string{fifthID}},
   365  		// full-id
   366  		{imageID1, []string{thirdID, fifthID}},
   367  		{imageID1Tagged, []string{fourthID}},
   368  		{imageID2, []string{fifthID}},
   369  	}
   370  
   371  	var out string
   372  	for _, filter := range filterTestSuite {
   373  		out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+filter.filterName)
   374  		checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), filter.filterName, filter.expectedIDs)
   375  	}
   376  
   377  	// Multiple ancestor filter
   378  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageName2, "--filter=ancestor="+imageName1Tagged)
   379  	checkPsAncestorFilterOutput(c, RemoveOutputForExistingElements(out, existingContainers), imageName2+","+imageName1Tagged, []string{fourthID, fifthID})
   380  }
   381  
   382  func checkPsAncestorFilterOutput(c *testing.T, out string, filterName string, expectedIDs []string) {
   383  	var actualIDs []string
   384  	if out != "" {
   385  		actualIDs = strings.Split(out[:len(out)-1], "\n")
   386  	}
   387  	sort.Strings(actualIDs)
   388  	sort.Strings(expectedIDs)
   389  
   390  	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))
   391  	if len(expectedIDs) > 0 {
   392  		same := true
   393  		for i := range expectedIDs {
   394  			if actualIDs[i] != expectedIDs[i] {
   395  				c.Logf("%s, %s", actualIDs[i], expectedIDs[i])
   396  				same = false
   397  				break
   398  			}
   399  		}
   400  		assert.Equal(c, same, true, fmt.Sprintf("Expected filtered container(s) for %s ancestor filter to be %v, got %v", filterName, expectedIDs, actualIDs))
   401  	}
   402  }
   403  
   404  func (s *DockerSuite) TestPsListContainersFilterLabel(c *testing.T) {
   405  	// start container
   406  	dockerCmd(c, "run", "--name=first", "-l", "match=me", "-l", "second=tag", "busybox")
   407  	firstID := getIDByName(c, "first")
   408  
   409  	// start another container
   410  	dockerCmd(c, "run", "--name=second", "-l", "match=me too", "busybox")
   411  	secondID := getIDByName(c, "second")
   412  
   413  	// start third container
   414  	dockerCmd(c, "run", "--name=third", "-l", "nomatch=me", "busybox")
   415  	thirdID := getIDByName(c, "third")
   416  
   417  	// filter containers by exact match
   418  	out, _ := dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me")
   419  	containerOut := strings.TrimSpace(out)
   420  	assert.Equal(c, containerOut, firstID, fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
   421  
   422  	// filter containers by two labels
   423  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag")
   424  	containerOut = strings.TrimSpace(out)
   425  	assert.Equal(c, containerOut, firstID, fmt.Sprintf("Expected id %s, got %s for exited filter, output: %q", firstID, containerOut, out))
   426  
   427  	// filter containers by two labels, but expect not found because of AND behavior
   428  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match=me", "--filter=label=second=tag-no")
   429  	containerOut = strings.TrimSpace(out)
   430  	assert.Equal(c, containerOut, "", fmt.Sprintf("Expected nothing, got %s for exited filter, output: %q", containerOut, out))
   431  
   432  	// filter containers by exact key
   433  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=label=match")
   434  	containerOut = strings.TrimSpace(out)
   435  	assert.Assert(c, strings.Contains(containerOut, firstID))
   436  	assert.Assert(c, strings.Contains(containerOut, secondID))
   437  	assert.Assert(c, !strings.Contains(containerOut, thirdID))
   438  }
   439  
   440  func (s *DockerSuite) TestPsListContainersFilterExited(c *testing.T) {
   441  	// TODO Flaky on  Windows CI [both RS1 and RS5]
   442  	// On slower machines the container may not have exited
   443  	// yet when we filter below by exit status/exit value.
   444  	skip.If(c, DaemonIsWindows(), "FLAKY on Windows, see #20819")
   445  	runSleepingContainer(c, "--name=sleep")
   446  
   447  	firstZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   448  	secondZero, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   449  
   450  	out, _, err := dockerCmdWithError("run", "--name", "nonzero1", "busybox", "false")
   451  	assert.Assert(c, err != nil, "Should fail. out: %s", out)
   452  	firstNonZero := getIDByName(c, "nonzero1")
   453  
   454  	out, _, err = dockerCmdWithError("run", "--name", "nonzero2", "busybox", "false")
   455  	assert.Assert(c, err != nil, "Should fail. out: %s", out)
   456  	secondNonZero := getIDByName(c, "nonzero2")
   457  
   458  	// filter containers by exited=0
   459  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=0")
   460  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstZero)))
   461  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondZero)))
   462  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstNonZero)))
   463  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondNonZero)))
   464  	out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=exited=1")
   465  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(firstNonZero)))
   466  	assert.Assert(c, strings.Contains(out, strings.TrimSpace(secondNonZero)))
   467  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(firstZero)))
   468  	assert.Assert(c, !strings.Contains(out, strings.TrimSpace(secondZero)))
   469  }
   470  
   471  func (s *DockerSuite) TestPsRightTagName(c *testing.T) {
   472  	// TODO Investigate further why this fails on Windows to Windows CI
   473  	testRequires(c, DaemonIsLinux)
   474  
   475  	existingContainers := ExistingContainerNames(c)
   476  
   477  	tag := "asybox:shmatest"
   478  	dockerCmd(c, "tag", "busybox", tag)
   479  
   480  	var id1 string
   481  	out := runSleepingContainer(c)
   482  	id1 = strings.TrimSpace(out)
   483  
   484  	var id2 string
   485  	out = runSleepingContainerInImage(c, tag)
   486  	id2 = strings.TrimSpace(out)
   487  
   488  	var imageID string
   489  	out = inspectField(c, "busybox", "Id")
   490  	imageID = strings.TrimSpace(out)
   491  
   492  	var id3 string
   493  	out = runSleepingContainerInImage(c, imageID)
   494  	id3 = strings.TrimSpace(out)
   495  
   496  	out, _ = dockerCmd(c, "ps", "--no-trunc")
   497  	lines := strings.Split(strings.TrimSpace(out), "\n")
   498  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   499  	// skip header
   500  	lines = lines[1:]
   501  	assert.Equal(c, len(lines), 3, "There should be 3 running container, got %d", len(lines))
   502  	for _, line := range lines {
   503  		f := strings.Fields(line)
   504  		switch f[0] {
   505  		case id1:
   506  			assert.Equal(c, f[1], "busybox", fmt.Sprintf("Expected %s tag for id %s, got %s", "busybox", id1, f[1]))
   507  		case id2:
   508  			assert.Equal(c, f[1], tag, fmt.Sprintf("Expected %s tag for id %s, got %s", tag, id2, f[1]))
   509  		case id3:
   510  			assert.Equal(c, f[1], imageID, fmt.Sprintf("Expected %s imageID for id %s, got %s", tag, id3, f[1]))
   511  		default:
   512  			c.Fatalf("Unexpected id %s, expected %s and %s and %s", f[0], id1, id2, id3)
   513  		}
   514  	}
   515  }
   516  
   517  func (s *DockerSuite) TestPsListContainersFilterCreated(c *testing.T) {
   518  	// create a container
   519  	out, _ := dockerCmd(c, "create", "busybox")
   520  	cID := strings.TrimSpace(out)
   521  	shortCID := cID[:12]
   522  
   523  	// Make sure it DOESN'T show up w/o a '-a' for normal 'ps'
   524  	out, _ = dockerCmd(c, "ps", "-q")
   525  	assert.Assert(c, !strings.Contains(out, shortCID), "Should have not seen '%s' in ps output:\n%s", shortCID, out)
   526  	// Make sure it DOES show up as 'Created' for 'ps -a'
   527  	out, _ = dockerCmd(c, "ps", "-a")
   528  
   529  	hits := 0
   530  	for _, line := range strings.Split(out, "\n") {
   531  		if !strings.Contains(line, shortCID) {
   532  			continue
   533  		}
   534  		hits++
   535  		assert.Assert(c, strings.Contains(line, "Created"), "Missing 'Created' on '%s'", line)
   536  	}
   537  
   538  	assert.Equal(c, hits, 1, fmt.Sprintf("Should have seen '%s' in ps -a output once:%d\n%s", shortCID, hits, out))
   539  
   540  	// filter containers by 'create' - note, no -a needed
   541  	out, _ = dockerCmd(c, "ps", "-q", "-f", "status=created")
   542  	containerOut := strings.TrimSpace(out)
   543  	assert.Assert(c, strings.HasPrefix(cID, containerOut))
   544  }
   545  
   546  // Test for GitHub issue #12595
   547  func (s *DockerSuite) TestPsImageIDAfterUpdate(c *testing.T) {
   548  	// TODO: Investigate why this fails on Windows to Windows CI further.
   549  	testRequires(c, DaemonIsLinux)
   550  	originalImageName := "busybox:TestPsImageIDAfterUpdate-original"
   551  	updatedImageName := "busybox:TestPsImageIDAfterUpdate-updated"
   552  
   553  	existingContainers := ExistingContainerIDs(c)
   554  
   555  	icmd.RunCommand(dockerBinary, "tag", "busybox:latest", originalImageName).Assert(c, icmd.Success)
   556  
   557  	originalImageID := getIDByName(c, originalImageName)
   558  
   559  	result := icmd.RunCommand(dockerBinary, append([]string{"run", "-d", originalImageName}, sleepCommandForDaemonPlatform()...)...)
   560  	result.Assert(c, icmd.Success)
   561  	containerID := strings.TrimSpace(result.Combined())
   562  
   563  	result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
   564  	result.Assert(c, icmd.Success)
   565  
   566  	lines := strings.Split(strings.TrimSpace(result.Combined()), "\n")
   567  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   568  	// skip header
   569  	lines = lines[1:]
   570  	assert.Equal(c, len(lines), 1)
   571  
   572  	for _, line := range lines {
   573  		f := strings.Fields(line)
   574  		assert.Equal(c, f[1], originalImageName)
   575  	}
   576  
   577  	icmd.RunCommand(dockerBinary, "commit", containerID, updatedImageName).Assert(c, icmd.Success)
   578  	icmd.RunCommand(dockerBinary, "tag", updatedImageName, originalImageName).Assert(c, icmd.Success)
   579  
   580  	result = icmd.RunCommand(dockerBinary, "ps", "--no-trunc")
   581  	result.Assert(c, icmd.Success)
   582  
   583  	lines = strings.Split(strings.TrimSpace(result.Combined()), "\n")
   584  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   585  	// skip header
   586  	lines = lines[1:]
   587  	assert.Equal(c, len(lines), 1)
   588  
   589  	for _, line := range lines {
   590  		f := strings.Fields(line)
   591  		assert.Equal(c, f[1], originalImageID)
   592  	}
   593  
   594  }
   595  
   596  func (s *DockerSuite) TestPsNotShowPortsOfStoppedContainer(c *testing.T) {
   597  	testRequires(c, DaemonIsLinux)
   598  	dockerCmd(c, "run", "--name=foo", "-d", "-p", "6000:5000", "busybox", "top")
   599  	assert.Assert(c, waitRun("foo") == nil)
   600  	ports, _ := dockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo")
   601  	expected := ":6000->5000/tcp"
   602  	assert.Assert(c, is.Contains(ports, expected), "Expected: %v, got: %v", expected, ports)
   603  
   604  	dockerCmd(c, "kill", "foo")
   605  	dockerCmd(c, "wait", "foo")
   606  	ports, _ = dockerCmd(c, "ps", "--format", "{{ .Ports }}", "--filter", "name=foo")
   607  	assert.Equal(c, ports, "", "Should not got %v", expected)
   608  }
   609  
   610  func (s *DockerSuite) TestPsShowMounts(c *testing.T) {
   611  	existingContainers := ExistingContainerNames(c)
   612  
   613  	prefix, slash := getPrefixAndSlashFromDaemonPlatform()
   614  
   615  	mp := prefix + slash + "test"
   616  
   617  	dockerCmd(c, "volume", "create", "ps-volume-test")
   618  	// volume mount containers
   619  	runSleepingContainer(c, "--name=volume-test-1", "--volume", "ps-volume-test:"+mp)
   620  	assert.Assert(c, waitRun("volume-test-1") == nil)
   621  	runSleepingContainer(c, "--name=volume-test-2", "--volume", mp)
   622  	assert.Assert(c, waitRun("volume-test-2") == nil)
   623  	// bind mount container
   624  	var bindMountSource string
   625  	var bindMountDestination string
   626  	if DaemonIsWindows() {
   627  		bindMountSource = "c:\\"
   628  		bindMountDestination = "c:\\t"
   629  	} else {
   630  		bindMountSource = "/tmp"
   631  		bindMountDestination = "/t"
   632  	}
   633  	runSleepingContainer(c, "--name=bind-mount-test", "-v", bindMountSource+":"+bindMountDestination)
   634  	assert.Assert(c, waitRun("bind-mount-test") == nil)
   635  
   636  	out, _ := dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}")
   637  
   638  	lines := strings.Split(strings.TrimSpace(out), "\n")
   639  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   640  	assert.Equal(c, len(lines), 3)
   641  
   642  	fields := strings.Fields(lines[0])
   643  	assert.Equal(c, len(fields), 2)
   644  	assert.Equal(c, fields[0], "bind-mount-test")
   645  	assert.Equal(c, fields[1], bindMountSource)
   646  
   647  	fields = strings.Fields(lines[1])
   648  	assert.Equal(c, len(fields), 2)
   649  
   650  	anonymousVolumeID := fields[1]
   651  
   652  	fields = strings.Fields(lines[2])
   653  	assert.Equal(c, fields[1], "ps-volume-test")
   654  
   655  	// filter by volume name
   656  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=ps-volume-test")
   657  
   658  	lines = strings.Split(strings.TrimSpace(out), "\n")
   659  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   660  	assert.Equal(c, len(lines), 1)
   661  
   662  	fields = strings.Fields(lines[0])
   663  	assert.Equal(c, fields[1], "ps-volume-test")
   664  
   665  	// empty results filtering by unknown volume
   666  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume=this-volume-should-not-exist")
   667  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   668  
   669  	// filter by mount destination
   670  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+mp)
   671  
   672  	lines = strings.Split(strings.TrimSpace(out), "\n")
   673  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   674  	assert.Equal(c, len(lines), 2)
   675  
   676  	fields = strings.Fields(lines[0])
   677  	assert.Equal(c, fields[1], anonymousVolumeID)
   678  	fields = strings.Fields(lines[1])
   679  	assert.Equal(c, fields[1], "ps-volume-test")
   680  
   681  	// filter by bind mount source
   682  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountSource)
   683  
   684  	lines = strings.Split(strings.TrimSpace(out), "\n")
   685  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   686  	assert.Equal(c, len(lines), 1)
   687  
   688  	fields = strings.Fields(lines[0])
   689  	assert.Equal(c, len(fields), 2)
   690  	assert.Equal(c, fields[0], "bind-mount-test")
   691  	assert.Equal(c, fields[1], bindMountSource)
   692  
   693  	// filter by bind mount destination
   694  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+bindMountDestination)
   695  
   696  	lines = strings.Split(strings.TrimSpace(out), "\n")
   697  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   698  	assert.Equal(c, len(lines), 1)
   699  
   700  	fields = strings.Fields(lines[0])
   701  	assert.Equal(c, len(fields), 2)
   702  	assert.Equal(c, fields[0], "bind-mount-test")
   703  	assert.Equal(c, fields[1], bindMountSource)
   704  
   705  	// empty results filtering by unknown mount point
   706  	out, _ = dockerCmd(c, "ps", "--format", "{{.Names}} {{.Mounts}}", "--filter", "volume="+prefix+slash+"this-path-was-never-mounted")
   707  	assert.Equal(c, len(strings.TrimSpace(out)), 0)
   708  }
   709  
   710  func (s *DockerSuite) TestPsListContainersFilterNetwork(c *testing.T) {
   711  	existing := ExistingContainerIDs(c)
   712  
   713  	// TODO default network on Windows is not called "bridge", and creating a
   714  	// custom network fails on Windows fails with "Error response from daemon: plugin not found")
   715  	testRequires(c, DaemonIsLinux)
   716  
   717  	// create some containers
   718  	runSleepingContainer(c, "--net=bridge", "--name=onbridgenetwork")
   719  	runSleepingContainer(c, "--net=none", "--name=onnonenetwork")
   720  
   721  	// Filter docker ps on non existing network
   722  	out, _ := dockerCmd(c, "ps", "--filter", "network=doesnotexist")
   723  	containerOut := strings.TrimSpace(out)
   724  	lines := strings.Split(containerOut, "\n")
   725  
   726  	// skip header
   727  	lines = lines[1:]
   728  
   729  	// ps output should have no containers
   730  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 0)
   731  
   732  	// Filter docker ps on network bridge
   733  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge")
   734  	containerOut = strings.TrimSpace(out)
   735  
   736  	lines = strings.Split(containerOut, "\n")
   737  
   738  	// skip header
   739  	lines = lines[1:]
   740  
   741  	// ps output should have only one container
   742  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
   743  
   744  	// Making sure onbridgenetwork is on the output
   745  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   746  	// Filter docker ps on networks bridge and none
   747  	out, _ = dockerCmd(c, "ps", "--filter", "network=bridge", "--filter", "network=none")
   748  	containerOut = strings.TrimSpace(out)
   749  
   750  	lines = strings.Split(containerOut, "\n")
   751  
   752  	// skip header
   753  	lines = lines[1:]
   754  
   755  	// ps output should have both the containers
   756  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 2)
   757  
   758  	// Making sure onbridgenetwork and onnonenetwork is on the output
   759  	assert.Assert(c, strings.Contains(containerOut, "onnonenetwork"), "Missing the container on none network\n")
   760  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on bridge network\n")
   761  	nwID, _ := dockerCmd(c, "network", "inspect", "--format", "{{.ID}}", "bridge")
   762  
   763  	// Filter by network ID
   764  	out, _ = dockerCmd(c, "ps", "--filter", "network="+nwID)
   765  	containerOut = strings.TrimSpace(out)
   766  
   767  	assert.Assert(c, is.Contains(containerOut, "onbridgenetwork"))
   768  
   769  	// Filter by partial network ID
   770  	partialnwID := nwID[0:4]
   771  
   772  	out, _ = dockerCmd(c, "ps", "--filter", "network="+partialnwID)
   773  	containerOut = strings.TrimSpace(out)
   774  
   775  	lines = strings.Split(containerOut, "\n")
   776  
   777  	// skip header
   778  	lines = lines[1:]
   779  
   780  	// ps output should have only one container
   781  	assert.Equal(c, len(RemoveLinesForExistingElements(lines, existing)), 1)
   782  
   783  	// Making sure onbridgenetwork is on the output
   784  	assert.Assert(c, strings.Contains(containerOut, "onbridgenetwork"), "Missing the container on network\n")
   785  }
   786  
   787  func (s *DockerSuite) TestPsByOrder(c *testing.T) {
   788  	out := runSleepingContainer(c, "--name", "xyz-abc")
   789  	container1 := strings.TrimSpace(out)
   790  
   791  	out = runSleepingContainer(c, "--name", "xyz-123")
   792  	container2 := strings.TrimSpace(out)
   793  
   794  	runSleepingContainer(c, "--name", "789-abc")
   795  	runSleepingContainer(c, "--name", "789-123")
   796  
   797  	// Run multiple time should have the same result
   798  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
   799  	assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
   800  
   801  	// Run multiple time should have the same result
   802  	out = cli.DockerCmd(c, "ps", "--no-trunc", "-q", "-f", "name=xyz").Combined()
   803  	assert.Equal(c, strings.TrimSpace(out), fmt.Sprintf("%s\n%s", container2, container1))
   804  }
   805  
   806  func (s *DockerSuite) TestPsListContainersFilterPorts(c *testing.T) {
   807  	testRequires(c, DaemonIsLinux)
   808  	existingContainers := ExistingContainerIDs(c)
   809  
   810  	out, _ := dockerCmd(c, "run", "-d", "--publish=80", "busybox", "top")
   811  	id1 := strings.TrimSpace(out)
   812  
   813  	out, _ = dockerCmd(c, "run", "-d", "--expose=8080", "busybox", "top")
   814  	id2 := strings.TrimSpace(out)
   815  
   816  	out, _ = dockerCmd(c, "run", "-d", "-p", "1090:90", "busybox", "top")
   817  	id3 := strings.TrimSpace(out)
   818  
   819  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q")
   820  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id1))
   821  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id2))
   822  	assert.Assert(c, strings.Contains(strings.TrimSpace(out), id3))
   823  
   824  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-8080/udp")
   825  	assert.Assert(c, strings.TrimSpace(out) != id1)
   826  	assert.Assert(c, strings.TrimSpace(out) != id2)
   827  	assert.Assert(c, strings.TrimSpace(out) != id3)
   828  
   829  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8081")
   830  	assert.Assert(c, strings.TrimSpace(out) != id1)
   831  	assert.Assert(c, strings.TrimSpace(out) != id2)
   832  	assert.Assert(c, strings.TrimSpace(out) != id3)
   833  
   834  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=80-81")
   835  	assert.Assert(c, strings.TrimSpace(out) != id1)
   836  	assert.Assert(c, strings.TrimSpace(out) != id2)
   837  	assert.Assert(c, strings.TrimSpace(out) != id3)
   838  
   839  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=80/tcp")
   840  	assert.Equal(c, strings.TrimSpace(out), id1)
   841  	assert.Assert(c, strings.TrimSpace(out) != id2)
   842  	assert.Assert(c, strings.TrimSpace(out) != id3)
   843  
   844  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "publish=1090")
   845  	assert.Assert(c, strings.TrimSpace(out) != id1)
   846  	assert.Assert(c, strings.TrimSpace(out) != id2)
   847  	assert.Equal(c, strings.TrimSpace(out), id3)
   848  
   849  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-q", "--filter", "expose=8080/tcp")
   850  	out = RemoveOutputForExistingElements(out, existingContainers)
   851  	assert.Assert(c, strings.TrimSpace(out) != id1)
   852  	assert.Equal(c, strings.TrimSpace(out), id2)
   853  	assert.Assert(c, strings.TrimSpace(out) != id3)
   854  }
   855  
   856  func (s *DockerSuite) TestPsNotShowLinknamesOfDeletedContainer(c *testing.T) {
   857  	testRequires(c, DaemonIsLinux, MinimumAPIVersion("1.31"))
   858  	existingContainers := ExistingContainerNames(c)
   859  
   860  	dockerCmd(c, "create", "--name=aaa", "busybox", "top")
   861  	dockerCmd(c, "create", "--name=bbb", "--link=aaa", "busybox", "top")
   862  
   863  	out, _ := dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   864  	lines := strings.Split(strings.TrimSpace(out), "\n")
   865  	lines = RemoveLinesForExistingElements(lines, existingContainers)
   866  	expected := []string{"bbb", "aaa,bbb/aaa"}
   867  	var names []string
   868  	names = append(names, lines...)
   869  	assert.Assert(c, is.DeepEqual(names, expected), "Expected array with non-truncated names: %v, got: %v", expected, names)
   870  
   871  	dockerCmd(c, "rm", "bbb")
   872  
   873  	out, _ = dockerCmd(c, "ps", "--no-trunc", "-a", "--format", "{{.Names}}")
   874  	out = RemoveOutputForExistingElements(out, existingContainers)
   875  	assert.Equal(c, strings.TrimSpace(out), "aaa")
   876  }