github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/container_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 containerd
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"io"
    23  	"io/ioutil"
    24  	"os"
    25  	"os/exec"
    26  	"path"
    27  	"runtime"
    28  	"strings"
    29  	"syscall"
    30  	"testing"
    31  	"time"
    32  
    33  	// Register the typeurl
    34  	"github.com/containerd/containerd/cio"
    35  	"github.com/containerd/containerd/containers"
    36  	"github.com/containerd/containerd/namespaces"
    37  	"github.com/containerd/containerd/oci"
    38  	"github.com/containerd/containerd/platforms"
    39  	"github.com/containerd/containerd/plugin"
    40  	_ "github.com/containerd/containerd/runtime"
    41  	"github.com/containerd/containerd/runtime/v2/runc/options"
    42  	"github.com/containerd/typeurl"
    43  	specs "github.com/opencontainers/runtime-spec/specs-go"
    44  
    45  	"github.com/containerd/containerd/errdefs"
    46  	"github.com/containerd/go-runc"
    47  	gogotypes "github.com/gogo/protobuf/types"
    48  )
    49  
    50  func empty() cio.Creator {
    51  	// TODO (@mlaventure) windows searches for pipes
    52  	// when none are provided
    53  	if runtime.GOOS == "windows" {
    54  		return cio.NewCreator(cio.WithStdio)
    55  	}
    56  	return cio.NullIO
    57  }
    58  
    59  func TestContainerList(t *testing.T) {
    60  	client, err := newClient(t, address)
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	defer client.Close()
    65  
    66  	ctx, cancel := testContext(t)
    67  	defer cancel()
    68  
    69  	containers, err := client.Containers(ctx)
    70  	if err != nil {
    71  		t.Fatalf("container list returned error %v", err)
    72  	}
    73  	if len(containers) != 0 {
    74  		t.Errorf("expected 0 containers but received %d", len(containers))
    75  	}
    76  }
    77  
    78  func TestNewContainer(t *testing.T) {
    79  	t.Parallel()
    80  
    81  	id := t.Name()
    82  	client, err := newClient(t, address)
    83  	if err != nil {
    84  		t.Fatal(err)
    85  	}
    86  	defer client.Close()
    87  
    88  	ctx, cancel := testContext(t)
    89  	defer cancel()
    90  
    91  	container, err := client.NewContainer(ctx, id, WithNewSpec())
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	defer container.Delete(ctx)
    96  	if container.ID() != id {
    97  		t.Errorf("expected container id %q but received %q", id, container.ID())
    98  	}
    99  	if _, err = container.Spec(ctx); err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	if err := container.Delete(ctx); err != nil {
   103  		t.Fatal(err)
   104  	}
   105  }
   106  
   107  func TestContainerStart(t *testing.T) {
   108  	t.Parallel()
   109  
   110  	client, err := newClient(t, address)
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  	defer client.Close()
   115  
   116  	var (
   117  		image       Image
   118  		ctx, cancel = testContext(t)
   119  		id          = t.Name()
   120  	)
   121  	defer cancel()
   122  
   123  	image, err = client.GetImage(ctx, testImage)
   124  	if err != nil {
   125  		t.Fatal(err)
   126  	}
   127  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)))
   128  	if err != nil {
   129  		t.Fatal(err)
   130  	}
   131  	defer container.Delete(ctx, WithSnapshotCleanup)
   132  
   133  	task, err := container.NewTask(ctx, empty())
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	}
   137  	defer task.Delete(ctx)
   138  
   139  	statusC, err := task.Wait(ctx)
   140  	if err != nil {
   141  		t.Fatal(err)
   142  	}
   143  
   144  	if runtime.GOOS != "windows" {
   145  		// task.Pid not implemented on Windows
   146  		if pid := task.Pid(); pid < 1 {
   147  			t.Errorf("invalid task pid %d", pid)
   148  		}
   149  	}
   150  
   151  	if err := task.Start(ctx); err != nil {
   152  		t.Error(err)
   153  		task.Delete(ctx)
   154  		return
   155  	}
   156  	status := <-statusC
   157  	code, _, err := status.Result()
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	if code != 7 {
   162  		t.Errorf("expected status 7 from wait but received %d", code)
   163  	}
   164  
   165  	deleteStatus, err := task.Delete(ctx)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  	if ec := deleteStatus.ExitCode(); ec != 7 {
   170  		t.Errorf("expected status 7 from delete but received %d", ec)
   171  	}
   172  }
   173  
   174  func TestContainerOutput(t *testing.T) {
   175  	t.Parallel()
   176  
   177  	client, err := newClient(t, address)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	defer client.Close()
   182  
   183  	var (
   184  		image       Image
   185  		ctx, cancel = testContext(t)
   186  		id          = t.Name()
   187  		expected    = "kingkoye"
   188  	)
   189  	defer cancel()
   190  
   191  	image, err = client.GetImage(ctx, testImage)
   192  	if err != nil {
   193  		t.Fatal(err)
   194  	}
   195  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withProcessArgs("echo", expected)))
   196  	if err != nil {
   197  		t.Fatal(err)
   198  	}
   199  	defer container.Delete(ctx, WithSnapshotCleanup)
   200  
   201  	stdout := bytes.NewBuffer(nil)
   202  	task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout)))
   203  	if err != nil {
   204  		t.Fatal(err)
   205  	}
   206  	defer task.Delete(ctx)
   207  
   208  	statusC, err := task.Wait(ctx)
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  
   213  	if err := task.Start(ctx); err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	status := <-statusC
   218  	code, _, err := status.Result()
   219  	if code != 0 {
   220  		t.Errorf("expected status 0 but received %d: %v", code, err)
   221  	}
   222  	if _, err := task.Delete(ctx); err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	actual := stdout.String()
   227  	// echo adds a new line
   228  	expected = expected + newLine
   229  	if actual != expected {
   230  		t.Errorf("expected output %q but received %q", expected, actual)
   231  	}
   232  }
   233  
   234  func withByteBuffers(stdout io.Writer) cio.Opt {
   235  	// TODO: could this use ioutil.Discard?
   236  	return func(streams *cio.Streams) {
   237  		streams.Stdin = new(bytes.Buffer)
   238  		streams.Stdout = stdout
   239  		streams.Stderr = new(bytes.Buffer)
   240  	}
   241  }
   242  
   243  func TestContainerExec(t *testing.T) {
   244  	t.Parallel()
   245  
   246  	client, err := newClient(t, address)
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	defer client.Close()
   251  
   252  	var (
   253  		image       Image
   254  		ctx, cancel = testContext(t)
   255  		id          = t.Name()
   256  	)
   257  	defer cancel()
   258  
   259  	image, err = client.GetImage(ctx, testImage)
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  	defer container.Delete(ctx, WithSnapshotCleanup)
   269  
   270  	task, err := container.NewTask(ctx, empty())
   271  	if err != nil {
   272  		t.Fatal(err)
   273  	}
   274  	defer task.Delete(ctx)
   275  
   276  	finishedC, err := task.Wait(ctx)
   277  	if err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	if err := task.Start(ctx); err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	spec, err := container.Spec(ctx)
   285  	if err != nil {
   286  		t.Fatal(err)
   287  	}
   288  
   289  	// start an exec process without running the original container process info
   290  	processSpec := spec.Process
   291  	withExecExitStatus(processSpec, 6)
   292  	execID := t.Name() + "_exec"
   293  	process, err := task.Exec(ctx, execID, processSpec, empty())
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  	processStatusC, err := process.Wait(ctx)
   298  	if err != nil {
   299  		t.Fatal(err)
   300  	}
   301  
   302  	if err := process.Start(ctx); err != nil {
   303  		t.Fatal(err)
   304  	}
   305  
   306  	// wait for the exec to return
   307  	status := <-processStatusC
   308  	code, _, err := status.Result()
   309  	if err != nil {
   310  		t.Fatal(err)
   311  	}
   312  
   313  	if code != 6 {
   314  		t.Errorf("expected exec exit code 6 but received %d", code)
   315  	}
   316  	deleteStatus, err := process.Delete(ctx)
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  	if ec := deleteStatus.ExitCode(); ec != 6 {
   321  		t.Errorf("expected delete exit code 6 but received %d", ec)
   322  	}
   323  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   324  		t.Error(err)
   325  	}
   326  	<-finishedC
   327  }
   328  func TestContainerLargeExecArgs(t *testing.T) {
   329  	t.Parallel()
   330  
   331  	client, err := newClient(t, address)
   332  	if err != nil {
   333  		t.Fatal(err)
   334  	}
   335  	defer client.Close()
   336  
   337  	var (
   338  		image       Image
   339  		ctx, cancel = testContext(t)
   340  		id          = t.Name()
   341  	)
   342  	defer cancel()
   343  
   344  	image, err = client.GetImage(ctx, testImage)
   345  	if err != nil {
   346  		t.Fatal(err)
   347  	}
   348  
   349  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	defer container.Delete(ctx, WithSnapshotCleanup)
   354  
   355  	task, err := container.NewTask(ctx, empty())
   356  	if err != nil {
   357  		t.Fatal(err)
   358  	}
   359  	defer task.Delete(ctx)
   360  
   361  	finishedC, err := task.Wait(ctx)
   362  	if err != nil {
   363  		t.Fatal(err)
   364  	}
   365  
   366  	if err := task.Start(ctx); err != nil {
   367  		t.Fatal(err)
   368  	}
   369  	spec, err := container.Spec(ctx)
   370  	if err != nil {
   371  		t.Fatal(err)
   372  	}
   373  
   374  	processSpec := spec.Process
   375  	withExecArgs(processSpec, "echo", strings.Repeat("a", 20000))
   376  	execID := t.Name() + "_exec"
   377  	process, err := task.Exec(ctx, execID, processSpec, empty())
   378  	if err != nil {
   379  		t.Fatal(err)
   380  	}
   381  	processStatusC, err := process.Wait(ctx)
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	if err := process.Start(ctx); err != nil {
   387  		t.Fatal(err)
   388  	}
   389  
   390  	// wait for the exec to return
   391  	status := <-processStatusC
   392  	if _, _, err := status.Result(); err != nil {
   393  		t.Fatal(err)
   394  	}
   395  	if _, err := process.Delete(ctx); err != nil {
   396  		t.Fatal(err)
   397  	}
   398  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   399  		t.Error(err)
   400  	}
   401  	<-finishedC
   402  }
   403  
   404  func TestContainerPids(t *testing.T) {
   405  	t.Parallel()
   406  
   407  	client, err := newClient(t, address)
   408  	if err != nil {
   409  		t.Fatal(err)
   410  	}
   411  	defer client.Close()
   412  
   413  	var (
   414  		image       Image
   415  		ctx, cancel = testContext(t)
   416  		id          = t.Name()
   417  	)
   418  	defer cancel()
   419  
   420  	image, err = client.GetImage(ctx, testImage)
   421  	if err != nil {
   422  		t.Fatal(err)
   423  	}
   424  
   425  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   426  	if err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	defer container.Delete(ctx, WithSnapshotCleanup)
   430  
   431  	task, err := container.NewTask(ctx, empty())
   432  	if err != nil {
   433  		t.Fatal(err)
   434  	}
   435  	defer task.Delete(ctx)
   436  
   437  	statusC, err := task.Wait(ctx)
   438  	if err != nil {
   439  		t.Fatal(err)
   440  	}
   441  
   442  	if err := task.Start(ctx); err != nil {
   443  		t.Fatal(err)
   444  	}
   445  
   446  	pid := task.Pid()
   447  	if pid < 1 {
   448  		t.Errorf("invalid task pid %d", pid)
   449  	}
   450  	processes, err := task.Pids(ctx)
   451  	switch runtime.GOOS {
   452  	case "windows":
   453  		// TODO: This is currently not implemented on windows
   454  	default:
   455  		if err != nil {
   456  			t.Fatal(err)
   457  		}
   458  		// 2 processes, 1 for sh and one for sleep
   459  		if l := len(processes); l != 2 {
   460  			t.Errorf("expected 2 process but received %d", l)
   461  		}
   462  		if len(processes) > 0 {
   463  			actual := processes[0].Pid
   464  			if pid != actual {
   465  				t.Errorf("expected pid %d but received %d", pid, actual)
   466  			}
   467  		}
   468  	}
   469  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   470  		select {
   471  		case s := <-statusC:
   472  			t.Log(s.Result())
   473  		default:
   474  		}
   475  		t.Error(err)
   476  	}
   477  	<-statusC
   478  }
   479  
   480  func TestContainerCloseIO(t *testing.T) {
   481  	t.Parallel()
   482  
   483  	client, err := newClient(t, address)
   484  	if err != nil {
   485  		t.Fatal(err)
   486  	}
   487  	defer client.Close()
   488  
   489  	var (
   490  		image       Image
   491  		ctx, cancel = testContext(t)
   492  		id          = t.Name()
   493  	)
   494  	defer cancel()
   495  
   496  	image, err = client.GetImage(ctx, testImage)
   497  	if err != nil {
   498  		t.Fatal(err)
   499  	}
   500  
   501  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withCat()))
   502  	if err != nil {
   503  		t.Fatal(err)
   504  	}
   505  	defer container.Delete(ctx, WithSnapshotCleanup)
   506  
   507  	stdout := bytes.NewBuffer(nil)
   508  
   509  	r, w, err := os.Pipe()
   510  	if err != nil {
   511  		t.Fatal(err)
   512  	}
   513  
   514  	task, err := container.NewTask(ctx, cio.NewCreator(cio.WithStreams(r, stdout, ioutil.Discard)))
   515  	if err != nil {
   516  		t.Fatal(err)
   517  	}
   518  	defer task.Delete(ctx)
   519  
   520  	statusC, err := task.Wait(ctx)
   521  	if err != nil {
   522  		t.Fatal(err)
   523  	}
   524  
   525  	if err := task.Start(ctx); err != nil {
   526  		t.Fatal(err)
   527  	}
   528  	w.Close()
   529  	if err := task.CloseIO(ctx, WithStdinCloser); err != nil {
   530  		t.Error(err)
   531  	}
   532  
   533  	<-statusC
   534  }
   535  
   536  func TestDeleteRunningContainer(t *testing.T) {
   537  	t.Parallel()
   538  
   539  	client, err := newClient(t, address)
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  	defer client.Close()
   544  
   545  	var (
   546  		image       Image
   547  		ctx, cancel = testContext(t)
   548  		id          = t.Name()
   549  	)
   550  	defer cancel()
   551  
   552  	image, err = client.GetImage(ctx, testImage)
   553  	if err != nil {
   554  		t.Fatal(err)
   555  	}
   556  
   557  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   558  	if err != nil {
   559  		t.Fatal(err)
   560  	}
   561  	defer container.Delete(ctx, WithSnapshotCleanup)
   562  
   563  	task, err := container.NewTask(ctx, empty())
   564  	if err != nil {
   565  		t.Fatal(err)
   566  	}
   567  	defer task.Delete(ctx)
   568  
   569  	statusC, err := task.Wait(ctx)
   570  	if err != nil {
   571  		t.Fatal(err)
   572  	}
   573  
   574  	if err := task.Start(ctx); err != nil {
   575  		t.Fatal(err)
   576  	}
   577  
   578  	err = container.Delete(ctx, WithSnapshotCleanup)
   579  	if err == nil {
   580  		t.Error("delete did not error with running task")
   581  	}
   582  	if !errdefs.IsFailedPrecondition(err) {
   583  		t.Errorf("expected error %q but received %q", errdefs.ErrFailedPrecondition, err)
   584  	}
   585  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   586  		t.Fatal(err)
   587  	}
   588  	<-statusC
   589  }
   590  
   591  func TestContainerKill(t *testing.T) {
   592  	t.Parallel()
   593  
   594  	client, err := newClient(t, address)
   595  	if err != nil {
   596  		t.Fatal(err)
   597  	}
   598  	defer client.Close()
   599  
   600  	var (
   601  		image       Image
   602  		ctx, cancel = testContext(t)
   603  		id          = t.Name()
   604  	)
   605  	defer cancel()
   606  
   607  	image, err = client.GetImage(ctx, testImage)
   608  	if err != nil {
   609  		t.Fatal(err)
   610  	}
   611  
   612  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	defer container.Delete(ctx)
   617  
   618  	task, err := container.NewTask(ctx, empty())
   619  	if err != nil {
   620  		t.Fatal(err)
   621  	}
   622  	defer task.Delete(ctx)
   623  
   624  	statusC, err := task.Wait(ctx)
   625  	if err != nil {
   626  		t.Fatal(err)
   627  	}
   628  
   629  	if err := task.Start(ctx); err != nil {
   630  		t.Fatal(err)
   631  	}
   632  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   633  		t.Fatal(err)
   634  	}
   635  	<-statusC
   636  
   637  	err = task.Kill(ctx, syscall.SIGTERM)
   638  	if err == nil {
   639  		t.Fatal("second call to kill should return an error")
   640  	}
   641  	if !errdefs.IsNotFound(err) {
   642  		t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err)
   643  	}
   644  }
   645  
   646  func TestKillContainerDeletedByRunc(t *testing.T) {
   647  	t.Parallel()
   648  
   649  	if runtime.GOOS == "windows" {
   650  		t.Skip("Test relies on runc and is not supported on Windows")
   651  	}
   652  
   653  	// We skip this case when runtime is crun.
   654  	// More information in https://github.com/containerd/containerd/pull/4214#discussion_r422769497
   655  	if os.Getenv("RUNC_FLAVOR") == "crun" {
   656  		t.Skip("skip it when using crun")
   657  	}
   658  
   659  	client, err := newClient(t, address)
   660  	if err != nil {
   661  		t.Fatal(err)
   662  	}
   663  	defer client.Close()
   664  
   665  	if client.runtime == plugin.RuntimeLinuxV1 {
   666  		t.Skip("test relies on runtime v2")
   667  	}
   668  
   669  	var (
   670  		image       Image
   671  		ctx, cancel = testContext(t)
   672  		id          = t.Name()
   673  		runcRoot    = "/tmp/runc-test"
   674  	)
   675  	defer cancel()
   676  
   677  	image, err = client.GetImage(ctx, testImage)
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	container, err := client.NewContainer(ctx, id,
   682  		WithNewSnapshot(id, image),
   683  		WithNewSpec(oci.WithImageConfig(image), longCommand),
   684  		WithRuntime(client.runtime, &options.Options{Root: runcRoot}))
   685  	if err != nil {
   686  		t.Fatal(err)
   687  	}
   688  	defer container.Delete(ctx)
   689  
   690  	task, err := container.NewTask(ctx, empty())
   691  	if err != nil {
   692  		t.Fatal(err)
   693  	}
   694  	defer task.Delete(ctx)
   695  
   696  	statusC, err := task.Wait(ctx)
   697  	if err != nil {
   698  		t.Fatal(err)
   699  	}
   700  
   701  	if err := task.Start(ctx); err != nil {
   702  		t.Fatal(err)
   703  	}
   704  
   705  	rcmd := &runc.Runc{
   706  		Root: path.Join(runcRoot, testNamespace),
   707  	}
   708  
   709  	if err := rcmd.Delete(ctx, id, &runc.DeleteOpts{Force: true}); err != nil {
   710  		t.Fatal(err)
   711  	}
   712  	err = task.Kill(ctx, syscall.SIGKILL)
   713  	if err == nil {
   714  		t.Fatal("kill should return NotFound error")
   715  	} else if !errdefs.IsNotFound(err) {
   716  		t.Errorf("expected error %q but received %q", errdefs.ErrNotFound, err)
   717  	}
   718  
   719  	select {
   720  	case <-statusC:
   721  	case <-time.After(2 * time.Second):
   722  		t.Errorf("unexpected timeout when try to get exited container's status")
   723  	}
   724  }
   725  
   726  func TestContainerNoBinaryExists(t *testing.T) {
   727  	t.Parallel()
   728  
   729  	client, err := newClient(t, address)
   730  	if err != nil {
   731  		t.Fatal(err)
   732  	}
   733  	defer client.Close()
   734  
   735  	var (
   736  		image       Image
   737  		ctx, cancel = testContext(t)
   738  		id          = t.Name()
   739  	)
   740  	defer cancel()
   741  
   742  	image, err = client.GetImage(ctx, testImage)
   743  	if err != nil {
   744  		t.Fatal(err)
   745  	}
   746  
   747  	container, err := client.NewContainer(ctx, id,
   748  		WithNewSnapshot(id, image),
   749  		WithNewSpec(oci.WithImageConfig(image), oci.WithProcessArgs("nothing")))
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  	defer container.Delete(ctx, WithSnapshotCleanup)
   754  
   755  	task, err := container.NewTask(ctx, empty())
   756  	switch runtime.GOOS {
   757  	case "windows":
   758  		if err != nil {
   759  			t.Fatalf("failed to create task %v", err)
   760  		}
   761  		defer task.Delete(ctx, WithProcessKill)
   762  		if err := task.Start(ctx); err == nil {
   763  			t.Error("task.Start() should return an error when binary does not exist")
   764  		}
   765  	default:
   766  		if err == nil {
   767  			t.Error("NewTask should return an error when binary does not exist")
   768  			task.Delete(ctx)
   769  		}
   770  	}
   771  }
   772  
   773  func TestContainerExecNoBinaryExists(t *testing.T) {
   774  	t.Parallel()
   775  
   776  	client, err := newClient(t, address)
   777  	if err != nil {
   778  		t.Fatal(err)
   779  	}
   780  	defer client.Close()
   781  
   782  	var (
   783  		image       Image
   784  		ctx, cancel = testContext(t)
   785  		id          = t.Name()
   786  	)
   787  	defer cancel()
   788  
   789  	image, err = client.GetImage(ctx, testImage)
   790  	if err != nil {
   791  		t.Fatal(err)
   792  	}
   793  
   794  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   795  	if err != nil {
   796  		t.Fatal(err)
   797  	}
   798  	defer container.Delete(ctx, WithSnapshotCleanup)
   799  
   800  	task, err := container.NewTask(ctx, empty())
   801  	if err != nil {
   802  		t.Fatal(err)
   803  	}
   804  	defer task.Delete(ctx)
   805  
   806  	finishedC, err := task.Wait(ctx)
   807  	if err != nil {
   808  		t.Error(err)
   809  	}
   810  	if err := task.Start(ctx); err != nil {
   811  		t.Fatal(err)
   812  	}
   813  	spec, err := container.Spec(ctx)
   814  	if err != nil {
   815  		t.Fatal(err)
   816  	}
   817  
   818  	// start an exec process without running the original container process
   819  	processSpec := spec.Process
   820  	processSpec.Args = []string{
   821  		"none",
   822  	}
   823  	execID := t.Name() + "_exec"
   824  	process, err := task.Exec(ctx, execID, processSpec, empty())
   825  	if err != nil {
   826  		t.Fatal(err)
   827  	}
   828  	defer process.Delete(ctx)
   829  	if err := process.Start(ctx); err == nil {
   830  		t.Error("Process.Start should fail when process does not exist")
   831  	}
   832  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   833  		t.Error(err)
   834  	}
   835  	<-finishedC
   836  }
   837  
   838  func TestWaitStoppedTask(t *testing.T) {
   839  	t.Parallel()
   840  
   841  	client, err := newClient(t, address)
   842  	if err != nil {
   843  		t.Fatal(err)
   844  	}
   845  	defer client.Close()
   846  
   847  	var (
   848  		image       Image
   849  		ctx, cancel = testContext(t)
   850  		id          = t.Name()
   851  	)
   852  	defer cancel()
   853  
   854  	image, err = client.GetImage(ctx, testImage)
   855  	if err != nil {
   856  		t.Fatal(err)
   857  	}
   858  
   859  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withExitStatus(7)))
   860  	if err != nil {
   861  		t.Fatal(err)
   862  	}
   863  	defer container.Delete(ctx, WithSnapshotCleanup)
   864  
   865  	task, err := container.NewTask(ctx, empty())
   866  	if err != nil {
   867  		t.Fatal(err)
   868  	}
   869  	defer task.Delete(ctx)
   870  
   871  	statusC, err := task.Wait(ctx)
   872  	if err != nil {
   873  		t.Fatal(err)
   874  	}
   875  
   876  	if runtime.GOOS != "windows" {
   877  		// Getting the pid is not currently implemented on windows
   878  		if pid := task.Pid(); pid < 1 {
   879  			t.Errorf("invalid task pid %d", pid)
   880  		}
   881  	}
   882  	if err := task.Start(ctx); err != nil {
   883  		t.Error(err)
   884  		task.Delete(ctx)
   885  		return
   886  	}
   887  
   888  	// wait for the task to stop then call wait again
   889  	<-statusC
   890  	statusC, err = task.Wait(ctx)
   891  	if err != nil {
   892  		t.Fatal(err)
   893  	}
   894  	status := <-statusC
   895  	code, _, err := status.Result()
   896  	if err != nil {
   897  		t.Fatal(err)
   898  	}
   899  	if code != 7 {
   900  		t.Errorf("exit status from stopped task should be 7 but received %d", code)
   901  	}
   902  }
   903  
   904  func TestWaitStoppedProcess(t *testing.T) {
   905  	t.Parallel()
   906  
   907  	client, err := newClient(t, address)
   908  	if err != nil {
   909  		t.Fatal(err)
   910  	}
   911  	defer client.Close()
   912  
   913  	var (
   914  		image       Image
   915  		ctx, cancel = testContext(t)
   916  		id          = t.Name()
   917  	)
   918  	defer cancel()
   919  
   920  	image, err = client.GetImage(ctx, testImage)
   921  	if err != nil {
   922  		t.Fatal(err)
   923  	}
   924  
   925  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
   926  	if err != nil {
   927  		t.Fatal(err)
   928  	}
   929  	defer container.Delete(ctx, WithSnapshotCleanup)
   930  
   931  	task, err := container.NewTask(ctx, empty())
   932  	if err != nil {
   933  		t.Fatal(err)
   934  	}
   935  	defer task.Delete(ctx)
   936  
   937  	finishedC, err := task.Wait(ctx)
   938  	if err != nil {
   939  		t.Error(err)
   940  	}
   941  
   942  	if err := task.Start(ctx); err != nil {
   943  		t.Fatal(err)
   944  	}
   945  	spec, err := container.Spec(ctx)
   946  	if err != nil {
   947  		t.Fatal(err)
   948  	}
   949  
   950  	// start an exec process without running the original container process info
   951  	processSpec := spec.Process
   952  	withExecExitStatus(processSpec, 6)
   953  	execID := t.Name() + "_exec"
   954  	process, err := task.Exec(ctx, execID, processSpec, empty())
   955  	if err != nil {
   956  		t.Fatal(err)
   957  	}
   958  	defer process.Delete(ctx)
   959  
   960  	statusC, err := process.Wait(ctx)
   961  	if err != nil {
   962  		t.Fatal(err)
   963  	}
   964  
   965  	if err := process.Start(ctx); err != nil {
   966  		t.Fatal(err)
   967  	}
   968  
   969  	// wait for the exec to return
   970  	<-statusC
   971  
   972  	// try to wait on the process after it has stopped
   973  	statusC, err = process.Wait(ctx)
   974  	if err != nil {
   975  		t.Fatal(err)
   976  	}
   977  	status := <-statusC
   978  	code, _, err := status.Result()
   979  	if err != nil {
   980  		t.Fatal(err)
   981  	}
   982  	if code != 6 {
   983  		t.Errorf("exit status from stopped process should be 6 but received %d", code)
   984  	}
   985  
   986  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
   987  		t.Error(err)
   988  	}
   989  	<-finishedC
   990  }
   991  
   992  func TestTaskForceDelete(t *testing.T) {
   993  	t.Parallel()
   994  
   995  	client, err := newClient(t, address)
   996  	if err != nil {
   997  		t.Fatal(err)
   998  	}
   999  	defer client.Close()
  1000  
  1001  	var (
  1002  		image       Image
  1003  		ctx, cancel = testContext(t)
  1004  		id          = t.Name()
  1005  	)
  1006  	defer cancel()
  1007  
  1008  	image, err = client.GetImage(ctx, testImage)
  1009  	if err != nil {
  1010  		t.Fatal(err)
  1011  	}
  1012  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
  1013  	if err != nil {
  1014  		t.Fatal(err)
  1015  	}
  1016  	defer container.Delete(ctx, WithSnapshotCleanup)
  1017  
  1018  	task, err := container.NewTask(ctx, empty())
  1019  	if err != nil {
  1020  		t.Fatal(err)
  1021  	}
  1022  	if err := task.Start(ctx); err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  	if _, err := task.Delete(ctx); err == nil {
  1026  		t.Error("task.Delete of a running task should create an error")
  1027  	}
  1028  	if _, err := task.Delete(ctx, WithProcessKill); err != nil {
  1029  		t.Fatal(err)
  1030  	}
  1031  }
  1032  
  1033  func TestProcessForceDelete(t *testing.T) {
  1034  	t.Parallel()
  1035  
  1036  	client, err := newClient(t, address)
  1037  	if err != nil {
  1038  		t.Fatal(err)
  1039  	}
  1040  	defer client.Close()
  1041  
  1042  	var (
  1043  		image       Image
  1044  		ctx, cancel = testContext(t)
  1045  		id          = t.Name()
  1046  	)
  1047  	defer cancel()
  1048  
  1049  	image, err = client.GetImage(ctx, testImage)
  1050  	if err != nil {
  1051  		t.Fatal(err)
  1052  	}
  1053  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
  1054  	if err != nil {
  1055  		t.Fatal(err)
  1056  	}
  1057  	defer container.Delete(ctx, WithSnapshotCleanup)
  1058  
  1059  	task, err := container.NewTask(ctx, empty())
  1060  	if err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  	defer task.Delete(ctx)
  1064  
  1065  	statusC, err := task.Wait(ctx)
  1066  	if err != nil {
  1067  		t.Fatal(err)
  1068  	}
  1069  
  1070  	// task must be started on windows
  1071  	if err := task.Start(ctx); err != nil {
  1072  		t.Fatal(err)
  1073  	}
  1074  	spec, err := container.Spec(ctx)
  1075  	if err != nil {
  1076  		t.Fatal(err)
  1077  	}
  1078  
  1079  	processSpec := spec.Process
  1080  	if runtime.GOOS == "windows" {
  1081  		withExecArgs(processSpec, "cmd", "/c", "ping -t localhost")
  1082  	} else {
  1083  		withExecArgs(processSpec, "/bin/sh", "-c", "while true; do sleep 1; done")
  1084  	}
  1085  	execID := t.Name() + "_exec"
  1086  	process, err := task.Exec(ctx, execID, processSpec, empty())
  1087  	if err != nil {
  1088  		t.Fatal(err)
  1089  	}
  1090  	if err := process.Start(ctx); err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  	if _, err := process.Delete(ctx); err == nil {
  1094  		t.Error("process.Delete should return an error when process is running")
  1095  	}
  1096  	if _, err := process.Delete(ctx, WithProcessKill); err != nil {
  1097  		t.Error(err)
  1098  	}
  1099  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
  1100  		t.Fatal(err)
  1101  	}
  1102  	<-statusC
  1103  }
  1104  
  1105  func TestContainerHostname(t *testing.T) {
  1106  	t.Parallel()
  1107  
  1108  	client, err := newClient(t, address)
  1109  	if err != nil {
  1110  		t.Fatal(err)
  1111  	}
  1112  	defer client.Close()
  1113  
  1114  	var (
  1115  		image       Image
  1116  		ctx, cancel = testContext(t)
  1117  		id          = t.Name()
  1118  		expected    = "myhostname"
  1119  	)
  1120  	defer cancel()
  1121  
  1122  	image, err = client.GetImage(ctx, testImage)
  1123  	if err != nil {
  1124  		t.Fatal(err)
  1125  	}
  1126  
  1127  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image),
  1128  		withProcessArgs("hostname"),
  1129  		oci.WithHostname(expected),
  1130  	))
  1131  	if err != nil {
  1132  		t.Fatal(err)
  1133  	}
  1134  	defer container.Delete(ctx, WithSnapshotCleanup)
  1135  
  1136  	stdout := bytes.NewBuffer(nil)
  1137  	task, err := container.NewTask(ctx, cio.NewCreator(withByteBuffers(stdout)))
  1138  	if err != nil {
  1139  		t.Fatal(err)
  1140  	}
  1141  	defer task.Delete(ctx)
  1142  
  1143  	statusC, err := task.Wait(ctx)
  1144  	if err != nil {
  1145  		t.Fatal(err)
  1146  	}
  1147  
  1148  	if err := task.Start(ctx); err != nil {
  1149  		t.Fatal(err)
  1150  	}
  1151  
  1152  	status := <-statusC
  1153  	code, _, err := status.Result()
  1154  	if err != nil {
  1155  		t.Fatal(err)
  1156  	}
  1157  	if code != 0 {
  1158  		t.Errorf("expected status 0 but received %d", code)
  1159  	}
  1160  	if _, err := task.Delete(ctx); err != nil {
  1161  		t.Fatal(err)
  1162  	}
  1163  	cutset := "\n"
  1164  	if runtime.GOOS == "windows" {
  1165  		cutset = "\r\n"
  1166  	}
  1167  
  1168  	actual := strings.TrimSuffix(stdout.String(), cutset)
  1169  	if actual != expected {
  1170  		t.Errorf("expected output %q but received %q", expected, actual)
  1171  	}
  1172  }
  1173  
  1174  func TestContainerExitedAtSet(t *testing.T) {
  1175  	t.Parallel()
  1176  
  1177  	client, err := newClient(t, address)
  1178  	if err != nil {
  1179  		t.Fatal(err)
  1180  	}
  1181  	defer client.Close()
  1182  
  1183  	var (
  1184  		image       Image
  1185  		ctx, cancel = testContext(t)
  1186  		id          = t.Name()
  1187  	)
  1188  	defer cancel()
  1189  
  1190  	image, err = client.GetImage(ctx, testImage)
  1191  	if err != nil {
  1192  		t.Fatal(err)
  1193  	}
  1194  
  1195  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), withTrue()))
  1196  	if err != nil {
  1197  		t.Fatal(err)
  1198  	}
  1199  	defer container.Delete(ctx, WithSnapshotCleanup)
  1200  
  1201  	task, err := container.NewTask(ctx, empty())
  1202  	if err != nil {
  1203  		t.Fatal(err)
  1204  	}
  1205  	defer task.Delete(ctx)
  1206  
  1207  	statusC, err := task.Wait(ctx)
  1208  	if err != nil {
  1209  		t.Error(err)
  1210  	}
  1211  
  1212  	startTime := time.Now()
  1213  	if err := task.Start(ctx); err != nil {
  1214  		t.Fatal(err)
  1215  	}
  1216  
  1217  	status := <-statusC
  1218  	code, _, err := status.Result()
  1219  	if code != 0 {
  1220  		t.Errorf("expected status 0 but received %d (err: %v)", code, err)
  1221  	}
  1222  
  1223  	if s, err := task.Status(ctx); err != nil {
  1224  		t.Errorf("failed to retrieve status: %v", err)
  1225  	} else if s.ExitTime.After(startTime) == false {
  1226  		t.Errorf("exit time is not after start time: %v <= %v", startTime, s.ExitTime)
  1227  	}
  1228  
  1229  	if _, err := task.Delete(ctx); err != nil {
  1230  		t.Fatal(err)
  1231  	}
  1232  }
  1233  
  1234  func TestDeleteContainerExecCreated(t *testing.T) {
  1235  	t.Parallel()
  1236  
  1237  	client, err := newClient(t, address)
  1238  	if err != nil {
  1239  		t.Fatal(err)
  1240  	}
  1241  	defer client.Close()
  1242  
  1243  	var (
  1244  		image       Image
  1245  		ctx, cancel = testContext(t)
  1246  		id          = t.Name()
  1247  	)
  1248  	defer cancel()
  1249  
  1250  	image, err = client.GetImage(ctx, testImage)
  1251  	if err != nil {
  1252  		t.Fatal(err)
  1253  	}
  1254  
  1255  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
  1256  	if err != nil {
  1257  		t.Fatal(err)
  1258  	}
  1259  	defer container.Delete(ctx, WithSnapshotCleanup)
  1260  
  1261  	task, err := container.NewTask(ctx, empty())
  1262  	if err != nil {
  1263  		t.Fatal(err)
  1264  	}
  1265  	defer task.Delete(ctx)
  1266  
  1267  	finished, err := task.Wait(ctx)
  1268  	if err != nil {
  1269  		t.Error(err)
  1270  	}
  1271  
  1272  	if err := task.Start(ctx); err != nil {
  1273  		t.Fatal(err)
  1274  	}
  1275  	spec, err := container.Spec(ctx)
  1276  	if err != nil {
  1277  		t.Fatal(err)
  1278  	}
  1279  
  1280  	// start an exec process without running the original container process info
  1281  	processSpec := spec.Process
  1282  	withExecExitStatus(processSpec, 6)
  1283  	execID := t.Name() + "_exec"
  1284  	process, err := task.Exec(ctx, execID, processSpec, empty())
  1285  	if err != nil {
  1286  		t.Fatal(err)
  1287  	}
  1288  	deleteStatus, err := process.Delete(ctx)
  1289  	if err != nil {
  1290  		t.Fatal(err)
  1291  	}
  1292  	if ec := deleteStatus.ExitCode(); ec != 0 {
  1293  		t.Errorf("expected delete exit code 0 but received %d", ec)
  1294  	}
  1295  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
  1296  		t.Error(err)
  1297  	}
  1298  	<-finished
  1299  }
  1300  
  1301  func TestContainerMetrics(t *testing.T) {
  1302  	if runtime.GOOS == "windows" {
  1303  		t.Skip("metrics are currently not supported on windows")
  1304  	}
  1305  	t.Parallel()
  1306  
  1307  	client, err := newClient(t, address)
  1308  	if err != nil {
  1309  		t.Fatal(err)
  1310  	}
  1311  	defer client.Close()
  1312  
  1313  	var (
  1314  		image       Image
  1315  		ctx, cancel = testContext(t)
  1316  		id          = t.Name()
  1317  	)
  1318  	defer cancel()
  1319  
  1320  	image, err = client.GetImage(ctx, testImage)
  1321  	if err != nil {
  1322  		t.Fatal(err)
  1323  	}
  1324  	container, err := client.NewContainer(ctx, id,
  1325  		WithNewSnapshot(id, image),
  1326  		WithNewSpec(oci.WithImageConfig(image), longCommand))
  1327  	if err != nil {
  1328  		t.Fatal(err)
  1329  	}
  1330  	defer container.Delete(ctx, WithSnapshotCleanup)
  1331  
  1332  	task, err := container.NewTask(ctx, empty())
  1333  	if err != nil {
  1334  		t.Fatal(err)
  1335  	}
  1336  	defer task.Delete(ctx, WithProcessKill)
  1337  
  1338  	statusC, err := task.Wait(ctx)
  1339  	if err != nil {
  1340  		t.Fatal(err)
  1341  	}
  1342  
  1343  	metric, err := task.Metrics(ctx)
  1344  	if err != nil {
  1345  		t.Error(err)
  1346  		return
  1347  	}
  1348  	if metric.ID != id {
  1349  		t.Errorf("expected metric id %q but received %q", id, metric.ID)
  1350  	}
  1351  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
  1352  		t.Fatal(err)
  1353  	}
  1354  
  1355  	<-statusC
  1356  }
  1357  
  1358  func TestDeletedContainerMetrics(t *testing.T) {
  1359  	if runtime.GOOS == "windows" {
  1360  		t.Skip("metrics are currently not supported on windows")
  1361  	}
  1362  	t.Parallel()
  1363  
  1364  	client, err := newClient(t, address)
  1365  	if err != nil {
  1366  		t.Fatal(err)
  1367  	}
  1368  	defer client.Close()
  1369  
  1370  	var (
  1371  		image       Image
  1372  		ctx, cancel = testContext(t)
  1373  		id          = t.Name()
  1374  	)
  1375  	defer cancel()
  1376  
  1377  	image, err = client.GetImage(ctx, testImage)
  1378  	if err != nil {
  1379  		t.Fatal(err)
  1380  	}
  1381  	container, err := client.NewContainer(ctx, id,
  1382  		WithNewSnapshot(id, image),
  1383  		WithNewSpec(oci.WithImageConfig(image), withExitStatus(0)))
  1384  	if err != nil {
  1385  		t.Fatal(err)
  1386  	}
  1387  	defer container.Delete(ctx, WithSnapshotCleanup)
  1388  
  1389  	task, err := container.NewTask(ctx, empty())
  1390  	if err != nil {
  1391  		t.Fatal(err)
  1392  	}
  1393  	defer task.Delete(ctx)
  1394  
  1395  	if err := task.Start(ctx); err != nil {
  1396  		t.Fatal(err)
  1397  	}
  1398  
  1399  	statusC, err := task.Wait(ctx)
  1400  	if err != nil {
  1401  		t.Fatal(err)
  1402  	}
  1403  	<-statusC
  1404  
  1405  	if _, err := task.Delete(ctx); err != nil {
  1406  		t.Fatal(err)
  1407  	}
  1408  
  1409  	if _, err := task.Metrics(ctx); err == nil {
  1410  		t.Errorf("Getting metrics of deleted task should have failed")
  1411  	}
  1412  }
  1413  
  1414  func TestContainerExtensions(t *testing.T) {
  1415  	t.Parallel()
  1416  
  1417  	ctx, cancel := testContext(t)
  1418  	defer cancel()
  1419  	id := t.Name()
  1420  
  1421  	client, err := newClient(t, address)
  1422  	if err != nil {
  1423  		t.Fatal(err)
  1424  	}
  1425  	defer client.Close()
  1426  
  1427  	ext := gogotypes.Any{TypeUrl: "test.ext.url", Value: []byte("hello")}
  1428  	container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerExtension("hello", &ext))
  1429  	if err != nil {
  1430  		t.Fatal(err)
  1431  	}
  1432  	defer container.Delete(ctx)
  1433  
  1434  	checkExt := func(container Container) {
  1435  		cExts, err := container.Extensions(ctx)
  1436  		if err != nil {
  1437  			t.Fatal(err)
  1438  		}
  1439  		if len(cExts) != 1 {
  1440  			t.Errorf("expected 1 container extension")
  1441  		}
  1442  		if cExts["hello"].TypeUrl != ext.TypeUrl {
  1443  			t.Errorf("got unexpected type url for extension: %s", cExts["hello"].TypeUrl)
  1444  		}
  1445  		if !bytes.Equal(cExts["hello"].Value, ext.Value) {
  1446  			t.Errorf("expected extension value %q, got: %q", ext.Value, cExts["hello"].Value)
  1447  		}
  1448  	}
  1449  
  1450  	checkExt(container)
  1451  
  1452  	container, err = client.LoadContainer(ctx, container.ID())
  1453  	if err != nil {
  1454  		t.Fatal(err)
  1455  	}
  1456  	checkExt(container)
  1457  }
  1458  
  1459  func TestContainerUpdate(t *testing.T) {
  1460  	t.Parallel()
  1461  
  1462  	ctx, cancel := testContext(t)
  1463  	defer cancel()
  1464  	id := t.Name()
  1465  
  1466  	client, err := newClient(t, address)
  1467  	if err != nil {
  1468  		t.Fatal(err)
  1469  	}
  1470  	defer client.Close()
  1471  
  1472  	container, err := client.NewContainer(ctx, id, WithNewSpec())
  1473  	if err != nil {
  1474  		t.Fatal(err)
  1475  	}
  1476  	defer container.Delete(ctx)
  1477  
  1478  	spec, err := container.Spec(ctx)
  1479  	if err != nil {
  1480  		t.Fatal(err)
  1481  	}
  1482  
  1483  	const hostname = "updated-hostname"
  1484  	spec.Hostname = hostname
  1485  
  1486  	if err := container.Update(ctx, func(ctx context.Context, client *Client, c *containers.Container) error {
  1487  		a, err := typeurl.MarshalAny(spec)
  1488  		if err != nil {
  1489  			return err
  1490  		}
  1491  		c.Spec = a
  1492  		return nil
  1493  	}); err != nil {
  1494  		t.Fatal(err)
  1495  	}
  1496  	if spec, err = container.Spec(ctx); err != nil {
  1497  		t.Fatal(err)
  1498  	}
  1499  	if spec.Hostname != hostname {
  1500  		t.Errorf("hostname %q != %q", spec.Hostname, hostname)
  1501  	}
  1502  }
  1503  
  1504  func TestContainerInfo(t *testing.T) {
  1505  	t.Parallel()
  1506  
  1507  	ctx, cancel := testContext(t)
  1508  	defer cancel()
  1509  	id := t.Name()
  1510  
  1511  	client, err := newClient(t, address)
  1512  	if err != nil {
  1513  		t.Fatal(err)
  1514  	}
  1515  	defer client.Close()
  1516  
  1517  	container, err := client.NewContainer(ctx, id, WithNewSpec())
  1518  	if err != nil {
  1519  		t.Fatal(err)
  1520  	}
  1521  	defer container.Delete(ctx)
  1522  
  1523  	info, err := container.Info(ctx)
  1524  	if err != nil {
  1525  		t.Fatal(err)
  1526  	}
  1527  	if info.ID != container.ID() {
  1528  		t.Fatalf("info.ID=%s != container.ID()=%s", info.ID, container.ID())
  1529  	}
  1530  }
  1531  
  1532  func TestContainerLabels(t *testing.T) {
  1533  	t.Parallel()
  1534  
  1535  	ctx, cancel := testContext(t)
  1536  	defer cancel()
  1537  	id := t.Name()
  1538  
  1539  	client, err := newClient(t, address)
  1540  	if err != nil {
  1541  		t.Fatal(err)
  1542  	}
  1543  	defer client.Close()
  1544  
  1545  	container, err := client.NewContainer(ctx, id, WithNewSpec(), WithContainerLabels(map[string]string{
  1546  		"test": "yes",
  1547  	}))
  1548  	if err != nil {
  1549  		t.Fatal(err)
  1550  	}
  1551  	defer container.Delete(ctx)
  1552  
  1553  	labels, err := container.Labels(ctx)
  1554  	if err != nil {
  1555  		t.Fatal(err)
  1556  	}
  1557  	if labels["test"] != "yes" {
  1558  		t.Fatalf("expected label \"test\" to be \"yes\"")
  1559  	}
  1560  	labels["test"] = "no"
  1561  	if labels, err = container.SetLabels(ctx, labels); err != nil {
  1562  		t.Fatal(err)
  1563  	}
  1564  	if labels["test"] != "no" {
  1565  		t.Fatalf("expected label \"test\" to be \"no\"")
  1566  	}
  1567  }
  1568  
  1569  func TestContainerHook(t *testing.T) {
  1570  	t.Parallel()
  1571  
  1572  	client, err := newClient(t, address)
  1573  	if err != nil {
  1574  		t.Fatal(err)
  1575  	}
  1576  	defer client.Close()
  1577  
  1578  	var (
  1579  		image       Image
  1580  		ctx, cancel = testContext(t)
  1581  		id          = t.Name()
  1582  	)
  1583  	defer cancel()
  1584  
  1585  	image, err = client.GetImage(ctx, testImage)
  1586  	if err != nil {
  1587  		t.Fatal(err)
  1588  	}
  1589  	hook := func(_ context.Context, _ oci.Client, _ *containers.Container, s *specs.Spec) error {
  1590  		if s.Hooks == nil {
  1591  			s.Hooks = &specs.Hooks{}
  1592  		}
  1593  		path, err := exec.LookPath("containerd")
  1594  		if err != nil {
  1595  			return err
  1596  		}
  1597  		psPath, err := exec.LookPath("ps")
  1598  		if err != nil {
  1599  			return err
  1600  		}
  1601  		s.Hooks.Prestart = []specs.Hook{
  1602  			{
  1603  				Path: path,
  1604  				Args: []string{
  1605  					"containerd",
  1606  					"oci-hook", "--",
  1607  					psPath, "--pid", "{{pid}}",
  1608  				},
  1609  				Env: os.Environ(),
  1610  			},
  1611  		}
  1612  		return nil
  1613  	}
  1614  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), hook))
  1615  	if err != nil {
  1616  		t.Fatal(err)
  1617  	}
  1618  	defer container.Delete(ctx, WithSnapshotCleanup)
  1619  
  1620  	task, err := container.NewTask(ctx, empty())
  1621  	if err != nil {
  1622  		t.Fatal(err)
  1623  	}
  1624  	defer task.Delete(ctx, WithProcessKill)
  1625  }
  1626  
  1627  func TestShimSockLength(t *testing.T) {
  1628  	t.Parallel()
  1629  
  1630  	// Max length of namespace should be 76
  1631  	namespace := strings.Repeat("n", 76)
  1632  
  1633  	ctx, cancel := context.WithCancel(context.Background())
  1634  	defer cancel()
  1635  
  1636  	ctx = namespaces.WithNamespace(ctx, namespace)
  1637  
  1638  	client, err := newClient(t, address)
  1639  	if err != nil {
  1640  		t.Fatal(err)
  1641  	}
  1642  	defer client.Close()
  1643  
  1644  	image, err := client.Pull(ctx, testImage,
  1645  		WithPlatformMatcher(platforms.Default()),
  1646  		WithPullUnpack,
  1647  	)
  1648  	if err != nil {
  1649  		t.Fatal(err)
  1650  	}
  1651  
  1652  	id := strings.Repeat("c", 64)
  1653  
  1654  	// We don't have limitation with length of container name,
  1655  	// but 64 bytes of sha256 is the common case
  1656  	container, err := client.NewContainer(ctx, id,
  1657  		WithNewSnapshot(id, image),
  1658  		WithNewSpec(oci.WithImageConfig(image), withExitStatus(0)),
  1659  	)
  1660  	if err != nil {
  1661  		t.Fatal(err)
  1662  	}
  1663  	defer container.Delete(ctx, WithSnapshotCleanup)
  1664  
  1665  	task, err := container.NewTask(ctx, empty())
  1666  	if err != nil {
  1667  		t.Fatal(err)
  1668  	}
  1669  	defer task.Delete(ctx)
  1670  
  1671  	statusC, err := task.Wait(ctx)
  1672  	if err != nil {
  1673  		t.Fatal(err)
  1674  	}
  1675  
  1676  	if err := task.Start(ctx); err != nil {
  1677  		t.Fatal(err)
  1678  	}
  1679  
  1680  	<-statusC
  1681  }
  1682  
  1683  func TestContainerExecLargeOutputWithTTY(t *testing.T) {
  1684  	if runtime.GOOS == "windows" {
  1685  		t.Skip("Test does not run on Windows")
  1686  	}
  1687  
  1688  	t.Parallel()
  1689  
  1690  	client, err := newClient(t, address)
  1691  	if err != nil {
  1692  		t.Fatal(err)
  1693  	}
  1694  	defer client.Close()
  1695  
  1696  	var (
  1697  		image       Image
  1698  		ctx, cancel = testContext(t)
  1699  		id          = t.Name()
  1700  	)
  1701  	defer cancel()
  1702  
  1703  	image, err = client.GetImage(ctx, testImage)
  1704  	if err != nil {
  1705  		t.Fatal(err)
  1706  	}
  1707  
  1708  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), longCommand))
  1709  	if err != nil {
  1710  		t.Fatal(err)
  1711  	}
  1712  	defer container.Delete(ctx, WithSnapshotCleanup)
  1713  
  1714  	task, err := container.NewTask(ctx, empty())
  1715  	if err != nil {
  1716  		t.Fatal(err)
  1717  	}
  1718  	defer task.Delete(ctx)
  1719  
  1720  	finishedC, err := task.Wait(ctx)
  1721  	if err != nil {
  1722  		t.Fatal(err)
  1723  	}
  1724  
  1725  	if err := task.Start(ctx); err != nil {
  1726  		t.Fatal(err)
  1727  	}
  1728  
  1729  	for i := 0; i < 100; i++ {
  1730  		spec, err := container.Spec(ctx)
  1731  		if err != nil {
  1732  			t.Fatal(err)
  1733  		}
  1734  
  1735  		// start an exec process without running the original container process info
  1736  		processSpec := spec.Process
  1737  		withExecArgs(processSpec, "sh", "-c", `seq -s " " 1000000`)
  1738  
  1739  		stdout := bytes.NewBuffer(nil)
  1740  
  1741  		execID := t.Name() + "_exec"
  1742  		process, err := task.Exec(ctx, execID, processSpec, cio.NewCreator(withByteBuffers(stdout), withProcessTTY()))
  1743  		if err != nil {
  1744  			t.Fatal(err)
  1745  		}
  1746  		processStatusC, err := process.Wait(ctx)
  1747  		if err != nil {
  1748  			t.Fatal(err)
  1749  		}
  1750  
  1751  		if err := process.Start(ctx); err != nil {
  1752  			t.Fatal(err)
  1753  		}
  1754  
  1755  		// wait for the exec to return
  1756  		status := <-processStatusC
  1757  		code, _, err := status.Result()
  1758  		if err != nil {
  1759  			t.Fatal(err)
  1760  		}
  1761  
  1762  		if code != 0 {
  1763  			t.Errorf("expected exec exit code 0 but received %d", code)
  1764  		}
  1765  		if _, err := process.Delete(ctx); err != nil {
  1766  			t.Fatal(err)
  1767  		}
  1768  
  1769  		const expectedSuffix = "999999 1000000"
  1770  		stdoutString := stdout.String()
  1771  		if !strings.Contains(stdoutString, expectedSuffix) {
  1772  			t.Fatalf("process output does not end with %q at iteration %d, here are the last 20 characters of the output:\n\n %q", expectedSuffix, i, stdoutString[len(stdoutString)-20:])
  1773  		}
  1774  
  1775  	}
  1776  
  1777  	if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
  1778  		t.Error(err)
  1779  	}
  1780  	<-finishedC
  1781  }
  1782  
  1783  func TestShortRunningTaskPid(t *testing.T) {
  1784  	t.Parallel()
  1785  
  1786  	client, err := newClient(t, address)
  1787  	if err != nil {
  1788  		t.Fatal(err)
  1789  	}
  1790  	defer client.Close()
  1791  
  1792  	var (
  1793  		image       Image
  1794  		ctx, cancel = testContext(t)
  1795  		id          = t.Name()
  1796  	)
  1797  	defer cancel()
  1798  
  1799  	image, err = client.GetImage(ctx, testImage)
  1800  	if err != nil {
  1801  		t.Fatal(err)
  1802  	}
  1803  
  1804  	container, err := client.NewContainer(ctx, id, WithNewSnapshot(id, image), WithNewSpec(oci.WithImageConfig(image), shortCommand))
  1805  	if err != nil {
  1806  		t.Fatal(err)
  1807  	}
  1808  	defer container.Delete(ctx, WithSnapshotCleanup)
  1809  
  1810  	task, err := container.NewTask(ctx, empty())
  1811  	if err != nil {
  1812  		t.Fatal(err)
  1813  	}
  1814  	defer task.Delete(ctx)
  1815  
  1816  	finishedC, err := task.Wait(ctx)
  1817  	if err != nil {
  1818  		t.Fatal(err)
  1819  	}
  1820  
  1821  	if err := task.Start(ctx); err != nil {
  1822  		t.Fatal(err)
  1823  	}
  1824  
  1825  	int32PID := int32(task.Pid())
  1826  	if int32PID <= 0 {
  1827  		t.Errorf("Unexpected task pid %d", int32PID)
  1828  	}
  1829  	<-finishedC
  1830  }
  1831  
  1832  func withProcessTTY() cio.Opt {
  1833  	return func(opt *cio.Streams) {
  1834  		cio.WithTerminal(opt)
  1835  	}
  1836  }