Merge pull request #113588 from wojtek-t/generalize_cacher_tests_1

Reuse generic GetListNonRecursive test for watchcache
This commit is contained in:
Kubernetes Prow Robot 2022-11-05 14:56:25 -07:00 committed by GitHub
commit 1f9e20eb86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 145 additions and 182 deletions

View File

@ -85,12 +85,12 @@ func RunTestCreateWithTTL(ctx context.Context, t *testing.T, store storage.Inter
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckEventType(t, watch.Deleted, w) testCheckEventType(t, watch.Deleted, w)
} }
func RunTestCreateWithKeyExist(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestCreateWithKeyExist(ctx context.Context, t *testing.T, store storage.Interface) {
obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
key, _ := TestPropagateStore(ctx, t, store, obj) key, _ := testPropagateStore(ctx, t, store, obj)
out := &example.Pod{} out := &example.Pod{}
err := store.Create(ctx, key, obj, out, 0) err := store.Create(ctx, key, obj, out, 0)
if err == nil || !storage.IsExist(err) { if err == nil || !storage.IsExist(err) {
@ -100,7 +100,7 @@ func RunTestCreateWithKeyExist(ctx context.Context, t *testing.T, store storage.
func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
// create an object to test // create an object to test
key, createdObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, createdObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
// update the object once to allow get by exact resource version to be tested // update the object once to allow get by exact resource version to be tested
updateObj := createdObj.DeepCopy() updateObj := createdObj.DeepCopy()
updateObj.Annotations = map[string]string{"test-annotation": "1"} updateObj.Annotations = map[string]string{"test-annotation": "1"}
@ -129,14 +129,15 @@ func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
ignoreNotFound bool ignoreNotFound bool
expectNotFoundErr bool expectNotFoundErr bool
expectRVTooLarge bool expectRVTooLarge bool
expectedOut []*example.Pod expectedOut *example.Pod
expectedAlternatives []*example.Pod
rv string rv string
}{{ }{{
name: "get existing", name: "get existing",
key: key, key: key,
ignoreNotFound: false, ignoreNotFound: false,
expectNotFoundErr: false, expectNotFoundErr: false,
expectedOut: []*example.Pod{storedObj}, expectedOut: storedObj,
}, { }, {
// For RV=0 arbitrarily old version is allowed, including from the moment // For RV=0 arbitrarily old version is allowed, including from the moment
// when the object didn't yet exist. // when the object didn't yet exist.
@ -145,24 +146,24 @@ func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
name: "resource version 0", name: "resource version 0",
key: key, key: key,
ignoreNotFound: true, ignoreNotFound: true,
expectedOut: []*example.Pod{{}, createdObj, storedObj}, expectedAlternatives: []*example.Pod{{}, createdObj, storedObj},
rv: "0", rv: "0",
}, { }, {
// Given that Get with set ResourceVersion is effectively always // Given that Get with set ResourceVersion is effectively always
// NotOlderThan semantic, both versions of object are allowed. // NotOlderThan semantic, both versions of object are allowed.
name: "object created resource version", name: "object created resource version",
key: key, key: key,
expectedOut: []*example.Pod{createdObj, storedObj}, expectedAlternatives: []*example.Pod{createdObj, storedObj},
rv: createdObj.ResourceVersion, rv: createdObj.ResourceVersion,
}, { }, {
name: "current object resource version, match=NotOlderThan", name: "current object resource version, match=NotOlderThan",
key: key, key: key,
expectedOut: []*example.Pod{storedObj}, expectedOut: storedObj,
rv: fmt.Sprintf("%d", currentRV), rv: fmt.Sprintf("%d", currentRV),
}, { }, {
name: "latest resource version", name: "latest resource version",
key: key, key: key,
expectedOut: []*example.Pod{storedObj}, expectedOut: storedObj,
rv: fmt.Sprintf("%d", lastUpdatedCurrentRV), rv: fmt.Sprintf("%d", lastUpdatedCurrentRV),
}, { }, {
name: "too high resource version", name: "too high resource version",
@ -179,11 +180,14 @@ func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
key: "/non-existing", key: "/non-existing",
ignoreNotFound: true, ignoreNotFound: true,
expectNotFoundErr: false, expectNotFoundErr: false,
expectedOut: []*example.Pod{{}}, expectedOut: &example.Pod{},
}} }}
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
out := &example.Pod{} out := &example.Pod{}
err := store.Get(ctx, tt.key, storage.GetOptions{IgnoreNotFound: tt.ignoreNotFound, ResourceVersion: tt.rv}, out) err := store.Get(ctx, tt.key, storage.GetOptions{IgnoreNotFound: tt.ignoreNotFound, ResourceVersion: tt.rv}, out)
if tt.expectNotFoundErr { if tt.expectNotFoundErr {
@ -202,8 +206,8 @@ func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
t.Fatalf("Get failed: %v", err) t.Fatalf("Get failed: %v", err)
} }
if len(tt.expectedOut) == 1 { if tt.expectedAlternatives == nil {
ExpectNoDiff(t, fmt.Sprintf("%s: incorrect pod", tt.name), tt.expectedOut[0], out) ExpectNoDiff(t, fmt.Sprintf("%s: incorrect pod", tt.name), tt.expectedOut, out)
} else { } else {
toInterfaceSlice := func(pods []*example.Pod) []interface{} { toInterfaceSlice := func(pods []*example.Pod) []interface{} {
result := make([]interface{}, 0, len(pods)) result := make([]interface{}, 0, len(pods))
@ -212,14 +216,14 @@ func RunTestGet(ctx context.Context, t *testing.T, store storage.Interface) {
} }
return result return result
} }
ExpectContains(t, fmt.Sprintf("%s: incorrect pod", tt.name), toInterfaceSlice(tt.expectedOut), out) ExpectContains(t, fmt.Sprintf("%s: incorrect pod", tt.name), toInterfaceSlice(tt.expectedAlternatives), out)
} }
}) })
} }
} }
func RunTestUnconditionalDelete(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestUnconditionalDelete(ctx context.Context, t *testing.T, store storage.Interface) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
tests := []struct { tests := []struct {
name string name string
@ -263,7 +267,7 @@ func RunTestUnconditionalDelete(ctx context.Context, t *testing.T, store storage
} }
func RunTestConditionalDelete(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestConditionalDelete(ctx context.Context, t *testing.T, store storage.Interface) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}})
tests := []struct { tests := []struct {
name string name string
@ -299,7 +303,7 @@ func RunTestConditionalDelete(ctx context.Context, t *testing.T, store storage.I
} }
out.ResourceVersion = storedObj.ResourceVersion out.ResourceVersion = storedObj.ResourceVersion
ExpectNoDiff(t, "incorrect pod:", storedObj, out) ExpectNoDiff(t, "incorrect pod:", storedObj, out)
key, storedObj = TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}}) key, storedObj = testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}})
}) })
} }
} }
@ -330,7 +334,7 @@ func RunTestConditionalDelete(ctx context.Context, t *testing.T, store storage.I
// [DONE] Added TestPreconditionalDeleteWithSuggestion // [DONE] Added TestPreconditionalDeleteWithSuggestion
func RunTestDeleteWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestDeleteWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}})
out := &example.Pod{} out := &example.Pod{}
if err := store.Delete(ctx, key, out, nil, storage.ValidateAllObjectFunc, originalPod); err != nil { if err := store.Delete(ctx, key, out, nil, storage.ValidateAllObjectFunc, originalPod); err != nil {
@ -343,7 +347,7 @@ func RunTestDeleteWithSuggestion(ctx context.Context, t *testing.T, store storag
} }
func RunTestDeleteWithSuggestionAndConflict(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestDeleteWithSuggestionAndConflict(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}})
// First update, so originalPod is outdated. // First update, so originalPod is outdated.
updatedPod := &example.Pod{} updatedPod := &example.Pod{}
@ -367,7 +371,7 @@ func RunTestDeleteWithSuggestionAndConflict(ctx context.Context, t *testing.T, s
} }
func RunTestDeleteWithSuggestionOfDeletedObject(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestDeleteWithSuggestionOfDeletedObject(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}})
// First delete, so originalPod is outdated. // First delete, so originalPod is outdated.
deletedPod := &example.Pod{} deletedPod := &example.Pod{}
@ -383,7 +387,7 @@ func RunTestDeleteWithSuggestionOfDeletedObject(ctx context.Context, t *testing.
} }
func RunTestValidateDeletionWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestValidateDeletionWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}})
// Check that validaing fresh object fails is called once and fails. // Check that validaing fresh object fails is called once and fails.
validationCalls := 0 validationCalls := 0
@ -435,7 +439,7 @@ func RunTestValidateDeletionWithSuggestion(ctx context.Context, t *testing.T, st
} }
func RunTestPreconditionalDeleteWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestPreconditionalDeleteWithSuggestion(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "name"}})
// First update, so originalPod is outdated. // First update, so originalPod is outdated.
updatedPod := &example.Pod{} updatedPod := &example.Pod{}
@ -673,7 +677,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface) {
expectContinue: true, expectContinue: true,
expectedRemainingItemCount: utilpointer.Int64Ptr(1), expectedRemainingItemCount: utilpointer.Int64Ptr(1),
rv: "0", rv: "0",
expectRVFunc: ResourceVersionNotOlderThan(list.ResourceVersion), expectRVFunc: resourceVersionNotOlderThan(list.ResourceVersion),
}, },
{ {
name: "test List with limit at resource version 0 match=NotOlderThan", name: "test List with limit at resource version 0 match=NotOlderThan",
@ -688,7 +692,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface) {
expectedRemainingItemCount: utilpointer.Int64Ptr(1), expectedRemainingItemCount: utilpointer.Int64Ptr(1),
rv: "0", rv: "0",
rvMatch: metav1.ResourceVersionMatchNotOlderThan, rvMatch: metav1.ResourceVersionMatchNotOlderThan,
expectRVFunc: ResourceVersionNotOlderThan(list.ResourceVersion), expectRVFunc: resourceVersionNotOlderThan(list.ResourceVersion),
}, },
{ {
name: "test List with limit at resource version before first write and match=Exact", name: "test List with limit at resource version before first write and match=Exact",
@ -795,7 +799,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface) {
Field: fields.OneTermEqualSelector("metadata.name", "bar"), Field: fields.OneTermEqualSelector("metadata.name", "bar"),
Label: labels.Everything(), Label: labels.Everything(),
Limit: 2, Limit: 2,
Continue: EncodeContinueOrDie("z-level/3", int64(continueRV)), Continue: encodeContinueOrDie("z-level/3", int64(continueRV)),
}, },
expectedOut: []*example.Pod{preset[4]}, expectedOut: []*example.Pod{preset[4]},
}, },
@ -806,7 +810,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface) {
Field: fields.OneTermEqualSelector("metadata.name", "bar"), Field: fields.OneTermEqualSelector("metadata.name", "bar"),
Label: labels.Everything(), Label: labels.Everything(),
Limit: 1, Limit: 1,
Continue: EncodeContinueOrDie("z-level/3/test-2", int64(continueRV)), Continue: encodeContinueOrDie("z-level/3/test-2", int64(continueRV)),
}, },
expectedOut: []*example.Pod{preset[4]}, expectedOut: []*example.Pod{preset[4]},
}, },
@ -817,7 +821,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface) {
Field: fields.OneTermEqualSelector("metadata.name", "bar"), Field: fields.OneTermEqualSelector("metadata.name", "bar"),
Label: labels.Everything(), Label: labels.Everything(),
Limit: 2, Limit: 2,
Continue: EncodeContinueOrDie("z-level/3/test-2", int64(continueRV)), Continue: encodeContinueOrDie("z-level/3/test-2", int64(continueRV)),
}, },
expectedOut: []*example.Pod{preset[4]}, expectedOut: []*example.Pod{preset[4]},
}, },
@ -1048,17 +1052,26 @@ func seedMultiLevelData(ctx context.Context, store storage.Interface) (string, [
} }
func RunTestGetListNonRecursive(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestGetListNonRecursive(ctx context.Context, t *testing.T, store storage.Interface) {
prevKey, prevStoredObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "prev"}}) key, prevStoredObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
prevRV, _ := strconv.Atoi(prevStoredObj.ResourceVersion) prevRV, _ := strconv.Atoi(prevStoredObj.ResourceVersion)
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
storedObj := &example.Pod{}
if err := store.GuaranteedUpdate(ctx, key, storedObj, false, nil,
func(_ runtime.Object, _ storage.ResponseMeta) (runtime.Object, *uint64, error) {
newPod := prevStoredObj.DeepCopy()
newPod.Annotations = map[string]string{"version": "second"}
return newPod, nil, nil
}, nil); err != nil {
t.Fatalf("update failed: %v", err)
}
currentRV, _ := strconv.Atoi(storedObj.ResourceVersion) currentRV, _ := strconv.Atoi(storedObj.ResourceVersion)
tests := []struct { tests := []struct {
name string name string
key string key string
pred storage.SelectionPredicate pred storage.SelectionPredicate
expectedOut []*example.Pod expectedOut []example.Pod
expectedAlternatives [][]example.Pod
rv string rv string
rvMatch metav1.ResourceVersionMatch rvMatch metav1.ResourceVersionMatch
expectRVTooLarge bool expectRVTooLarge bool
@ -1066,59 +1079,59 @@ func RunTestGetListNonRecursive(ctx context.Context, t *testing.T, store storage
name: "existing key", name: "existing key",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedOut: []example.Pod{*storedObj},
}, { }, {
name: "existing key, resourceVersion=0", name: "existing key, resourceVersion=0",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedAlternatives: [][]example.Pod{nil, {*storedObj}},
rv: "0", rv: "0",
}, { }, {
name: "existing key, resourceVersion=0, resourceVersionMatch=notOlderThan", name: "existing key, resourceVersion=0, resourceVersionMatch=notOlderThan",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedAlternatives: [][]example.Pod{nil, {*storedObj}},
rv: "0", rv: "0",
rvMatch: metav1.ResourceVersionMatchNotOlderThan, rvMatch: metav1.ResourceVersionMatchNotOlderThan,
}, { }, {
name: "existing key, resourceVersion=current", name: "existing key, resourceVersion=current",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedOut: []example.Pod{*storedObj},
rv: fmt.Sprintf("%d", currentRV), rv: fmt.Sprintf("%d", currentRV),
}, { }, {
name: "existing key, resourceVersion=current, resourceVersionMatch=notOlderThan", name: "existing key, resourceVersion=current, resourceVersionMatch=notOlderThan",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedOut: []example.Pod{*storedObj},
rv: fmt.Sprintf("%d", currentRV), rv: fmt.Sprintf("%d", currentRV),
rvMatch: metav1.ResourceVersionMatchNotOlderThan, rvMatch: metav1.ResourceVersionMatchNotOlderThan,
}, { }, {
name: "existing key, resourceVersion=previous, resourceVersionMatch=notOlderThan", name: "existing key, resourceVersion=previous, resourceVersionMatch=notOlderThan",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedAlternatives: [][]example.Pod{{*prevStoredObj}, {*storedObj}},
rv: fmt.Sprintf("%d", prevRV), rv: fmt.Sprintf("%d", prevRV),
rvMatch: metav1.ResourceVersionMatchNotOlderThan, rvMatch: metav1.ResourceVersionMatchNotOlderThan,
}, { }, {
name: "existing key, resourceVersion=current, resourceVersionMatch=exact", name: "existing key, resourceVersion=current, resourceVersionMatch=exact",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedOut: []example.Pod{*storedObj},
rv: fmt.Sprintf("%d", currentRV), rv: fmt.Sprintf("%d", currentRV),
rvMatch: metav1.ResourceVersionMatchExact, rvMatch: metav1.ResourceVersionMatchExact,
}, { }, {
name: "existing key, resourceVersion=current, resourceVersionMatch=exact", name: "existing key, resourceVersion=previous, resourceVersionMatch=exact",
key: prevKey, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{prevStoredObj}, expectedOut: []example.Pod{*prevStoredObj},
rv: fmt.Sprintf("%d", prevRV), rv: fmt.Sprintf("%d", prevRV),
rvMatch: metav1.ResourceVersionMatchExact, rvMatch: metav1.ResourceVersionMatchExact,
}, { }, {
name: "existing key, resourceVersion=too high", name: "existing key, resourceVersion=too high",
key: key, key: key,
pred: storage.Everything, pred: storage.Everything,
expectedOut: []*example.Pod{storedObj}, expectedOut: []example.Pod{*storedObj},
rv: strconv.FormatInt(math.MaxInt64, 10), rv: strconv.FormatInt(math.MaxInt64, 10),
expectRVTooLarge: true, expectRVTooLarge: true,
}, { }, {
@ -1141,7 +1154,10 @@ func RunTestGetListNonRecursive(ctx context.Context, t *testing.T, store storage
}} }}
for _, tt := range tests { for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
t.Parallel()
out := &example.PodList{} out := &example.PodList{}
storageOpts := storage.ListOptions{ storageOpts := storage.ListOptions{
ResourceVersion: tt.rv, ResourceVersion: tt.rv,
@ -1164,13 +1180,18 @@ func RunTestGetListNonRecursive(ctx context.Context, t *testing.T, store storage
if len(out.ResourceVersion) == 0 { if len(out.ResourceVersion) == 0 {
t.Errorf("%s: unset resourceVersion", tt.name) t.Errorf("%s: unset resourceVersion", tt.name)
} }
if len(out.Items) != len(tt.expectedOut) {
t.Errorf("%s: length of list want=%d, get=%d", tt.name, len(tt.expectedOut), len(out.Items)) if tt.expectedAlternatives == nil {
return ExpectNoDiff(t, "incorrect list pods", tt.expectedOut, out.Items)
} else {
toInterfaceSlice := func(podLists [][]example.Pod) []interface{} {
result := make([]interface{}, 0, len(podLists))
for i := range podLists {
result = append(result, podLists[i])
} }
for j, wantPod := range tt.expectedOut { return result
getPod := &out.Items[j] }
ExpectNoDiff(t, fmt.Sprintf("%s: incorrect pod", tt.name), wantPod, getPod) ExpectContains(t, "incorrect list pods", toInterfaceSlice(tt.expectedAlternatives), out.Items)
} }
}) })
} }
@ -1572,7 +1593,7 @@ func RunTestListInconsistentContinuation(ctx context.Context, t *testing.T, stor
if len(out.Continue) == 0 { if len(out.Continue) == 0 {
t.Fatalf("No continuation token set") t.Fatalf("No continuation token set")
} }
validateResourceVersion := ResourceVersionNotOlderThan(lastRVString) validateResourceVersion := resourceVersionNotOlderThan(lastRVString)
ExpectNoDiff(t, "incorrect second page", []example.Pod{*preset[1].storedObj}, out.Items) ExpectNoDiff(t, "incorrect second page", []example.Pod{*preset[1].storedObj}, out.Items)
if err := validateResourceVersion(out.ResourceVersion); err != nil { if err := validateResourceVersion(out.ResourceVersion); err != nil {
t.Fatal(err) t.Fatal(err)
@ -1776,7 +1797,7 @@ func RunTestGuaranteedUpdate(ctx context.Context, t *testing.T, store InterfaceW
for i, tt := range tests { for i, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
key, storeObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}}) key, storeObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", UID: "A"}})
out := &example.Pod{} out := &example.Pod{}
name := fmt.Sprintf("foo-%d", i) name := fmt.Sprintf("foo-%d", i)
@ -1866,7 +1887,7 @@ func RunTestGuaranteedUpdateWithTTL(ctx context.Context, t *testing.T, store sto
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckEventType(t, watch.Deleted, w) testCheckEventType(t, watch.Deleted, w)
} }
func RunTestGuaranteedUpdateChecksStoredData(ctx context.Context, t *testing.T, store InterfaceWithPrefixTransformer) { func RunTestGuaranteedUpdateChecksStoredData(ctx context.Context, t *testing.T, store InterfaceWithPrefixTransformer) {
@ -1880,7 +1901,7 @@ func RunTestGuaranteedUpdateChecksStoredData(ctx context.Context, t *testing.T,
transformer.prefix = []byte(string(transformer.prefix) + " ") transformer.prefix = []byte(string(transformer.prefix) + " ")
return transformer return transformer
}) })
_, initial := TestPropagateStore(ctx, t, store, input) _, initial := testPropagateStore(ctx, t, store, input)
revertTransformer() revertTransformer()
// this update should write the canonical value to etcd because the new serialization differs // this update should write the canonical value to etcd because the new serialization differs
@ -1935,7 +1956,7 @@ func RunTestGuaranteedUpdateChecksStoredData(ctx context.Context, t *testing.T,
} }
func RunTestGuaranteedUpdateWithConflict(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestGuaranteedUpdateWithConflict(ctx context.Context, t *testing.T, store storage.Interface) {
key, _ := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, _ := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
errChan := make(chan error, 1) errChan := make(chan error, 1)
var firstToFinish sync.WaitGroup var firstToFinish sync.WaitGroup
@ -1980,7 +2001,7 @@ func RunTestGuaranteedUpdateWithConflict(ctx context.Context, t *testing.T, stor
} }
func RunTestGuaranteedUpdateWithSuggestionAndConflict(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestGuaranteedUpdateWithSuggestionAndConflict(ctx context.Context, t *testing.T, store storage.Interface) {
key, originalPod := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, originalPod := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
// First, update without a suggestion so originalPod is outdated // First, update without a suggestion so originalPod is outdated
updatedPod := &example.Pod{} updatedPod := &example.Pod{}
@ -2142,7 +2163,9 @@ func RunTestCount(ctx context.Context, t *testing.T, store storage.Interface) {
obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("foo-%d", i)}} obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("foo-%d", i)}}
key := fmt.Sprintf("%s/%d", resourceA, i) key := fmt.Sprintf("%s/%d", resourceA, i)
TestPropagateStoreWithKey(ctx, t, store, key, obj) if err := store.Create(ctx, key, obj, nil, 0); err != nil {
t.Fatalf("Create failed: %v", err)
}
} }
resourceBCount := 4 resourceBCount := 4
@ -2150,7 +2173,9 @@ func RunTestCount(ctx context.Context, t *testing.T, store storage.Interface) {
obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("foo-%d", i)}} obj := &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("foo-%d", i)}}
key := fmt.Sprintf("%s/%d", resourceB, i) key := fmt.Sprintf("%s/%d", resourceB, i)
TestPropagateStoreWithKey(ctx, t, store, key, obj) if err := store.Create(ctx, key, obj, nil, 0); err != nil {
t.Fatalf("Create failed: %v", err)
}
} }
resourceACountGot, err := store.Count(resourceA) resourceACountGot, err := store.Count(resourceA)

