From 120105a0a9b360fbdb3a64fdaef4c9d2162d7fb8 Mon Sep 17 00:00:00 2001 From: Omer Aplatony Date: Tue, 17 Dec 2024 07:30:51 +0200 Subject: [PATCH] kubectl: add test coverage for cordon command (#129202) * kubectl: add test coverage for cordon command Signed-off-by: Omer Aplatony * using cmp.Diff Signed-off-by: Omer Aplatony --------- Signed-off-by: Omer Aplatony Kubernetes-commit: 3ec97a445f036a38bfec6291dee661954138bac9 --- go.mod | 2 +- go.sum | 4 +- pkg/drain/cordon_test.go | 147 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 3 deletions(-) create mode 100644 pkg/drain/cordon_test.go diff --git a/go.mod b/go.mod index b99e298b5..a906f3721 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( k8s.io/api v0.0.0-20241214014715-eac45518d7fe k8s.io/apimachinery v0.0.0-20241214014415-767f17a6afea k8s.io/cli-runtime v0.0.0-20241214022530-e4532273187e - k8s.io/client-go v0.0.0-20241214015128-61ee2c5802c7 + k8s.io/client-go v0.0.0-20241215015103-67da6d1a4174 k8s.io/component-base v0.0.0-20241214020124-b7fbd0d55e44 k8s.io/component-helpers v0.0.0-20241214020249-81a0289f4873 k8s.io/klog/v2 v2.130.1 diff --git a/go.sum b/go.sum index 0b991848e..523bff453 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,8 @@ k8s.io/apimachinery v0.0.0-20241214014415-767f17a6afea h1:ZUHj/k511rdZLx69atS9F5 k8s.io/apimachinery v0.0.0-20241214014415-767f17a6afea/go.mod h1:vmecNW2HWfNZboIXS3Vg/3qp+T42YyW6jCpcdhnas9s= k8s.io/cli-runtime v0.0.0-20241214022530-e4532273187e h1:Ie/aQEIDo9fPuITJKm5xetW+8JGsD8Zvj7Zm63urQWw= k8s.io/cli-runtime v0.0.0-20241214022530-e4532273187e/go.mod h1:zBvvuqEnbfCG7dmlroXrfVhDrCGEtz7MfknRnmp8Kpg= -k8s.io/client-go v0.0.0-20241214015128-61ee2c5802c7 h1:W2NxcoEN3y/P48IBQdJgBj2nWlU+dyXvRQKjRYdV6y8= -k8s.io/client-go v0.0.0-20241214015128-61ee2c5802c7/go.mod h1:9DOj9Eg/2wdCibOBBR8J+SamkzoU+TVr9bk5B7KAbgM= +k8s.io/client-go v0.0.0-20241215015103-67da6d1a4174 h1:NcD7ZRs38+ChK6qTJN5ahkVq7MWuNaZZiO1AspZLwck= +k8s.io/client-go v0.0.0-20241215015103-67da6d1a4174/go.mod h1:9DOj9Eg/2wdCibOBBR8J+SamkzoU+TVr9bk5B7KAbgM= k8s.io/component-base v0.0.0-20241214020124-b7fbd0d55e44 h1:UGwTOasY4f/2bmwNlInBJjkhZw3lWGy+gk+w5tQOAvc= k8s.io/component-base v0.0.0-20241214020124-b7fbd0d55e44/go.mod h1:u4F22/ZnzBZX8Sw10wXHts7D9Ak81nBSrbdckaDcvjE= k8s.io/component-helpers v0.0.0-20241214020249-81a0289f4873 h1:xoV3np7eRxerPwLtt56i6mpBTXVDQa1HLMZFJINO9Cc= diff --git a/pkg/drain/cordon_test.go b/pkg/drain/cordon_test.go new file mode 100644 index 000000000..f584f564f --- /dev/null +++ b/pkg/drain/cordon_test.go @@ -0,0 +1,147 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package drain + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +type newCordonHelperFromRuntimeObjectTestCase struct { + name string + nodeObject runtime.Object + expectError bool + expected *CordonHelper +} + +func TestNewCordonHelperFromRuntimeObject(t *testing.T) { + tests := []newCordonHelperFromRuntimeObjectTestCase{ + { + name: "valid node object", + nodeObject: &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + }, + }, + expectError: false, + expected: &CordonHelper{ + node: &corev1.Node{ + TypeMeta: metav1.TypeMeta{ + Kind: "Node", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + }, + }, + }, + }, + { + name: "invalid object type", + nodeObject: &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + }, + }, + expectError: true, + expected: nil, + }, + } + scheme := runtime.NewScheme() + _ = corev1.AddToScheme(scheme) + gvk := schema.GroupVersionKind{ + Group: "", + Version: "v1", + Kind: "Node", + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + helper, err := NewCordonHelperFromRuntimeObject(tt.nodeObject, scheme, gvk) + if tt.expectError && err == nil { + t.Error("Expected error but got none") + } + if !tt.expectError && err != nil { + t.Errorf("Unexpected error: %v", err) + } + if !tt.expectError && helper == nil { + t.Error("Expected non-nil helper") + } + if tt.expected != nil && helper != nil { + if diff := cmp.Diff(tt.expected.node, helper.node); diff != "" { + t.Errorf("Node mismatch (-want +got):\n%s", diff) + } + } + }) + } +} + +type updateIfRequiredTestCase struct { + name string + currentState bool + desiredState bool + expectUpdated bool +} + +func TestUpdateIfRequired(t *testing.T) { + tests := []updateIfRequiredTestCase{ + { + name: "no change required", + currentState: true, + desiredState: true, + expectUpdated: false, + }, + { + name: "update required - cordon", + currentState: false, + desiredState: true, + expectUpdated: true, + }, + { + name: "update required - uncordon", + currentState: true, + desiredState: false, + expectUpdated: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node := &corev1.Node{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-node", + }, + Spec: corev1.NodeSpec{ + Unschedulable: tt.currentState, + }, + } + + helper := NewCordonHelper(node) + updated := helper.UpdateIfRequired(tt.desiredState) + if updated != tt.expectUpdated { + t.Errorf("Expected UpdateIfRequired to return %v, got %v", tt.expectUpdated, updated) + } + if helper.desired != tt.desiredState { + t.Errorf("Expected desired state to be %v, got %v", tt.desiredState, helper.desired) + } + }) + } +}