Skip to content

Commit

Permalink
Added unit tests
Browse files Browse the repository at this point in the history
Signed-off-by: Marc Sluiter <[email protected]>
  • Loading branch information
slintes committed Oct 21, 2019
1 parent 1244faa commit 984cae9
Show file tree
Hide file tree
Showing 19 changed files with 480 additions and 89 deletions.
1 change: 1 addition & 0 deletions pkg/virt-api/rest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ go_library(
importpath = "kubevirt.io/kubevirt/pkg/virt-api/rest",
visibility = ["//visibility:public"],
deps = [
"//pkg/controller:go_default_library",
"//pkg/rest:go_default_library",
"//staging/src/kubevirt.io/client-go/api/v1:go_default_library",
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
Expand Down
10 changes: 10 additions & 0 deletions pkg/virt-api/rest/subresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import (
"strings"
"sync"

"kubevirt.io/kubevirt/pkg/controller"

"github.com/emicklei/go-restful"
"k8s.io/apimachinery/pkg/api/errors"
k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Expand Down Expand Up @@ -604,6 +606,10 @@ func (app *SubresourceAPIApp) SuspendVMIRequestHandler(request *restful.Request,
if vmi == nil || vmi.IsFinal() || vmi.Status.Phase == v1.Unknown || vmi.Status.Phase == v1.VmPhaseUnset {
return fmt.Errorf("VM is not running")
}
condManager := controller.NewVirtualMachineInstanceConditionManager()
if condManager.HasCondition(vmi, v1.VirtualMachineInstancePaused) {
return fmt.Errorf("VM is already paused")
}
return nil
}

Expand All @@ -620,6 +626,10 @@ func (app *SubresourceAPIApp) ResumeVMIRequestHandler(request *restful.Request,
if vmi == nil || vmi.IsFinal() || vmi.Status.Phase == v1.Unknown || vmi.Status.Phase == v1.VmPhaseUnset {
return fmt.Errorf("VM is not running")
}
condManager := controller.NewVirtualMachineInstanceConditionManager()
if !condManager.HasCondition(vmi, v1.VirtualMachineInstancePaused) {
return fmt.Errorf("VM is not paused")
}
return nil
}
getURL := func(vmi *v1.VirtualMachineInstance, conn kubecli.VirtHandlerConn) (string, error) {
Expand Down
149 changes: 130 additions & 19 deletions pkg/virt-api/rest/subresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
package rest

import (
"crypto/tls"
"flag"
"fmt"
"net/http"
"net/http/httptest"
"sync"

"github.com/onsi/ginkgo/extensions/table"

Expand Down Expand Up @@ -60,6 +62,8 @@ var _ = Describe("VirtualMachineInstance Subresources", func() {
flag.Set("kubeconfig", "")
flag.Set("master", server.URL())
app.virtCli, _ = kubecli.GetKubevirtClientFromFlags(server.URL(), "")
app.credentialsLock = &sync.Mutex{}
app.handlerTLSConfiguration = &tls.Config{}

request = restful.NewRequest(&http.Request{})
response = restful.NewResponse(httptest.NewRecorder())
Expand All @@ -77,31 +81,35 @@ var _ = Describe("VirtualMachineInstance Subresources", func() {
)
})

expectHandlerPod := func() {
pod := &k8sv1.Pod{}
pod.Labels = map[string]string{}
pod.Labels[v1.AppLabel] = "virt-handler"
pod.ObjectMeta.Name = "madeup-name"

pod.Spec.NodeName = "mynode"
pod.Status.Phase = k8sv1.PodRunning
pod.Status.PodIP = "10.35.1.1"

podList := k8sv1.PodList{}
podList.Items = []k8sv1.Pod{}
podList.Items = append(podList.Items, *pod)

server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v1/namespaces/kubevirt/pods"),
ghttp.RespondWithJSONEncoded(http.StatusOK, podList),
),
)
}

Context("Subresource api", func() {
It("should find matching pod for running VirtualMachineInstance", func(done Done) {
vmi := v1.NewMinimalVMI("testvmi")
vmi.Status.Phase = v1.Running
vmi.ObjectMeta.SetUID(uuid.NewUUID())

pod := &k8sv1.Pod{}
pod.Labels = map[string]string{}
pod.Labels[v1.AppLabel] = "virt-handler"
pod.ObjectMeta.Name = "madeup-name"

pod.Spec.NodeName = "mynode"
pod.Status.Phase = k8sv1.PodRunning
pod.Status.PodIP = "10.35.1.1"

podList := k8sv1.PodList{}
podList.Items = []k8sv1.Pod{}
podList.Items = append(podList.Items, *pod)

server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v1/namespaces/kubevirt/pods"),
ghttp.RespondWithJSONEncoded(http.StatusOK, podList),
),
)
expectHandlerPod()

result, err := app.getVirtHandlerConnForVMI(vmi)

Expand Down Expand Up @@ -901,6 +909,109 @@ var _ = Describe("VirtualMachineInstance Subresources", func() {
})
})

expectVMI := func(running, paused bool) {
request.PathParameters()["name"] = "testvmi"
request.PathParameters()["namespace"] = "default"

phase := v1.Running
if !running {
phase = v1.Failed
}

vmi := v1.VirtualMachineInstance{
Status: v1.VirtualMachineInstanceStatus{
Phase: phase,
},
}

if paused {
vmi.Status.Conditions = []v1.VirtualMachineInstanceCondition{
{
Type: v1.VirtualMachineInstancePaused,
Status: k8sv1.ConditionTrue,
},
}
}

server.AppendHandlers(
ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/apis/kubevirt.io/v1alpha3/namespaces/default/virtualmachineinstances/testvmi"),
ghttp.RespondWithJSONEncoded(http.StatusOK, vmi),
),
)

expectHandlerPod()

}

Context("SuspendResume", func() {
It("Should suspend a running, not paused VMI", func() {

expectVMI(true, false)

app.SuspendVMIRequestHandler(request, response)

Expect(response.Error()).ToNot(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusOK))

})

It("Should fail suspending a not running VMI", func() {

expectVMI(false, false)

app.SuspendVMIRequestHandler(request, response)

Expect(response.Error()).To(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusBadRequest))

})

It("Should fail suspending a running but paused VMI", func() {

expectVMI(true, true)

app.SuspendVMIRequestHandler(request, response)

Expect(response.Error()).To(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusBadRequest))

})

It("Should fail resuming a running, not paused VMI", func() {

expectVMI(true, false)

app.ResumeVMIRequestHandler(request, response)

Expect(response.Error()).To(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusBadRequest))

})

It("Should fail resuming a not running VMI", func() {

expectVMI(false, false)

app.ResumeVMIRequestHandler(request, response)

Expect(response.Error()).To(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusBadRequest))

})

