浏览代码

Complete unit tests on api/client/ps package

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester 9 年之前
父节点
当前提交
6baf65d1a6
共有 4 个文件被更改,包括 293 次插入77 次删除
  1. 0 65
      api/client/ps/custom.go
  2. 18 12
      api/client/ps/custom_test.go
  3. 67 0
      api/client/ps/formatter.go
  4. 208 0
      api/client/ps/formatter_test.go

+ 0 - 65
api/client/ps/custom.go

@@ -1,12 +1,9 @@
 package ps
 
 import (
-	"bytes"
 	"fmt"
 	"strconv"
 	"strings"
-	"text/tabwriter"
-	"text/template"
 	"time"
 
 	"github.com/docker/docker/api"
@@ -152,68 +149,6 @@ func (c *containerContext) addHeader(header string) {
 	c.header = append(c.header, strings.ToUpper(header))
 }
 
-func customFormat(ctx Context, containers []types.Container) {
-	var (
-		table  bool
-		header string
-		format = ctx.Format
-		buffer = bytes.NewBufferString("")
-	)
-
-	if strings.HasPrefix(ctx.Format, tableKey) {
-		table = true
-		format = format[len(tableKey):]
-	}
-
-	format = strings.Trim(format, " ")
-	r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
-	format = r.Replace(format)
-
-	if table && ctx.Size {
-		format += "\t{{.Size}}"
-	}
-
-	tmpl, err := template.New("").Parse(format)
-	if err != nil {
-		buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err))
-		buffer.WriteTo(ctx.Output)
-		return
-	}
-
-	for _, container := range containers {
-		containerCtx := &containerContext{
-			trunc: ctx.Trunc,
-			c:     container,
-		}
-		if err := tmpl.Execute(buffer, containerCtx); err != nil {
-			buffer = bytes.NewBufferString(fmt.Sprintf("Template parsing error: %v\n", err))
-			buffer.WriteTo(ctx.Output)
-			return
-		}
-		if table && len(header) == 0 {
-			header = containerCtx.fullHeader()
-		}
-		buffer.WriteString("\n")
-	}
-
-	if table {
-		if len(header) == 0 {
-			// if we still don't have a header, we didn't have any containers so we need to fake it to get the right headers from the template
-			containerCtx := &containerContext{}
-			tmpl.Execute(bytes.NewBufferString(""), containerCtx)
-			header = containerCtx.fullHeader()
-		}
-
-		t := tabwriter.NewWriter(ctx.Output, 20, 1, 3, ' ', 0)
-		t.Write([]byte(header))
-		t.Write([]byte("\n"))
-		buffer.WriteTo(t)
-		t.Flush()
-	} else {
-		buffer.WriteTo(ctx.Output)
-	}
-}
-
 func stripNamePrefix(ss []string) []string {
 	for i, s := range ss {
 		ss[i] = s[1:]

+ 18 - 12
api/client/ps/custom_test.go

@@ -1,7 +1,6 @@
 package ps
 
 import (
-	"bytes"
 	"reflect"
 	"strings"
 	"testing"
@@ -24,8 +23,11 @@ func TestContainerPsContext(t *testing.T) {
 		call      func() string
 	}{
 		{types.Container{ID: containerID}, true, stringid.TruncateID(containerID), idHeader, ctx.ID},
+		{types.Container{ID: containerID}, false, containerID, idHeader, ctx.ID},
 		{types.Container{Names: []string{"/foobar_baz"}}, true, "foobar_baz", namesHeader, ctx.Names},
 		{types.Container{Image: "ubuntu"}, true, "ubuntu", imageHeader, ctx.Image},
+		{types.Container{Image: "verylongimagename"}, true, "verylongimag", imageHeader, ctx.Image},
+		{types.Container{Image: "verylongimagename"}, false, "verylongimagename", imageHeader, ctx.Image},
 		{types.Container{Image: ""}, true, "<no image>", imageHeader, ctx.Image},
 		{types.Container{Command: "sh -c 'ls -la'"}, true, `"sh -c 'ls -la'"`, commandHeader, ctx.Command},
 		{types.Container{Created: unix}, true, time.Unix(unix, 0).String(), createdAtHeader, ctx.CreatedAt},
@@ -33,7 +35,9 @@ func TestContainerPsContext(t *testing.T) {
 		{types.Container{Status: "RUNNING"}, true, "RUNNING", statusHeader, ctx.Status},
 		{types.Container{SizeRw: 10}, true, "10 B", sizeHeader, ctx.Size},
 		{types.Container{SizeRw: 10, SizeRootFs: 20}, true, "10 B (virtual 20 B)", sizeHeader, ctx.Size},
+		{types.Container{}, true, "", labelsHeader, ctx.Labels},
 		{types.Container{Labels: map[string]string{"cpu": "6", "storage": "ssd"}}, true, "cpu=6,storage=ssd", labelsHeader, ctx.Labels},
+		{types.Container{Created: unix}, true, "Less than a second", runningForHeader, ctx.RunningFor},
 	}
 
 	for _, c := range cases {
@@ -68,8 +72,8 @@ func TestContainerPsContext(t *testing.T) {
 		}
 	}
 
-	c := types.Container{Labels: map[string]string{"com.docker.swarm.swarm-id": "33", "com.docker.swarm.node_name": "ubuntu"}}
-	ctx = containerContext{c: c, trunc: true}
+	c1 := types.Container{Labels: map[string]string{"com.docker.swarm.swarm-id": "33", "com.docker.swarm.node_name": "ubuntu"}}
+	ctx = containerContext{c: c1, trunc: true}
 
 	sid := ctx.Label("com.docker.swarm.swarm-id")
 	node := ctx.Label("com.docker.swarm.node_name")
@@ -86,17 +90,19 @@ func TestContainerPsContext(t *testing.T) {
 		t.Fatalf("Expected %s, was %s\n", "SWARM ID\tNODE NAME", h)
 
 	}
-}
 
-func TestContainerPsFormatError(t *testing.T) {
-	out := bytes.NewBufferString("")
-	ctx := Context{
-		Format: "{{InvalidFunction}}",
-		Output: out,
+	c2 := types.Container{}
+	ctx = containerContext{c: c2, trunc: true}
+
+	label := ctx.Label("anything.really")
+	if label != "" {
+		t.Fatalf("Expected an empty string, was %s", label)
 	}
 
-	customFormat(ctx, make([]types.Container, 0))
-	if out.String() != "Template parsing error: template: :1: function \"InvalidFunction\" not defined\n" {
-		t.Fatalf("Expected format error, got `%v`\n", out.String())
+	ctx = containerContext{c: c2, trunc: true}
+	fullHeader := ctx.fullHeader()
+	if fullHeader != "" {
+		t.Fatalf("Expected fullHeader to be empty, was %s", fullHeader)
 	}
+
 }

+ 67 - 0
api/client/ps/formatter.go

@@ -1,7 +1,12 @@
 package ps
 
 import (
+	"bytes"
+	"fmt"
 	"io"
+	"strings"
+	"text/tabwriter"
+	"text/template"
 
 	"github.com/docker/docker/api/types"
 )
@@ -71,3 +76,65 @@ func tableFormat(ctx Context, containers []types.Container) {
 
 	customFormat(ctx, containers)
 }
+
+func customFormat(ctx Context, containers []types.Container) {
+	var (
+		table  bool
+		header string
+		format = ctx.Format
+		buffer = bytes.NewBufferString("")
+	)
+
+	if strings.HasPrefix(ctx.Format, tableKey) {
+		table = true
+		format = format[len(tableKey):]
+	}
+
+	format = strings.Trim(format, " ")
+	r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
+	format = r.Replace(format)
+
+	if table && ctx.Size {
+		format += "\t{{.Size}}"
+	}
+
+	tmpl, err := template.New("").Parse(format)
+	if err != nil {
+		buffer.WriteString(fmt.Sprintf("Template parsing error: %v\n", err))
+		buffer.WriteTo(ctx.Output)
+		return
+	}
+
+	for _, container := range containers {
+		containerCtx := &containerContext{
+			trunc: ctx.Trunc,
+			c:     container,
+		}
+		if err := tmpl.Execute(buffer, containerCtx); err != nil {
+			buffer = bytes.NewBufferString(fmt.Sprintf("Template parsing error: %v\n", err))
+			buffer.WriteTo(ctx.Output)
+			return
+		}
+		if table && len(header) == 0 {
+			header = containerCtx.fullHeader()
+		}
+		buffer.WriteString("\n")
+	}
+
+	if table {
+		if len(header) == 0 {
+			// if we still don't have a header, we didn't have any containers so we need to fake it to get the right headers from the template
+			containerCtx := &containerContext{}
+			tmpl.Execute(bytes.NewBufferString(""), containerCtx)
+			header = containerCtx.fullHeader()
+		}
+
+		t := tabwriter.NewWriter(ctx.Output, 20, 1, 3, ' ', 0)
+		t.Write([]byte(header))
+		t.Write([]byte("\n"))
+		buffer.WriteTo(t)
+		t.Flush()
+	} else {
+		buffer.WriteTo(ctx.Output)
+	}
+}

+ 208 - 0
api/client/ps/formatter_test.go

@@ -0,0 +1,208 @@
+package ps
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/docker/docker/api/types"
+)
+
+func TestFormat(t *testing.T) {
+	contexts := []struct {
+		context  Context
+		expected string
+	}{
+		// Errors
+		{
+			Context{
+				Format: "{{InvalidFunction}}",
+			},
+			`Template parsing error: template: :1: function "InvalidFunction" not defined
+`,
+		},
+		{
+			Context{
+				Format: "{{nil}}",
+			},
+			`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
+`,
+		},
+		// Table Format
+		{
+			Context{
+				Format: "table",
+			},
+			`CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
+containerID1        ubuntu              ""                  45 years ago                                                foobar_baz
+containerID2        ubuntu              ""                  45 years ago                                                foobar_bar
+`,
+		},
+		{
+			Context{
+				Format: "table {{.Image}}",
+			},
+			"IMAGE\nubuntu\nubuntu\n",
+		},
+		{
+			Context{
+				Format: "table {{.Image}}",
+				Size:   true,
+			},
+			"IMAGE               SIZE\nubuntu              0 B\nubuntu              0 B\n",
+		},
+		{
+			Context{
+				Format: "table {{.Image}}",
+				Quiet:  true,
+			},
+			"IMAGE\nubuntu\nubuntu\n",
+		},
+		{
+			Context{
+				Format: "table",
+				Quiet:  true,
+			},
+			"containerID1\ncontainerID2\n",
+		},
+		// Raw Format
+		{
+			Context{
+				Format: "raw",
+			},
+			`container_id: containerID1
+image: ubuntu
+command: ""
+created_at: 1970-01-01 00:00:00 +0000 UTC
+status: 
+names: foobar_baz
+labels: 
+ports: 
+
+container_id: containerID2
+image: ubuntu
+command: ""
+created_at: 1970-01-01 00:00:00 +0000 UTC
+status: 
+names: foobar_bar
+labels: 
+ports: 
+
+`,
+		},
+		{
+			Context{
+				Format: "raw",
+				Size:   true,
+			},
+			`container_id: containerID1
+image: ubuntu
+command: ""
+created_at: 1970-01-01 00:00:00 +0000 UTC
+status: 
+names: foobar_baz
+labels: 
+ports: 
+size: 0 B
+
+container_id: containerID2
+image: ubuntu
+command: ""
+created_at: 1970-01-01 00:00:00 +0000 UTC
+status: 
+names: foobar_bar
+labels: 
+ports: 
+size: 0 B
+
+`,
+		},
+		{
+			Context{
+				Format: "raw",
+				Quiet:  true,
+			},
+			"container_id: containerID1\ncontainer_id: containerID2\n",
+		},
+		// Custom Format
+		{
+			Context{
+				Format: "{{.Image}}",
+			},
+			"ubuntu\nubuntu\n",
+		},
+		{
+			Context{
+				Format: "{{.Image}}",
+				Size:   true,
+			},
+			"ubuntu\nubuntu\n",
+		},
+	}
+
+	for _, context := range contexts {
+		containers := []types.Container{
+			{ID: "containerID1", Names: []string{"/foobar_baz"}, Image: "ubuntu"},
+			{ID: "containerID2", Names: []string{"/foobar_bar"}, Image: "ubuntu"},
+		}
+		out := bytes.NewBufferString("")
+		context.context.Output = out
+		Format(context.context, containers)
+		actual := out.String()
+		if actual != context.expected {
+			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
+		}
+		// Clean buffer
+		out.Reset()
+	}
+}
+
+func TestCustomFormatNoContainers(t *testing.T) {
+	out := bytes.NewBufferString("")
+	containers := []types.Container{}
+
+	contexts := []struct {
+		context  Context
+		expected string
+	}{
+		{
+			Context{
+				Format: "{{.Image}}",
+				Output: out,
+			},
+			"",
+		},
+		{
+			Context{
+				Format: "table {{.Image}}",
+				Output: out,
+			},
+			"IMAGE\n",
+		},
+		{
+			Context{
+				Format: "{{.Image}}",
+				Output: out,
+				Size:   true,
+			},
+			"",
+		},
+		{
+			Context{
+				Format: "table {{.Image}}",
+				Output: out,
+				Size:   true,
+			},
+			"IMAGE               SIZE\n",
+		},
+	}
+
+	for _, context := range contexts {
+		customFormat(context.context, containers)
+		actual := out.String()
+		if actual != context.expected {
+			t.Fatalf("Expected \n%s, got \n%s", context.expected, actual)
+		}
+		// Clean buffer
+		out.Reset()
+	}
+}