github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration-cli/docker_cli_ps_test.go (about)

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