github.com/lalkh/containerd@v1.4.3/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 }