Skip to content

Commit

Permalink
Tests: Introduce event package
Browse files Browse the repository at this point in the history
This package can be used to safely expect
events on object. This allow us to expect
events even in parallel tests.

Note: Objects that are not namespaced or
shared between tests, such as nodes, disallow
us to use this package without running Serial.

Signed-off-by: L. Pivarc <[email protected]>
  • Loading branch information
xpivarc committed Jun 28, 2023
1 parent b9799d1 commit 42fed1c
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
18 changes: 18 additions & 0 deletions tests/events/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["events.go"],
importpath = "kubevirt.io/kubevirt/tests/events",
visibility = ["//visibility:public"],
deps = [
"//staging/src/kubevirt.io/client-go/kubecli:go_default_library",
"//tests/util:go_default_library",
"//vendor/github.com/onsi/ginkgo/v2:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/github.com/onsi/gomega/types:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
],
)
106 changes: 106 additions & 0 deletions tests/events/events.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package events

import (
"context"
"fmt"
"reflect"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/types"

"kubevirt.io/client-go/kubecli"

"kubevirt.io/kubevirt/tests/util"

k8sv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

type k8sObject interface {
metav1.Object
schema.ObjectKind
}

// ExpectNoEvent is safe to use in parallel as long as you are asserting namespaced object that is not shared between tests
func ExpectNoEvent(object k8sObject, eventType, reason string) {
By("Expecting for an event to be not triggered")
expectEvent(object, eventType, reason, BeEmpty())
}

// ExpectEvent is safe to use in parallel as long as you are asserting namespaced object that is not shared between tests
func ExpectEvent(object k8sObject, eventType, reason string) {
By("Expecting for an event to be triggered")
expectEvent(object, eventType, reason, Not(BeEmpty()))
}

// DeleteEvents is safe to use in parallel as long as you are asserting namespaced object that is not shared between tests
func DeleteEvents(object k8sObject, eventType, reason string) {
By("Expecting events to be removed")
virtClient, err := kubecli.GetKubevirtClient()
util.PanicOnError(err)

fieldSelector, namespace := constructFieldSelectorAndNamespace(object, eventType, reason)

events, err := virtClient.CoreV1().Events(namespace).List(context.Background(),
metav1.ListOptions{
FieldSelector: fieldSelector,
})
ExpectWithOffset(1, err).ToNot(HaveOccurred())
for _, event := range events.Items {
err = virtClient.CoreV1().Events(event.Namespace).Delete(
context.TODO(),
event.Name,
metav1.DeleteOptions{},
)
ExpectWithOffset(1, err).ToNot(HaveOccurred(), fmt.Sprintf("failed to delete event %s/%s", event.Namespace, event.Name))
}

EventuallyWithOffset(1, func() []k8sv1.Event {
events, err := virtClient.CoreV1().Events(namespace).List(context.Background(),
metav1.ListOptions{
FieldSelector: fieldSelector,
})
ExpectWithOffset(1, err).ToNot(HaveOccurred())

return events.Items
}, 30*time.Second, 1*time.Second).Should(BeEmpty(), fmt.Sprintf("Used fieldselector %s", fieldSelector))
}

func expectEvent(object k8sObject, eventType, reason string, matcher types.GomegaMatcher) {
virtClient, err := kubecli.GetKubevirtClient()
ExpectWithOffset(2, err).ToNot(HaveOccurred())

fieldSelector, namespace := constructFieldSelectorAndNamespace(object, eventType, reason)

EventuallyWithOffset(2, func() []k8sv1.Event {
events, err := virtClient.CoreV1().Events(namespace).List(
context.Background(),
metav1.ListOptions{
FieldSelector: fieldSelector,
},
)
ExpectWithOffset(3, err).ToNot(HaveOccurred())
return events.Items
}, 30*time.Second).Should(matcher, fmt.Sprintf("Used fieldselector %s", fieldSelector))
}

// constructFieldSelectorAndNamespace does best effort to overcome https://github.com/kubernetes/client-go/issues/861
func constructFieldSelectorAndNamespace(object k8sObject, eventType, reason string) (string, string) {
kind := object.GroupVersionKind().Kind
if kind == "" {
kind = reflect.ValueOf(object).Type().Name()
}
kindSelector := fmt.Sprintf("involvedObject.kind=%s,", kind)
if kind == "" {
kindSelector = ""
}

name := object.GetName()
namespace := object.GetNamespace()

fieldSelector := fmt.Sprintf("%sinvolvedObject.name=%s,type=%s,reason=%s", kindSelector, name, eventType, reason)
return fieldSelector, namespace
}

0 comments on commit 42fed1c

Please sign in to comment.