Skip to content

Commit

Permalink
Support --format tables in ps output
Browse files Browse the repository at this point in the history
- Added tests to help ensure there is no future regressions
- Added WaitWithTimeout(int) rather than calling
  WaitWithDefaultTimeout() multiple times
- Exposed DefaultWaitTimeout to allow test to use a multiplier

Fixes containers#2221

Signed-off-by: Jhon Honce <[email protected]>
  • Loading branch information
jwhonce authored and mheon committed Sep 22, 2021
1 parent 45f8b01 commit 70a4286
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 26 deletions.
8 changes: 6 additions & 2 deletions cmd/podman/containers/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,10 @@ func ps(cmd *cobra.Command, _ []string) error {
}

hdrs, format := createPsOut()

noHeading, _ := cmd.Flags().GetBool("noheading")
if cmd.Flags().Changed("format") {
noHeading = noHeading || !report.HasTable(listOpts.Format)
format = report.NormalizeFormat(listOpts.Format)
format = report.EnforceRange(format)
}
Expand All @@ -240,8 +243,7 @@ func ps(cmd *cobra.Command, _ []string) error {
defer w.Flush()

headers := func() error { return nil }
noHeading, _ := cmd.Flags().GetBool("noheading")
if !(noHeading || listOpts.Quiet || cmd.Flags().Changed("format")) {
if !noHeading {
headers = func() error {
return tmpl.Execute(w, hdrs)
}
Expand Down Expand Up @@ -298,9 +300,11 @@ func createPsOut() ([]map[string]string, string) {
"IPC": "ipc",
"MNT": "mnt",
"NET": "net",
"Networks": "networks",
"PIDNS": "pidns",
"Pod": "pod id",
"PodName": "podname", // undo camelcase space break
"RunningFor": "running for",
"UTS": "uts",
"User": "userns",
})
Expand Down
57 changes: 38 additions & 19 deletions test/e2e/ps_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"regexp"
"sort"
"strconv"
"strings"

. "github.com/containers/podman/v3/test/utils"
"github.com/containers/storage/pkg/stringid"
Expand Down Expand Up @@ -187,7 +186,10 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
Expect(result.OutputToString()).To(ContainSubstring("bravo"))

actual := result.OutputToString()
Expect(actual).To(ContainSubstring("bravo"))
Expect(actual).To(ContainSubstring("NAMES"))
})

It("podman ps --filter network=container:<id>", func() {
Expand All @@ -206,7 +208,9 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
Expect(result.OutputToString()).To(ContainSubstring("second"))
actual := result.OutputToString()
Expect(actual).To(ContainSubstring("second"))
Expect(actual).ToNot(ContainSubstring("table"))
})

