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 }