|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | package qemu | 
|  |  | 
|  | import ( | 
|  | "errors" | 
|  | "testing" | 
|  |  | 
|  | "github.com/google/go-cmp/cmp" | 
|  | ) | 
|  |  | 
|  | type expected struct { | 
|  | cmd []string | 
|  | err error | 
|  | } | 
|  |  | 
|  | func check(t *testing.T, e expected, cmd []string, err error) { | 
|  | t.Helper() | 
|  | if diff := cmp.Diff(e.err, err, cmp.Comparer(func(x, y error) bool { | 
|  | return x == nil && y == nil || x != nil && y != nil && x.Error() == y.Error() | 
|  | })); diff != "" { | 
|  | t.Errorf("-want, +got: %s", diff) | 
|  | } | 
|  | if diff := cmp.Diff(e.cmd, cmd); diff != "" { | 
|  | t.Errorf("-want, +got: %s", diff) | 
|  | } | 
|  | } | 
|  |  | 
|  | func TestQEMUCommandBuilder(t *testing.T) { | 
|  | // Invalid Target | 
|  | b := &QEMUCommandBuilder{} | 
|  | b.SetTarget(Target("badtarget"), false) | 
|  | cmd, err := b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{}, | 
|  | err: errors.New("invalid target: \"badtarget\""), | 
|  | }, cmd, err) | 
|  |  | 
|  | // No binary set. | 
|  | b = &QEMUCommandBuilder{} | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{}, | 
|  | err: errors.New("QEMU binary path must be set."), | 
|  | }, cmd, err) | 
|  |  | 
|  | // No kernel set. | 
|  | b = &QEMUCommandBuilder{} | 
|  | b.SetBinary("./bin/qemu") | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{}, | 
|  | err: errors.New("QEMU kernel path must be set."), | 
|  | }, cmd, err) | 
|  |  | 
|  | b.SetKernel("./data/qemu-kernel") | 
|  |  | 
|  | // No initrd set. | 
|  | b = &QEMUCommandBuilder{} | 
|  | b.SetBinary("./bin/qemu") | 
|  | b.SetKernel("./data/qemu-kernel") | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{}, | 
|  | err: errors.New("QEMU initrd path must be set."), | 
|  | }, cmd, err) | 
|  |  | 
|  | // Invalid HCI | 
|  | b = &QEMUCommandBuilder{} | 
|  | b.SetBinary("./bin/qemu") | 
|  | b.SetKernel("./data/qemu-kernel") | 
|  | b.SetInitrd("./data/zircon-a") | 
|  | b.AddHCI("invalid") | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{}, | 
|  | err: errors.New("unimplemented host controller interface: \"invalid\""), | 
|  | }, cmd, err) | 
|  |  | 
|  | b = &QEMUCommandBuilder{} | 
|  | b.SetBinary("./bin/qemu") | 
|  | b.SetKernel("./data/qemu-kernel") | 
|  | b.SetInitrd("./data/zircon-a") | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-net", "none"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.SetTarget(TargetEnum.AArch64, true) | 
|  | b.SetMemory(4096) | 
|  | b.SetCPUCount(4) | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-net", "none"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddVirtioBlkPciDrive( | 
|  | Drive{ | 
|  | ID:   "otherdisk", | 
|  | File: "./data/otherdisk", | 
|  | Addr: "04.2", | 
|  | }, | 
|  | ) | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-net", "none"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddKernelArg("kernel.serial=legacy") | 
|  | b.AddKernelArg("infra.foo=bar") | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-net", "none", | 
|  | "-append", "kernel.serial=legacy infra.foo=bar"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddSerial( | 
|  | Chardev{ | 
|  | ID:      "char0", | 
|  | Logfile: "logfile.txt", | 
|  | Signal:  false, | 
|  | }, | 
|  | ) | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-chardev", "stdio,id=char0,logfile=logfile.txt,signal=off", | 
|  | "-serial", "chardev:char0", | 
|  | "-net", "none", | 
|  | "-append", "kernel.serial=legacy infra.foo=bar"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddNetwork( | 
|  | Netdev{ | 
|  | ID:   "net0", | 
|  | User: &NetdevUser{}, | 
|  | Device: Device{ | 
|  | Model:   DeviceModelVirtioNetPCI, | 
|  | options: []string{"mac=52:54:00:63:5e:7a"}, | 
|  | }, | 
|  | }, | 
|  | ) | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-chardev", "stdio,id=char0,logfile=logfile.txt,signal=off", | 
|  | "-serial", "chardev:char0", | 
|  | "-netdev", "user,id=net0", | 
|  | "-device", "virtio-net-pci,mac=52:54:00:63:5e:7a,netdev=net0", | 
|  | "-append", "kernel.serial=legacy infra.foo=bar"}, | 
|  | err: nil, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddUSBDrive(Drive{ | 
|  | ID:   "usb", | 
|  | File: "/usbdrive", | 
|  | Addr: "2.0", | 
|  | }) | 
|  |  | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-chardev", "stdio,id=char0,logfile=logfile.txt,signal=off", | 
|  | "-serial", "chardev:char0", | 
|  | "-netdev", "user,id=net0", | 
|  | "-device", "virtio-net-pci,mac=52:54:00:63:5e:7a,netdev=net0", | 
|  | "-drive", "if=none,id=usb,file=/usbdrive,format=raw", | 
|  | "-device", "usb-storage,drive=usb", | 
|  | "-append", "kernel.serial=legacy infra.foo=bar"}, | 
|  | }, cmd, err) | 
|  |  | 
|  | b.AddHCI(XHCI) | 
|  | cmd, err = b.Build() | 
|  | check(t, expected{ | 
|  | cmd: []string{ | 
|  | "./bin/qemu", | 
|  | "-kernel", "./data/qemu-kernel", | 
|  | "-initrd", "./data/zircon-a", | 
|  | "-machine", "virt-2.12,gic-version=host", | 
|  | "-cpu", "host", | 
|  | "-enable-kvm", | 
|  | "-m", "4096", | 
|  | "-smp", "4", | 
|  | "-object", "iothread,id=iothread-otherdisk", | 
|  | "-drive", "id=otherdisk,file=./data/otherdisk,format=raw,if=none,cache=unsafe,aio=threads", | 
|  | "-device", "virtio-blk-pci,drive=otherdisk,iothread=iothread-otherdisk,addr=04.2", | 
|  | "-chardev", "stdio,id=char0,logfile=logfile.txt,signal=off", | 
|  | "-serial", "chardev:char0", | 
|  | "-netdev", "user,id=net0", | 
|  | "-device", "virtio-net-pci,mac=52:54:00:63:5e:7a,netdev=net0", | 
|  | "-drive", "if=none,id=usb,file=/usbdrive,format=raw", | 
|  | "-device", "usb-storage,drive=usb", | 
|  | "-device", "qemu-xhci,id=xhci", | 
|  | "-append", "kernel.serial=legacy infra.foo=bar"}, | 
|  | }, cmd, err) | 
|  | } |