59d541f193
* Generate the remaining consts. There were a number of hand-written consts in go-libvirt, including flag values for various libvirt functions. Remove these and generate them instead, so that we now have a complete set, and the naming is consistent. I used c-for-go to do this generation, but turned off any cgo usage by the generated code - we don't want or need to introduce a dependency on cgo just to get constants from C headers. All code is still generated using 'go generate ./...', which now calls a wrapper script for added robustness. This change also returns to using Go types for flags for most libvirt functions, instead of plain integers.
306 lines
5.7 KiB
Go
306 lines
5.7 KiB
Go
// Copyright 2016 The go-libvirt Authors.
|
|
//
|
|
// 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.
|
|
|
|
// +build integration
|
|
|
|
package libvirt
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"net"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/digitalocean/go-libvirt/internal/constants"
|
|
)
|
|
|
|
const testAddr = "127.0.0.1:16509"
|
|
|
|
func TestConnectIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestDisconnectIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
if err := l.Disconnect(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCapabilities(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
resp, err := l.Capabilities()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// verify UUID exists within returned XML
|
|
var caps struct {
|
|
Host struct {
|
|
UUID string `xml:"uuid"`
|
|
} `xml:"host"`
|
|
}
|
|
|
|
if err := xml.Unmarshal(resp, &caps); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if caps.Host.UUID == "" {
|
|
t.Error("expected capabilities to contain a UUID")
|
|
}
|
|
}
|
|
|
|
func TestSecretsIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
secrets, err := l.Secrets()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
wantLen := 1
|
|
gotLen := len(secrets)
|
|
if gotLen != wantLen {
|
|
t.Fatalf("expected %d secrets, got %d", wantLen, gotLen)
|
|
}
|
|
|
|
s := secrets[0]
|
|
|
|
wantType := SecretUsageTypeVolume
|
|
if s.UsageType != int32(wantType) {
|
|
t.Errorf("expected usage type: %d, got %d", wantType, s.UsageType)
|
|
}
|
|
|
|
wantID := "/tmp"
|
|
if s.UsageID != wantID {
|
|
t.Errorf("expected usage id: %q, got %q", wantID, s.UsageID)
|
|
}
|
|
|
|
// 19fdc2f2-fa64-46f3-bacf-42a8aafca6dd
|
|
wantUUID := [constants.UUIDSize]byte{
|
|
0x19, 0xfd, 0xc2, 0xf2, 0xfa, 0x64, 0x46, 0xf3,
|
|
0xba, 0xcf, 0x42, 0xa8, 0xaa, 0xfc, 0xa6, 0xdd,
|
|
}
|
|
if s.UUID != wantUUID {
|
|
t.Errorf("expected UUID %q, got %q", wantUUID, s.UUID)
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
wantName := "test"
|
|
pool, err := l.StoragePool(wantName)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
gotName := pool.Name
|
|
if gotName != wantName {
|
|
t.Errorf("expected name %q, got %q", wantName, gotName)
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolInvalidIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := l.StoragePool("test-does-not-exist")
|
|
if err == nil {
|
|
t.Errorf("expected non-existent storage pool return error")
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolsIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pools, err := l.StoragePools(ConnectListStoragePoolsActive)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
wantLen := 1
|
|
gotLen := len(pools)
|
|
if gotLen != wantLen {
|
|
t.Fatalf("expected %d storage pool, got %d", wantLen, gotLen)
|
|
}
|
|
|
|
wantName := "test"
|
|
gotName := pools[0].Name
|
|
if gotName != wantName {
|
|
t.Errorf("expected name %q, got %q", wantName, gotName)
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolsAutostartIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pools, err := l.StoragePools(ConnectListStoragePoolsAutostart)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
wantLen := 0
|
|
gotLen := len(pools)
|
|
if gotLen != wantLen {
|
|
t.Errorf("expected %d storage pool, got %d", wantLen, gotLen)
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolRefreshIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pool, err := l.StoragePool("test")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = l.StoragePoolRefresh(pool, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestStoragePoolRefreshInvalidIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
defer l.Disconnect()
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
pool, err := l.StoragePool("test-does-not-exist")
|
|
if err == nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
err = l.StoragePoolRefresh(pool, 0)
|
|
if err == nil {
|
|
t.Error("expected non-existent storage pool to fail refresh")
|
|
}
|
|
}
|
|
|
|
func TestXMLIntegration(t *testing.T) {
|
|
l := New(testConn(t))
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
defer l.Disconnect()
|
|
|
|
var flags DomainXMLFlags
|
|
data, err := l.XML("test", flags)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
var v interface{}
|
|
if err := xml.Unmarshal(data, &v); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// verify we're able to concurrently communicate with libvirtd.
|
|
// see: https://github.com/digitalocean/go-libvirt/pull/52
|
|
func Test_concurrentWrite(t *testing.T) {
|
|
l := New(testConn(t))
|
|
|
|
if err := l.Connect(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
defer l.Disconnect()
|
|
|
|
count := 10
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(count)
|
|
|
|
start := make(chan struct{})
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
wg.Wait()
|
|
close(done)
|
|
}()
|
|
|
|
for i := 0; i < count; i++ {
|
|
go func() {
|
|
defer wg.Done()
|
|
<-start
|
|
|
|
_, err := l.Domains()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
close(start)
|
|
|
|
select {
|
|
case <-done:
|
|
case <-time.After(10 * time.Second):
|
|
t.Fatal("timed out waiting for execution to complete")
|
|
}
|
|
}
|
|
|
|
func testConn(t *testing.T) net.Conn {
|
|
conn, err := net.DialTimeout("tcp", testAddr, time.Second*2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
return conn
|
|
}
|