It("Should resume a running, paused VMI", func() {

expectVMI(true, true)

app.ResumeVMIRequestHandler(request, response)

Expect(response.Error()).ToNot(HaveOccurred())
Expect(response.StatusCode()).To(Equal(http.StatusOK))

})
})

AfterEach(func() {
server.Close()
backend.Close()
Expand Down
41 changes: 41 additions & 0 deletions pkg/virt-controller/watch/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -816,6 +816,47 @@ var _ = Describe("VirtualMachine", func() {
testutils.ExpectEvents(recorder, FailedDeleteVirtualMachineReason)
})

It("should add paused condition", func() {
vm, vmi := DefaultVirtualMachine(true)
addVirtualMachine(vm)

markAsReady(vmi)
vmi.Status.Conditions = append(vmi.Status.Conditions, virtv1.VirtualMachineInstanceCondition{
Type: virtv1.VirtualMachineInstancePaused,
Status: k8sv1.ConditionTrue,
})
vmiFeeder.Add(vmi)

vmInterface.EXPECT().Update(gomock.Any()).Do(func(obj interface{}) {
objVM := obj.(*v1.VirtualMachine)
Expect(objVM.Status.Conditions).To(HaveLen(1))
cond := objVM.Status.Conditions[0]
Expect(cond.Type).To(Equal(v1.VirtualMachinePaused))
Expect(cond.Status).To(Equal(k8sv1.ConditionTrue))
}).Return(vm, nil)

controller.Execute()
})

It("should remove paused condition", func() {
vm, vmi := DefaultVirtualMachine(true)
vm.Status.Conditions = append(vm.Status.Conditions, virtv1.VirtualMachineCondition{
Type: virtv1.VirtualMachinePaused,
Status: k8sv1.ConditionTrue,
})
addVirtualMachine(vm)

markAsReady(vmi)
vmiFeeder.Add(vmi)

vmInterface.EXPECT().Update(gomock.Any()).Do(func(obj interface{}) {
objVM := obj.(*v1.VirtualMachine)
Expect(objVM.Status.Conditions).To(HaveLen(0))
}).Return(vm, nil)

controller.Execute()
})

It("should back off if a sync error occurs", func() {
vm, vmi := DefaultVirtualMachine(false)

Expand Down
7 changes: 5 additions & 2 deletions pkg/virt-handler/rest/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ import (

"github.com/emicklei/go-restful"

cmdclient "kubevirt.io/kubevirt/pkg/virt-handler/cmd-client"

"k8s.io/client-go/tools/cache"

"kubevirt.io/client-go/log"
cmdclient "kubevirt.io/kubevirt/pkg/virt-handler/cmd-client"
)

type LifecycleHandler struct {
Expand Down Expand Up @@ -64,6 +63,8 @@ func (lh *LifecycleHandler) SuspendHandler(request *restful.Request, response *r
log.Log.Object(vmi).Reason(err).Error("Failed to suspend VMI")
response.WriteError(http.StatusInternalServerError, err)
}

response.WriteHeader(http.StatusAccepted)
}

func (lh *LifecycleHandler) ResumeHandler(request *restful.Request, response *restful.Response) {
Expand All @@ -88,4 +89,6 @@ func (lh *LifecycleHandler) ResumeHandler(request *restful.Request, response *re
log.Log.Object(vmi).Reason(err).Error("Failed to suspend VMI")
response.WriteError(http.StatusInternalServerError, err)
}

response.WriteHeader(http.StatusAccepted)
}
55 changes: 55 additions & 0 deletions pkg/virt-handler/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,61 @@ var _ = Describe("VirtualMachineInstance", func() {
controller.Execute()
})

It("should add and remove paused condition", func() {
vmi := v1.NewMinimalVMI("testvmi")
vmi.UID = testUUID
vmi.ObjectMeta.ResourceVersion = "1"
vmi.Status.Phase = v1.Running

mockWatchdog.CreateFile(vmi)

domain := api.NewMinimalDomainWithUUID("testvmi", testUUID)

By("suspending domain")
domain.Status.Status = api.Paused
domain.Status.Reason = api.ReasonPausedUser

updatedVMI := vmi.DeepCopy()
updatedVMI.Status.Conditions = []v1.VirtualMachineInstanceCondition{
{
Type: v1.VirtualMachineInstanceIsMigratable,
Status: k8sv1.ConditionTrue,
},
{
Type: v1.VirtualMachineInstancePaused,
Status: k8sv1.ConditionTrue,
},
}

vmiFeeder.Add(vmi)
domainFeeder.Add(domain)

client.EXPECT().SyncVirtualMachine(vmi, gomock.Any())
vmiInterface.EXPECT().Update(NewVMICondMatcher(*updatedVMI))

controller.Execute()

By("resuming domain")
domain.Status.Status = api.Running
domain.Status.Reason = ""

updatedVMI = vmi.DeepCopy()
updatedVMI.Status.Conditions = []v1.VirtualMachineInstanceCondition{
{
Type: v1.VirtualMachineInstanceIsMigratable,
Status: k8sv1.ConditionTrue,
},
}

vmiFeeder.Add(vmi)
domainFeeder.Add(domain)

client.EXPECT().SyncVirtualMachine(vmi, gomock.Any())
vmiInterface.EXPECT().Update(NewVMICondMatcher(*updatedVMI))

controller.Execute()
})

It("should move VirtualMachineInstance from Scheduled to Failed if watchdog file is missing", func() {
vmi := v1.NewMinimalVMI("testvmi")
vmi.ObjectMeta.ResourceVersion = "1"
Expand Down
14 changes: 14 additions & 0 deletions pkg/virt-launcher/virtwrap/cmd-server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,20 @@ var _ = Describe("Virt remote commands", func() {
Expect(err).ToNot(HaveOccurred())
})

It("should suspend a vmi", func() {
vmi := v1.NewVMIReferenceFromName("testvmi")
domainManager.EXPECT().SuspendVMI(vmi)
err := client.SuspendVirtualMachine(vmi)
Expect(err).ToNot(HaveOccurred())
})

It("should resume a vmi", func() {
vmi := v1.NewVMIReferenceFromName("testvmi")
domainManager.EXPECT().ResumeVMI(vmi)
err := client.ResumeVirtualMachine(vmi)
Expect(err).ToNot(HaveOccurred())
})

It("should list domains", func() {
var list []*api.Domain
list = append(list, api.NewMinimalDomain("testvmi1"))
Expand Down
Loading

0 comments on commit 984cae9

Please sign in to comment.