virtcontainers: Add ACRN unit test cases

This patch adds unit test cases for acrn specific changes.

Fixes: #1778
Signed-off-by: Vijay Dhanraj <vijay.dhanraj@intel.com>
This commit is contained in:
Vijay Dhanraj 2019-06-27 10:41:45 -07:00
parent f246a799aa
commit 98a69736c5
3 changed files with 608 additions and 0 deletions

View File

@ -0,0 +1,299 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"fmt"
"io/ioutil"
"net"
"path/filepath"
"testing"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/store"
"github.com/kata-containers/runtime/virtcontainers/types"
"github.com/stretchr/testify/assert"
)
const (
acrnArchBaseAcrnPath = "/usr/bin/acrn"
acrnArchBaseAcrnCtlPath = "/usr/bin/acrnctl"
)
var acrnArchBaseKernelParamsNonDebug = []Param{
{"quiet", ""},
}
var acrnArchBaseKernelParamsDebug = []Param{
{"debug", ""},
}
var acrnArchBaseKernelParams = []Param{
{"root", "/dev/vda"},
}
func newAcrnArchBase() *acrnArchBase {
return &acrnArchBase{
path: acrnArchBaseAcrnPath,
ctlpath: acrnArchBaseAcrnCtlPath,
kernelParamsNonDebug: acrnArchBaseKernelParamsNonDebug,
kernelParamsDebug: acrnArchBaseKernelParamsDebug,
kernelParams: acrnArchBaseKernelParams,
}
}
func TestAcrnArchBaseAcrnPaths(t *testing.T) {
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
p, err := acrnArchBase.acrnPath()
assert.NoError(err)
assert.Equal(p, acrnArchBaseAcrnPath)
ctlp, err := acrnArchBase.acrnctlPath()
assert.NoError(err)
assert.Equal(ctlp, acrnArchBaseAcrnCtlPath)
}
func TestAcrnArchBaseKernelParameters(t *testing.T) {
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
// with debug params
expectedParams := acrnArchBaseKernelParams
debugParams := acrnArchBaseKernelParamsDebug
expectedParams = append(expectedParams, debugParams...)
p := acrnArchBase.kernelParameters(true)
assert.Equal(expectedParams, p)
// with non-debug params
expectedParams = acrnArchBaseKernelParams
nonDebugParams := acrnArchBaseKernelParamsNonDebug
expectedParams = append(expectedParams, nonDebugParams...)
p = acrnArchBase.kernelParameters(false)
assert.Equal(expectedParams, p)
}
func TestAcrnArchBaseCapabilities(t *testing.T) {
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
c := acrnArchBase.capabilities()
assert.True(c.IsBlockDeviceSupported())
assert.True(c.IsBlockDeviceHotplugSupported())
assert.False(c.IsFsSharingSupported())
}
func TestAcrnArchBaseMemoryTopology(t *testing.T) {
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
mem := uint64(8192)
expectedMemory := Memory{
Size: fmt.Sprintf("%dM", mem),
}
m := acrnArchBase.memoryTopology(mem)
assert.Equal(expectedMemory, m)
}
func TestAcrnArchBaseAppendConsoles(t *testing.T) {
var devices []Device
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
path := filepath.Join(store.SandboxRuntimeRootPath(sandboxID), consoleSocket)
expectedOut := []Device{
ConsoleDevice{
Name: "console0",
Backend: Socket,
PortType: ConsoleBE,
Path: path,
},
}
devices = acrnArchBase.appendConsole(devices, path)
assert.Equal(expectedOut, devices)
}
func TestAcrnArchBaseAppendImage(t *testing.T) {
var devices []Device
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
image, err := ioutil.TempFile("", "img")
assert.NoError(err)
err = image.Close()
assert.NoError(err)
devices, err = acrnArchBase.appendImage(devices, image.Name())
assert.NoError(err)
assert.Len(devices, 1)
expectedOut := []Device{
BlockDevice{
FilePath: image.Name(),
Index: 0,
},
}
assert.Equal(expectedOut, devices)
}
func TestAcrnArchBaseAppendBridges(t *testing.T) {
function := 0
emul := acrnHostBridge
config := ""
var devices []Device
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
devices = acrnArchBase.appendBridges(devices)
assert.Len(devices, 1)
expectedOut := []Device{
BridgeDevice{
Function: function,
Emul: emul,
Config: config,
},
}
assert.Equal(expectedOut, devices)
}
func TestAcrnArchBaseAppendLpcDevice(t *testing.T) {
function := 0
emul := acrnLPCDev
var devices []Device
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
devices = acrnArchBase.appendLPC(devices)
assert.Len(devices, 1)
expectedOut := []Device{
LPCDevice{
Function: function,
Emul: emul,
},
}
assert.Equal(expectedOut, devices)
}
func testAcrnArchBaseAppend(t *testing.T, structure interface{}, expected []Device) {
var devices []Device
var err error
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
switch s := structure.(type) {
case types.Socket:
devices = acrnArchBase.appendSocket(devices, s)
case config.BlockDrive:
devices = acrnArchBase.appendBlockDevice(devices, s)
}
assert.NoError(err)
assert.Equal(devices, expected)
}
func TestAcrnArchBaseAppendSocket(t *testing.T) {
name := "archserial.test"
hostPath := "/tmp/archserial.sock"
expectedOut := []Device{
ConsoleDevice{
Name: name,
Backend: Socket,
PortType: SerialBE,
Path: hostPath,
},
}
socket := types.Socket{
HostPath: hostPath,
Name: name,
}
testAcrnArchBaseAppend(t, socket, expectedOut)
}
func TestAcrnArchBaseAppendBlockDevice(t *testing.T) {
path := "/tmp/archtest.img"
index := 5
expectedOut := []Device{
BlockDevice{
FilePath: path,
Index: index,
},
}
drive := config.BlockDrive{
File: path,
Index: index,
}
testAcrnArchBaseAppend(t, drive, expectedOut)
}
func TestAcrnArchBaseAppendNetwork(t *testing.T) {
var devices []Device
assert := assert.New(t)
acrnArchBase := newAcrnArchBase()
macAddr := net.HardwareAddr{0x02, 0x00, 0xCA, 0xFE, 0x00, 0x04}
vethEp := &VethEndpoint{
NetPair: NetworkInterfacePair{
TapInterface: TapInterface{
ID: "uniqueTestID0",
Name: "br0_kata",
TAPIface: NetworkInterface{
Name: "tap0_kata",
},
},
VirtIface: NetworkInterface{
Name: "eth0",
HardAddr: macAddr.String(),
},
NetInterworkingModel: DefaultNetInterworkingModel,
},
EndpointType: VethEndpointType,
}
macvtapEp := &MacvtapEndpoint{
EndpointType: MacvtapEndpointType,
EndpointProperties: NetworkInfo{
Iface: NetlinkIface{
Type: "macvtap",
},
},
}
expectedOut := []Device{
NetDevice{
Type: TAP,
IFName: vethEp.NetPair.TAPIface.Name,
MACAddress: vethEp.NetPair.TAPIface.HardAddr,
},
NetDevice{
Type: MACVTAP,
IFName: macvtapEp.Name(),
MACAddress: macvtapEp.HardwareAddr(),
},
}
devices = acrnArchBase.appendNetwork(devices, vethEp)
devices = acrnArchBase.appendNetwork(devices, macvtapEp)
assert.Equal(expectedOut, devices)
}