It("podman ps namespace flag", func() {
Expand All @@ -228,7 +232,7 @@ var _ = Describe("Podman ps", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
// it must contains `::` when some ns is null. If it works normally, it should be "$num1:$num2:$num3"
Expect(result.OutputToString()).To(Not(ContainSubstring(`::`)))
Expect(result.OutputToString()).ToNot(ContainSubstring(`::`))
})

It("podman ps with no containers is valid json format", func() {
Expand Down Expand Up @@ -285,11 +289,14 @@ var _ = Describe("Podman ps", func() {

result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.ImageID}} {{.Labels}}"})
result.WaitWithDefaultTimeout()

Expect(result.OutputToStringArray()[0]).ToNot(ContainSubstring("table"))
Expect(result.OutputToStringArray()[0]).ToNot(ContainSubstring("ImageID"))
Expect(result.OutputToStringArray()[0]).To(ContainSubstring("alpine:latest"))
Expect(result).Should(Exit(0))

Expect(result.OutputToString()).ToNot(ContainSubstring("table"))

actual := result.OutputToStringArray()
Expect(actual[0]).To(ContainSubstring("CONTAINER ID"))
Expect(actual[0]).ToNot(ContainSubstring("ImageID"))
Expect(actual[1]).To(ContainSubstring("alpine:latest"))
})

It("podman ps ancestor filter flag", func() {
Expand Down Expand Up @@ -380,7 +387,9 @@ var _ = Describe("Podman ps", func() {
psFilter.WaitWithDefaultTimeout()
Expect(psFilter).Should(Exit(0))

Expect(strings.Contains(psFilter.OutputToString(), ctrName)).To(BeFalse())
actual := psFilter.OutputToString()
Expect(actual).ToNot(ContainSubstring(ctrName))
Expect(actual).ToNot(ContainSubstring("NAMES"))
})

It("podman ps mutually exclusive flags", func() {
Expand Down Expand Up @@ -453,14 +462,13 @@ var _ = Describe("Podman ps", func() {
Expect(session).Should(Exit(0))

session = podmanTest.Podman([]string{"ps", "-a", "--sort=command", "--format", "{{.Command}}"})

session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))

sortedArr := session.OutputToStringArray()
Expect(session.OutputToString()).ToNot(ContainSubstring("COMMAND"))

sortedArr := session.OutputToStringArray()
Expect(sort.SliceIsSorted(sortedArr, func(i, j int) bool { return sortedArr[i] < sortedArr[j] })).To(BeTrue())

})

It("podman --pod", func() {
Expand All @@ -474,7 +482,7 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--no-trunc"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(Not(ContainSubstring(podid)))
Expect(session.OutputToString()).ToNot(ContainSubstring(podid))

session = podmanTest.Podman([]string{"ps", "--pod", "--no-trunc"})
session.WaitWithDefaultTimeout()
Expand Down Expand Up @@ -510,7 +518,11 @@ var _ = Describe("Podman ps", func() {

session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
Expect(session.OutputToString()).To(ContainSubstring("0.0.0.0:2000-2006"))
Expect(session).To(Exit(0))

actual := session.OutputToString()
Expect(actual).To(ContainSubstring("0.0.0.0:2000-2006"))
Expect(actual).ToNot(ContainSubstring("PORT"))
})

It("podman ps test with invalid port range", func() {
Expand Down Expand Up @@ -628,7 +640,10 @@ var _ = Describe("Podman ps", func() {
result := podmanTest.Podman([]string{"ps", "-a", "--format", "{{.RunningFor}}"})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
Expect(result.OutputToString()).To(ContainSubstring("ago"))

actual := result.OutputToString()
Expect(actual).To(ContainSubstring("ago"))
Expect(actual).ToNot(ContainSubstring("RUNNING FOR"))
})

It("podman ps filter test", func() {
Expand Down Expand Up @@ -823,8 +838,9 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--all", "--no-trunc", "--filter", "network=" + net})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring(ctrWithNet))
Expect(session.OutputToString()).To(Not(ContainSubstring(ctrWithoutNet)))
actual := session.OutputToString()
Expect(actual).To(ContainSubstring(ctrWithNet))
Expect(actual).ToNot(ContainSubstring(ctrWithoutNet))
})

It("podman ps --format networks", func() {
Expand All @@ -835,12 +851,15 @@ var _ = Describe("Podman ps", func() {
session = podmanTest.Podman([]string{"ps", "--all", "--format", "{{ .Networks }}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))

actual := session.OutputToString()
Expect(actual).ToNot(ContainSubstring("NETWORKS"))
if isRootless() {
// rootless container don't have a network by default
Expect(session.OutputToString()).To(Equal(""))
Expect(actual).To(BeEmpty())
} else {
// default network name is podman
Expect(session.OutputToString()).To(Equal("podman"))
Expect(actual).To(Equal("podman"))
}

net1 := stringid.GenerateNonCryptoID()
Expand Down
15 changes: 10 additions & 5 deletions test/utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
)

var (
defaultWaitTimeout = 90
DefaultWaitTimeout = 90
OSReleasePath = "/etc/os-release"
ProcessOneCgroupPath = "/proc/1/cgroup"
)
Expand Down Expand Up @@ -317,15 +317,20 @@ func (s *PodmanSession) IsJSONOutputValid() bool {
return true
}

// WaitWithDefaultTimeout waits for process finished with defaultWaitTimeout
// WaitWithDefaultTimeout waits for process finished with DefaultWaitTimeout
func (s *PodmanSession) WaitWithDefaultTimeout() {
Eventually(s, defaultWaitTimeout).Should(Exit())
s.WaitWithTimeout(DefaultWaitTimeout)
}

// WaitWithTimeout waits for process finished with DefaultWaitTimeout
func (s *PodmanSession) WaitWithTimeout(timeout int) {
Eventually(s, timeout).Should(Exit())
os.Stdout.Sync()
os.Stderr.Sync()
fmt.Println("output:", s.OutputToString())
}

// CreateTempDirinTempDir create a temp dir with prefix podman_test
// CreateTempDirInTempDir create a temp dir with prefix podman_test
func CreateTempDirInTempDir() (string, error) {
return ioutil.TempDir("", "podman_test")
}
Expand All @@ -337,7 +342,7 @@ func SystemExec(command string, args []string) *PodmanSession {
if err != nil {
Fail(fmt.Sprintf("unable to run command: %s %s", command, strings.Join(args, " ")))
}
session.Wait(defaultWaitTimeout)
session.Wait(DefaultWaitTimeout)
return &PodmanSession{session}
}

Expand Down

0 comments on commit 70a4286

Please sign in to comment.