github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_list_windows_test.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/containerd/nerdctl/pkg/formatter"
    25  	"github.com/containerd/nerdctl/pkg/strutil"
    26  	"github.com/containerd/nerdctl/pkg/tabutil"
    27  	"github.com/containerd/nerdctl/pkg/testutil"
    28  	"gotest.tools/v3/assert"
    29  )
    30  
    31  type psTestContainer struct {
    32  	name    string
    33  	labels  map[string]string
    34  	volumes []string
    35  	network string
    36  }
    37  
    38  func preparePsTestContainer(t *testing.T, identity string, restart bool, hyperv bool) (*testutil.Base, psTestContainer) {
    39  	base := testutil.NewBase(t)
    40  
    41  	base.Cmd("pull", testutil.NginxAlpineImage).AssertOK()
    42  
    43  	testContainerName := testutil.Identifier(t) + identity
    44  	t.Cleanup(func() {
    45  		base.Cmd("rm", "-f", testContainerName).AssertOK()
    46  	})
    47  
    48  	// A container can have multiple labels.
    49  	// Therefore, this test container has multiple labels to check it.
    50  	testLabels := make(map[string]string)
    51  	keys := []string{
    52  		testutil.Identifier(t) + identity,
    53  		testutil.Identifier(t) + identity,
    54  	}
    55  	// fill the value of testLabels
    56  	for _, k := range keys {
    57  		testLabels[k] = k
    58  	}
    59  
    60  	args := []string{
    61  		"run",
    62  		"-d",
    63  		"--name",
    64  		testContainerName,
    65  		"--label",
    66  		formatter.FormatLabels(testLabels),
    67  		testutil.NginxAlpineImage,
    68  	}
    69  	if !restart {
    70  		args = append(args, "--restart=no")
    71  	}
    72  	if hyperv {
    73  		args = append(args[:3], args[1:]...)
    74  		args[1], args[2] = "--isolation", "hyperv"
    75  	}
    76  
    77  	base.Cmd(args...).AssertOK()
    78  	if restart {
    79  		base.EnsureContainerStarted(testContainerName)
    80  	}
    81  
    82  	return base, psTestContainer{
    83  		name:    testContainerName,
    84  		labels:  testLabels,
    85  		network: testContainerName,
    86  	}
    87  }
    88  
    89  func TestListProcessContainer(t *testing.T) {
    90  	base, testContainer := preparePsTestContainer(t, "list", true, false)
    91  
    92  	// hope there are no tests running parallel
    93  	base.Cmd("ps", "-n", "1", "-s").AssertOutWithFunc(func(stdout string) error {
    94  		// An example of nerdctl/docker ps -n 1 -s
    95  		// CONTAINER ID    IMAGE                               COMMAND    CREATED           STATUS    PORTS    NAMES            SIZE
    96  		// be8d386c991e    docker.io/library/busybox:latest    "top"      1 second ago    Up                 c1       16.0 KiB (virtual 1.3 MiB)
    97  
    98  		lines := strings.Split(strings.TrimSpace(stdout), "\n")
    99  		if len(lines) < 2 {
   100  			return fmt.Errorf("expected at least 2 lines, got %d", len(lines))
   101  		}
   102  
   103  		tab := tabutil.NewReader("CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES\tSIZE")
   104  		err := tab.ParseHeader(lines[0])
   105  		if err != nil {
   106  			return fmt.Errorf("failed to parse header: %v", err)
   107  		}
   108  
   109  		container, _ := tab.ReadRow(lines[1], "NAMES")
   110  		assert.Equal(t, container, testContainer.name)
   111  
   112  		image, _ := tab.ReadRow(lines[1], "IMAGE")
   113  		assert.Equal(t, image, testutil.NginxAlpineImage)
   114  
   115  		size, _ := tab.ReadRow(lines[1], "SIZE")
   116  
   117  		// there is some difference between nerdctl and docker in calculating the size of the container
   118  		expectedSize := "36.0 MiB (virtual "
   119  
   120  		if !strings.Contains(size, expectedSize) {
   121  			return fmt.Errorf("expect container size %s, but got %s", expectedSize, size)
   122  		}
   123  
   124  		return nil
   125  	})
   126  }
   127  
   128  func TestListHyperVContainer(t *testing.T) {
   129  	if !testutil.HyperVSupported() {
   130  		t.Skip("HyperV is not enabled, skipping test")
   131  	}
   132  
   133  	base, testContainer := preparePsTestContainer(t, "list", true, true)
   134  	inspect := base.InspectContainer(testContainer.name)
   135  	//check with HCS if the container is ineed a VM
   136  	isHypervContainer, err := testutil.HyperVContainer(inspect)
   137  	if err != nil {
   138  		t.Fatalf("unable to list HCS containers: %s", err)
   139  	}
   140  	assert.Assert(t, isHypervContainer, true)
   141  
   142  	// hope there are no tests running parallel
   143  	base.Cmd("ps", "-n", "1", "-s").AssertOutWithFunc(func(stdout string) error {
   144  		// An example of nerdctl/docker ps -n 1 -s
   145  		// CONTAINER ID    IMAGE                               COMMAND    CREATED           STATUS    PORTS    NAMES            SIZE
   146  		// be8d386c991e    docker.io/library/busybox:latest    "top"      1 second ago    Up                 c1       16.0 KiB (virtual 1.3 MiB)
   147  
   148  		lines := strings.Split(strings.TrimSpace(stdout), "\n")
   149  		if len(lines) < 2 {
   150  			return fmt.Errorf("expected at least 2 lines, got %d", len(lines))
   151  		}
   152  
   153  		tab := tabutil.NewReader("CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES\tSIZE")
   154  		err := tab.ParseHeader(lines[0])
   155  		if err != nil {
   156  			return fmt.Errorf("failed to parse header: %v", err)
   157  		}
   158  
   159  		container, _ := tab.ReadRow(lines[1], "NAMES")
   160  		assert.Equal(t, container, testContainer.name)
   161  
   162  		image, _ := tab.ReadRow(lines[1], "IMAGE")
   163  		assert.Equal(t, image, testutil.NginxAlpineImage)
   164  
   165  		size, _ := tab.ReadRow(lines[1], "SIZE")
   166  
   167  		// there is some difference between nerdctl and docker in calculating the size of the container
   168  		expectedSize := "72.0 MiB (virtual "
   169  
   170  		if !strings.Contains(size, expectedSize) {
   171  			return fmt.Errorf("expect container size %s, but got %s", expectedSize, size)
   172  		}
   173  
   174  		return nil
   175  	})
   176  }
   177  
   178  func TestListProcessContainerWideMode(t *testing.T) {
   179  	testutil.DockerIncompatible(t)
   180  	base, testContainer := preparePsTestContainer(t, "listWithMode", true, false)
   181  
   182  	// hope there are no tests running parallel
   183  	base.Cmd("ps", "-n", "1", "--format", "wide").AssertOutWithFunc(func(stdout string) error {
   184  
   185  		// An example of nerdctl ps --format wide
   186  		// CONTAINER ID    IMAGE                               PLATFORM       COMMAND    CREATED              STATUS    PORTS    NAMES            RUNTIME                  SIZE
   187  		// 17181f208b61    docker.io/library/busybox:latest    linux/amd64    "top"      About an hour ago    Up                 busybox-17181    io.containerd.runc.v2    16.0 KiB (virtual 1.3 MiB)
   188  
   189  		lines := strings.Split(strings.TrimSpace(stdout), "\n")
   190  		if len(lines) < 2 {
   191  			return fmt.Errorf("expected at least 2 lines, got %d", len(lines))
   192  		}
   193  
   194  		tab := tabutil.NewReader("CONTAINER ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tPORTS\tNAMES\tRUNTIME\tPLATFORM\tSIZE")
   195  		err := tab.ParseHeader(lines[0])
   196  		if err != nil {
   197  			return fmt.Errorf("failed to parse header: %v", err)
   198  		}
   199  
   200  		container, _ := tab.ReadRow(lines[1], "NAMES")
   201  		assert.Equal(t, container, testContainer.name)
   202  
   203  		image, _ := tab.ReadRow(lines[1], "IMAGE")
   204  		assert.Equal(t, image, testutil.NginxAlpineImage)
   205  
   206  		runtime, _ := tab.ReadRow(lines[1], "RUNTIME")
   207  		assert.Equal(t, runtime, "io.containerd.runhcs.v1")
   208  
   209  		size, _ := tab.ReadRow(lines[1], "SIZE")
   210  		expectedSize := "36.0 MiB (virtual "
   211  		if !strings.Contains(size, expectedSize) {
   212  			return fmt.Errorf("expect container size %s, but got %s", expectedSize, size)
   213  		}
   214  		return nil
   215  	})
   216  }
   217  
   218  func TestListProcessContainerWithLabels(t *testing.T) {
   219  	base, testContainer := preparePsTestContainer(t, "listWithLabels", true, false)
   220  
   221  	// hope there are no tests running parallel
   222  	base.Cmd("ps", "-n", "1", "--format", "{{.Labels}}").AssertOutWithFunc(func(stdout string) error {
   223  
   224  		// An example of nerdctl ps --format "{{.Labels}}"
   225  		// key1=value1,key2=value2,key3=value3
   226  		lines := strings.Split(strings.TrimSpace(stdout), "\n")
   227  		if len(lines) != 1 {
   228  			return fmt.Errorf("expected 1 line, got %d", len(lines))
   229  		}
   230  
   231  		// check labels using map
   232  		// 1. the results has no guarantee to show the same order.
   233  		// 2. the results has no guarantee to show only configured labels.
   234  		labelsMap, err := strutil.ParseCSVMap(lines[0])
   235  		if err != nil {
   236  			return fmt.Errorf("failed to parse labels: %v", err)
   237  		}
   238  
   239  		for i := range testContainer.labels {
   240  			if value, ok := labelsMap[i]; ok {
   241  				assert.Equal(t, value, testContainer.labels[i])
   242  			}
   243  		}
   244  		return nil
   245  	})
   246  }