285
virtcontainers/acrn_test.go Normal file
View File

@ -0,0 +1,285 @@
// Copyright (c) 2019 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package virtcontainers
import (
"context"
"fmt"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/store"
"github.com/kata-containers/runtime/virtcontainers/types"
"github.com/stretchr/testify/assert"
)
func newAcrnConfig() HypervisorConfig {
return HypervisorConfig{
KernelPath: testAcrnKernelPath,
ImagePath: testAcrnImagePath,
HypervisorPath: testAcrnPath,
HypervisorCtlPath: testAcrnCtlPath,
NumVCPUs: defaultVCPUs,
MemorySize: defaultMemSzMiB,
BlockDeviceDriver: config.VirtioBlock,
DefaultBridges: defaultBridges,
DefaultMaxVCPUs: MaxAcrnVCPUs(),
// Adding this here, as hypervisorconfig.valid()
// forcefully adds it even when 9pfs is not supported
Msize9p: defaultMsize9p,
}
}
func testAcrnKernelParameters(t *testing.T, kernelParams []Param, debug bool) {
acrnConfig := newAcrnConfig()
acrnConfig.KernelParams = kernelParams
if debug == true {
acrnConfig.Debug = true
}
a := &acrn{
config: acrnConfig,
arch: &acrnArchBase{},
}
expected := fmt.Sprintf("panic=1 maxcpus=%d foo=foo bar=bar", a.config.NumVCPUs)
params := a.kernelParameters()
if params != expected {
t.Fatalf("Got: %v, Expecting: %v", params, expected)
}
}
func TestAcrnKernelParameters(t *testing.T) {
params := []Param{
{
Key: "foo",
Value: "foo",
},
{
Key: "bar",
Value: "bar",
},
}
testAcrnKernelParameters(t, params, true)
testAcrnKernelParameters(t, params, false)
}
func TestAcrnCapabilities(t *testing.T) {
a := &acrn{
ctx: context.Background(),
arch: &acrnArchBase{},
}
caps := a.capabilities()
if !caps.IsBlockDeviceSupported() {
t.Fatal("Block device should be supported")
}
if !caps.IsBlockDeviceHotplugSupported() {
t.Fatal("Block device hotplug should be supported")
}
}
func testAcrnAddDevice(t *testing.T, devInfo interface{}, devType deviceType, expected []Device) {
a := &acrn{
ctx: context.Background(),
arch: &acrnArchBase{},
}
err := a.addDevice(devInfo, devType)
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(a.acrnConfig.Devices, expected) == false {
t.Fatalf("Got %v\nExpecting %v", a.acrnConfig.Devices, expected)
}
}
func TestAcrnAddDeviceSerialPortDev(t *testing.T) {
name := "serial.test"
hostPath := "/tmp/serial.sock"
expectedOut := []Device{
ConsoleDevice{
Name: name,
Backend: Socket,
PortType: SerialBE,
Path: hostPath,
},
}
socket := types.Socket{
HostPath: hostPath,
Name: name,
}
testAcrnAddDevice(t, socket, serialPortDev, expectedOut)
}
func TestAcrnAddDeviceBlockDev(t *testing.T) {
path := "/tmp/test.img"
index := 1
expectedOut := []Device{
BlockDevice{
FilePath: path,
Index: index,
},
}
drive := config.BlockDrive{
File: path,
Index: index,
}
testAcrnAddDevice(t, drive, blockDev, expectedOut)
}
func TestAcrnHotplugUnsupportedDeviceType(t *testing.T) {
assert := assert.New(t)
acrnConfig := newAcrnConfig()
a := &acrn{
ctx: context.Background(),
id: "acrnTest",
config: acrnConfig,
}
_, err := a.hotplugAddDevice(&memoryDevice{0, 128, uint64(0), false}, fsDev)
assert.Error(err)
}
func TestAcrnUpdateBlockDeviceInvalidPath(t *testing.T) {
assert := assert.New(t)
path := ""
index := 1
acrnConfig := newAcrnConfig()
a := &acrn{
ctx: context.Background(),
id: "acrnBlkTest",
config: acrnConfig,
}
drive := &config.BlockDrive{
File: path,
Index: index,
}
err := a.updateBlockDevice(drive)
assert.Error(err)
}
func TestAcrnUpdateBlockDeviceInvalidIdx(t *testing.T) {
assert := assert.New(t)
path := "/tmp/test.img"
index := AcrnBlkDevPoolSz + 1
acrnConfig := newAcrnConfig()
a := &acrn{
ctx: context.Background(),
id: "acrnBlkTest",
config: acrnConfig,
}
drive := &config.BlockDrive{
File: path,
Index: index,
}
err := a.updateBlockDevice(drive)
assert.Error(err)
}
func TestAcrnGetSandboxConsole(t *testing.T) {
a := &acrn{
ctx: context.Background(),
}
sandboxID := "testSandboxID"
expected := filepath.Join(store.RunVMStoragePath, sandboxID, consoleSocket)
result, err := a.getSandboxConsole(sandboxID)
if err != nil {
t.Fatal(err)
}
if result != expected {
t.Fatalf("Got %s\nExpecting %s", result, expected)
}
}
func TestAcrnCreateSandbox(t *testing.T) {
acrnConfig := newAcrnConfig()
a := &acrn{}
sandbox := &Sandbox{
ctx: context.Background(),
id: "testSandbox",
config: &SandboxConfig{
HypervisorConfig: acrnConfig,
},
}
vcStore, err := store.NewVCSandboxStore(sandbox.ctx, sandbox.id)
if err != nil {
t.Fatal(err)
}
sandbox.store = vcStore
if err = globalSandboxList.addSandbox(sandbox); err != nil {
t.Fatalf("Could not add sandbox to global list: %v", err)
}
defer globalSandboxList.removeSandbox(sandbox.id)
// Create the hypervisor fake binary
testAcrnPath := filepath.Join(testDir, testHypervisor)
_, err = os.Create(testAcrnPath)
if err != nil {
t.Fatalf("Could not create hypervisor file %s: %v", testAcrnPath, err)
}
if err := a.createSandbox(context.Background(), sandbox.id, &sandbox.config.HypervisorConfig, sandbox.store); err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(acrnConfig, a.config) == false {
t.Fatalf("Got %v\nExpecting %v", a.config, acrnConfig)
}
}
func TestAcrnMemoryTopology(t *testing.T) {
mem := uint32(1000)
a := &acrn{
arch: &acrnArchBase{},
config: HypervisorConfig{
MemorySize: mem,
},
}
expectedOut := Memory{
Size: fmt.Sprintf("%dM", mem),
}
memory, err := a.memoryTopology()
if err != nil {
t.Fatal(err)
}
if reflect.DeepEqual(memory, expectedOut) == false {
t.Fatalf("Got %v\nExpecting %v", memory, expectedOut)
}
}

