diff --git a/virtcontainers/acrn_arch_base_test.go b/virtcontainers/acrn_arch_base_test.go new file mode 100644 index 0000000000..1ba57ac637 --- /dev/null +++ b/virtcontainers/acrn_arch_base_test.go @@ -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) +} diff --git a/virtcontainers/acrn_test.go b/virtcontainers/acrn_test.go new file mode 100644 index 0000000000..c57f682409 --- /dev/null +++ b/virtcontainers/acrn_test.go @@ -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) + } +} diff --git a/virtcontainers/virtcontainers_test.go b/virtcontainers/virtcontainers_test.go index 424a83ed6d..21c499d524 100644 --- a/virtcontainers/virtcontainers_test.go +++ b/virtcontainers/virtcontainers_test.go @@ -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")