From d535f55ef9dd391712db09ac69dd083089457366 Mon Sep 17 00:00:00 2001 From: Lukasz Szaszkiewicz Date: Thu, 6 Jun 2024 14:14:33 +0200 Subject: [PATCH 1/2] client-go/consistencydetector: refactor TestDataConsistencyChecker to work with unstructured data --- .../data_consistency_detector_test.go | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go b/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go index 59682a68abc..f4165fe889b 100644 --- a/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go +++ b/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go @@ -34,22 +34,24 @@ func TestDataConsistencyChecker(t *testing.T) { scenarios := []struct { name string - listResponse *v1.PodList - retrievedItems []*v1.Pod - requestOptions metav1.ListOptions + lastSyncedResourceVersion string + listResponse runtime.Object + retrievedItems []runtime.Object + requestOptions metav1.ListOptions expectedRequestOptions []metav1.ListOptions expectedListRequests int expectPanic bool }{ { - name: "data consistency check won't panic when data is consistent", + name: "data consistency check won't panic when data is consistent", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2")}, }, requestOptions: metav1.ListOptions{TimeoutSeconds: ptr.To(int64(39))}, - retrievedItems: []*v1.Pod{makePod("p1", "1"), makePod("p2", "2")}, + retrievedItems: []runtime.Object{makePod("p1", "1"), makePod("p2", "2")}, expectedListRequests: 1, expectedRequestOptions: []metav1.ListOptions{ { @@ -61,13 +63,14 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "legacy, the limit is removed from the list options when it wasn't honored by the watch cache", + name: "legacy, the limit is removed from the list options when it wasn't honored by the watch cache", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2"), *makePod("p3", "3")}, }, requestOptions: metav1.ListOptions{ResourceVersion: "0", Limit: 2}, - retrievedItems: []*v1.Pod{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, + retrievedItems: []runtime.Object{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, expectedListRequests: 1, expectedRequestOptions: []metav1.ListOptions{ { @@ -78,13 +81,14 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "the limit is NOT removed from the list options for non-legacy request", + name: "the limit is NOT removed from the list options for non-legacy request", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2"), *makePod("p3", "3")}, }, requestOptions: metav1.ListOptions{ResourceVersion: "2", Limit: 2}, - retrievedItems: []*v1.Pod{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, + retrievedItems: []runtime.Object{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, expectedListRequests: 1, expectedRequestOptions: []metav1.ListOptions{ { @@ -96,13 +100,14 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "legacy, the limit is NOT removed from the list options when the watch cache is disabled", + name: "legacy, the limit is NOT removed from the list options when the watch cache is disabled", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2"), *makePod("p3", "3")}, }, requestOptions: metav1.ListOptions{ResourceVersion: "0", Limit: 5}, - retrievedItems: []*v1.Pod{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, + retrievedItems: []runtime.Object{makePod("p1", "1"), makePod("p2", "2"), makePod("p3", "3")}, expectedListRequests: 1, expectedRequestOptions: []metav1.ListOptions{ { @@ -114,7 +119,8 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "data consistency check won't panic when there is no data", + name: "data consistency check won't panic when there is no data", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, }, @@ -136,7 +142,8 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "data consistency check won't be performed when ResourceVersion was set to 0", + name: "data consistency check won't be performed when ResourceVersion was set to 0", + lastSyncedResourceVersion: "0", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "0"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2")}, @@ -146,13 +153,14 @@ func TestDataConsistencyChecker(t *testing.T) { }, { - name: "data consistency panics when data is inconsistent", + name: "data consistency panics when data is inconsistent", + lastSyncedResourceVersion: "2", listResponse: &v1.PodList{ ListMeta: metav1.ListMeta{ResourceVersion: "2"}, Items: []v1.Pod{*makePod("p1", "1"), *makePod("p2", "2"), *makePod("p3", "3")}, }, requestOptions: metav1.ListOptions{TimeoutSeconds: ptr.To(int64(39))}, - retrievedItems: []*v1.Pod{makePod("p1", "1"), makePod("p2", "2")}, + retrievedItems: []runtime.Object{makePod("p1", "1"), makePod("p2", "2")}, expectedListRequests: 1, expectedRequestOptions: []metav1.ListOptions{ { @@ -172,16 +180,16 @@ func TestDataConsistencyChecker(t *testing.T) { scenario.listResponse = &v1.PodList{} } fakeLister := &listWrapper{response: scenario.listResponse} - retrievedItemsFunc := func() []*v1.Pod { + retrievedItemsFunc := func() []runtime.Object { return scenario.retrievedItems } if scenario.expectPanic { require.Panics(t, func() { - CheckDataConsistency(ctx, "", scenario.listResponse.ResourceVersion, fakeLister.List, scenario.requestOptions, retrievedItemsFunc) + CheckDataConsistency(ctx, "", scenario.lastSyncedResourceVersion, fakeLister.List, scenario.requestOptions, retrievedItemsFunc) }) } else { - CheckDataConsistency(ctx, "", scenario.listResponse.ResourceVersion, fakeLister.List, scenario.requestOptions, retrievedItemsFunc) + CheckDataConsistency(ctx, "", scenario.lastSyncedResourceVersion, fakeLister.List, scenario.requestOptions, retrievedItemsFunc) } require.Equal(t, fakeLister.counter, scenario.expectedListRequests) @@ -218,10 +226,10 @@ func (lw *errorLister) List(_ context.Context, _ metav1.ListOptions) (runtime.Ob type listWrapper struct { counter int requestOptions []metav1.ListOptions - response *v1.PodList + response runtime.Object } -func (lw *listWrapper) List(_ context.Context, opts metav1.ListOptions) (*v1.PodList, error) { +func (lw *listWrapper) List(_ context.Context, opts metav1.ListOptions) (runtime.Object, error) { lw.counter++ lw.requestOptions = append(lw.requestOptions, opts) return lw.response, nil From c8971c456f23627a91dc79bb8bc840a32dea611f Mon Sep 17 00:00:00 2001 From: Lukasz Szaszkiewicz Date: Fri, 7 Jun 2024 10:33:11 +0200 Subject: [PATCH 2/2] client-go/consistencydetector: extend TestDataConsistencyChecker to test unstructured data --- .../data_consistency_detector_test.go | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go b/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go index f4165fe889b..300e8d9ea09 100644 --- a/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go +++ b/staging/src/k8s.io/client-go/util/consistencydetector/data_consistency_detector_test.go @@ -25,6 +25,7 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" @@ -62,6 +63,34 @@ func TestDataConsistencyChecker(t *testing.T) { }, }, + { + name: "data consistency check works with unstructured data (dynamic client)", + lastSyncedResourceVersion: "2", + listResponse: &unstructured.UnstructuredList{ + Object: map[string]interface{}{ + "apiVersion": "vTest", + "kind": "rTestList", + }, + Items: []unstructured.Unstructured{ + *makeUnstructuredObject("vTest", "rTest", "item1"), + *makeUnstructuredObject("vTest", "rTest", "item2"), + }, + }, + requestOptions: metav1.ListOptions{TimeoutSeconds: ptr.To(int64(39))}, + retrievedItems: []runtime.Object{ + makeUnstructuredObject("vTest", "rTest", "item1"), + makeUnstructuredObject("vTest", "rTest", "item2"), + }, + expectedListRequests: 1, + expectedRequestOptions: []metav1.ListOptions{ + { + ResourceVersion: "2", + ResourceVersionMatch: metav1.ResourceVersionMatchExact, + TimeoutSeconds: ptr.To(int64(39)), + }, + }, + }, + { name: "legacy, the limit is removed from the list options when it wasn't honored by the watch cache", lastSyncedResourceVersion: "2", @@ -238,3 +267,15 @@ func (lw *listWrapper) List(_ context.Context, opts metav1.ListOptions) (runtime func makePod(name, rv string) *v1.Pod { return &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: name, ResourceVersion: rv, UID: types.UID(name)}} } + +func makeUnstructuredObject(version, kind, name string) *unstructured.Unstructured { + return &unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": version, + "kind": kind, + "metadata": map[string]interface{}{ + "name": name, + }, + }, + } +}