View File

@ -25,6 +25,7 @@ const testKernel = "kernel"
const testInitrd = "initrd"
const testImage = "image"
const testHypervisor = "hypervisor"
const testHypervisorCtl = "hypervisorctl"
const testBundle = "bundle"
const testDisabledAsNonRoot = "Test disabled as requires root privileges"
@ -41,6 +42,10 @@ var testQemuKernelPath = ""
var testQemuInitrdPath = ""
var testQemuImagePath = ""
var testQemuPath = ""
var testAcrnKernelPath = ""
var testAcrnImagePath = ""
var testAcrnPath = ""
var testAcrnCtlPath = ""
var testHyperstartCtlSocket = ""
var testHyperstartTtySocket = ""
@ -67,6 +72,18 @@ func setup() {
}
}
func setupAcrn() {
os.Mkdir(filepath.Join(testDir, testBundle), store.DirMode)
for _, filename := range []string{testAcrnKernelPath, testAcrnImagePath, testAcrnPath, testAcrnCtlPath} {
_, err := os.Create(filename)
if err != nil {
fmt.Printf("Could not recreate %s:%v", filename, err)
os.Exit(1)
}
}
}
// TestMain is the common main function used by ALL the test functions
// for this package.
func TestMain(m *testing.M) {
@ -102,6 +119,13 @@ func TestMain(m *testing.M) {
setup()
testAcrnKernelPath = filepath.Join(testDir, testKernel)
testAcrnImagePath = filepath.Join(testDir, testImage)
testAcrnPath = filepath.Join(testDir, testHypervisor)
testAcrnCtlPath = filepath.Join(testDir, testHypervisorCtl)
setupAcrn()
// allow the tests to run without affecting the host system.
store.ConfigStoragePath = filepath.Join(testDir, store.StoragePathSuffix, "config")
store.RunStoragePath = filepath.Join(testDir, store.StoragePathSuffix, "run")