Files
kata-containers/virtcontainers/qemu_test.go
Samuel Ortiz 24eff72d82 virtcontainers: Initial import
This is a virtcontainers 1.0.8 import into Kata Containers runtime.

virtcontainers is a Go library designed to manage hardware virtualized
pods and containers. It is the core Clear Containers framework and will
become the core Kata Containers framework, as discussed at
https://github.com/kata-containers/runtime/issues/33

Some more more pointers:

virtcontainers README, including some design and architecure notes:
https://github.com/containers/virtcontainers/blob/master/README.md

virtcontainers 1.0 API:
https://github.com/containers/virtcontainers/blob/master/documentation/api/1.0/api.md

Fixes #40

Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
2018-03-13 00:49:46 +01:00

329 lines
7.0 KiB
Go

//
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package virtcontainers
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"
govmmQemu "github.com/intel/govmm/qemu"
"github.com/stretchr/testify/assert"
)
func newQemuConfig() HypervisorConfig {
return HypervisorConfig{
KernelPath: testQemuKernelPath,
ImagePath: testQemuImagePath,
HypervisorPath: testQemuPath,
DefaultVCPUs: defaultVCPUs,
DefaultMemSz: defaultMemSzMiB,
DefaultBridges: defaultBridges,
BlockDeviceDriver: defaultBlockDriver,
DefaultMaxVCPUs: defaultMaxQemuVCPUs,
}
}
func testQemuKernelParameters(t *testing.T, kernelParams []Param, expected string, debug bool) {
qemuConfig := newQemuConfig()
qemuConfig.KernelParams = kernelParams
if debug == true {
qemuConfig.Debug = true
}
q := &qemu{
config: qemuConfig,
arch: &qemuArchBase{},
}
params := q.kernelParameters()
if params != expected {
t.Fatalf("Got: %v, Expecting: %v", params, expected)
}
}
func TestQemuKernelParameters(t *testing.T) {
expectedOut := "panic=1 initcall_debug foo=foo bar=bar"
params := []Param{
{
Key: "foo",
Value: "foo",
},
{
Key: "bar",
Value: "bar",
},
}
testQemuKernelParameters(t, params, expectedOut, true)
testQemuKernelParameters(t, params, expectedOut, false)
}
func TestQemuInit(t *testing.T) {
qemuConfig := newQemuConfig()
q := &qemu{}
pod := &Pod{
id: "testPod",
storage: &filesystem{},
config: &PodConfig{
HypervisorConfig: qemuConfig,
},
}
// Create parent dir path for hypervisor.json
parentDir := filepath.Join(runStoragePath, pod.id)
if err := os.MkdirAll(parentDir, dirMode); err != nil {
t.Fatalf("Could not create parent directory %s: %v", parentDir, err)
}
if err := q.init(pod); err != nil {
t.Fatal(err)
}
if err := os.RemoveAll(parentDir); err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(qemuConfig, q.config) == false {
t.Fatalf("Got %v\nExpecting %v", q.config, qemuConfig)
}
}
func TestQemuInitMissingParentDirFail(t *testing.T) {
qemuConfig := newQemuConfig()
q := &qemu{}
pod := &Pod{
id: "testPod",
storage: &filesystem{},
config: &PodConfig{
HypervisorConfig: qemuConfig,
},
}
// Ensure parent dir path for hypervisor.json does not exist.
parentDir := filepath.Join(runStoragePath, pod.id)
if err := os.RemoveAll(parentDir); err != nil {
t.Fatal(err)
}
if err := q.init(pod); err == nil {
t.Fatal("Qemu init() expected to fail because of missing parent directory for storage")
}
}
func TestQemuCPUTopology(t *testing.T) {
vcpus := 1
q := &qemu{
arch: &qemuArchBase{},
config: HypervisorConfig{
DefaultVCPUs: uint32(vcpus),
},
}
expectedOut := govmmQemu.SMP{
CPUs: uint32(vcpus),
Sockets: uint32(vcpus),
Cores: defaultCores,
Threads: defaultThreads,
MaxCPUs: defaultMaxQemuVCPUs,
}
smp := q.cpuTopology()
if reflect.DeepEqual(smp, expectedOut) == false {
t.Fatalf("Got %v\nExpecting %v", smp, expectedOut)
}
}
func TestQemuMemoryTopology(t *testing.T) {
mem := 1000
q := &qemu{
arch: &qemuArchBase{},
}
hostMemKb, err := getHostMemorySizeKb(procMemInfo)
if err != nil {
t.Fatal(err)
}
memMax := fmt.Sprintf("%dM", int(float64(hostMemKb)/1024))
expectedOut := govmmQemu.Memory{
Size: fmt.Sprintf("%dM", mem),
Slots: defaultMemSlots,
MaxMem: memMax,
}
vmConfig := Resources{
Memory: uint(mem),
}
podConfig := PodConfig{
VMConfig: vmConfig,
}
memory, err := q.memoryTopology(podConfig)
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(memory, expectedOut) == false {
t.Fatalf("Got %v\nExpecting %v", memory, expectedOut)
}
}
func testQemuAddDevice(t *testing.T, devInfo interface{}, devType deviceType, expected []govmmQemu.Device) {
q := &qemu{
arch: &qemuArchBase{},
}
err := q.addDevice(devInfo, devType)
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(q.qemuConfig.Devices, expected) == false {
t.Fatalf("Got %v\nExpecting %v", q.qemuConfig.Devices, expected)
}
}
func TestQemuAddDeviceFsDev(t *testing.T) {
mountTag := "testMountTag"
hostPath := "testHostPath"
expectedOut := []govmmQemu.Device{
govmmQemu.FSDevice{
Driver: govmmQemu.Virtio9P,
FSDriver: govmmQemu.Local,
ID: fmt.Sprintf("extra-9p-%s", mountTag),
Path: hostPath,
MountTag: mountTag,
SecurityModel: govmmQemu.None,
},
}
volume := Volume{
MountTag: mountTag,
HostPath: hostPath,
}
testQemuAddDevice(t, volume, fsDev, expectedOut)
}
func TestQemuAddDeviceSerialPortDev(t *testing.T) {
deviceID := "channelTest"
id := "charchTest"
hostPath := "/tmp/hyper_test.sock"
name := "sh.hyper.channel.test"
expectedOut := []govmmQemu.Device{
govmmQemu.CharDevice{
Driver: govmmQemu.VirtioSerialPort,
Backend: govmmQemu.Socket,
DeviceID: deviceID,
ID: id,
Path: hostPath,
Name: name,
},
}
socket := Socket{
DeviceID: deviceID,
ID: id,
HostPath: hostPath,
Name: name,
}
testQemuAddDevice(t, socket, serialPortDev, expectedOut)
}
func TestQemuGetPodConsole(t *testing.T) {
q := &qemu{}
podID := "testPodID"
expected := filepath.Join(runStoragePath, podID, defaultConsole)
if result := q.getPodConsole(podID); result != expected {
t.Fatalf("Got %s\nExpecting %s", result, expected)
}
}
func TestQemuCapabilities(t *testing.T) {
q := &qemu{
arch: &qemuArchBase{},
}
caps := q.capabilities()
if !caps.isBlockDeviceHotplugSupported() {
t.Fatal("Block device hotplug should be supported")
}
}
func TestQemuQemuPath(t *testing.T) {
assert := assert.New(t)
f, err := ioutil.TempFile("", "qemu")
assert.NoError(err)
defer func() { _ = f.Close() }()
defer func() { _ = os.Remove(f.Name()) }()
expectedPath := f.Name()
qemuConfig := newQemuConfig()
qemuConfig.HypervisorPath = expectedPath
qkvm := &qemuArchBase{
machineType: "pc",
qemuPaths: map[string]string{
"pc": expectedPath,
},
}
q := &qemu{
config: qemuConfig,
arch: qkvm,
}
// get config hypervisor path
path, err := q.qemuPath()
assert.NoError(err)
assert.Equal(path, expectedPath)
// config hypervisor path does not exist
q.config.HypervisorPath = "/abc/rgb/123"
path, err = q.qemuPath()
assert.Error(err)
assert.Equal(path, "")
// get arch hypervisor path
q.config.HypervisorPath = ""
path, err = q.qemuPath()
assert.NoError(err)
assert.Equal(path, expectedPath)
// bad machine type, arch should fail
qkvm.machineType = "rgb"
q.arch = qkvm
path, err = q.qemuPath()
assert.Error(err)
assert.Equal(path, "")
}