Skip to content

Commit

Permalink
Merge pull request #209 from booxter/test_helper
Browse files Browse the repository at this point in the history
Introduce test helper module
  • Loading branch information
openshift-merge-bot[bot] committed Jan 31, 2024
2 parents d76ba56 + 6a2741c commit def099a
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 171 deletions.
5 changes: 4 additions & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.19

require (
github.com/go-logr/logr v1.4.1
github.com/google/uuid v1.5.0
github.com/onsi/gomega v1.30.0
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240124141114-55d029e4658b
k8s.io/api v0.26.13
k8s.io/apimachinery v0.26.13
Expand All @@ -26,15 +28,16 @@ require (
github.com/google/gnostic v0.6.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openshift/api v3.9.0+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.14.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0 h1:VzM3TYHDgqPkettiP6I6q2jOeQFL4nrJM+UcAc4f6Fs=
github.com/k8snetworkplumbingwg/network-attachment-definition-client v1.4.0/go.mod h1:nqCI7aelBJU61wiBeeZWJ6oi4bJy5nrjkM6lWIMA4j0=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
Expand Down Expand Up @@ -218,8 +220,12 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs=
github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY=
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240124141114-55d029e4658b h1:8tPUN0Aj4MKEltI2pv3vjy2HyxPEAYXcs6UNrz2vzm8=
github.com/openstack-k8s-operators/lib-common/modules/common v0.3.1-0.20240124141114-55d029e4658b/go.mod h1:F2490pi067Cc3tU3b1nCJPfZ5bLpm+rwldEdMUPA0d4=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
296 changes: 296 additions & 0 deletions api/test/helpers/crd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
/*
Copyright 2024 Red Hat
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.
*/

package helpers

import (
"context"
"time"

"github.com/go-logr/logr"
"github.com/google/uuid"
"github.com/onsi/gomega"
"github.com/openstack-k8s-operators/lib-common/modules/common/condition"
ovnv1 "github.com/openstack-k8s-operators/ovn-operator/api/v1beta1"
k8s_errors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"

base "github.com/openstack-k8s-operators/lib-common/modules/common/test/helpers"
)

// TestHelper is a collection of helpers for testing operators. It extends the
// generic TestHelper from modules/test.
type TestHelper struct {
*base.TestHelper
}

// NewTestHelper returns a TestHelper
func NewTestHelper(
ctx context.Context,
k8sClient client.Client,
timeout time.Duration,
interval time.Duration,
logger logr.Logger,
) *TestHelper {
helper := &TestHelper{}
helper.TestHelper = base.NewTestHelper(ctx, k8sClient, timeout, interval, logger)
return helper
}

// CreateOVNNorthd creates a new OVNNorthd instance with the specified
// namespace in the Kubernetes cluster.
//
// Example usage:
//
// ovnNorthd := th.CreateOVNNorthd(namespace, spec)
// DeferCleanup(th.DeleteOVNNorthd, ovnNorthd)
func (th *TestHelper) CreateOVNNorthd(namespace string, spec ovnv1.OVNNorthdSpec) types.NamespacedName {
name := "ovnnorthd-" + uuid.New().String()
ovnnorthd := &ovnv1.OVNNorthd{
TypeMeta: metav1.TypeMeta{
APIVersion: "ovn.openstack.org/v1beta1",
Kind: "OVNNorthd",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: spec,
}

gomega.Expect(th.K8sClient.Create(th.Ctx, ovnnorthd)).Should(gomega.Succeed())
th.Logger.Info("OVNNorthd created", "OVNNorthd", name)
return types.NamespacedName{Namespace: namespace, Name: name}
}

// DeleteOVNNorthd deletes a OVNNorthd resource from the Kubernetes cluster.
//
// After the deletion, the function checks again if the OVNNorthd is
// successfully deleted.
//
// Example usage:
//
// ovnNorthd := th.CreateOVNNorthd(namespace, spec)
// DeferCleanup(th.DeleteOVNNorthd, ovnNorthd)
func (th *TestHelper) DeleteOVNNorthd(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
ovnnorthd := &ovnv1.OVNNorthd{}
err := th.K8sClient.Get(th.Ctx, name, ovnnorthd)
// if it is already gone that is OK
if k8s_errors.IsNotFound(err) {
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())

g.Expect(th.K8sClient.Delete(th.Ctx, ovnnorthd)).Should(gomega.Succeed())

err = th.K8sClient.Get(th.Ctx, name, ovnnorthd)
g.Expect(k8s_errors.IsNotFound(err)).To(gomega.BeTrue())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
}

// GetOVNNorthd retrieves a OVNNorthd resource.
//
// The function returns a pointer to the retrieved OVNNorthd resource.
//
// Example usage:
//
// ovnNorthdName := th.CreateOVNNorthd(namespace, spec)
// ovnNorthd := th.GetOVNNorthd(ovnNorthdName)
func (th *TestHelper) GetOVNNorthd(name types.NamespacedName) *ovnv1.OVNNorthd {
instance := &ovnv1.OVNNorthd{}
gomega.Eventually(func(g gomega.Gomega) {
g.Expect(th.K8sClient.Get(th.Ctx, name, instance)).Should(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
return instance
}

// SimulateOVNNorthdReady simulates the readiness of a OVNNorthd resource by
// setting the Ready condition of the OVNNorthd to true.
//
// Example usage:
// th.SimulateOVNNorthdReady(ovnNorthdName)
func (th *TestHelper) SimulateOVNNorthdReady(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
service := th.GetOVNNorthd(name)
service.Status.Conditions.MarkTrue(condition.ReadyCondition, "Ready")
g.Expect(th.K8sClient.Status().Update(th.Ctx, service)).To(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
th.Logger.Info("Simulated GetOVNNorthd ready", "on", name)
}

// CreateOVNDBCluster creates a new OVNDBCluster instance with the specified
// namespace in the Kubernetes cluster.
//
// Example usage:
//
// ovnDBCluster := th.CreateOVNDBCluster(namespace, spec)
// DeferCleanup(th.DeleteOVNDBCluster, ovnDBCluster)
func (th *TestHelper) CreateOVNDBCluster(namespace string, spec ovnv1.OVNDBClusterSpec) types.NamespacedName {
name := "ovndbcluster-" + uuid.New().String()
ovnDBCluster := &ovnv1.OVNDBCluster{
TypeMeta: metav1.TypeMeta{
APIVersion: "ovn.openstack.org/v1beta1",
Kind: "OVNDBCluster",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: spec,
}

gomega.Expect(th.K8sClient.Create(th.Ctx, ovnDBCluster)).Should(gomega.Succeed())
th.Logger.Info("OVNDBCluster created", "OVNDBCluster", name)
return types.NamespacedName{Namespace: namespace, Name: name}
}

// DeleteOVNDBCluster deletes a OVNDBCluster resource from the Kubernetes cluster.
//
// After the deletion, the function checks again if the OVNDBCluster is
// successfully deleted.
//
// Example usage:
//
// ovnDBCluster := th.CreateOVNDBCluster(namespace, spec)
// DeferCleanup(th.DeleteOVNDBCluster, ovnDBCluster)
func (th *TestHelper) DeleteOVNDBCluster(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
ovnDBCluster := &ovnv1.OVNDBCluster{}
err := th.K8sClient.Get(th.Ctx, name, ovnDBCluster)
// if it is already gone that is OK
if k8s_errors.IsNotFound(err) {
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())

g.Expect(th.K8sClient.Delete(th.Ctx, ovnDBCluster)).Should(gomega.Succeed())

err = th.K8sClient.Get(th.Ctx, name, ovnDBCluster)
g.Expect(k8s_errors.IsNotFound(err)).To(gomega.BeTrue())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
}

// GetOVNDBCluster retrieves a OVNDBCluster resource.
//
// The function returns a pointer to the retrieved OVNDBCluster resource.
//
// Example usage:
//
// ovnDBClusterName := th.CreateOVNDBCluster(namespace, spec)
// ovnDBCluster := th.GetOVNDBCluster(ovnDBClusterName)
func (th *TestHelper) GetOVNDBCluster(name types.NamespacedName) *ovnv1.OVNDBCluster {
instance := &ovnv1.OVNDBCluster{}
gomega.Eventually(func(g gomega.Gomega) {
g.Expect(th.K8sClient.Get(th.Ctx, name, instance)).Should(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
return instance
}

// SimulateOVNDBClusterReady simulates the readiness of a OVNDBCluster resource by
// setting the Ready condition of the OVNDBCluster to true.
//
// Example usage:
// th.SimulateOVNDBClusterReady(ovnDBClusterName)
func (th *TestHelper) SimulateOVNDBClusterReady(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
service := th.GetOVNDBCluster(name)
service.Status.Conditions.MarkTrue(condition.ReadyCondition, "Ready")
g.Expect(th.K8sClient.Status().Update(th.Ctx, service)).To(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
th.Logger.Info("Simulated GetOVNDBCluster ready", "on", name)
}

// CreateOVNController creates a new OVNController instance with the specified
// namespace in the Kubernetes cluster.
//
// Example usage:
//
// ovnController := th.CreateOVNController(namespace, spec)
// DeferCleanup(th.DeleteOVNController, ovnController)
func (th *TestHelper) CreateOVNController(namespace string, spec ovnv1.OVNControllerSpec) types.NamespacedName {
name := "ovncontroller-" + uuid.New().String()
ovnController := &ovnv1.OVNController{
TypeMeta: metav1.TypeMeta{
APIVersion: "ovn.openstack.org/v1beta1",
Kind: "OVNController",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: spec,
}

gomega.Expect(th.K8sClient.Create(th.Ctx, ovnController)).Should(gomega.Succeed())
th.Logger.Info("OVNController created", "OVNController", name)
return types.NamespacedName{Namespace: namespace, Name: name}
}

// DeleteOVNController deletes a OVNController resource from the Kubernetes cluster.
//
// After the deletion, the function checks again if the OVNController is
// successfully deleted.
//
// Example usage:
//
// ovnController := th.CreateOVNController(namespace, spec)
// DeferCleanup(th.DeleteOVNController, ovnController)
func (th *TestHelper) DeleteOVNController(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
ovnController := &ovnv1.OVNController{}
err := th.K8sClient.Get(th.Ctx, name, ovnController)
// if it is already gone that is OK
if k8s_errors.IsNotFound(err) {
return
}
g.Expect(err).NotTo(gomega.HaveOccurred())

g.Expect(th.K8sClient.Delete(th.Ctx, ovnController)).Should(gomega.Succeed())

err = th.K8sClient.Get(th.Ctx, name, ovnController)
g.Expect(k8s_errors.IsNotFound(err)).To(gomega.BeTrue())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
}

// GetOVNController retrieves a OVNController resource.
//
// The function returns a pointer to the retrieved OVNController resource.
//
// Example usage:
//
// ovnControllerName := th.CreateOVNController(namespace, spec)
// ovnController := th.GetOVNController(ovnControllerName)
func (th *TestHelper) GetOVNController(name types.NamespacedName) *ovnv1.OVNController {
instance := &ovnv1.OVNController{}
gomega.Eventually(func(g gomega.Gomega) {
g.Expect(th.K8sClient.Get(th.Ctx, name, instance)).Should(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
return instance
}

// SimulateOVNControllerReady simulates the readiness of a OVNController resource by
// setting the Ready condition of the OVNController to true.
//
// Example usage:
// th.SimulateOVNControllerReady(ovnControllerName)
func (th *TestHelper) SimulateOVNControllerReady(name types.NamespacedName) {
gomega.Eventually(func(g gomega.Gomega) {
service := th.GetOVNController(name)
service.Status.Conditions.MarkTrue(condition.ReadyCondition, "Ready")
g.Expect(th.K8sClient.Status().Update(th.Ctx, service)).To(gomega.Succeed())
}, th.Timeout, th.Interval).Should(gomega.Succeed())
th.Logger.Info("Simulated GetOVNController ready", "on", name)
}
Loading

0 comments on commit def099a

Please sign in to comment.