Files
kata-containers/pkg/katautils/utils_test.go
fupan f0cb0c7ef7 cli: refactor to align with katautils package
refactor the cli codes which can be shared with shimv2.

Signed-off-by: fupan <lifupan@gmail.com>
Signed-off-by: Eric Ernst <eric.ernst@intel.com>
2018-11-27 17:17:31 +08:00

383 lines
8.1 KiB
Go

// Copyright (c) 2018 Intel Corporation
// Copyright (c) 2018 HyperHQ Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package katautils
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
"syscall"
"testing"
"github.com/kata-containers/runtime/virtcontainers/pkg/oci"
"github.com/stretchr/testify/assert"
)
const (
testDirMode = os.FileMode(0750)
testFileMode = os.FileMode(0640)
testDisabledNeedRoot = "Test disabled as requires root user"
testDisabledNeedNonRoot = "Test disabled as requires non-root user"
// small docker image used to create root filesystems from
testDockerImage = "busybox"
testSandboxID = "99999999-9999-9999-99999999999999999"
testContainerID = "1"
testBundle = "bundle"
specConfig = "config.json"
)
var testDir = ""
func init() {
var err error
fmt.Printf("INFO: creating test directory\n")
testDir, err = ioutil.TempDir("", fmt.Sprintf("%s-", name))
if err != nil {
panic(fmt.Sprintf("ERROR: failed to create test directory: %v", err))
}
fmt.Printf("INFO: test directory is %v\n", testDir)
testBundleDir = filepath.Join(testDir, testBundle)
err = os.MkdirAll(testBundleDir, testDirMode)
if err != nil {
panic(fmt.Sprintf("ERROR: failed to create bundle directory %v: %v", testBundleDir, err))
}
fmt.Printf("INFO: creating OCI bundle in %v for tests to use\n", testBundleDir)
err = realMakeOCIBundle(testBundleDir)
if err != nil {
panic(fmt.Sprintf("ERROR: failed to create OCI bundle: %v", err))
}
}
// createOCIConfig creates an OCI configuration (spec) file in
// the bundle directory specified (which must exist).
func createOCIConfig(bundleDir string) error {
if bundleDir == "" {
return errors.New("BUG: Need bundle directory")
}
if !FileExists(bundleDir) {
return fmt.Errorf("BUG: Bundle directory %s does not exist", bundleDir)
}
var configCmd string
// Search for a suitable version of runc to use to generate
// the OCI config file.
for _, cmd := range []string{"docker-runc", "runc"} {
fullPath, err := exec.LookPath(cmd)
if err == nil {
configCmd = fullPath
break
}
}
if configCmd == "" {
return errors.New("Cannot find command to generate OCI config file")
}
_, err := RunCommand([]string{configCmd, "spec", "--bundle", bundleDir})
if err != nil {
return err
}
specFile := filepath.Join(bundleDir, specConfig)
if !FileExists(specFile) {
return fmt.Errorf("generated OCI config file does not exist: %v", specFile)
}
return nil
}
// realMakeOCIBundle will create an OCI bundle (including the "config.json"
// config file) in the directory specified (which must already exist).
//
// XXX: Note that tests should *NOT* call this function - they should
// XXX: instead call makeOCIBundle().
func realMakeOCIBundle(bundleDir string) error {
if bundleDir == "" {
return errors.New("BUG: Need bundle directory")
}
if !FileExists(bundleDir) {
return fmt.Errorf("BUG: Bundle directory %v does not exist", bundleDir)
}
err := createOCIConfig(bundleDir)
if err != nil {
return err
}
// Note the unusual parameter (a directory, not the config
// file to parse!)
spec, err := oci.ParseConfigJSON(bundleDir)
if err != nil {
return err
}
// Determine the rootfs directory name the OCI config refers to
ociRootPath := spec.Root.Path
rootfsDir := filepath.Join(bundleDir, ociRootPath)
if strings.HasPrefix(ociRootPath, "/") {
return fmt.Errorf("Cannot handle absolute rootfs as bundle must be unique to each test")
}
err = createRootfs(rootfsDir)
if err != nil {
return err
}
return nil
}
// createRootfs creates a minimal root filesystem below the specified
// directory.
func createRootfs(dir string) error {
err := os.MkdirAll(dir, testDirMode)
if err != nil {
return err
}
container, err := RunCommand([]string{"docker", "create", testDockerImage})
if err != nil {
return err
}
cmd1 := exec.Command("docker", "export", container)
cmd2 := exec.Command("tar", "-C", dir, "-xvf", "-")
cmd1Stdout, err := cmd1.StdoutPipe()
if err != nil {
return err
}
cmd2.Stdin = cmd1Stdout
err = cmd2.Start()
if err != nil {
return err
}
err = cmd1.Run()
if err != nil {
return err
}
err = cmd2.Wait()
if err != nil {
return err
}
// Clean up
_, err = RunCommand([]string{"docker", "rm", container})
if err != nil {
return err
}
return nil
}
func createFile(file, contents string) error {
return ioutil.WriteFile(file, []byte(contents), testFileMode)
}
func createEmptyFile(path string) (err error) {
return ioutil.WriteFile(path, []byte(""), testFileMode)
}
func TestUtilsResolvePathEmptyPath(t *testing.T) {
_, err := ResolvePath("")
assert.Error(t, err)
}
func TestUtilsResolvePathValidPath(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
target := path.Join(dir, "target")
linkDir := path.Join(dir, "a/b/c")
linkFile := path.Join(linkDir, "link")
err = createEmptyFile(target)
assert.NoError(t, err)
absolute, err := filepath.Abs(target)
assert.NoError(t, err)
resolvedTarget, err := filepath.EvalSymlinks(absolute)
assert.NoError(t, err)
err = os.MkdirAll(linkDir, testDirMode)
assert.NoError(t, err)
err = syscall.Symlink(target, linkFile)
assert.NoError(t, err)
resolvedLink, err := ResolvePath(linkFile)
assert.NoError(t, err)
assert.Equal(t, resolvedTarget, resolvedLink)
}
func TestUtilsResolvePathENOENT(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
target := path.Join(dir, "target")
linkDir := path.Join(dir, "a/b/c")
linkFile := path.Join(linkDir, "link")
err = createEmptyFile(target)
assert.NoError(t, err)
err = os.MkdirAll(linkDir, testDirMode)
assert.NoError(t, err)
err = syscall.Symlink(target, linkFile)
assert.NoError(t, err)
cwd, err := os.Getwd()
assert.NoError(t, err)
defer os.Chdir(cwd)
err = os.Chdir(dir)
assert.NoError(t, err)
err = os.RemoveAll(dir)
assert.NoError(t, err)
_, err = ResolvePath(filepath.Base(linkFile))
assert.Error(t, err)
}
func TestFileSize(t *testing.T) {
assert := assert.New(t)
dir, err := ioutil.TempDir(testDir, "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
file := filepath.Join(dir, "foo")
// ENOENT
_, err = fileSize(file)
assert.Error(err)
err = createEmptyFile(file)
assert.NoError(err)
// zero size
size, err := fileSize(file)
assert.NoError(err)
assert.Equal(size, int64(0))
msg := "hello"
msgLen := len(msg)
err = WriteFile(file, msg, testFileMode)
assert.NoError(err)
size, err = fileSize(file)
assert.NoError(err)
assert.Equal(size, int64(msgLen))
}
func TestWriteFileErrWriteFail(t *testing.T) {
assert := assert.New(t)
err := WriteFile("", "", 0000)
assert.Error(err)
}
func TestWriteFileErrNoPath(t *testing.T) {
assert := assert.New(t)
dir, err := ioutil.TempDir(testDir, "")
assert.NoError(err)
defer os.RemoveAll(dir)
// attempt to write a file over an existing directory
err = WriteFile(dir, "", 0000)
assert.Error(err)
}
func TestGetFileContents(t *testing.T) {
type testData struct {
contents string
}
data := []testData{
{""},
{" "},
{"\n"},
{"\n\n"},
{"\n\n\n"},
{"foo"},
{"foo\nbar"},
{"processor : 0\nvendor_id : GenuineIntel\n"},
}
dir, err := ioutil.TempDir(testDir, "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
file := filepath.Join(dir, "foo")
// file doesn't exist
_, err = GetFileContents(file)
assert.Error(t, err)
for _, d := range data {
// create the file
err = ioutil.WriteFile(file, []byte(d.contents), testFileMode)
if err != nil {
t.Fatal(err)
}
defer os.Remove(file)
contents, err := GetFileContents(file)
assert.NoError(t, err)
assert.Equal(t, contents, d.contents)
}
}
func TestIsEphemeralStorage(t *testing.T) {
sampleEphePath := "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/kubernetes.io~empty-dir/cache-volume"
isEphe := IsEphemeralStorage(sampleEphePath)
if !isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
sampleEphePath = "/var/lib/kubelet/pods/366c3a75-4869-11e8-b479-507b9ddd5ce4/volumes/cache-volume"
isEphe = IsEphemeralStorage(sampleEphePath)
if isEphe {
t.Fatalf("Unable to correctly determine volume type")
}
}