Skip to content

Commit

Permalink
Migrate e2e components tests to Gomega (#1481)
Browse files Browse the repository at this point in the history
* Migrate e2e components test to Gomega

* Add better error handling in Gomega wrappers

* Fix findings

* Fix linters

* Rename WithT to NewWithT

* Finx findings

* Add more tests

* Fix findings

* Fix findings
  • Loading branch information
lburgazzoli authored Jan 13, 2025
1 parent 3843dcd commit a6ecd90
Show file tree
Hide file tree
Showing 27 changed files with 1,770 additions and 3,612 deletions.
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ linters-settings:
- predicate.Predicate
- client.Object
- common.PlatformObject
- types.AsyncAssertion
- kubernetes.Interface
revive:
rules:
- name: dot-imports
Expand Down Expand Up @@ -116,3 +118,6 @@ issues:
linters:
- typecheck
- dupl
- path: pkg/utils/test/testf/(.+)\.go
linters:
- containedctx
4 changes: 4 additions & 0 deletions pkg/controller/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ type Client struct {
dynamic dynamic.Interface
}

func (c *Client) Kubernetes() kubernetes.Interface {
return c.kubernetes
}

func (c *Client) Discovery() discovery.DiscoveryInterface {
return c.kubernetes.Discovery()
}
Expand Down
33 changes: 25 additions & 8 deletions pkg/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"

Expand Down Expand Up @@ -282,21 +283,30 @@ func KindForObject(scheme *runtime.Scheme, obj runtime.Object) (string, error) {
return gvk.Kind, nil
}

func EnsureGroupVersionKind(s *runtime.Scheme, obj client.Object) error {
if obj.GetObjectKind().GroupVersionKind().Kind != "" {
return nil
func GetGroupVersionKindForObject(s *runtime.Scheme, obj runtime.Object) (schema.GroupVersionKind, error) {
if obj == nil {
return schema.GroupVersionKind{}, errors.New("nil object")
}

kinds, _, err := s.ObjectKinds(obj)
if obj.GetObjectKind().GroupVersionKind().Version != "" && obj.GetObjectKind().GroupVersionKind().Kind != "" {
return obj.GetObjectKind().GroupVersionKind(), nil
}

gvk, err := apiutil.GVKForObject(obj, s)
if err != nil {
return fmt.Errorf("cannot get kind of resource: %w", err)
return schema.GroupVersionKind{}, fmt.Errorf("failed to get GVK: %w", err)
}

if len(kinds) != 1 {
return fmt.Errorf("expected to find a single GVK for %v, but got %d", obj, len(kinds))
return gvk, nil
}

func EnsureGroupVersionKind(s *runtime.Scheme, obj client.Object) error {
gvk, err := GetGroupVersionKindForObject(s, obj)
if err != nil {
return err
}

obj.GetObjectKind().SetGroupVersionKind(kinds[0])
obj.GetObjectKind().SetGroupVersionKind(gvk)

return nil
}
Expand All @@ -310,3 +320,10 @@ func HasDevFlags(in common.WithDevFlags) bool {

return df != nil && len(df.Manifests) != 0
}

func NamespacedNameFromObject(obj client.Object) types.NamespacedName {
return types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
}
79 changes: 79 additions & 0 deletions pkg/resources/resources_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package resources_test

import (
"errors"
"testing"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"

"github.com/opendatahub-io/opendatahub-operator/v2/pkg/cluster/gvk"
"github.com/opendatahub-io/opendatahub-operator/v2/pkg/resources"

. "github.com/onsi/gomega"
Expand Down Expand Up @@ -57,3 +62,77 @@ func TestHasAnnotationAndLabels(t *testing.T) {
})
}
}

func TestGetGroupVersionKindForObject(t *testing.T) {
g := NewWithT(t)

scheme := runtime.NewScheme()
g.Expect(corev1.AddToScheme(scheme)).To(Succeed())
g.Expect(appsv1.AddToScheme(scheme)).To(Succeed())

t.Run("ObjectWithGVK", func(t *testing.T) {
obj := &unstructured.Unstructured{}
obj.SetGroupVersionKind(gvk.Deployment)

gotGVK, err := resources.GetGroupVersionKindForObject(scheme, obj)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(gotGVK).To(Equal(gvk.Deployment))
})

t.Run("ObjectWithoutGVK_SuccessfulLookup", func(t *testing.T) {
obj := &appsv1.Deployment{}

gotGVK, err := resources.GetGroupVersionKindForObject(scheme, obj)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(gotGVK).To(Equal(gvk.Deployment))
})

t.Run("ObjectWithoutGVK_ErrorInLookup", func(t *testing.T) {
obj := &unstructured.Unstructured{}

_, err := resources.GetGroupVersionKindForObject(scheme, obj)
g.Expect(err).To(WithTransform(
errors.Unwrap,
MatchError(runtime.IsMissingKind, "IsMissingKind"),
))
})

t.Run("NilObject", func(t *testing.T) {
_, err := resources.GetGroupVersionKindForObject(scheme, nil)
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring("nil object"))
})
}

func TestEnsureGroupVersionKind(t *testing.T) {
g := NewWithT(t)

scheme := runtime.NewScheme()
g.Expect(corev1.AddToScheme(scheme)).To(Succeed())
g.Expect(appsv1.AddToScheme(scheme)).To(Succeed())

t.Run("ForObject", func(t *testing.T) {
obj := &unstructured.Unstructured{}
obj.SetAPIVersion(gvk.Deployment.GroupVersion().String())
obj.SetKind(gvk.Deployment.Kind)

err := resources.EnsureGroupVersionKind(scheme, obj)
g.Expect(err).ToNot(HaveOccurred())
g.Expect(obj.GetObjectKind().GroupVersionKind()).To(Equal(gvk.Deployment))
})

t.Run("ErrorOnNilObject", func(t *testing.T) {
err := resources.EnsureGroupVersionKind(scheme, nil)
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring("nil object"))
})

t.Run("ErrorOnInvalidObject", func(t *testing.T) {
obj := &unstructured.Unstructured{}
obj.SetKind("UnknownKind")

err := resources.EnsureGroupVersionKind(scheme, obj)
g.Expect(err).To(HaveOccurred())
g.Expect(err.Error()).To(ContainSubstring("failed to get GVK"))
})
}
46 changes: 29 additions & 17 deletions pkg/utils/test/matchers/jq/jq_transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,39 @@ import (

func Extract(expression string) func(in any) (any, error) {
return func(in any) (any, error) {
query, err := gojq.Parse(expression)
if err != nil {
return nil, fmt.Errorf("unable to parse expression %s, %w", expression, err)
}
return ExtractValue[any](in, expression)
}
}

data, err := toType(in)
if err != nil {
return false, err
}
func ExtractValue[T any](in any, expression string) (T, error) {
var result T
var ok bool

it := query.Run(data)
query, err := gojq.Parse(expression)
if err != nil {
return result, fmt.Errorf("unable to parse expression %s, %w", expression, err)
}

v, ok := it.Next()
if !ok {
return false, nil
}
data, err := toType(in)
if err != nil {
return result, err
}

if err, ok := v.(error); ok {
return false, err
}
it := query.Run(data)

return v, nil
v, ok := it.Next()
if !ok {
return result, nil
}

if err, ok := v.(error); ok {
return result, err
}

result, ok = v.(T)
if !ok {
return result, fmt.Errorf("result value is not of the expected type (expected:%T, got:%T", result, v)
}

return result, nil
}
29 changes: 29 additions & 0 deletions pkg/utils/test/matchers/jq/jq_transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,32 @@ func TestExtract(t *testing.T) {
),
)
}

func TestExtractValue(t *testing.T) {
t.Parallel()

g := NewWithT(t)

transform1 := func(in string) (any, error) {
return jq.ExtractValue[any](in, `.foo`)
}

g.Expect(`{ "foo": { "a": 1 }}`).Should(
WithTransform(transform1, WithTransform(json.Marshal,
jq.Match(`.a == 1`),
)),
)

transform2 := func(in string) (any, error) {
return jq.ExtractValue[any](in, `.status`)
}

g.Expect(`{ "status": { "foo": { "bar": "fr", "baz": "fz" } } }`).Should(
WithTransform(transform2,
And(
jq.Match(`.foo.bar == "fr"`),
jq.Match(`.foo.baz == "fz"`),
),
),
)
}
Loading

0 comments on commit a6ecd90

Please sign in to comment.