Files
kata-containers/virtcontainers/hook_test.go
Archana Shinde a301a9e641 hooks: Send the bundle path in the state that is sent with hooks
We currently just send the pid in the state. While OCI specifies
a few other fields as well, this commit just adds the bundle path
and the container id to the state. This should fix the errors seen
with hooks that rely on the bundle path.

Other fields like running "state" string have been left out. As this
would need sending the strings that OCI recognises. Hooks have been
implemented in virtcontainers and sending the state string would
require calling into OCI specific code in virtcontainers.

The bundle path again is OCI specific, but this can be accessed
using annotations. Hooks really need to be moved to the cli as they
are OCI specific. This however needs network hotplug to be implemented
first so that the hooks can be called from the cli after the
VM has been created.

Fixes #271

Signed-off-by: Archana Shinde <archana.m.shinde@intel.com>
2018-04-27 15:48:58 -07:00

270 lines
4.8 KiB
Go

// Copyright (c) 2017 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sync"
"testing"
vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations"
. "github.com/kata-containers/runtime/virtcontainers/pkg/mock"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
// Important to keep these values in sync with hook test binary
var testKeyHook = "test-key"
var testContainerIDHook = "test-container-id"
var testControllerIDHook = "test-controller-id"
var testProcessIDHook = 12345
var testBinHookPath = "/usr/bin/virtcontainers/bin/test/hook"
var testBundlePath = "/test/bundle"
func getMockHookBinPath() string {
if DefaultMockHookBinPath == "" {
return testBinHookPath
}
return DefaultMockHookBinPath
}
func TestBuildHookState(t *testing.T) {
t.Skip()
expected := specs.State{
Pid: testProcessIDHook,
}
s := &Sandbox{}
hookState := buildHookState(testProcessIDHook, s)
if reflect.DeepEqual(hookState, expected) == false {
t.Fatal()
}
s = createTestSandbox()
hookState = buildHookState(testProcessIDHook, s)
expected = specs.State{
Pid: testProcessIDHook,
Bundle: testBundlePath,
ID: testSandboxID,
}
if reflect.DeepEqual(hookState, expected) == false {
t.Fatal()
}
}
func createHook(timeout int) *Hook {
return &Hook{
Path: getMockHookBinPath(),
Args: []string{testKeyHook, testContainerIDHook, testControllerIDHook},
Env: os.Environ(),
Timeout: timeout,
}
}
func createWrongHook() *Hook {
return &Hook{
Path: getMockHookBinPath(),
Args: []string{"wrong-args"},
Env: os.Environ(),
}
}
func createTestSandbox() *Sandbox {
c := &SandboxConfig{
Annotations: map[string]string{
vcAnnotations.BundlePathKey: testBundlePath,
},
}
return &Sandbox{
annotationsLock: &sync.RWMutex{},
config: c,
id: testSandboxID,
}
}
func testRunHookFull(t *testing.T, timeout int, expectFail bool) {
hook := createHook(timeout)
s := createTestSandbox()
err := hook.runHook(s)
if expectFail {
if err == nil {
t.Fatal("unexpected success")
}
} else {
if err != nil {
t.Fatalf("unexpected failure: %v", err)
}
}
}
func testRunHook(t *testing.T, timeout int) {
testRunHookFull(t, timeout, false)
}
func TestRunHook(t *testing.T) {
cleanUp()
testRunHook(t, 0)
}
func TestRunHookTimeout(t *testing.T) {
testRunHook(t, 1)
}
func TestRunHookExitFailure(t *testing.T) {
hook := createWrongHook()
s := createTestSandbox()
err := hook.runHook(s)
if err == nil {
t.Fatal()
}
}
func TestRunHookTimeoutFailure(t *testing.T) {
hook := createHook(1)
hook.Args = append(hook.Args, "2")
s := createTestSandbox()
err := hook.runHook(s)
if err == nil {
t.Fatal()
}
}
func TestRunHookWaitFailure(t *testing.T) {
hook := createHook(60)
hook.Args = append(hook.Args, "1", "panic")
s := createTestSandbox()
err := hook.runHook(s)
if err == nil {
t.Fatal()
}
}
func testRunHookInvalidCommand(t *testing.T, timeout int) {
cleanUp()
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(dir)
cmd := filepath.Join(dir, "does-not-exist")
savedDefaultMockHookBinPath := DefaultMockHookBinPath
DefaultMockHookBinPath = cmd
defer func() {
DefaultMockHookBinPath = savedDefaultMockHookBinPath
}()
testRunHookFull(t, timeout, true)
}
func TestRunHookInvalidCommand(t *testing.T) {
testRunHookInvalidCommand(t, 0)
}
func TestRunHookTimeoutInvalidCommand(t *testing.T) {
testRunHookInvalidCommand(t, 1)
}
func testHooks(t *testing.T, hook *Hook) {
hooks := &Hooks{
PreStartHooks: []Hook{*hook},
PostStartHooks: []Hook{*hook},
PostStopHooks: []Hook{*hook},
}
s := createTestSandbox()
err := hooks.preStartHooks(s)
if err != nil {
t.Fatal(err)
}
err = hooks.postStartHooks(s)
if err != nil {
t.Fatal(err)
}
err = hooks.postStopHooks(s)
if err != nil {
t.Fatal(err)
}
}
func testFailingHooks(t *testing.T, hook *Hook) {
hooks := &Hooks{
PreStartHooks: []Hook{*hook},
PostStartHooks: []Hook{*hook},
PostStopHooks: []Hook{*hook},
}
s := createTestSandbox()
err := hooks.preStartHooks(s)
if err == nil {
t.Fatal(err)
}
err = hooks.postStartHooks(s)
if err != nil {
t.Fatal(err)
}
err = hooks.postStopHooks(s)
if err != nil {
t.Fatal(err)
}
}
func TestHooks(t *testing.T) {
testHooks(t, createHook(0))
}
func TestHooksTimeout(t *testing.T) {
testHooks(t, createHook(1))
}
func TestFailingHooks(t *testing.T) {
testFailingHooks(t, createWrongHook())
}
func TestEmptyHooks(t *testing.T) {
hooks := &Hooks{}
s := createTestSandbox()
err := hooks.preStartHooks(s)
if err != nil {
t.Fatal(err)
}
err = hooks.postStartHooks(s)
if err != nil {
t.Fatal(err)
}
err = hooks.postStopHooks(s)
if err != nil {
t.Fatal(err)
}
}