View File

@ -37,11 +37,6 @@ import (
"k8s.io/apiserver/pkg/storage/value" "k8s.io/apiserver/pkg/storage/value"
) )
// CreateObj will create a single object using the storage interface.
func CreateObj(helper storage.Interface, name string, obj, out runtime.Object, ttl uint64) error {
return helper.Create(context.TODO(), name, obj, out, ttl)
}
// CreateObjList will create a list from the array of objects. // CreateObjList will create a list from the array of objects.
func CreateObjList(prefix string, helper storage.Interface, items []runtime.Object) error { func CreateObjList(prefix string, helper storage.Interface, items []runtime.Object) error {
for i := range items { for i := range items {
@ -50,7 +45,7 @@ func CreateObjList(prefix string, helper storage.Interface, items []runtime.Obje
if err != nil { if err != nil {
return err return err
} }
err = CreateObj(helper, path.Join(prefix, meta.GetName()), obj, obj, 0) err = helper.Create(context.Background(), path.Join(prefix, meta.GetName()), obj, obj, 0)
if err != nil { if err != nil {
return err return err
} }
@ -82,16 +77,12 @@ func DeepEqualSafePodSpec() example.PodSpec {
} }
} }
// TestPropagateStore helps propagates store with objects, automates key generation, and returns // testPropagateStore helps propagates store with objects, automates key generation, and returns
// keys and stored objects. // keys and stored objects.
func TestPropagateStore(ctx context.Context, t *testing.T, store storage.Interface, obj *example.Pod) (string, *example.Pod) { func testPropagateStore(ctx context.Context, t *testing.T, store storage.Interface, obj *example.Pod) (string, *example.Pod) {
// Setup store with a key and grab the output for returning. // Setup store with a key and grab the output for returning.
key := fmt.Sprintf("/%s/%s", obj.Namespace, obj.Name) key := fmt.Sprintf("/%s/%s", obj.Namespace, obj.Name)
return key, TestPropagateStoreWithKey(ctx, t, store, key, obj)
}
// TestPropagateStoreWithKey helps propagate store with objects, the given object will be stored at the specified key.
func TestPropagateStoreWithKey(ctx context.Context, t *testing.T, store storage.Interface, key string, obj *example.Pod) *example.Pod {
// Setup store with the specified key and grab the output for returning. // Setup store with the specified key and grab the output for returning.
err := store.Delete(ctx, key, &example.Pod{}, nil, storage.ValidateAllObjectFunc, nil) err := store.Delete(ctx, key, &example.Pod{}, nil, storage.ValidateAllObjectFunc, nil)
if err != nil && !storage.IsNotFound(err) { if err != nil && !storage.IsNotFound(err) {
@ -101,7 +92,7 @@ func TestPropagateStoreWithKey(ctx context.Context, t *testing.T, store storage.
if err := store.Create(ctx, key, obj, setOutput, 0); err != nil { if err := store.Create(ctx, key, obj, setOutput, 0); err != nil {
t.Fatalf("Set failed: %v", err) t.Fatalf("Set failed: %v", err)
} }
return setOutput return key, setOutput
} }
func ExpectNoDiff(t *testing.T, msg string, expected, got interface{}) { func ExpectNoDiff(t *testing.T, msg string, expected, got interface{}) {
@ -135,7 +126,7 @@ func ExpectContains(t *testing.T, msg string, expectedList []interface{}, got in
const dummyPrefix = "adapter" const dummyPrefix = "adapter"
func EncodeContinueOrDie(key string, resourceVersion int64) string { func encodeContinueOrDie(key string, resourceVersion int64) string {
token, err := storage.EncodeContinue(dummyPrefix+key, dummyPrefix, resourceVersion) token, err := storage.EncodeContinue(dummyPrefix+key, dummyPrefix, resourceVersion)
if err != nil { if err != nil {
panic(err) panic(err)
@ -143,7 +134,7 @@ func EncodeContinueOrDie(key string, resourceVersion int64) string {
return token return token
} }
func TestCheckEventType(t *testing.T, expectEventType watch.EventType, w watch.Interface) { func testCheckEventType(t *testing.T, expectEventType watch.EventType, w watch.Interface) {
select { select {
case res := <-w.ResultChan(): case res := <-w.ResultChan():
if res.Type != expectEventType { if res.Type != expectEventType {
@ -154,14 +145,14 @@ func TestCheckEventType(t *testing.T, expectEventType watch.EventType, w watch.I
} }
} }
func TestCheckResult(t *testing.T, expectEventType watch.EventType, w watch.Interface, expectObj *example.Pod) { func testCheckResult(t *testing.T, expectEventType watch.EventType, w watch.Interface, expectObj *example.Pod) {
TestCheckResultFunc(t, expectEventType, w, func(object runtime.Object) error { testCheckResultFunc(t, expectEventType, w, func(object runtime.Object) error {
ExpectNoDiff(t, "incorrect object", expectObj, object) ExpectNoDiff(t, "incorrect object", expectObj, object)
return nil return nil
}) })
} }
func TestCheckResultFunc(t *testing.T, expectEventType watch.EventType, w watch.Interface, check func(object runtime.Object) error) { func testCheckResultFunc(t *testing.T, expectEventType watch.EventType, w watch.Interface, check func(object runtime.Object) error) {
select { select {
case res := <-w.ResultChan(): case res := <-w.ResultChan():
if res.Type != expectEventType { if res.Type != expectEventType {
@ -176,7 +167,7 @@ func TestCheckResultFunc(t *testing.T, expectEventType watch.EventType, w watch.
} }
} }
func TestCheckStop(t *testing.T, w watch.Interface) { func testCheckStop(t *testing.T, w watch.Interface) {
select { select {
case e, ok := <-w.ResultChan(): case e, ok := <-w.ResultChan():
if ok { if ok {
@ -194,10 +185,10 @@ func TestCheckStop(t *testing.T, w watch.Interface) {
} }
} }
// ResourceVersionNotOlderThan returns a function to validate resource versions. Resource versions // resourceVersionNotOlderThan returns a function to validate resource versions. Resource versions
// referring to points in logical time before the sentinel generate an error. All logical times as // referring to points in logical time before the sentinel generate an error. All logical times as
// new as the sentinel or newer generate no error. // new as the sentinel or newer generate no error.
func ResourceVersionNotOlderThan(sentinel string) func(string) error { func resourceVersionNotOlderThan(sentinel string) func(string) error {
return func(resourceVersion string) error { return func(resourceVersion string) error {
objectVersioner := storage.APIObjectVersioner{} objectVersioner := storage.APIObjectVersioner{}
actualRV, err := objectVersioner.ParseResourceVersion(resourceVersion) actualRV, err := objectVersioner.ParseResourceVersion(resourceVersion)

View File

@ -113,12 +113,12 @@ func testWatch(ctx context.Context, t *testing.T, store storage.Interface, recur
expectObj = prevObj expectObj = prevObj
expectObj.ResourceVersion = out.ResourceVersion expectObj.ResourceVersion = out.ResourceVersion
} }
TestCheckResult(t, watchTest.watchType, w, expectObj) testCheckResult(t, watchTest.watchType, w, expectObj)
} }
prevObj = out prevObj = out
} }
w.Stop() w.Stop()
TestCheckStop(t, w) testCheckStop(t, w)
}) })
} }
} }
@ -127,13 +127,13 @@ func testWatch(ctx context.Context, t *testing.T, store storage.Interface, recur
// - watch from 0 should sync up and grab the object added before // - watch from 0 should sync up and grab the object added before
// - watch from 0 is able to return events for objects whose previous version has been compacted // - watch from 0 is able to return events for objects whose previous version has been compacted
func RunTestWatchFromZero(ctx context.Context, t *testing.T, store storage.Interface, compaction Compaction) { func RunTestWatchFromZero(ctx context.Context, t *testing.T, store storage.Interface, compaction Compaction) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "ns"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "ns"}})
w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: "0", Predicate: storage.Everything}) w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: "0", Predicate: storage.Everything})
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckResult(t, watch.Added, w, storedObj) testCheckResult(t, watch.Added, w, storedObj)
w.Stop() w.Stop()
// Update // Update
@ -151,7 +151,7 @@ func RunTestWatchFromZero(ctx context.Context, t *testing.T, store storage.Inter
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckResult(t, watch.Added, w, out) testCheckResult(t, watch.Added, w, out)
w.Stop() w.Stop()
if compaction == nil { if compaction == nil {
@ -176,11 +176,11 @@ func RunTestWatchFromZero(ctx context.Context, t *testing.T, store storage.Inter
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckResult(t, watch.Added, w, out) testCheckResult(t, watch.Added, w, out)
} }
func RunTestDeleteTriggerWatch(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestDeleteTriggerWatch(ctx context.Context, t *testing.T, store storage.Interface) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything}) w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything})
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
@ -188,11 +188,11 @@ func RunTestDeleteTriggerWatch(ctx context.Context, t *testing.T, store storage.
if err := store.Delete(ctx, key, &example.Pod{}, nil, storage.ValidateAllObjectFunc, nil); err != nil { if err := store.Delete(ctx, key, &example.Pod{}, nil, storage.ValidateAllObjectFunc, nil); err != nil {
t.Fatalf("Delete failed: %v", err) t.Fatalf("Delete failed: %v", err)
} }
TestCheckEventType(t, watch.Deleted, w) testCheckEventType(t, watch.Deleted, w)
} }
func RunTestWatchFromNoneZero(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestWatchFromNoneZero(ctx context.Context, t *testing.T, store storage.Interface) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything}) w, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything})
if err != nil { if err != nil {
@ -203,7 +203,7 @@ func RunTestWatchFromNoneZero(ctx context.Context, t *testing.T, store storage.I
func(runtime.Object) (runtime.Object, error) { func(runtime.Object) (runtime.Object, error) {
return &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}, err return &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}, err
}), nil) }), nil)
TestCheckResult(t, watch.Modified, w, out) testCheckResult(t, watch.Modified, w, out)
} }
func RunTestWatchError(ctx context.Context, t *testing.T, store InterfaceWithPrefixTransformer) { func RunTestWatchError(ctx context.Context, t *testing.T, store InterfaceWithPrefixTransformer) {
@ -236,7 +236,7 @@ func RunTestWatchError(ctx context.Context, t *testing.T, store InterfaceWithPre
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
} }
TestCheckEventType(t, watch.Error, w) testCheckEventType(t, watch.Error, w)
} }
func RunTestWatchContextCancel(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestWatchContextCancel(ctx context.Context, t *testing.T, store storage.Interface) {
@ -263,7 +263,7 @@ func RunTestWatchContextCancel(ctx context.Context, t *testing.T, store storage.
} }
func RunTestWatchDeleteEventObjectHaveLatestRV(ctx context.Context, t *testing.T, store storage.Interface) { func RunTestWatchDeleteEventObjectHaveLatestRV(ctx context.Context, t *testing.T, store storage.Interface) {
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
watchCtx, _ := context.WithTimeout(ctx, wait.ForeverTestTimeout) watchCtx, _ := context.WithTimeout(ctx, wait.ForeverTestTimeout)
w, err := store.Watch(watchCtx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything}) w, err := store.Watch(watchCtx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything})
@ -295,7 +295,7 @@ func RunTestWatchInitializationSignal(ctx context.Context, t *testing.T, store s
initSignal := utilflowcontrol.NewInitializationSignal() initSignal := utilflowcontrol.NewInitializationSignal()
ctx = utilflowcontrol.WithInitializationSignal(ctx, initSignal) ctx = utilflowcontrol.WithInitializationSignal(ctx, initSignal)
key, storedObj := TestPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) key, storedObj := testPropagateStore(ctx, t, store, &example.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}})
_, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything}) _, err := store.Watch(ctx, key, storage.ListOptions{ResourceVersion: storedObj.ResourceVersion, Predicate: storage.Everything})
if err != nil { if err != nil {
t.Fatalf("Watch failed: %v", err) t.Fatalf("Watch failed: %v", err)
@ -315,7 +315,7 @@ func RunOptionalTestProgressNotify(ctx context.Context, t *testing.T, store stor
if err := store.Create(ctx, key, input, out, 0); err != nil { if err := store.Create(ctx, key, input, out, 0); err != nil {
t.Fatalf("Create failed: %v", err) t.Fatalf("Create failed: %v", err)
} }
validateResourceVersion := ResourceVersionNotOlderThan(out.ResourceVersion) validateResourceVersion := resourceVersionNotOlderThan(out.ResourceVersion)
opts := storage.ListOptions{ opts := storage.ListOptions{
ResourceVersion: out.ResourceVersion, ResourceVersion: out.ResourceVersion,
@ -329,7 +329,7 @@ func RunOptionalTestProgressNotify(ctx context.Context, t *testing.T, store stor
// when we send a bookmark event, the client expects the event to contain an // when we send a bookmark event, the client expects the event to contain an
// object of the correct type, but with no fields set other than the resourceVersion // object of the correct type, but with no fields set other than the resourceVersion
TestCheckResultFunc(t, watch.Bookmark, w, func(object runtime.Object) error { testCheckResultFunc(t, watch.Bookmark, w, func(object runtime.Object) error {
// first, check that we have the correct resource version // first, check that we have the correct resource version
obj, ok := object.(metav1.Object) obj, ok := object.(metav1.Object)
if !ok { if !ok {

View File

@ -165,67 +165,14 @@ func updatePod(t *testing.T, s storage.Interface, obj, old *example.Pod) *exampl
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
ctx, cacher, terminate := testSetup(t) ctx, cacher, terminate := testSetup(t)
defer terminate() t.Cleanup(terminate)
storagetesting.RunTestGet(ctx, t, cacher) storagetesting.RunTestGet(ctx, t, cacher)
} }
func TestGetListNonRecursive(t *testing.T) { func TestGetListNonRecursive(t *testing.T) {
server, etcdStorage := newEtcdTestStorage(t, etcd3testing.PathPrefix()) ctx, cacher, terminate := testSetup(t)
defer server.Terminate(t) t.Cleanup(terminate)
cacher, _, err := newTestCacher(etcdStorage) storagetesting.RunTestGetListNonRecursive(ctx, t, cacher)
if err != nil {
t.Fatalf("Couldn't create cacher: %v", err)
}
defer cacher.Stop()
storedObj := updatePod(t, etcdStorage, makeTestPod("foo"), nil)
key := "pods/" + storedObj.Namespace + "/" + storedObj.Name
tests := []struct {
key string
pred storage.SelectionPredicate
expectedOut []*example.Pod
}{{ // test non-recursive GetList on existing key
key: key,
pred: storage.Everything,
expectedOut: []*example.Pod{storedObj},
}, { // test non-recursive GetList on non-existing key
key: "/non-existing",
pred: storage.Everything,
expectedOut: nil,
}, { // test non-recursive GetList with matching pod name
key: "/non-existing",
pred: storage.SelectionPredicate{
Label: labels.Everything(),
Field: fields.ParseSelectorOrDie("metadata.name!=" + storedObj.Name),
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
pod := obj.(*example.Pod)
return nil, fields.Set{"metadata.name": pod.Name}, nil
},
},
expectedOut: nil,
}}
for i, tt := range tests {
out := &example.PodList{}
err := cacher.GetList(context.TODO(), tt.key, storage.ListOptions{Predicate: tt.pred, Recursive: false}, out)
if err != nil {
t.Fatalf("GetList failed: %v", err)
}
if len(out.ResourceVersion) == 0 {
t.Errorf("#%d: unset resourceVersion", i)
}
if len(out.Items) != len(tt.expectedOut) {
t.Errorf("#%d: length of list want=%d, get=%d", i, len(tt.expectedOut), len(out.Items))
continue
}
for j, wantPod := range tt.expectedOut {
getPod := &out.Items[j]
if !reflect.DeepEqual(wantPod, getPod) {
t.Errorf("#%d: pod want=%#v, get=%#v", i, wantPod, getPod)
}
}
}
} }
func TestList(t *testing.T) { func TestList(t *testing.T) {