/*
* This file is part of the libvirt-go project
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* Copyright (c) 2013 Alex Zorin
* Copyright (C) 2016 Red Hat, Inc.
*
*/
package libvirt
import (
"strings"
"testing"
"time"
)
func buildTestDomain() (*Domain, *Connect) {
conn := buildTestConnection()
dom, err := conn.DomainDefineXML(`
` + time.Now().String() + `
8192
hvm
`)
if err != nil {
panic(err)
}
return dom, conn
}
func buildSMPTestDomain() (*Domain, *Connect) {
conn := buildTestConnection()
dom, err := conn.DomainDefineXML(`
` + time.Now().String() + `
8192
8
hvm
`)
if err != nil {
panic(err)
}
return dom, conn
}
func buildTransientTestDomain() (*Domain, *Connect) {
conn := buildTestConnection()
dom, err := conn.DomainCreateXML(`
`+time.Now().String()+`
8192
hvm
`, DOMAIN_NONE)
if err != nil {
panic(err)
}
return dom, conn
}
func TestUndefineDomain(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
name, err := dom.GetName()
if err != nil {
t.Error(err)
return
}
if err := dom.Undefine(); err != nil {
t.Error(err)
return
}
if _, err := conn.LookupDomainByName(name); err == nil {
t.Fatal("Shouldn't have been able to find domain")
return
}
}
func TestGetDomainName(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Undefine()
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if _, err := dom.GetName(); err != nil {
t.Error(err)
return
}
}
func TestGetDomainState(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
state, reason, err := dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_SHUTOFF {
t.Error("Domain state in test transport should be shutoff")
return
}
if DomainShutoffReason(reason) != DOMAIN_SHUTOFF_UNKNOWN {
t.Error("Domain reason in test transport should be unknown")
return
}
}
func TestGetDomainID(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error("Failed to create domain")
}
if id, err := dom.GetID(); id == ^uint(0) || err != nil {
dom.Destroy()
t.Error("Couldn't get domain ID")
return
}
dom.Destroy()
}
func TestGetDomainUUID(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
_, err := dom.GetUUID()
// how to test uuid validity?
if err != nil {
t.Error(err)
return
}
}
func TestGetDomainUUIDString(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
_, err := dom.GetUUIDString()
if err != nil {
t.Error(err)
return
}
}
func TestGetDomainInfo(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
_, err := dom.GetInfo()
if err != nil {
t.Error(err)
return
}
}
func TestGetDomainXMLDesc(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
_, err := dom.GetXMLDesc(0)
if err != nil {
t.Error(err)
return
}
}
func TestCreateDomainSnapshotXML(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
ss, err := dom.CreateSnapshotXML(`
Test snapshot that will fail because its unsupported
`, 0)
if err != nil {
t.Error(err)
return
}
defer ss.Free()
}
func TestSaveDomain(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
// get the name so we can get a handle on it later
domName, err := dom.GetName()
if err != nil {
t.Error(err)
return
}
const tmpFile = "/tmp/libvirt-go-test.tmp"
if err := dom.Save(tmpFile); err != nil {
t.Error(err)
return
}
if err := conn.DomainRestore(tmpFile); err != nil {
t.Error(err)
return
}
if dom2, err := conn.LookupDomainByName(domName); err != nil {
t.Error(err)
return
} else {
dom2.Free()
}
}
func TestSaveDomainFlags(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
const srcFile = "/tmp/libvirt-go-test.tmp"
if err := dom.SaveFlags(srcFile, "", 0); err == nil {
t.Fatal("expected xml modification unsupported")
return
}
}
func TestCreateDestroyDomain(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
state, reason, err := dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_RUNNING {
t.Fatal("Domain should be running")
return
}
if DomainRunningReason(reason) != DOMAIN_RUNNING_BOOTED {
t.Fatal("Domain reason should be booted")
return
}
if err = dom.Destroy(); err != nil {
t.Error(err)
return
}
state, reason, err = dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_SHUTOFF {
t.Fatal("Domain should be destroyed")
return
}
if DomainShutoffReason(reason) != DOMAIN_SHUTOFF_DESTROYED {
t.Fatal("Domain reason should be destroyed")
return
}
}
func TestShutdownDomain(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.Shutdown(); err != nil {
t.Error(err)
return
}
state, reason, err := dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_SHUTOFF {
t.Error("Domain state in test transport should be shutoff")
return
}
if DomainShutoffReason(reason) != DOMAIN_SHUTOFF_SHUTDOWN {
t.Error("Domain reason in test transport should be shutdown")
return
}
}
func TestShutdownReboot(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.Reboot(0); err != nil {
t.Error(err)
return
}
}
func TestDomainAutostart(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
as, err := dom.GetAutostart()
if err != nil {
t.Error(err)
return
}
if as {
t.Fatal("autostart should be false")
return
}
if err := dom.SetAutostart(true); err != nil {
t.Error(err)
return
}
as, err = dom.GetAutostart()
if err != nil {
t.Error(err)
return
}
if !as {
t.Fatal("autostart should be true")
return
}
}
func TestDomainIsActive(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Log(err)
return
}
active, err := dom.IsActive()
if err != nil {
t.Error(err)
return
}
if !active {
t.Fatal("Domain should be active")
return
}
if err := dom.Destroy(); err != nil {
t.Error(err)
return
}
active, err = dom.IsActive()
if err != nil {
t.Error(err)
return
}
if active {
t.Fatal("Domain should be inactive")
return
}
}
func TestDomainIsPersistent(t *testing.T) {
dom, conn := buildTransientTestDomain()
dom2, conn2 := buildTestDomain()
defer func() {
dom.Free()
dom2.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
if res, _ := conn2.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
persistent, err := dom.IsPersistent()
if err != nil {
t.Error(err)
return
}
if persistent {
t.Fatal("Domain shouldn't be persistent")
return
}
persistent, err = dom2.IsPersistent()
if err != nil {
t.Error(err)
return
}
if !persistent {
t.Fatal("Domain should be persistent")
return
}
}
func TestDomainSetMaxMemory(t *testing.T) {
const mem = 8192 * 100
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.SetMaxMemory(mem); err != nil {
t.Error(err)
return
}
}
func TestDomainSetMemory(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.SetMemory(1024); err != nil {
t.Error(err)
return
}
}
func TestDomainSetVcpus(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.SetVcpus(1); err != nil {
t.Error(err)
return
}
if err := dom.SetVcpusFlags(1, DOMAIN_VCPU_LIVE); err != nil {
t.Error(err)
return
}
}
func TestDomainFree(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Free(); err != nil {
t.Error(err)
return
}
}
func TestDomainSuspend(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
defer dom.Destroy()
if err := dom.Suspend(); err != nil {
t.Error(err)
return
}
defer dom.Resume()
}
func TesDomainShutdownFlags(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.ShutdownFlags(DOMAIN_SHUTDOWN_SIGNAL); err != nil {
t.Error(err)
return
}
state, reason, err := dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_SHUTOFF {
t.Error("Domain state in test transport should be shutoff")
return
}
if DomainShutoffReason(reason) != DOMAIN_SHUTOFF_SHUTDOWN {
t.Error("Domain reason in test transport should be shutdown")
return
}
}
func TesDomainDestoryFlags(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
if err := dom.DestroyFlags(DOMAIN_DESTROY_GRACEFUL); err != nil {
t.Error(err)
return
}
state, reason, err := dom.GetState()
if err != nil {
t.Error(err)
return
}
if state != DOMAIN_SHUTOFF {
t.Error("Domain state in test transport should be shutoff")
return
}
if DomainShutoffReason(reason) != DOMAIN_SHUTOFF_SHUTDOWN {
t.Error("Domain reason in test transport should be shutdown")
return
}
}
func TestDomainScreenshot(t *testing.T) {
if VERSION_NUMBER == 2005000 {
/* 2.5.0 broke screenshot for test:///default driver */
return
}
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
stream, err := conn.NewStream(0)
if err != nil {
t.Fatalf("failed to create new stream: %s", err)
}
defer stream.Free()
mime, err := dom.Screenshot(stream, 0, 0)
if err != nil {
t.Fatalf("failed to take screenshot: %s", err)
}
if strings.Index(mime, "image/") != 0 {
t.Fatalf("Wanted image/*, got %s", mime)
}
}
func TestDomainGetVcpus(t *testing.T) {
dom, conn := buildSMPTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
defer dom.Destroy()
stats, err := dom.GetVcpus()
if err != nil {
t.Fatal(err)
}
if len(stats) != 8 {
t.Fatal("should have 1 cpu")
}
if stats[0].State != 1 {
t.Fatal("state should be 1")
}
}
func TestDomainGetVcpusFlags(t *testing.T) {
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
defer dom.Destroy()
num, err := dom.GetVcpusFlags(0)
if err != nil {
t.Fatal(err)
}
if num != 1 {
t.Fatal("should have 1 cpu", num)
}
}
func TestDomainPinVcpu(t *testing.T) {
dom, conn := buildSMPTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
defer dom.Destroy()
err := dom.PinVcpu(2, []bool{false, true, false, false,
true, false, false, false})
if err != nil {
t.Fatal(err)
}
}
type CPUStringData struct {
cpustr string
cpumap []bool
err bool
}
func TestParserCPUString(t *testing.T) {
testDataList := []CPUStringData{
CPUStringData{
"0-1,4,7-9,^8",
[]bool{
true, true, false, false,
true, false, false, true,
false, true,
},
false,
},
CPUStringData{
"0-0,1,^1",
[]bool{true, false},
false,
},
CPUStringData{
"0-3,,",
[]bool{},
true,
},
CPUStringData{
"0-3,,",
[]bool{},
true,
},
CPUStringData{
"3-0",
[]bool{},
true,
},
CPUStringData{
"!0-3",
[]bool{},
true,
},
}
for _, testData := range testDataList {
actual, err := parseCPUString(testData.cpustr)
if testData.err {
if err == nil {
t.Errorf("Expected parse error from %s",
testData.cpustr)
return
}
} else {
if err != nil {
t.Errorf("Unexpected parse error from %s",
testData.cpustr)
return
}
}
if len(actual) != len(testData.cpumap) {
t.Errorf("Expected %s got %s",
actual, testData.cpumap)
return
}
for idx, val := range actual {
if val != testData.cpumap[idx] {
t.Errorf("Expected %s got %s",
actual, testData.cpumap)
return
}
}
}
}
func TestSetMetadata(t *testing.T) {
xmlns := "http://libvirt.org/xmlns/libvirt-go/test"
xmlprefix := "test"
meta := ""
dom, conn := buildTestDomain()
defer func() {
dom.Free()
if res, _ := conn.Close(); res != 0 {
t.Errorf("Close() == %d, expected 0", res)
}
}()
if err := dom.Create(); err != nil {
t.Error(err)
return
}
defer dom.Destroy()
data, err := dom.GetMetadata(DOMAIN_METADATA_ELEMENT, xmlns, DOMAIN_AFFECT_LIVE)
if err == nil {
t.Errorf("Expected an error for missing metadata")
return
}
err = dom.SetMetadata(DOMAIN_METADATA_ELEMENT, meta, xmlprefix, xmlns, DOMAIN_AFFECT_LIVE)
if err != nil {
t.Error(err)
return
}
data, err = dom.GetMetadata(DOMAIN_METADATA_ELEMENT, xmlns, DOMAIN_AFFECT_LIVE)
if err != nil {
t.Errorf("Unexpected an error for metadata")
return
}
if data != meta {
t.Errorf("Metadata %s doesn't match %s", data, meta)
return
}
err = dom.SetMetadata(DOMAIN_METADATA_ELEMENT, "", "", xmlns, DOMAIN_AFFECT_LIVE)
if err != nil {
t.Error(err)
return
}
data, err = dom.GetMetadata(DOMAIN_METADATA_ELEMENT, xmlns, DOMAIN_AFFECT_LIVE)
if err == nil {
t.Errorf("Expected an error for deleted metadata")
return
}
}