kubernetes-operator/test/support/test.go

230 lines
4.8 KiB
Go

package support
import (
"context"
"errors"
"net/http"
"os"
"sync"
"testing"
"time"
helmsupport "github.com/dapr/kubernetes-operator/test/support/helm"
daprApi "github.com/dapr/kubernetes-operator/api/operator/v1alpha1"
"k8s.io/client-go/kubernetes/scheme"
"github.com/go-logr/logr/testr"
"github.com/hashicorp/go-cleanhttp"
"github.com/onsi/gomega"
"github.com/rs/xid"
supportclient "github.com/dapr/kubernetes-operator/test/support/client"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/klog/v2"
corev1 "k8s.io/api/core/v1"
olmV1 "github.com/operator-framework/api/pkg/operators/v1"
olmV1Alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
)
func durationFromEnvOrDefault(name string, def time.Duration) time.Duration {
val := os.Getenv(name)
if val == "" {
return def
}
result, err := time.ParseDuration(val)
if err != nil {
panic(err)
}
return result
}
const (
DefaultTestTimeoutMini = 5 * time.Second
DefaultTestTimeoutShort = 1 * time.Minute
DefaultTestTimeoutMedium = 2 * time.Minute
DefaultTestTimeoutLong = 5 * time.Minute
)
var (
TestTimeoutMini = durationFromEnvOrDefault("E2E_TEST_TIMEOUT_MINI", DefaultTestTimeoutMini)
TestTimeoutShort = durationFromEnvOrDefault("E2E_TEST_TIMEOUT_SHORT", DefaultTestTimeoutShort)
TestTimeoutMedium = durationFromEnvOrDefault("E2E_TEST_TIMEOUT_MEDIUM", DefaultTestTimeoutMedium)
TestTimeoutLong = durationFromEnvOrDefault("E2E_TEST_TIMEOUT_LONG", DefaultTestTimeoutLong)
DefaultEventuallyPollingInterval = 500 * time.Millisecond
DefaultEventuallyTimeout = TestTimeoutLong
DefaultConsistentlyDuration = 500 * time.Millisecond
DefaultConsistentlyPollingInterval = 500 * time.Millisecond
)
func init() {
if err := daprApi.AddToScheme(scheme.Scheme); err != nil {
panic(err)
}
if err := olmV1.AddToScheme(scheme.Scheme); err != nil {
panic(err)
}
if err := olmV1Alpha1.AddToScheme(scheme.Scheme); err != nil {
panic(err)
}
}
type Test interface {
gomega.Gomega
T() *testing.T
Ctx() context.Context
ID() string
Cleanup(f func() []runtime.Object)
Client() *supportclient.Client
Helm() *helmsupport.Helm
HTTPClient() *http.Client
NewTestNamespace(opts ...Option[*corev1.Namespace]) *corev1.Namespace
}
type Option[T any] interface {
applyTo(to T) error
}
func With(t *testing.T) Test {
t.Helper()
lr := testr.New(t)
klog.SetLogger(lr.WithName("client"))
ctx := context.Background()
if deadline, ok := t.Deadline(); ok {
withDeadline, cancel := context.WithDeadline(ctx, deadline)
t.Cleanup(cancel)
ctx = withDeadline
}
answer := &T{
WithT: gomega.NewWithT(t),
id: xid.New().String(),
t: t,
ctx: ctx,
http: cleanhttp.DefaultClient(),
cleanup: make([]func() []runtime.Object, 0),
}
answer.SetDefaultEventuallyPollingInterval(DefaultEventuallyPollingInterval)
answer.SetDefaultEventuallyTimeout(DefaultEventuallyTimeout)
answer.SetDefaultConsistentlyDuration(DefaultConsistentlyDuration)
answer.SetDefaultConsistentlyPollingInterval(DefaultConsistentlyPollingInterval)
t.Cleanup(func() {
t.Log("Run Test cleanup")
allerr := make([]error, 0)
for i := len(answer.cleanup) - 1; i >= 0; i-- {
objects := answer.cleanup[i]()
for i := range objects {
err := runCleanup(answer, objects[i])
if err != nil {
allerr = append(allerr, err)
}
}
}
if len(allerr) != 0 {
t.Fatal(errors.Join(allerr...))
}
t.Log("Test cleanup done")
})
return answer
}
type T struct {
*gomega.WithT
id string
t *testing.T
client *supportclient.Client
clientOnce sync.Once
helm *helmsupport.Helm
helmOnce sync.Once
http *http.Client
cleanup []func() []runtime.Object
//nolint:containedctx
ctx context.Context
}
func (t *T) ID() string {
return t.id
}
func (t *T) T() *testing.T {
return t.t
}
func (t *T) Ctx() context.Context {
return t.ctx
}
func (t *T) Client() *supportclient.Client {
t.clientOnce.Do(func() {
c, err := supportclient.New(t.t)
if err != nil {
t.T().Fatalf("Error creating client: %v", err)
}
t.client = c
})
return t.client
}
func (t *T) Helm() *helmsupport.Helm {
t.helmOnce.Do(func() {
h, err := helmsupport.New(helmsupport.WithLog(func(s string, i ...interface{}) {
t.T().Logf("[helm] "+s, i...)
}))
if err != nil {
t.T().Fatalf("Error creating helm client: %v", err)
}
t.helm = h
})
return t.helm
}
func (t *T) HTTPClient() *http.Client {
return t.http
}
func (t *T) Cleanup(f func() []runtime.Object) {
t.cleanup = append(t.cleanup, f)
}
func (t *T) NewTestNamespace(options ...Option[*corev1.Namespace]) *corev1.Namespace {
t.T().Helper()
namespace := createTestNamespace(t, options...)
t.Cleanup(func() []runtime.Object {
deleteTestNamespace(t, namespace)
return nil
})
return namespace
}