github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/configuration/config_util_test.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 configuration
    21  
    22  import (
    23  	. "github.com/onsi/ginkgo/v2"
    24  	. "github.com/onsi/gomega"
    25  
    26  	corev1 "k8s.io/api/core/v1"
    27  	"sigs.k8s.io/controller-runtime/pkg/client"
    28  	"sigs.k8s.io/controller-runtime/pkg/log"
    29  
    30  	appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1"
    31  	cfgcore "github.com/1aal/kubeblocks/pkg/configuration/core"
    32  	intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil"
    33  	"github.com/1aal/kubeblocks/pkg/generics"
    34  	testapps "github.com/1aal/kubeblocks/pkg/testutil/apps"
    35  	testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s"
    36  )
    37  
    38  var _ = Describe("ConfigWrapper util test", func() {
    39  	const clusterDefName = "test-clusterdef"
    40  	const clusterVersionName = "test-clusterversion"
    41  	const statefulCompDefName = "replicasets"
    42  	const configSpecName = "mysql-config-tpl"
    43  	const configVolumeName = "mysql-config"
    44  
    45  	var (
    46  		// ctrl       *gomock.Controller
    47  		// mockClient *mock_client.MockClient
    48  		k8sMockClient *testutil.K8sClientMockHelper
    49  
    50  		reqCtx = intctrlutil.RequestCtx{
    51  			Ctx: ctx,
    52  			Log: log.FromContext(ctx).WithValues("reconfigure_for_test", testCtx.DefaultNamespace),
    53  		}
    54  	)
    55  
    56  	var (
    57  		configMapObj        *corev1.ConfigMap
    58  		configConstraintObj *appsv1alpha1.ConfigConstraint
    59  		clusterDefObj       *appsv1alpha1.ClusterDefinition
    60  		clusterVersionObj   *appsv1alpha1.ClusterVersion
    61  	)
    62  
    63  	cleanEnv := func() {
    64  		// must wait till resources deleted and no longer existed before the testcases start,
    65  		// otherwise if later it needs to create some new resource objects with the same name,
    66  		// in race conditions, it will find the existence of old objects, resulting failure to
    67  		// create the new objects.
    68  		By("clean resources")
    69  
    70  		// delete rest mocked objects
    71  		inNS := client.InNamespace(testCtx.DefaultNamespace)
    72  		ml := client.HasLabels{testCtx.TestObjLabelKey}
    73  		// namespaced
    74  		testapps.ClearResources(&testCtx, generics.ConfigMapSignature, inNS, ml)
    75  		// non-namespaced
    76  		testapps.ClearResources(&testCtx, generics.ClusterVersionSignature, ml)
    77  		testapps.ClearResources(&testCtx, generics.ClusterDefinitionSignature, ml)
    78  		testapps.ClearResources(&testCtx, generics.ConfigConstraintSignature, ml)
    79  	}
    80  
    81  	BeforeEach(func() {
    82  		cleanEnv()
    83  
    84  		// Add any setup steps that needs to be executed before each test
    85  		k8sMockClient = testutil.NewK8sMockClient()
    86  
    87  		By("creating a cluster")
    88  		configMapObj = testapps.CreateCustomizedObj(&testCtx,
    89  			"resources/mysql-config-template.yaml", &corev1.ConfigMap{},
    90  			testCtx.UseDefaultNamespace())
    91  
    92  		configConstraintObj = testapps.CreateCustomizedObj(&testCtx,
    93  			"resources/mysql-config-constraint.yaml",
    94  			&appsv1alpha1.ConfigConstraint{})
    95  
    96  		By("Create a clusterDefinition obj")
    97  		clusterDefObj = testapps.NewClusterDefFactory(clusterDefName).
    98  			AddComponentDef(testapps.StatefulMySQLComponent, statefulCompDefName).
    99  			AddConfigTemplate(configSpecName, configMapObj.Name, configConstraintObj.Name, testCtx.DefaultNamespace, configVolumeName).
   100  			Create(&testCtx).GetObject()
   101  
   102  		By("Create a clusterVersion obj")
   103  		clusterVersionObj = testapps.NewClusterVersionFactory(clusterVersionName, clusterDefObj.GetName()).
   104  			AddComponentVersion(statefulCompDefName).
   105  			Create(&testCtx).GetObject()
   106  	})
   107  
   108  	AfterEach(func() {
   109  		// Add any teardown steps that needs to be executed after each test
   110  		cleanEnv()
   111  
   112  		k8sMockClient.Finish()
   113  	})
   114  
   115  	Context("clusterdefinition CR test", func() {
   116  		It("Should success without error", func() {
   117  			availableTPL := configConstraintObj.DeepCopy()
   118  			availableTPL.Status.Phase = appsv1alpha1.CCAvailablePhase
   119  
   120  			k8sMockClient.MockPatchMethod(testutil.WithSucceed())
   121  			k8sMockClient.MockListMethod(testutil.WithSucceed())
   122  			k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSequenceResult(
   123  				map[client.ObjectKey][]testutil.MockGetReturned{
   124  					client.ObjectKeyFromObject(configMapObj): {{
   125  						Object: nil,
   126  						Err:    cfgcore.MakeError("failed to get cc object"),
   127  					}, {
   128  						Object: configMapObj,
   129  						Err:    nil,
   130  					}},
   131  					client.ObjectKeyFromObject(configConstraintObj): {{
   132  						Object: nil,
   133  						Err:    cfgcore.MakeError("failed to get cc object"),
   134  					}, {
   135  						Object: configConstraintObj,
   136  						Err:    nil,
   137  					}, {
   138  						Object: availableTPL,
   139  						Err:    nil,
   140  					}},
   141  				},
   142  			), testutil.WithAnyTimes()))
   143  
   144  			_, err := checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   145  			Expect(err).ShouldNot(Succeed())
   146  			Expect(err.Error()).Should(ContainSubstring("failed to get cc object"))
   147  
   148  			_, err = checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   149  			Expect(err).ShouldNot(Succeed())
   150  			Expect(err.Error()).Should(ContainSubstring("failed to get cc object"))
   151  
   152  			_, err = checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   153  			Expect(err).ShouldNot(Succeed())
   154  			Expect(err.Error()).Should(ContainSubstring("status not ready"))
   155  
   156  			ok, err := checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   157  			Expect(err).Should(Succeed())
   158  			Expect(ok).Should(BeTrue())
   159  
   160  			ok, err = updateLabelsByConfigSpec(k8sMockClient.Client(), reqCtx, clusterDefObj)
   161  			Expect(err).Should(Succeed())
   162  			Expect(ok).Should(BeTrue())
   163  
   164  			_, err = updateLabelsByConfigSpec(k8sMockClient.Client(), reqCtx, clusterDefObj)
   165  			Expect(err).Should(Succeed())
   166  
   167  			err = DeleteConfigMapFinalizer(k8sMockClient.Client(), reqCtx, clusterDefObj)
   168  			Expect(err).Should(Succeed())
   169  		})
   170  	})
   171  
   172  	Context("clusterdefinition CR test without config Constraints", func() {
   173  		It("Should success without error", func() {
   174  			// remove ConfigConstraintRef
   175  			_, err := handleConfigTemplate(clusterDefObj, func(templates []appsv1alpha1.ComponentConfigSpec) (bool, error) {
   176  				return true, nil
   177  			}, func(component *appsv1alpha1.ClusterComponentDefinition) error {
   178  				if len(component.ConfigSpecs) == 0 {
   179  					return nil
   180  				}
   181  				for i := range component.ConfigSpecs {
   182  					tpl := &component.ConfigSpecs[i]
   183  					tpl.ConfigConstraintRef = ""
   184  				}
   185  				return nil
   186  			})
   187  			Expect(err).Should(Succeed())
   188  
   189  			availableTPL := configConstraintObj.DeepCopy()
   190  			availableTPL.Status.Phase = appsv1alpha1.CCAvailablePhase
   191  
   192  			k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSequenceResult(
   193  				map[client.ObjectKey][]testutil.MockGetReturned{
   194  					client.ObjectKeyFromObject(configMapObj): {{
   195  						Object: nil,
   196  						Err:    cfgcore.MakeError("failed to get cc object"),
   197  					}, {
   198  						Object: configMapObj,
   199  						Err:    nil,
   200  					}}},
   201  			), testutil.WithAnyTimes()))
   202  
   203  			_, err = checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   204  			Expect(err).ShouldNot(Succeed())
   205  			Expect(err.Error()).Should(ContainSubstring("failed to get cc object"))
   206  
   207  			ok, err := checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterDefObj)
   208  			Expect(err).Should(Succeed())
   209  			Expect(ok).Should(BeTrue())
   210  		})
   211  	})
   212  
   213  	updateAVTemplates := func() {
   214  		var tpls []appsv1alpha1.ComponentConfigSpec
   215  		_, err := handleConfigTemplate(clusterDefObj, func(templates []appsv1alpha1.ComponentConfigSpec) (bool, error) {
   216  			tpls = templates
   217  			return true, nil
   218  		})
   219  		Expect(err).Should(Succeed())
   220  
   221  		if len(clusterVersionObj.Spec.ComponentVersions) == 0 {
   222  			return
   223  		}
   224  
   225  		// mock clusterVersionObj config templates
   226  		clusterVersionObj.Spec.ComponentVersions[0].ConfigSpecs = tpls
   227  	}
   228  
   229  	Context("clusterversion CR test", func() {
   230  		It("Should success without error", func() {
   231  			updateAVTemplates()
   232  			availableTPL := configConstraintObj.DeepCopy()
   233  			availableTPL.Status.Phase = appsv1alpha1.CCAvailablePhase
   234  
   235  			k8sMockClient.MockPatchMethod(testutil.WithSucceed())
   236  			k8sMockClient.MockListMethod(testutil.WithSucceed())
   237  			k8sMockClient.MockGetMethod(testutil.WithGetReturned(testutil.WithConstructSequenceResult(
   238  				map[client.ObjectKey][]testutil.MockGetReturned{
   239  					client.ObjectKeyFromObject(configMapObj): {{
   240  						Object: nil,
   241  						Err:    cfgcore.MakeError("failed to get cc object"),
   242  					}, {
   243  						Object: configMapObj,
   244  						Err:    nil,
   245  					}},
   246  					client.ObjectKeyFromObject(configConstraintObj): {{
   247  						Object: nil,
   248  						Err:    cfgcore.MakeError("failed to get cc object"),
   249  					}, {
   250  						Object: configConstraintObj,
   251  						Err:    nil,
   252  					}, {
   253  						Object: availableTPL,
   254  						Err:    nil,
   255  					}},
   256  				},
   257  			), testutil.WithAnyTimes()))
   258  
   259  			_, err := checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   260  			Expect(err).ShouldNot(Succeed())
   261  			Expect(err.Error()).Should(ContainSubstring("failed to get cc object"))
   262  
   263  			_, err = checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   264  			Expect(err).ShouldNot(Succeed())
   265  			Expect(err.Error()).Should(ContainSubstring("failed to get cc object"))
   266  
   267  			_, err = checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   268  			Expect(err).ShouldNot(Succeed())
   269  			Expect(err.Error()).Should(ContainSubstring("status not ready"))
   270  
   271  			ok, err := checkConfigTemplate(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   272  			Expect(err).Should(Succeed())
   273  			Expect(ok).Should(BeTrue())
   274  
   275  			ok, err = updateLabelsByConfigSpec(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   276  			Expect(err).Should(Succeed())
   277  			Expect(ok).Should(BeTrue())
   278  
   279  			_, err = updateLabelsByConfigSpec(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   280  			Expect(err).Should(Succeed())
   281  
   282  			err = DeleteConfigMapFinalizer(k8sMockClient.Client(), reqCtx, clusterVersionObj)
   283  			Expect(err).Should(Succeed())
   284  		})
   285  	})
   286  
   287  })