gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/pkg/katautils/utils_test.go (about)

     1  // Copyright (c) 2018 Intel Corporation
     2  // Copyright (c) 2018 HyperHQ Inc.
     3  //
     4  // SPDX-License-Identifier: Apache-2.0
     5  //
     6  
     7  package katautils
     8  
     9  import (
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"os"
    14  	"os/exec"
    15  	"path"
    16  	"path/filepath"
    17  	"strings"
    18  	"syscall"
    19  	"testing"
    20  
    21  	"github.com/kata-containers/runtime/virtcontainers/pkg/compatoci"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  const (
    26  	testDirMode  = os.FileMode(0750)
    27  	testFileMode = os.FileMode(0640)
    28  
    29  	// small docker image used to create root filesystems from
    30  	testDockerImage = "busybox"
    31  
    32  	testSandboxID   = "99999999-9999-9999-99999999999999999"
    33  	testContainerID = "1"
    34  	testBundle      = "bundle"
    35  	specConfig      = "config.json"
    36  )
    37  
    38  var (
    39  	testDir = ""
    40  )
    41  
    42  func init() {
    43  	var err error
    44  
    45  	fmt.Printf("INFO: creating test directory\n")
    46  	testDir, err = ioutil.TempDir("", fmt.Sprintf("%s-", name))
    47  	if err != nil {
    48  		panic(fmt.Sprintf("ERROR: failed to create test directory: %v", err))
    49  	}
    50  
    51  	fmt.Printf("INFO: test directory is %v\n", testDir)
    52  
    53  	testBundleDir = filepath.Join(testDir, testBundle)
    54  	err = os.MkdirAll(testBundleDir, testDirMode)
    55  	if err != nil {
    56  		panic(fmt.Sprintf("ERROR: failed to create bundle directory %v: %v", testBundleDir, err))
    57  	}
    58  
    59  	fmt.Printf("INFO: creating OCI bundle in %v for tests to use\n", testBundleDir)
    60  	err = realMakeOCIBundle(testBundleDir)
    61  	if err != nil {
    62  		panic(fmt.Sprintf("ERROR: failed to create OCI bundle: %v", err))
    63  	}
    64  }
    65  
    66  // createOCIConfig creates an OCI configuration (spec) file in
    67  // the bundle directory specified (which must exist).
    68  func createOCIConfig(bundleDir string) error {
    69  	if bundleDir == "" {
    70  		return errors.New("BUG: Need bundle directory")
    71  	}
    72  
    73  	if !FileExists(bundleDir) {
    74  		return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir)
    75  	}
    76  
    77  	var configCmd string
    78  
    79  	// Search for a suitable version of runc to use to generate
    80  	// the OCI config file.
    81  	for _, cmd := range []string{"docker-runc", "runc"} {
    82  		fullPath, err := exec.LookPath(cmd)
    83  		if err == nil {
    84  			configCmd = fullPath
    85  			break
    86  		}
    87  	}
    88  
    89  	if configCmd == "" {
    90  		return errors.New("Cannot find command to generate OCI config file")
    91  	}
    92  
    93  	_, err := RunCommand([]string{configCmd, "spec", "--bundle", bundleDir})
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	specFile := filepath.Join(bundleDir, specConfig)
    99  	if !FileExists(specFile) {
   100  		return fmt.Errorf("generated OCI config file does not exist: %v", specFile)
   101  	}
   102  
   103  	return nil
   104  }
   105  
   106  // realMakeOCIBundle will create an OCI bundle (including the "config.json"
   107  // config file) in the directory specified (which must already exist).
   108  //
   109  // XXX: Note that tests should *NOT* call this function - they should
   110  // XXX: instead call makeOCIBundle().
   111  func realMakeOCIBundle(bundleDir string) error {
   112  	if bundleDir == "" {
   113  		return errors.New("BUG: Need bundle directory")
   114  	}
   115  
   116  	if !FileExists(bundleDir) {
   117  		return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir)
   118  	}
   119  
   120  	err := createOCIConfig(bundleDir)
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	// Note the unusual parameter (a directory, not the config
   126  	// file to parse!)
   127  	spec, err := compatoci.ParseConfigJSON(bundleDir)
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	// Determine the rootfs directory name the OCI config refers to
   133  	ociRootPath := spec.Root.Path
   134  
   135  	rootfsDir := filepath.Join(bundleDir, ociRootPath)
   136  
   137  	if strings.HasPrefix(ociRootPath, "/") {
   138  		return fmt.Errorf("Cannot handle absolute rootfs as bundle must be unique to each test")
   139  	}
   140  
   141  	err = createRootfs(rootfsDir)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  // createRootfs creates a minimal root filesystem below the specified
   150  // directory.
   151  func createRootfs(dir string) error {
   152  	var (
   153  		output string
   154  		err    error
   155  	)
   156  
   157  	ctrEngine := CtrEngine{}
   158  	for _, name := range DockerLikeCtrEngines {
   159  		fmt.Printf("INFO: checking for container engine: %s\n", name)
   160  
   161  		output, err = ctrEngine.Init(name)
   162  		if err == nil {
   163  			break
   164  		}
   165  	}
   166  
   167  	if ctrEngine.Name == "" {
   168  		panic(fmt.Sprintf("ERROR: Docker-like container engine not accessible to current user: %v (error %v)",
   169  			output, err))
   170  	}
   171  
   172  	err = os.MkdirAll(dir, testDirMode)
   173  	if err != nil {
   174  		return err
   175  	}
   176  
   177  	container, err := ctrEngine.Create(testDockerImage)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	err = ctrEngine.GetRootfs(container, dir)
   183  	if err != nil {
   184  		return err
   185  	}
   186  
   187  	// Clean up
   188  	_, err = ctrEngine.Rm(container)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	return nil
   194  }
   195  
   196  func createFile(file, contents string) error {
   197  	return ioutil.WriteFile(file, []byte(contents), testFileMode)
   198  }
   199  
   200  func createEmptyFile(path string) (err error) {
   201  	return ioutil.WriteFile(path, []byte(""), testFileMode)
   202  }
   203  
   204  func TestUtilsResolvePathEmptyPath(t *testing.T) {
   205  	_, err := ResolvePath("")
   206  	assert.Error(t, err)
   207  }
   208  
   209  func TestUtilsResolvePathValidPath(t *testing.T) {
   210  	dir, err := ioutil.TempDir("", "")
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	defer os.RemoveAll(dir)
   215  
   216  	target := path.Join(dir, "target")
   217  	linkDir := path.Join(dir, "a/b/c")
   218  	linkFile := path.Join(linkDir, "link")
   219  
   220  	err = createEmptyFile(target)
   221  	assert.NoError(t, err)
   222  
   223  	absolute, err := filepath.Abs(target)
   224  	assert.NoError(t, err)
   225  
   226  	resolvedTarget, err := filepath.EvalSymlinks(absolute)
   227  	assert.NoError(t, err)
   228  
   229  	err = os.MkdirAll(linkDir, testDirMode)
   230  	assert.NoError(t, err)
   231  
   232  	err = syscall.Symlink(target, linkFile)
   233  	assert.NoError(t, err)
   234  
   235  	resolvedLink, err := ResolvePath(linkFile)
   236  	assert.NoError(t, err)
   237  
   238  	assert.Equal(t, resolvedTarget, resolvedLink)
   239  }
   240  
   241  func TestUtilsResolvePathENOENT(t *testing.T) {
   242  	dir, err := ioutil.TempDir("", "")
   243  	if err != nil {
   244  		t.Fatal(err)
   245  	}
   246  
   247  	target := path.Join(dir, "target")
   248  	linkDir := path.Join(dir, "a/b/c")
   249  	linkFile := path.Join(linkDir, "link")
   250  
   251  	err = createEmptyFile(target)
   252  	assert.NoError(t, err)
   253  
   254  	err = os.MkdirAll(linkDir, testDirMode)
   255  	assert.NoError(t, err)
   256  
   257  	err = syscall.Symlink(target, linkFile)
   258  	assert.NoError(t, err)
   259  
   260  	cwd, err := os.Getwd()
   261  	assert.NoError(t, err)
   262  	defer os.Chdir(cwd)
   263  
   264  	err = os.Chdir(dir)
   265  	assert.NoError(t, err)
   266  
   267  	err = os.RemoveAll(dir)
   268  	assert.NoError(t, err)
   269  
   270  	_, err = ResolvePath(filepath.Base(linkFile))
   271  	assert.Error(t, err)
   272  }
   273  
   274  func TestFileSize(t *testing.T) {
   275  	assert := assert.New(t)
   276  
   277  	dir, err := ioutil.TempDir(testDir, "")
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	defer os.RemoveAll(dir)
   282  
   283  	file := filepath.Join(dir, "foo")
   284  
   285  	// ENOENT
   286  	_, err = fileSize(file)
   287  	assert.Error(err)
   288  
   289  	err = createEmptyFile(file)
   290  	assert.NoError(err)
   291  
   292  	// zero size
   293  	size, err := fileSize(file)
   294  	assert.NoError(err)
   295  	assert.Equal(size, int64(0))
   296  
   297  	msg := "hello"
   298  	msgLen := len(msg)
   299  
   300  	err = WriteFile(file, msg, testFileMode)
   301  	assert.NoError(err)
   302  
   303  	size, err = fileSize(file)
   304  	assert.NoError(err)
   305  	assert.Equal(size, int64(msgLen))
   306  }
   307  
   308  func TestWriteFileErrWriteFail(t *testing.T) {
   309  	assert := assert.New(t)
   310  
   311  	err := WriteFile("", "", 0000)
   312  	assert.Error(err)
   313  }
   314  
   315  func TestWriteFileErrNoPath(t *testing.T) {
   316  	assert := assert.New(t)
   317  
   318  	dir, err := ioutil.TempDir(testDir, "")
   319  	assert.NoError(err)
   320  	defer os.RemoveAll(dir)
   321  
   322  	// attempt to write a file over an existing directory
   323  	err = WriteFile(dir, "", 0000)
   324  	assert.Error(err)
   325  }
   326  
   327  func TestGetFileContents(t *testing.T) {
   328  	type testData struct {
   329  		contents string
   330  	}
   331  
   332  	data := []testData{
   333  		{""},
   334  		{" "},
   335  		{"\n"},
   336  		{"\n\n"},
   337  		{"\n\n\n"},
   338  		{"foo"},
   339  		{"foo\nbar"},
   340  		{"processor   : 0\nvendor_id   : GenuineIntel\n"},
   341  	}
   342  
   343  	dir, err := ioutil.TempDir(testDir, "")
   344  	if err != nil {
   345  		t.Fatal(err)
   346  	}
   347  	defer os.RemoveAll(dir)
   348  
   349  	file := filepath.Join(dir, "foo")
   350  
   351  	// file doesn't exist
   352  	_, err = GetFileContents(file)
   353  	assert.Error(t, err)
   354  
   355  	for _, d := range data {
   356  		// create the file
   357  		err = ioutil.WriteFile(file, []byte(d.contents), testFileMode)
   358  		if err != nil {
   359  			t.Fatal(err)
   360  		}
   361  		defer os.Remove(file)
   362  
   363  		contents, err := GetFileContents(file)
   364  		assert.NoError(t, err)
   365  		assert.Equal(t, contents, d.contents)
   366  	}
   367  }