github.com/oam-dev/kubevela@v1.9.11/pkg/resourcekeeper/gc_rev_test.go (about)

     1  /*
     2  Copyright 2021 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package resourcekeeper
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/crossplane/crossplane-runtime/pkg/test"
    24  	"github.com/pkg/errors"
    25  	appsv1 "k8s.io/api/apps/v1"
    26  	corev1 "k8s.io/api/core/v1"
    27  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    30  	"k8s.io/apimachinery/pkg/runtime/schema"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  
    33  	apicommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
    34  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    35  	"github.com/oam-dev/kubevela/pkg/oam"
    36  )
    37  
    38  func Test_gcHandler_GarbageCollectApplicationRevision(t *testing.T) {
    39  	type fields struct {
    40  		resourceKeeper *resourceKeeper
    41  		cfg            *gcConfig
    42  	}
    43  	tests := []struct {
    44  		name    string
    45  		fields  fields
    46  		wantErr bool
    47  	}{
    48  		{
    49  			name: "cleanUpApplicationRevision and cleanUpWorkflowComponentRevision success",
    50  			fields: fields{
    51  				resourceKeeper: &resourceKeeper{
    52  					Client: test.NewMockClient(),
    53  					app:    &v1beta1.Application{},
    54  				},
    55  				cfg: &gcConfig{
    56  					disableApplicationRevisionGC: false,
    57  					disableComponentRevisionGC:   false,
    58  				},
    59  			},
    60  		},
    61  		{
    62  			name: "failed",
    63  			fields: fields{
    64  				resourceKeeper: &resourceKeeper{
    65  					Client: &test.MockClient{
    66  						MockGet:         test.NewMockGetFn(errors.New("mock")),
    67  						MockList:        test.NewMockListFn(errors.New("mock")),
    68  						MockCreate:      test.NewMockCreateFn(errors.New("mock")),
    69  						MockDelete:      test.NewMockDeleteFn(errors.New("mock")),
    70  						MockDeleteAllOf: test.NewMockDeleteAllOfFn(errors.New("mock")),
    71  						MockUpdate:      test.NewMockUpdateFn(errors.New("mock")),
    72  						MockPatch:       test.NewMockPatchFn(errors.New("mock")),
    73  					},
    74  					app: &v1beta1.Application{},
    75  				},
    76  				cfg: &gcConfig{
    77  					disableApplicationRevisionGC: false,
    78  					disableComponentRevisionGC:   false,
    79  				},
    80  			},
    81  			wantErr: true,
    82  		},
    83  	}
    84  	for _, tt := range tests {
    85  		t.Run(tt.name, func(t *testing.T) {
    86  			h := &gcHandler{
    87  				resourceKeeper: tt.fields.resourceKeeper,
    88  				cfg:            tt.fields.cfg,
    89  			}
    90  			if err := h.GarbageCollectApplicationRevision(context.Background()); (err != nil) != tt.wantErr {
    91  				t.Errorf("gcHandler.GarbageCollectApplicationRevision() error = %v, wantErr %v", err, tt.wantErr)
    92  			}
    93  		})
    94  	}
    95  }
    96  
    97  func Test_cleanUpApplicationRevision(t *testing.T) {
    98  	type args struct {
    99  		h *gcHandler
   100  	}
   101  	tests := []struct {
   102  		name    string
   103  		args    args
   104  		wantErr bool
   105  	}{
   106  		{
   107  			name: "clean up app-v2",
   108  			args: args{
   109  				h: &gcHandler{
   110  					resourceKeeper: &resourceKeeper{
   111  						Client: &test.MockClient{
   112  							MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
   113  								l, _ := list.(*v1beta1.ApplicationRevisionList)
   114  								l.Items = []v1beta1.ApplicationRevision{
   115  									{
   116  										ObjectMeta: metav1.ObjectMeta{
   117  											Name: "app-v1",
   118  										},
   119  									},
   120  									{
   121  										ObjectMeta: metav1.ObjectMeta{
   122  											Name: "app-v2",
   123  										},
   124  									},
   125  									{
   126  										ObjectMeta: metav1.ObjectMeta{
   127  											Name: "app-v3",
   128  										},
   129  									},
   130  								}
   131  								return nil
   132  							},
   133  							MockDelete: test.NewMockDeleteFn(nil),
   134  						},
   135  						app: &v1beta1.Application{
   136  							Status: apicommon.AppStatus{
   137  								LatestRevision: &apicommon.Revision{
   138  									Name: "app-v1",
   139  								},
   140  							},
   141  						},
   142  					},
   143  					cfg: &gcConfig{
   144  						disableApplicationRevisionGC: false,
   145  						appRevisionLimit:             1,
   146  					},
   147  				},
   148  			},
   149  		},
   150  		{
   151  			name: "disabled",
   152  			args: args{
   153  				h: &gcHandler{
   154  					cfg: &gcConfig{
   155  						disableApplicationRevisionGC: true,
   156  					},
   157  				},
   158  			},
   159  		},
   160  		{
   161  			name: "list failed",
   162  			args: args{
   163  				h: &gcHandler{
   164  					resourceKeeper: &resourceKeeper{
   165  						Client: &test.MockClient{
   166  							MockList: test.NewMockListFn(errors.New("mock")),
   167  						},
   168  						app: &v1beta1.Application{},
   169  					},
   170  					cfg: &gcConfig{
   171  						disableApplicationRevisionGC: false,
   172  						appRevisionLimit:             1,
   173  					},
   174  				},
   175  			},
   176  			wantErr: true,
   177  		},
   178  		{
   179  			name: "delete failed",
   180  			args: args{
   181  				h: &gcHandler{
   182  					resourceKeeper: &resourceKeeper{
   183  						Client: &test.MockClient{
   184  							MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
   185  								l, _ := list.(*v1beta1.ApplicationRevisionList)
   186  								l.Items = []v1beta1.ApplicationRevision{
   187  									{
   188  										ObjectMeta: metav1.ObjectMeta{
   189  											Name: "app-v1",
   190  										},
   191  									},
   192  									{
   193  										ObjectMeta: metav1.ObjectMeta{
   194  											Name: "app-v2",
   195  										},
   196  									},
   197  									{
   198  										ObjectMeta: metav1.ObjectMeta{
   199  											Name: "app-v3",
   200  										},
   201  									},
   202  								}
   203  								return nil
   204  							},
   205  							MockDelete: test.NewMockDeleteFn(errors.New("mock")),
   206  						},
   207  						app: &v1beta1.Application{
   208  							Status: apicommon.AppStatus{
   209  								LatestRevision: &apicommon.Revision{
   210  									Name: "app-v1",
   211  								},
   212  							},
   213  						},
   214  					},
   215  					cfg: &gcConfig{
   216  						disableApplicationRevisionGC: false,
   217  						appRevisionLimit:             1,
   218  					},
   219  				},
   220  			},
   221  			wantErr: true,
   222  		},
   223  	}
   224  	for _, tt := range tests {
   225  		t.Run(tt.name, func(t *testing.T) {
   226  			if err := cleanUpApplicationRevision(context.Background(), tt.args.h); (err != nil) != tt.wantErr {
   227  				t.Errorf("cleanUpApplicationRevision() error = %v, wantErr %v", err, tt.wantErr)
   228  			}
   229  		})
   230  	}
   231  }
   232  
   233  func Test_cleanUpWorkflowComponentRevision(t *testing.T) {
   234  	type args struct {
   235  		h *gcHandler
   236  	}
   237  	tests := []struct {
   238  		name    string
   239  		args    args
   240  		wantErr bool
   241  	}{
   242  		{
   243  			name: "clean up found revisions",
   244  			args: args{
   245  				h: &gcHandler{
   246  					resourceKeeper: &resourceKeeper{
   247  						_crRT: &v1beta1.ResourceTracker{},
   248  						Client: &test.MockClient{
   249  							MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
   250  								if key.Name == "revision3" {
   251  									return kerrors.NewNotFound(schema.GroupResource{}, "")
   252  								}
   253  								o, _ := obj.(*unstructured.Unstructured)
   254  								o.SetLabels(map[string]string{
   255  									oam.LabelAppComponentRevision: "revision1",
   256  								})
   257  								return nil
   258  							},
   259  							MockDelete: test.NewMockDeleteFn(nil),
   260  							MockUpdate: test.NewMockUpdateFn(nil),
   261  							MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
   262  								l, _ := list.(*appsv1.ControllerRevisionList)
   263  								l.Items = []appsv1.ControllerRevision{
   264  									{
   265  										ObjectMeta: metav1.ObjectMeta{Name: "revision1", Namespace: "default"},
   266  										Revision:   1,
   267  									},
   268  									{
   269  										ObjectMeta: metav1.ObjectMeta{Name: "revision2", Namespace: "default"},
   270  										Revision:   2,
   271  									},
   272  									{
   273  										ObjectMeta: metav1.ObjectMeta{Name: "revision3", Namespace: "default"},
   274  										Revision:   3,
   275  									},
   276  								}
   277  								return nil
   278  							},
   279  						},
   280  						app: &v1beta1.Application{
   281  							Status: apicommon.AppStatus{
   282  								AppliedResources: []apicommon.ClusterObjectReference{
   283  									{
   284  										ObjectReference: corev1.ObjectReference{
   285  											Namespace:  "default",
   286  											Name:       "revision1",
   287  											APIVersion: appsv1.SchemeGroupVersion.String(),
   288  											Kind:       "Deployment",
   289  										},
   290  									},
   291  									{
   292  										ObjectReference: corev1.ObjectReference{
   293  											Namespace:  "default",
   294  											Name:       "revision3",
   295  											APIVersion: appsv1.SchemeGroupVersion.String(),
   296  											Kind:       "Deployment",
   297  										},
   298  									},
   299  								},
   300  							},
   301  							ObjectMeta: metav1.ObjectMeta{}}},
   302  					cfg: &gcConfig{
   303  						disableComponentRevisionGC: false,
   304  						appRevisionLimit:           1,
   305  					},
   306  				},
   307  			},
   308  		},
   309  		{
   310  			name: "no need clean up",
   311  			args: args{
   312  				h: &gcHandler{
   313  					resourceKeeper: &resourceKeeper{
   314  						_crRT: &v1beta1.ResourceTracker{},
   315  						Client: &test.MockClient{
   316  							MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
   317  								o, _ := obj.(*unstructured.Unstructured)
   318  								o.SetLabels(map[string]string{
   319  									oam.LabelAppComponentRevision: "revision1",
   320  								})
   321  								return nil
   322  							},
   323  							MockDelete: test.NewMockDeleteFn(nil),
   324  							MockUpdate: test.NewMockUpdateFn(nil),
   325  							MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
   326  								l, _ := list.(*appsv1.ControllerRevisionList)
   327  								l.Items = []appsv1.ControllerRevision{
   328  									{
   329  										ObjectMeta: metav1.ObjectMeta{Name: "revision1", Namespace: "default"},
   330  										Revision:   1,
   331  									},
   332  								}
   333  								return nil
   334  							},
   335  						},
   336  						app: &v1beta1.Application{
   337  							Status: apicommon.AppStatus{
   338  								AppliedResources: []apicommon.ClusterObjectReference{
   339  									{},
   340  								},
   341  							},
   342  							ObjectMeta: metav1.ObjectMeta{}}},
   343  					cfg: &gcConfig{
   344  						disableComponentRevisionGC: false,
   345  						appRevisionLimit:           1,
   346  					},
   347  				},
   348  			},
   349  		},
   350  		{
   351  			name: "disabled",
   352  			args: args{
   353  				h: &gcHandler{
   354  					cfg: &gcConfig{
   355  						disableComponentRevisionGC: true,
   356  					},
   357  				},
   358  			},
   359  		},
   360  		{
   361  			name: "get failed",
   362  			args: args{
   363  				h: &gcHandler{
   364  					resourceKeeper: &resourceKeeper{
   365  						Client: &test.MockClient{
   366  							MockGet: test.NewMockGetFn(errors.New("mock")),
   367  						},
   368  						app: &v1beta1.Application{
   369  							Status: apicommon.AppStatus{
   370  								AppliedResources: []apicommon.ClusterObjectReference{
   371  									{},
   372  								},
   373  							},
   374  							ObjectMeta: metav1.ObjectMeta{}}},
   375  					cfg: &gcConfig{
   376  						disableComponentRevisionGC: false,
   377  						appRevisionLimit:           1,
   378  					},
   379  				},
   380  			},
   381  			wantErr: true,
   382  		},
   383  		{
   384  			name: "list failed",
   385  			args: args{
   386  				h: &gcHandler{
   387  					resourceKeeper: &resourceKeeper{
   388  						Client: &test.MockClient{
   389  							MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
   390  								o, _ := obj.(*unstructured.Unstructured)
   391  								o.SetLabels(map[string]string{
   392  									oam.LabelAppComponentRevision: "revision1",
   393  								})
   394  								return nil
   395  							},
   396  							MockList: test.NewMockListFn(errors.New("mock")),
   397  						},
   398  						app: &v1beta1.Application{
   399  							Status: apicommon.AppStatus{
   400  								AppliedResources: []apicommon.ClusterObjectReference{
   401  									{},
   402  								},
   403  							},
   404  							ObjectMeta: metav1.ObjectMeta{}}},
   405  					cfg: &gcConfig{
   406  						disableComponentRevisionGC: false,
   407  						appRevisionLimit:           1,
   408  					},
   409  				},
   410  			},
   411  			wantErr: true,
   412  		},
   413  		{
   414  			name: "deleteComponentRevision failed",
   415  			args: args{
   416  				h: &gcHandler{
   417  					resourceKeeper: &resourceKeeper{
   418  						_crRT: &v1beta1.ResourceTracker{},
   419  						Client: &test.MockClient{
   420  							MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
   421  								o, _ := obj.(*unstructured.Unstructured)
   422  								o.SetLabels(map[string]string{
   423  									oam.LabelAppComponentRevision: "revision1",
   424  								})
   425  								return nil
   426  							},
   427  							MockDelete: test.NewMockDeleteFn(errors.New("mock")),
   428  							MockUpdate: test.NewMockUpdateFn(nil),
   429  							MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
   430  								l, _ := list.(*appsv1.ControllerRevisionList)
   431  								l.Items = []appsv1.ControllerRevision{
   432  									{
   433  										ObjectMeta: metav1.ObjectMeta{Name: "revision1", Namespace: "default"},
   434  										Revision:   1,
   435  									},
   436  									{
   437  										ObjectMeta: metav1.ObjectMeta{Name: "revision2", Namespace: "default"},
   438  										Revision:   2,
   439  									},
   440  									{
   441  										ObjectMeta: metav1.ObjectMeta{Name: "revisio3", Namespace: "default"},
   442  										Revision:   3,
   443  									},
   444  								}
   445  								return nil
   446  							},
   447  						},
   448  						app: &v1beta1.Application{
   449  							Status: apicommon.AppStatus{
   450  								AppliedResources: []apicommon.ClusterObjectReference{
   451  									{},
   452  								},
   453  							},
   454  							ObjectMeta: metav1.ObjectMeta{}}},
   455  					cfg: &gcConfig{
   456  						disableComponentRevisionGC: false,
   457  						appRevisionLimit:           1,
   458  					},
   459  				},
   460  			},
   461  			wantErr: true,
   462  		},
   463  	}
   464  	for _, tt := range tests {
   465  		t.Run(tt.name, func(t *testing.T) {
   466  			if err := cleanUpComponentRevision(context.Background(), tt.args.h); (err != nil) != tt.wantErr {
   467  				t.Errorf("cleanUpWorkflowComponentRevision() error = %v, wantErr %v", err, tt.wantErr)
   468  			}
   469  		})
   470  	}
   471  }