mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 11:28:58 +00:00
test: add unit tests for deleteObject NotFound handling in garbage collector
When deleteObject returns a NotFound error (the object was externally deleted between the GET and the DELETE), attemptToDeleteItem should enqueue a virtual delete event and return enqueuedVirtualDeleteEventErr. Cover both code paths: - default (background propagation): item with dangling owner - waitingForDependentsDeletion: item whose owner is foreground-deleting
This commit is contained in:
@@ -627,7 +627,6 @@ func (gc *GarbageCollector) attemptToDeleteItem(ctx context.Context, item *node)
|
||||
policy := metav1.DeletePropagationForeground
|
||||
err := gc.deleteObject(item.identity, latest.ResourceVersion, latest.OwnerReferences, &policy)
|
||||
if errors.IsNotFound(err) {
|
||||
// the item was deleted externally, enqueue a virtual delete event
|
||||
gc.dependencyGraphBuilder.enqueueVirtualDeleteEvent(item.identity)
|
||||
return enqueuedVirtualDeleteEventErr
|
||||
}
|
||||
@@ -654,7 +653,6 @@ func (gc *GarbageCollector) attemptToDeleteItem(ctx context.Context, item *node)
|
||||
)
|
||||
err := gc.deleteObject(item.identity, latest.ResourceVersion, latest.OwnerReferences, &policy)
|
||||
if errors.IsNotFound(err) {
|
||||
// the item was deleted externally, enqueue a virtual delete event
|
||||
gc.dependencyGraphBuilder.enqueueVirtualDeleteEvent(item.identity)
|
||||
return enqueuedVirtualDeleteEventErr
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package garbagecollector
|
||||
|
||||
import (
|
||||
"context"
|
||||
goerrors "errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -255,6 +256,126 @@ func serilizeOrDie(t *testing.T, object interface{}) []byte {
|
||||
return data
|
||||
}
|
||||
|
||||
func TestAttemptToDeleteItemDeleteObjectNotFound(t *testing.T) {
|
||||
pod := getPod("ExternallyDeletedPod", []metav1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "owner1",
|
||||
UID: "123",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
})
|
||||
testHandler := &fakeActionHandler{
|
||||
response: map[string]FakeResponse{
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/owner1": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPod": {
|
||||
200,
|
||||
serilizeOrDie(t, pod),
|
||||
},
|
||||
"DELETE" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPod": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
},
|
||||
}
|
||||
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
|
||||
defer srv.Close()
|
||||
|
||||
gc := setupGC(t, clientConfig)
|
||||
defer close(gc.stop)
|
||||
|
||||
item := &node{
|
||||
identity: objectReference{
|
||||
OwnerReference: metav1.OwnerReference{
|
||||
Kind: pod.Kind,
|
||||
APIVersion: pod.APIVersion,
|
||||
Name: pod.Name,
|
||||
UID: pod.UID,
|
||||
},
|
||||
Namespace: pod.Namespace,
|
||||
},
|
||||
owners: nil,
|
||||
}
|
||||
|
||||
err := gc.attemptToDeleteItem(context.TODO(), item)
|
||||
if !goerrors.Is(err, enqueuedVirtualDeleteEventErr) {
|
||||
t.Errorf("expected enqueuedVirtualDeleteEventErr, got: %v", err)
|
||||
}
|
||||
if gc.dependencyGraphBuilder.graphChanges.Len() == 0 {
|
||||
t.Errorf("expected a virtual delete event to be enqueued in graphChanges, but the queue is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttemptToDeleteItemDeleteObjectNotFoundWaitingForDependents(t *testing.T) {
|
||||
pod := getPod("ExternallyDeletedPodFG", []metav1.OwnerReference{
|
||||
{
|
||||
Kind: "ReplicationController",
|
||||
Name: "owner1",
|
||||
UID: "123",
|
||||
APIVersion: "v1",
|
||||
BlockOwnerDeletion: func() *bool { b := true; return &b }(),
|
||||
},
|
||||
})
|
||||
owner := &v1.ReplicationController{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ReplicationController",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "owner1",
|
||||
Namespace: "ns1",
|
||||
UID: "123",
|
||||
DeletionTimestamp: func() *metav1.Time { t := metav1.Now(); return &t }(),
|
||||
Finalizers: []string{metav1.FinalizerDeleteDependents},
|
||||
},
|
||||
}
|
||||
testHandler := &fakeActionHandler{
|
||||
response: map[string]FakeResponse{
|
||||
"GET" + "/api/v1/namespaces/ns1/replicationcontrollers/owner1": {
|
||||
200,
|
||||
serilizeOrDie(t, owner),
|
||||
},
|
||||
"GET" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPodFG": {
|
||||
200,
|
||||
serilizeOrDie(t, pod),
|
||||
},
|
||||
"DELETE" + "/api/v1/namespaces/ns1/pods/ExternallyDeletedPodFG": {
|
||||
404,
|
||||
[]byte{},
|
||||
},
|
||||
},
|
||||
}
|
||||
srv, clientConfig := testServerAndClientConfig(testHandler.ServeHTTP)
|
||||
defer srv.Close()
|
||||
|
||||
gc := setupGC(t, clientConfig)
|
||||
defer close(gc.stop)
|
||||
|
||||
item := &node{
|
||||
identity: objectReference{
|
||||
OwnerReference: metav1.OwnerReference{
|
||||
Kind: pod.Kind,
|
||||
APIVersion: pod.APIVersion,
|
||||
Name: pod.Name,
|
||||
UID: pod.UID,
|
||||
},
|
||||
Namespace: pod.Namespace,
|
||||
},
|
||||
owners: nil,
|
||||
}
|
||||
|
||||
err := gc.attemptToDeleteItem(context.TODO(), item)
|
||||
if !goerrors.Is(err, enqueuedVirtualDeleteEventErr) {
|
||||
t.Errorf("expected enqueuedVirtualDeleteEventErr, got: %v", err)
|
||||
}
|
||||
if gc.dependencyGraphBuilder.graphChanges.Len() == 0 {
|
||||
t.Errorf("expected a virtual delete event to be enqueued in graphChanges, but the queue is empty")
|
||||
}
|
||||
}
|
||||
|
||||
// test the attemptToDeleteItem function making the expected actions.
|
||||
func TestAttemptToDeleteItem(t *testing.T) {
|
||||
pod := getPod("ToBeDeletedPod", []metav1.OwnerReference{
|
||||
|
||||
Reference in New Issue
Block a user