github.com/docker/containerd@v0.2.9-0.20170509230648-8ef7df579710/runtime/runtime_test.go (about)

     1  package runtime
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"syscall"
    12  	"testing"
    13  	"time"
    14  
    15  	utils "github.com/containerd/containerd/testutils"
    16  )
    17  
    18  var (
    19  	devNull     = "/dev/null"
    20  	stdin       io.WriteCloser
    21  	runtimeTool = flag.String("runtime", "runc", "Runtime to use for this test")
    22  )
    23  
    24  // Create containerd state and oci bundles directory
    25  func setup() error {
    26  	if err := os.MkdirAll(utils.StateDir, 0755); err != nil {
    27  		return err
    28  	}
    29  
    30  	if err := os.MkdirAll(utils.BundlesRoot, 0755); err != nil {
    31  		return err
    32  	}
    33  	return nil
    34  }
    35  
    36  // Creates the bundleDir with rootfs, io fifo dir and a default spec.
    37  // On success, returns the bundlePath
    38  func setupBundle(bundleName string) (string, error) {
    39  	bundlePath := filepath.Join(utils.BundlesRoot, bundleName)
    40  	if err := os.MkdirAll(bundlePath, 0755); err != nil {
    41  		fmt.Println("Unable to create bundlePath due to ", err)
    42  		return "", err
    43  	}
    44  
    45  	io := filepath.Join(bundlePath, "io")
    46  	if err := os.MkdirAll(io, 0755); err != nil {
    47  		fmt.Println("Unable to create io dir due to ", err)
    48  		return "", err
    49  	}
    50  
    51  	if err := utils.GenerateReferenceSpecs(bundlePath); err != nil {
    52  		fmt.Println("Unable to generate OCI reference spec: ", err)
    53  		return "", err
    54  	}
    55  
    56  	if err := utils.CreateBusyboxBundle(bundleName); err != nil {
    57  		fmt.Println("CreateBusyboxBundle error: ", err)
    58  		return "", err
    59  	}
    60  
    61  	return bundlePath, nil
    62  }
    63  
    64  func setupStdio(cwd string, bundlePath string, bundleName string) (Stdio, error) {
    65  	s := NewStdio(devNull, devNull, devNull)
    66  
    67  	pid := "init"
    68  	for _, pair := range []struct {
    69  		stdName string
    70  		stdPath *string
    71  	}{
    72  		{"stdin", &s.Stdin},
    73  		{"stdout", &s.Stdout},
    74  		{"stderr", &s.Stderr},
    75  	} {
    76  		*pair.stdPath = filepath.Join(cwd, bundlePath, "io", bundleName+"-"+pid+"-"+pair.stdName)
    77  		if err := syscall.Mkfifo(*pair.stdPath, 0755); err != nil && !os.IsExist(err) {
    78  			fmt.Println("Mkfifo error: ", err)
    79  			return s, err
    80  		}
    81  	}
    82  
    83  	err := attachStdio(s)
    84  	if err != nil {
    85  		fmt.Println("attachStdio error: ", err)
    86  		return s, err
    87  	}
    88  
    89  	return s, nil
    90  }
    91  
    92  func attachStdio(s Stdio) error {
    93  	stdinf, err := os.OpenFile(s.Stdin, syscall.O_RDWR, 0)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	stdin = stdinf
    98  	stdoutf, err := os.OpenFile(s.Stdout, syscall.O_RDWR, 0)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	go io.Copy(os.Stdout, stdoutf)
   103  	stderrf, err := os.OpenFile(s.Stderr, syscall.O_RDWR, 0)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	go io.Copy(os.Stderr, stderrf)
   108  	return nil
   109  }
   110  
   111  func teardownBundle(bundleName string) {
   112  	containerRoot := filepath.Join(utils.StateDir, bundleName)
   113  	os.RemoveAll(containerRoot)
   114  
   115  	bundlePath := filepath.Join(utils.BundlesRoot, bundleName)
   116  	os.RemoveAll(bundlePath)
   117  	return
   118  }
   119  
   120  // Remove containerd state and oci bundles directory
   121  func teardown() {
   122  	os.RemoveAll(utils.StateDir)
   123  	os.RemoveAll(utils.BundlesRoot)
   124  }
   125  
   126  func BenchmarkBusyboxSh(b *testing.B) {
   127  	bundleName := "busybox-sh"
   128  
   129  	wd := utils.GetTestOutDir()
   130  	if err := os.Chdir(wd); err != nil {
   131  		b.Fatalf("Could not change working directory: %v", err)
   132  	}
   133  
   134  	if err := setup(); err != nil {
   135  		b.Fatalf("Error setting up test: %v", err)
   136  	}
   137  	defer teardown()
   138  
   139  	for n := 0; n < b.N; n++ {
   140  		bundlePath, err := setupBundle(bundleName)
   141  		if err != nil {
   142  			return
   143  		}
   144  
   145  		s, err := setupStdio(wd, bundlePath, bundleName)
   146  		if err != nil {
   147  			return
   148  		}
   149  
   150  		c, err := New(ContainerOpts{
   151  			Root:    utils.StateDir,
   152  			ID:      bundleName,
   153  			Bundle:  filepath.Join(wd, bundlePath),
   154  			Runtime: *runtimeTool,
   155  			Shim:    "containerd-shim",
   156  			Timeout: 15 * time.Second,
   157  		})
   158  
   159  		if err != nil {
   160  			b.Fatalf("Error creating a New container: ", err)
   161  		}
   162  
   163  		benchmarkStartContainer(b, c, s, bundleName)
   164  
   165  		teardownBundle(bundleName)
   166  	}
   167  }
   168  
   169  func benchmarkStartContainer(b *testing.B, c Container, s Stdio, bundleName string) {
   170  	p, err := c.Start(context.Background(), "", s)
   171  	if err != nil {
   172  		b.Fatalf("Error starting container %v", err)
   173  	}
   174  
   175  	kill := exec.Command(c.Runtime(), "kill", bundleName, "KILL")
   176  	kill.Run()
   177  
   178  	p.Wait()
   179  	c.Delete()
   180  
   181  	// wait for kill to finish. selected wait time is arbitrary
   182  	time.Sleep(500 * time.Millisecond)
   183  
   184  }