github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/container_inspect_linux_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/inspecttypes/dockercompat"
    25  	"github.com/containerd/nerdctl/pkg/testutil"
    26  	"github.com/docker/go-connections/nat"
    27  	"gotest.tools/v3/assert"
    28  )
    29  
    30  func TestContainerInspectContainsPortConfig(t *testing.T) {
    31  	testContainer := testutil.Identifier(t)
    32  
    33  	base := testutil.NewBase(t)
    34  	defer base.Cmd("rm", "-f", testContainer).Run()
    35  
    36  	base.Cmd("run", "-d", "--name", testContainer, "-p", "8080:80", testutil.NginxAlpineImage).AssertOK()
    37  	inspect := base.InspectContainer(testContainer)
    38  	inspect80TCP := (*inspect.NetworkSettings.Ports)["80/tcp"]
    39  	expected := nat.PortBinding{
    40  		HostIP:   "0.0.0.0",
    41  		HostPort: "8080",
    42  	}
    43  	assert.Equal(base.T, expected, inspect80TCP[0])
    44  }
    45  
    46  func TestContainerInspectContainsMounts(t *testing.T) {
    47  	testContainer := testutil.Identifier(t)
    48  
    49  	base := testutil.NewBase(t)
    50  
    51  	testVolume := testutil.Identifier(t)
    52  
    53  	defer base.Cmd("volume", "rm", "-f", testVolume).Run()
    54  	base.Cmd("volume", "create", "--label", "tag=testVolume", testVolume).AssertOK()
    55  	inspectVolume := base.InspectVolume(testVolume)
    56  	namedVolumeSource := inspectVolume.Mountpoint
    57  
    58  	defer base.Cmd("rm", "-f", testContainer).Run()
    59  	base.Cmd("run", "-d", "--privileged",
    60  		"--name", testContainer,
    61  		"--network", "none",
    62  		"-v", "/anony-vol",
    63  		"--tmpfs", "/app1:size=64m",
    64  		"--mount", "type=bind,src=/tmp,dst=/app2,ro",
    65  		"--mount", fmt.Sprintf("type=volume,src=%s,dst=/app3,readonly=false", testVolume),
    66  		testutil.NginxAlpineImage).AssertOK()
    67  
    68  	inspect := base.InspectContainer(testContainer)
    69  
    70  	// convert array to map to get by key of Destination
    71  	actual := make(map[string]dockercompat.MountPoint)
    72  	for i := range inspect.Mounts {
    73  		actual[inspect.Mounts[i].Destination] = inspect.Mounts[i]
    74  	}
    75  
    76  	const localDriver = "local"
    77  
    78  	expected := []struct {
    79  		dest       string
    80  		mountPoint dockercompat.MountPoint
    81  	}{
    82  		// anonymous volume
    83  		{
    84  			dest: "/anony-vol",
    85  			mountPoint: dockercompat.MountPoint{
    86  				Type:        "volume",
    87  				Name:        "",
    88  				Source:      "", // source of anonymous volume is a generated path, so here will not check it.
    89  				Destination: "/anony-vol",
    90  				Driver:      localDriver,
    91  				RW:          true,
    92  			},
    93  		},
    94  
    95  		// bind
    96  		{
    97  			dest: "/app2",
    98  			mountPoint: dockercompat.MountPoint{
    99  				Type:        "bind",
   100  				Name:        "",
   101  				Source:      "/tmp",
   102  				Destination: "/app2",
   103  				Driver:      "",
   104  				RW:          false,
   105  			},
   106  		},
   107  
   108  		// named volume
   109  		{
   110  			dest: "/app3",
   111  			mountPoint: dockercompat.MountPoint{
   112  				Type:        "volume",
   113  				Name:        testVolume,
   114  				Source:      namedVolumeSource,
   115  				Destination: "/app3",
   116  				Driver:      localDriver,
   117  				RW:          true,
   118  			},
   119  		},
   120  	}
   121  
   122  	for i := range expected {
   123  		testCase := expected[i]
   124  		t.Logf("test volume[dest=%q]", testCase.dest)
   125  
   126  		mountPoint, ok := actual[testCase.dest]
   127  		assert.Assert(base.T, ok)
   128  
   129  		assert.Equal(base.T, testCase.mountPoint.Type, mountPoint.Type)
   130  		assert.Equal(base.T, testCase.mountPoint.Driver, mountPoint.Driver)
   131  		assert.Equal(base.T, testCase.mountPoint.RW, mountPoint.RW)
   132  		assert.Equal(base.T, testCase.mountPoint.Destination, mountPoint.Destination)
   133  
   134  		if testCase.mountPoint.Source != "" {
   135  			assert.Equal(base.T, testCase.mountPoint.Source, mountPoint.Source)
   136  		}
   137  		if testCase.mountPoint.Name != "" {
   138  			assert.Equal(base.T, testCase.mountPoint.Name, mountPoint.Name)
   139  		}
   140  	}
   141  }
   142  
   143  func TestContainerInspectContainsLabel(t *testing.T) {
   144  	t.Parallel()
   145  	testContainer := testutil.Identifier(t)
   146  
   147  	base := testutil.NewBase(t)
   148  	defer base.Cmd("rm", "-f", testContainer).Run()
   149  
   150  	base.Cmd("run", "-d", "--name", testContainer, "--label", "foo=foo", "--label", "bar=bar", testutil.NginxAlpineImage).AssertOK()
   151  	base.EnsureContainerStarted(testContainer)
   152  	inspect := base.InspectContainer(testContainer)
   153  	lbs := inspect.Config.Labels
   154  
   155  	assert.Equal(base.T, "foo", lbs["foo"])
   156  	assert.Equal(base.T, "bar", lbs["bar"])
   157  }
   158  
   159  func TestContainerInspectState(t *testing.T) {
   160  	t.Parallel()
   161  	testContainer := testutil.Identifier(t)
   162  	base := testutil.NewBase(t)
   163  
   164  	type testCase struct {
   165  		name, containerName, cmd string
   166  		want                     dockercompat.ContainerState
   167  	}
   168  	// nerdctl: run error produces a nil Task, so the Status is empty because Status comes from Task.
   169  	// docker : run error gives => `Status=created` as  in docker there is no a separation between container and Task.
   170  	errStatus := ""
   171  	if base.Target == testutil.Docker {
   172  		errStatus = "created"
   173  	}
   174  	testCases := []testCase{
   175  		{
   176  			name:          "inspect State with error",
   177  			containerName: fmt.Sprintf("%s-fail", testContainer),
   178  			cmd:           "aa",
   179  			want: dockercompat.ContainerState{
   180  				Error:  "executable file not found in $PATH",
   181  				Status: errStatus,
   182  			},
   183  		},
   184  		{
   185  			name:          "inspect State without error",
   186  			containerName: fmt.Sprintf("%s-success", testContainer),
   187  			cmd:           "ls",
   188  			want: dockercompat.ContainerState{
   189  				Error:  "",
   190  				Status: "exited",
   191  			},
   192  		},
   193  	}
   194  
   195  	for _, tc := range testCases {
   196  		tc := tc
   197  		t.Run(tc.name, func(t *testing.T) {
   198  			defer base.Cmd("rm", "-f", tc.containerName).Run()
   199  			if tc.want.Error != "" {
   200  				base.Cmd("run", "--name", tc.containerName, testutil.AlpineImage, tc.cmd).AssertFail()
   201  			} else {
   202  				base.Cmd("run", "--name", tc.containerName, testutil.AlpineImage, tc.cmd).AssertOK()
   203  			}
   204  			inspect := base.InspectContainer(tc.containerName)
   205  			assert.Assert(t, strings.Contains(inspect.State.Error, tc.want.Error), fmt.Sprintf("expected: %s, actual: %s", tc.want.Error, inspect.State.Error))
   206  			assert.Equal(base.T, inspect.State.Status, tc.want.Status)
   207  		})
   208  	}
   209  
   210  }