Skip to content

Commit dbaa9fe

Browse files
committed
added podgc orphaned pod unit tests
1 parent 8c1dc65 commit dbaa9fe

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

pkg/controller/podgc/gc_controller_test.go

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@ package podgc
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"testing"
2223
"time"
2324

2425
"github.com/google/go-cmp/cmp"
26+
"github.com/google/go-cmp/cmp/cmpopts"
27+
2528
v1 "k8s.io/api/core/v1"
2629
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2730
"k8s.io/apimachinery/pkg/labels"
2831
"k8s.io/apimachinery/pkg/util/sets"
32+
"k8s.io/apimachinery/pkg/util/strategicpatch"
2933
"k8s.io/apimachinery/pkg/util/wait"
3034
utilfeature "k8s.io/apiserver/pkg/util/feature"
3135
"k8s.io/client-go/informers"
@@ -43,6 +47,7 @@ import (
4347
"k8s.io/kubernetes/pkg/features"
4448
"k8s.io/kubernetes/pkg/kubelet/eviction"
4549
testingclock "k8s.io/utils/clock/testing"
50+
"k8s.io/utils/pointer"
4651
)
4752

4853
func alwaysReady() bool { return true }
@@ -671,6 +676,128 @@ func TestGCTerminating(t *testing.T) {
671676
testDeletingPodsMetrics(t, 7, metrics.PodGCReasonTerminatingOutOfService)
672677
}
673678

679+
func TestGCInspectingPatchedPodBeforeDeletion(t *testing.T) {
680+
testCases := []struct {
681+
name string
682+
pod *v1.Pod
683+
expectedPatchedPod *v1.Pod
684+
expectedDeleteAction *clienttesting.DeleteActionImpl
685+
}{
686+
{
687+
name: "orphaned pod should have DisruptionTarget condition added before deletion",
688+
pod: &v1.Pod{
689+
ObjectMeta: metav1.ObjectMeta{
690+
Namespace: "default",
691+
Name: "testPod",
692+
},
693+
Spec: v1.PodSpec{
694+
NodeName: "deletedNode",
695+
},
696+
Status: v1.PodStatus{
697+
Phase: v1.PodRunning,
698+
Conditions: []v1.PodCondition{
699+
{
700+
Type: v1.PodReady,
701+
Status: v1.ConditionTrue,
702+
},
703+
},
704+
},
705+
},
706+
expectedPatchedPod: &v1.Pod{
707+
ObjectMeta: metav1.ObjectMeta{
708+
Namespace: "default",
709+
Name: "testPod",
710+
},
711+
Spec: v1.PodSpec{
712+
NodeName: "deletedNode",
713+
},
714+
Status: v1.PodStatus{
715+
Phase: v1.PodFailed,
716+
Conditions: []v1.PodCondition{
717+
{
718+
Type: v1.DisruptionTarget,
719+
Status: v1.ConditionTrue,
720+
Reason: "DeletionByPodGC",
721+
Message: "PodGC: node no longer exists",
722+
},
723+
{
724+
Type: v1.PodReady,
725+
Status: v1.ConditionTrue,
726+
},
727+
},
728+
},
729+
},
730+
expectedDeleteAction: &clienttesting.DeleteActionImpl{
731+
Name: "testPod",
732+
DeleteOptions: metav1.DeleteOptions{GracePeriodSeconds: pointer.Int64(0)},
733+
},
734+
},
735+
}
736+
737+
for _, test := range testCases {
738+
t.Run(test.name, func(t *testing.T) {
739+
_, ctx := ktesting.NewTestContext(t)
740+
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodDisruptionConditions, true)()
741+
742+
pods := []*v1.Pod{test.pod}
743+
744+
client := setupNewSimpleClient(nil, pods)
745+
gcc, podInformer, _ := NewFromClient(ctx, client, -1)
746+
gcc.quarantineTime = time.Duration(-1)
747+
podInformer.Informer().GetStore().Add(test.pod)
748+
gcc.gc(ctx)
749+
750+
actions := client.Actions()
751+
752+
var patchAction clienttesting.PatchAction
753+
var deleteAction clienttesting.DeleteAction
754+
755+
for _, action := range actions {
756+
if action.GetVerb() == "patch" {
757+
patchAction = action.(clienttesting.PatchAction)
758+
}
759+
760+
if action.GetVerb() == "delete" {
761+
deleteAction = action.(clienttesting.DeleteAction)
762+
}
763+
}
764+
765+
if patchAction != nil && test.expectedPatchedPod == nil {
766+
t.Fatalf("Pod was pactched but expectedPatchedPod is nil")
767+
}
768+
if test.expectedPatchedPod != nil {
769+
patchedPodBytes := patchAction.GetPatch()
770+
originalPod, err := json.Marshal(test.pod)
771+
if err != nil {
772+
t.Fatalf("Failed to marshal original pod %#v: %v", originalPod, err)
773+
}
774+
updated, err := strategicpatch.StrategicMergePatch(originalPod, patchedPodBytes, v1.Pod{})
775+
if err != nil {
776+
t.Fatalf("Failed to apply strategic merge patch %q on pod %#v: %v", patchedPodBytes, originalPod, err)
777+
}
778+
779+
updatedPod := &v1.Pod{}
780+
if err := json.Unmarshal(updated, updatedPod); err != nil {
781+
t.Fatalf("Failed to unmarshal updated pod %q: %v", updated, err)
782+
}
783+
784+
if diff := cmp.Diff(test.expectedPatchedPod, updatedPod, cmpopts.IgnoreFields(v1.Pod{}, "TypeMeta"), cmpopts.IgnoreFields(v1.PodCondition{}, "LastTransitionTime")); diff != "" {
785+
t.Fatalf("Unexpected diff on pod (-want,+got):\n%s", diff)
786+
}
787+
}
788+
789+
if deleteAction != nil && test.expectedDeleteAction == nil {
790+
t.Fatalf("Pod was deleted but expectedDeleteAction is nil")
791+
}
792+
if test.expectedDeleteAction != nil {
793+
if diff := cmp.Diff(*test.expectedDeleteAction, deleteAction, cmpopts.IgnoreFields(clienttesting.DeleteActionImpl{}, "ActionImpl")); diff != "" {
794+
t.Fatalf("Unexpected diff on deleteAction (-want,+got):\n%s", diff)
795+
}
796+
}
797+
})
798+
}
799+
}
800+
674801
func verifyDeletedAndPatchedPods(t *testing.T, client *fake.Clientset, wantDeletedPodNames, wantPatchedPodNames sets.String) {
675802
t.Helper()
676803
deletedPodNames := getDeletedPodNames(client)

0 commit comments

Comments
 (0)