github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/testutil/type.go (about)

     1  /*
     2  Copyright (C) 2022-2023 ApeCloud Co., Ltd
     3  
     4  This file is part of KubeBlocks project
     5  
     6  This program is free software: you can redistribute it and/or modify
     7  it under the terms of the GNU Affero General Public License as published by
     8  the Free Software Foundation, either version 3 of the License, or
     9  (at your option) any later version.
    10  
    11  This program is distributed in the hope that it will be useful
    12  but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  GNU Affero General Public License for more details.
    15  
    16  You should have received a copy of the GNU Affero General Public License
    17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    18  */
    19  
    20  package testutil
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  	"os"
    26  	"time"
    27  
    28  	"github.com/onsi/gomega"
    29  	"github.com/sethvargo/go-password/password"
    30  	corev1 "k8s.io/api/core/v1"
    31  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    32  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    33  	"k8s.io/apimachinery/pkg/version"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  	"sigs.k8s.io/controller-runtime/pkg/envtest"
    36  
    37  	"github.com/1aal/kubeblocks/pkg/constant"
    38  	viper "github.com/1aal/kubeblocks/pkg/viperx"
    39  )
    40  
    41  type TestContext struct {
    42  	Ctx                                context.Context
    43  	Cli                                client.Client
    44  	TestEnv                            *envtest.Environment
    45  	TestObjLabelKey                    string
    46  	DefaultNamespace                   string
    47  	DefaultEventuallyTimeout           time.Duration
    48  	DefaultEventuallyPollingInterval   time.Duration
    49  	DefaultConsistentlyDuration        time.Duration
    50  	DefaultConsistentlyPollingInterval time.Duration
    51  	ClearResourceTimeout               time.Duration
    52  	ClearResourcePollingInterval       time.Duration
    53  	CreateObj                          func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error
    54  	CheckedCreateObj                   func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error
    55  }
    56  
    57  var ErrUninitError = fmt.Errorf("cli uninitialized error")
    58  
    59  const (
    60  	envExistingClusterType   = "EXISTING_CLUSTER_TYPE"
    61  	envUseExistingCluster    = "USE_EXISTING_CLUSTER"
    62  	DefaultStorageProvisoner = "kubernetes.io/no-provisioner"
    63  	DefaultCSIDriver         = "hostpath.csi.k8s.io"
    64  )
    65  
    66  func init() {
    67  	viper.AutomaticEnv()
    68  	viper.SetDefault("EventuallyTimeout", time.Second*10)
    69  	viper.SetDefault("EventuallyPollingInterval", time.Millisecond)
    70  	viper.SetDefault("ConsistentlyDuration", time.Second*3)
    71  	viper.SetDefault("ConsistentlyPollingInterval", time.Millisecond)
    72  	viper.SetDefault("ClearResourceTimeout", time.Second*10)
    73  	viper.SetDefault("ClearResourcePollingInterval", time.Millisecond)
    74  }
    75  
    76  // NewDefaultTestContext creates default test context, if provided namespace optional arg, a namespace
    77  // will be created if not exist
    78  func NewDefaultTestContext(ctx context.Context, cli client.Client, testEnv *envtest.Environment, namespace ...string) TestContext {
    79  	if cli == nil {
    80  		panic("missing required cli arg")
    81  	}
    82  	t := TestContext{
    83  		TestObjLabelKey:                    "kubeblocks.io/test",
    84  		DefaultNamespace:                   "default",
    85  		DefaultEventuallyTimeout:           viper.GetDuration("EventuallyTimeout"),
    86  		DefaultEventuallyPollingInterval:   viper.GetDuration("EventuallyPollingInterval"),
    87  		DefaultConsistentlyDuration:        viper.GetDuration("ConsistentlyDuration"),
    88  		DefaultConsistentlyPollingInterval: viper.GetDuration("ConsistentlyPollingInterval"),
    89  		ClearResourceTimeout:               viper.GetDuration("ClearResourceTimeout"),
    90  		ClearResourcePollingInterval:       viper.GetDuration("ClearResourcePollingInterval"),
    91  		Ctx:                                ctx,
    92  		Cli:                                cli,
    93  		TestEnv:                            testEnv,
    94  	}
    95  	t.CreateObj = func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
    96  		l := obj.GetLabels()
    97  		if l == nil {
    98  			l = map[string]string{}
    99  		}
   100  		l[t.TestObjLabelKey] = "true"
   101  		obj.SetLabels(l)
   102  		return t.Cli.Create(ctx, obj, opts...)
   103  	}
   104  
   105  	t.CheckedCreateObj = func(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
   106  		if err := t.CreateObj(ctx, obj, opts...); err != nil && !apierrors.IsAlreadyExists(err) {
   107  			return err
   108  		}
   109  		return nil
   110  	}
   111  
   112  	gomega.SetDefaultEventuallyTimeout(t.DefaultEventuallyTimeout)
   113  	gomega.SetDefaultEventuallyPollingInterval(t.DefaultEventuallyPollingInterval)
   114  	gomega.SetDefaultConsistentlyDuration(t.DefaultConsistentlyDuration)
   115  	gomega.SetDefaultConsistentlyPollingInterval(t.DefaultConsistentlyPollingInterval)
   116  
   117  	if len(namespace) > 0 && len(namespace[0]) > 0 && namespace[0] != "default" {
   118  		t.DefaultNamespace = namespace[0]
   119  		err := t.CreateNamespace()
   120  		gomega.Expect(client.IgnoreAlreadyExists(err)).To(gomega.Not(gomega.HaveOccurred()))
   121  	}
   122  	return t
   123  }
   124  
   125  func (testCtx TestContext) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
   126  	return testCtx.CreateObj(ctx, obj, opts...)
   127  }
   128  
   129  func (testCtx TestContext) GetNamespaceKey() client.ObjectKey {
   130  	return client.ObjectKey{
   131  		Name: testCtx.DefaultNamespace,
   132  	}
   133  }
   134  
   135  func (testCtx TestContext) GetNamespaceObj() corev1.Namespace {
   136  	return corev1.Namespace{
   137  		ObjectMeta: metav1.ObjectMeta{
   138  			Name: testCtx.DefaultNamespace,
   139  		},
   140  	}
   141  }
   142  
   143  func (testCtx TestContext) CreateNamespace() error {
   144  	if testCtx.DefaultNamespace == "default" {
   145  		return nil
   146  	}
   147  	namespace := testCtx.GetNamespaceObj()
   148  	return testCtx.Create(testCtx.Ctx, &namespace)
   149  }
   150  
   151  func (testCtx TestContext) GetRandomStr() string {
   152  	seq, _ := password.Generate(6, 2, 0, true, true)
   153  	return seq
   154  }
   155  
   156  func (testCtx TestContext) UsingExistingCluster() bool {
   157  	if testCtx.TestEnv == nil || testCtx.TestEnv.UseExistingCluster == nil {
   158  		return viper.GetBool(envUseExistingCluster)
   159  	}
   160  	return *testCtx.TestEnv.UseExistingCluster
   161  }
   162  
   163  func (testCtx TestContext) GetWebhookHostExternalName() string {
   164  	var (
   165  		minikubeType = "minikube"
   166  		minikubeHost = "host.minikube.internal"
   167  		k3dType      = "k3d"
   168  		k3dHost      = "host.k3d.internal"
   169  	)
   170  	clusterType := os.Getenv(envExistingClusterType)
   171  	if !testCtx.UsingExistingCluster() {
   172  		return ""
   173  	}
   174  	switch clusterType {
   175  	case minikubeType:
   176  		return minikubeHost
   177  	case k3dType:
   178  		return k3dHost
   179  	default:
   180  		return ""
   181  	}
   182  }
   183  
   184  func (testCtx TestContext) UseDefaultNamespace() func(client.Object) {
   185  	return func(obj client.Object) {
   186  		obj.SetNamespace(testCtx.DefaultNamespace)
   187  	}
   188  }
   189  
   190  // SetKubeServerVersionWithDistro provides "_KUBE_SERVER_INFO" viper settings helper function.
   191  func SetKubeServerVersionWithDistro(major, minor, patch, distro string) {
   192  	ver := version.Info{
   193  		Major:      major,
   194  		Minor:      minor,
   195  		GitVersion: fmt.Sprintf("v%s.%s.%s+%s", major, minor, patch, distro),
   196  	}
   197  	viper.Set(constant.CfgKeyServerInfo, ver)
   198  }
   199  
   200  // SetKubeServerVersion provides "_KUBE_SERVER_INFO" viper settings helper function.
   201  func SetKubeServerVersion(major, minor, patch string) {
   202  	ver := version.Info{
   203  		Major:      major,
   204  		Minor:      minor,
   205  		GitVersion: fmt.Sprintf("v%s.%s.%s", major, minor, patch),
   206  	}
   207  	viper.Set(constant.CfgKeyServerInfo, ver)
   208  }