github.com/cspotcode/docker-cli@v20.10.0-rc1.0.20201201121459-3faad7acc5b8+incompatible/cli/command/container/formatter_stats_test.go (about)

     1  package container
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/docker/cli/cli/command/formatter"
     8  	"github.com/docker/docker/pkg/stringid"
     9  	"gotest.tools/v3/assert"
    10  	is "gotest.tools/v3/assert/cmp"
    11  )
    12  
    13  func TestContainerStatsContext(t *testing.T) {
    14  	containerID := stringid.GenerateRandomID()
    15  
    16  	var ctx statsContext
    17  	tt := []struct {
    18  		stats     StatsEntry
    19  		osType    string
    20  		expValue  string
    21  		expHeader string
    22  		call      func() string
    23  	}{
    24  		{StatsEntry{Container: containerID}, "", containerID, containerHeader, ctx.Container},
    25  		{StatsEntry{CPUPercentage: 5.5}, "", "5.50%", cpuPercHeader, ctx.CPUPerc},
    26  		{StatsEntry{CPUPercentage: 5.5, IsInvalid: true}, "", "--", cpuPercHeader, ctx.CPUPerc},
    27  		{StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3}, "", "0.31B / 12.3B", netIOHeader, ctx.NetIO},
    28  		{StatsEntry{NetworkRx: 0.31, NetworkTx: 12.3, IsInvalid: true}, "", "--", netIOHeader, ctx.NetIO},
    29  		{StatsEntry{BlockRead: 0.1, BlockWrite: 2.3}, "", "0.1B / 2.3B", blockIOHeader, ctx.BlockIO},
    30  		{StatsEntry{BlockRead: 0.1, BlockWrite: 2.3, IsInvalid: true}, "", "--", blockIOHeader, ctx.BlockIO},
    31  		{StatsEntry{MemoryPercentage: 10.2}, "", "10.20%", memPercHeader, ctx.MemPerc},
    32  		{StatsEntry{MemoryPercentage: 10.2, IsInvalid: true}, "", "--", memPercHeader, ctx.MemPerc},
    33  		{StatsEntry{MemoryPercentage: 10.2}, "windows", "--", memPercHeader, ctx.MemPerc},
    34  		{StatsEntry{Memory: 24, MemoryLimit: 30}, "", "24B / 30B", memUseHeader, ctx.MemUsage},
    35  		{StatsEntry{Memory: 24, MemoryLimit: 30, IsInvalid: true}, "", "-- / --", memUseHeader, ctx.MemUsage},
    36  		{StatsEntry{Memory: 24, MemoryLimit: 30}, "windows", "24B", winMemUseHeader, ctx.MemUsage},
    37  		{StatsEntry{PidsCurrent: 10}, "", "10", pidsHeader, ctx.PIDs},
    38  		{StatsEntry{PidsCurrent: 10, IsInvalid: true}, "", "--", pidsHeader, ctx.PIDs},
    39  		{StatsEntry{PidsCurrent: 10}, "windows", "--", pidsHeader, ctx.PIDs},
    40  	}
    41  
    42  	for _, te := range tt {
    43  		ctx = statsContext{s: te.stats, os: te.osType}
    44  		if v := te.call(); v != te.expValue {
    45  			t.Fatalf("Expected %q, got %q", te.expValue, v)
    46  		}
    47  	}
    48  }
    49  
    50  func TestContainerStatsContextWrite(t *testing.T) {
    51  	tt := []struct {
    52  		context  formatter.Context
    53  		expected string
    54  	}{
    55  		{
    56  			formatter.Context{Format: "{{InvalidFunction}}"},
    57  			`Template parsing error: template: :1: function "InvalidFunction" not defined
    58  `,
    59  		},
    60  		{
    61  			formatter.Context{Format: "{{nil}}"},
    62  			`Template parsing error: template: :1:2: executing "" at <nil>: nil is not a command
    63  `,
    64  		},
    65  		{
    66  			formatter.Context{Format: "table {{.MemUsage}}"},
    67  			`MEM USAGE / LIMIT
    68  20B / 20B
    69  -- / --
    70  `,
    71  		},
    72  		{
    73  			formatter.Context{Format: "{{.Container}}  {{.ID}}  {{.Name}}"},
    74  			`container1  abcdef  foo
    75  container2    --
    76  `,
    77  		},
    78  		{
    79  			formatter.Context{Format: "{{.Container}}  {{.CPUPerc}}"},
    80  			`container1  20.00%
    81  container2  --
    82  `,
    83  		},
    84  	}
    85  
    86  	for _, te := range tt {
    87  		stats := []StatsEntry{
    88  			{
    89  				Container:        "container1",
    90  				ID:               "abcdef",
    91  				Name:             "/foo",
    92  				CPUPercentage:    20,
    93  				Memory:           20,
    94  				MemoryLimit:      20,
    95  				MemoryPercentage: 20,
    96  				NetworkRx:        20,
    97  				NetworkTx:        20,
    98  				BlockRead:        20,
    99  				BlockWrite:       20,
   100  				PidsCurrent:      2,
   101  				IsInvalid:        false,
   102  			},
   103  			{
   104  				Container:        "container2",
   105  				CPUPercentage:    30,
   106  				Memory:           30,
   107  				MemoryLimit:      30,
   108  				MemoryPercentage: 30,
   109  				NetworkRx:        30,
   110  				NetworkTx:        30,
   111  				BlockRead:        30,
   112  				BlockWrite:       30,
   113  				PidsCurrent:      3,
   114  				IsInvalid:        true,
   115  			},
   116  		}
   117  		var out bytes.Buffer
   118  		te.context.Output = &out
   119  		err := statsFormatWrite(te.context, stats, "linux", false)
   120  		if err != nil {
   121  			assert.Error(t, err, te.expected)
   122  		} else {
   123  			assert.Check(t, is.Equal(te.expected, out.String()))
   124  		}
   125  	}
   126  }
   127  
   128  func TestContainerStatsContextWriteWindows(t *testing.T) {
   129  	cases := []struct {
   130  		context  formatter.Context
   131  		expected string
   132  	}{
   133  		{
   134  			formatter.Context{Format: "table {{.MemUsage}}"},
   135  			`PRIV WORKING SET
   136  20B
   137  -- / --
   138  `,
   139  		},
   140  		{
   141  			formatter.Context{Format: "{{.Container}}  {{.CPUPerc}}"},
   142  			`container1  20.00%
   143  container2  --
   144  `,
   145  		},
   146  		{
   147  			formatter.Context{Format: "{{.Container}}  {{.MemPerc}}  {{.PIDs}}"},
   148  			`container1  --  --
   149  container2  --  --
   150  `,
   151  		},
   152  	}
   153  	stats := []StatsEntry{
   154  		{
   155  			Container:        "container1",
   156  			CPUPercentage:    20,
   157  			Memory:           20,
   158  			MemoryLimit:      20,
   159  			MemoryPercentage: 20,
   160  			NetworkRx:        20,
   161  			NetworkTx:        20,
   162  			BlockRead:        20,
   163  			BlockWrite:       20,
   164  			PidsCurrent:      2,
   165  			IsInvalid:        false,
   166  		},
   167  		{
   168  			Container:        "container2",
   169  			CPUPercentage:    30,
   170  			Memory:           30,
   171  			MemoryLimit:      30,
   172  			MemoryPercentage: 30,
   173  			NetworkRx:        30,
   174  			NetworkTx:        30,
   175  			BlockRead:        30,
   176  			BlockWrite:       30,
   177  			PidsCurrent:      3,
   178  			IsInvalid:        true,
   179  		},
   180  	}
   181  
   182  	for _, tc := range cases {
   183  		tc := tc
   184  		t.Run(string(tc.context.Format), func(t *testing.T) {
   185  			var out bytes.Buffer
   186  			tc.context.Output = &out
   187  			err := statsFormatWrite(tc.context, stats, "windows", false)
   188  			if err != nil {
   189  				assert.Error(t, err, tc.expected)
   190  			} else {
   191  				assert.Equal(t, out.String(), tc.expected)
   192  			}
   193  		})
   194  	}
   195  }
   196  
   197  func TestContainerStatsContextWriteWithNoStats(t *testing.T) {
   198  	var out bytes.Buffer
   199  
   200  	cases := []struct {
   201  		context  formatter.Context
   202  		expected string
   203  	}{
   204  		{
   205  			formatter.Context{
   206  				Format: "{{.Container}}",
   207  				Output: &out,
   208  			},
   209  			"",
   210  		},
   211  		{
   212  			formatter.Context{
   213  				Format: "table {{.Container}}",
   214  				Output: &out,
   215  			},
   216  			"CONTAINER\n",
   217  		},
   218  		{
   219  			formatter.Context{
   220  				Format: "table {{.Container}}\t{{.CPUPerc}}",
   221  				Output: &out,
   222  			},
   223  			"CONTAINER   CPU %\n",
   224  		},
   225  	}
   226  
   227  	for _, tc := range cases {
   228  		tc := tc
   229  		t.Run(string(tc.context.Format), func(t *testing.T) {
   230  			err := statsFormatWrite(tc.context, []StatsEntry{}, "linux", false)
   231  			assert.NilError(t, err)
   232  			assert.Equal(t, out.String(), tc.expected)
   233  			// Clean buffer
   234  			out.Reset()
   235  		})
   236  	}
   237  }
   238  
   239  func TestContainerStatsContextWriteWithNoStatsWindows(t *testing.T) {
   240  	var out bytes.Buffer
   241  
   242  	cases := []struct {
   243  		context  formatter.Context
   244  		expected string
   245  	}{
   246  		{
   247  			formatter.Context{
   248  				Format: "{{.Container}}",
   249  				Output: &out,
   250  			},
   251  			"",
   252  		},
   253  		{
   254  			formatter.Context{
   255  				Format: "table {{.Container}}\t{{.MemUsage}}",
   256  				Output: &out,
   257  			},
   258  			"CONTAINER   PRIV WORKING SET\n",
   259  		},
   260  		{
   261  			formatter.Context{
   262  				Format: "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}",
   263  				Output: &out,
   264  			},
   265  			"CONTAINER   CPU %     PRIV WORKING SET\n",
   266  		},
   267  	}
   268  
   269  	for _, tc := range cases {
   270  		tc := tc
   271  		t.Run(string(tc.context.Format), func(t *testing.T) {
   272  			err := statsFormatWrite(tc.context, []StatsEntry{}, "windows", false)
   273  			assert.NilError(t, err)
   274  			assert.Equal(t, out.String(), tc.expected)
   275  			out.Reset()
   276  		})
   277  	}
   278  }
   279  
   280  func TestContainerStatsContextWriteTrunc(t *testing.T) {
   281  	var out bytes.Buffer
   282  
   283  	contexts := []struct {
   284  		context  formatter.Context
   285  		trunc    bool
   286  		expected string
   287  	}{
   288  		{
   289  			formatter.Context{
   290  				Format: "{{.ID}}",
   291  				Output: &out,
   292  			},
   293  			false,
   294  			"b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc\n",
   295  		},
   296  		{
   297  			formatter.Context{
   298  				Format: "{{.ID}}",
   299  				Output: &out,
   300  			},
   301  			true,
   302  			"b95a83497c91\n",
   303  		},
   304  	}
   305  
   306  	for _, context := range contexts {
   307  		statsFormatWrite(context.context, []StatsEntry{{ID: "b95a83497c9161c9b444e3d70e1a9dfba0c1840d41720e146a95a08ebf938afc"}}, "linux", context.trunc)
   308  		assert.Check(t, is.Equal(context.expected, out.String()))
   309  		// Clean buffer
   310  		out.Reset()
   311  	}
   312  }