mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-11-04 07:49:35 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			741 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			741 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2018 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 wait
 | 
						|
 | 
						|
import (
 | 
						|
	"io/ioutil"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"time"
 | 
						|
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/davecgh/go-spew/spew"
 | 
						|
 | 
						|
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						|
	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/runtime/schema"
 | 
						|
	"k8s.io/apimachinery/pkg/types"
 | 
						|
	"k8s.io/apimachinery/pkg/util/wait"
 | 
						|
	"k8s.io/apimachinery/pkg/watch"
 | 
						|
	"k8s.io/cli-runtime/pkg/genericclioptions"
 | 
						|
	"k8s.io/cli-runtime/pkg/genericclioptions/printers"
 | 
						|
	"k8s.io/cli-runtime/pkg/genericclioptions/resource"
 | 
						|
	dynamicfakeclient "k8s.io/client-go/dynamic/fake"
 | 
						|
	clienttesting "k8s.io/client-go/testing"
 | 
						|
)
 | 
						|
 | 
						|
func newUnstructuredList(items ...*unstructured.Unstructured) *unstructured.UnstructuredList {
 | 
						|
	list := &unstructured.UnstructuredList{}
 | 
						|
	for i := range items {
 | 
						|
		list.Items = append(list.Items, *items[i])
 | 
						|
	}
 | 
						|
	return list
 | 
						|
}
 | 
						|
 | 
						|
func newUnstructured(apiVersion, kind, namespace, name string) *unstructured.Unstructured {
 | 
						|
	return &unstructured.Unstructured{
 | 
						|
		Object: map[string]interface{}{
 | 
						|
			"apiVersion": apiVersion,
 | 
						|
			"kind":       kind,
 | 
						|
			"metadata": map[string]interface{}{
 | 
						|
				"namespace": namespace,
 | 
						|
				"name":      name,
 | 
						|
				"uid":       "some-UID-value",
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func newUnstructuredStatus(status *metav1.Status) runtime.Unstructured {
 | 
						|
	obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(status)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
	return &unstructured.Unstructured{
 | 
						|
		Object: obj,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func addCondition(in *unstructured.Unstructured, name, status string) *unstructured.Unstructured {
 | 
						|
	conditions, _, _ := unstructured.NestedSlice(in.Object, "status", "conditions")
 | 
						|
	conditions = append(conditions, map[string]interface{}{
 | 
						|
		"type":   name,
 | 
						|
		"status": status,
 | 
						|
	})
 | 
						|
	unstructured.SetNestedSlice(in.Object, conditions, "status", "conditions")
 | 
						|
	return in
 | 
						|
}
 | 
						|
 | 
						|
func TestWaitForDeletion(t *testing.T) {
 | 
						|
	scheme := runtime.NewScheme()
 | 
						|
 | 
						|
	tests := []struct {
 | 
						|
		name       string
 | 
						|
		infos      []*resource.Info
 | 
						|
		fakeClient func() *dynamicfakeclient.FakeDynamicClient
 | 
						|
		timeout    time.Duration
 | 
						|
		uidMap     UIDMap
 | 
						|
 | 
						|
		expectedErr     string
 | 
						|
		validateActions func(t *testing.T, actions []clienttesting.Action)
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "missing on get",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				return dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 1 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:  "handles no infos",
 | 
						|
			infos: []*resource.Info{},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				return dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
			},
 | 
						|
			timeout:     10 * time.Second,
 | 
						|
			expectedErr: errNoMatchingResources.Error(),
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 0 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "uid conflict on get",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				count := 0
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					if count == 0 {
 | 
						|
						count++
 | 
						|
						fakeWatch := watch.NewRaceFreeFake()
 | 
						|
						go func() {
 | 
						|
							time.Sleep(100 * time.Millisecond)
 | 
						|
							fakeWatch.Stop()
 | 
						|
						}()
 | 
						|
						return true, fakeWatch, nil
 | 
						|
					}
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
			uidMap: UIDMap{
 | 
						|
				ResourceLocation{Namespace: "ns-foo", Name: "name-foo"}:                                                                               types.UID("some-UID-value"),
 | 
						|
				ResourceLocation{GroupResource: schema.GroupResource{Group: "group", Resource: "theresource"}, Namespace: "ns-foo", Name: "name-foo"}: types.UID("some-nonmatching-UID-value"),
 | 
						|
			},
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 1 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "times out",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 1 * time.Second,
 | 
						|
 | 
						|
			expectedErr: wait.ErrWaitTimeout.Error(),
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 2 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles watch close out",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					unstructuredObj := newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")
 | 
						|
					unstructuredObj.SetResourceVersion("123")
 | 
						|
					unstructuredList := newUnstructuredList(unstructuredObj)
 | 
						|
					unstructuredList.SetResourceVersion("234")
 | 
						|
					return true, unstructuredList, nil
 | 
						|
				})
 | 
						|
				count := 0
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					if count == 0 {
 | 
						|
						count++
 | 
						|
						fakeWatch := watch.NewRaceFreeFake()
 | 
						|
						go func() {
 | 
						|
							time.Sleep(100 * time.Millisecond)
 | 
						|
							fakeWatch.Stop()
 | 
						|
						}()
 | 
						|
						return true, fakeWatch, nil
 | 
						|
					}
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 3 * time.Second,
 | 
						|
 | 
						|
			expectedErr: wait.ErrWaitTimeout.Error(),
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 4 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") || actions[1].(clienttesting.WatchAction).GetWatchRestrictions().ResourceVersion != "234" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[2].Matches("list", "theresource") || actions[2].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[3].Matches("watch", "theresource") || actions[3].(clienttesting.WatchAction).GetWatchRestrictions().ResourceVersion != "234" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles watch delete",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					fakeWatch.Action(watch.Deleted, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"))
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 2 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "ignores watch error",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				count := 0
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					if count == 0 {
 | 
						|
						fakeWatch.Error(newUnstructuredStatus(&metav1.Status{
 | 
						|
							TypeMeta: metav1.TypeMeta{Kind: "Status", APIVersion: "v1"},
 | 
						|
							Status:   "Failure",
 | 
						|
							Code:     500,
 | 
						|
							Message:  "Bad",
 | 
						|
						}))
 | 
						|
						fakeWatch.Stop()
 | 
						|
					} else {
 | 
						|
						fakeWatch.Action(watch.Deleted, newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"))
 | 
						|
					}
 | 
						|
					count++
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 4 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[2].Matches("list", "theresource") || actions[2].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[3].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			fakeClient := test.fakeClient()
 | 
						|
			o := &WaitOptions{
 | 
						|
				ResourceFinder: genericclioptions.NewSimpleFakeResourceFinder(test.infos...),
 | 
						|
				UIDMap:         test.uidMap,
 | 
						|
				DynamicClient:  fakeClient,
 | 
						|
				Timeout:        test.timeout,
 | 
						|
 | 
						|
				Printer:     printers.NewDiscardingPrinter(),
 | 
						|
				ConditionFn: IsDeleted,
 | 
						|
				IOStreams:   genericclioptions.NewTestIOStreamsDiscard(),
 | 
						|
			}
 | 
						|
			err := o.RunWait()
 | 
						|
			switch {
 | 
						|
			case err == nil && len(test.expectedErr) == 0:
 | 
						|
			case err != nil && len(test.expectedErr) == 0:
 | 
						|
				t.Fatal(err)
 | 
						|
			case err == nil && len(test.expectedErr) != 0:
 | 
						|
				t.Fatalf("missing: %q", test.expectedErr)
 | 
						|
			case err != nil && len(test.expectedErr) != 0:
 | 
						|
				if !strings.Contains(err.Error(), test.expectedErr) {
 | 
						|
					t.Fatalf("expected %q, got %q", test.expectedErr, err.Error())
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			test.validateActions(t, fakeClient.Actions())
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestWaitForCondition(t *testing.T) {
 | 
						|
	scheme := runtime.NewScheme()
 | 
						|
 | 
						|
	tests := []struct {
 | 
						|
		name       string
 | 
						|
		infos      []*resource.Info
 | 
						|
		fakeClient func() *dynamicfakeclient.FakeDynamicClient
 | 
						|
		timeout    time.Duration
 | 
						|
 | 
						|
		expectedErr     string
 | 
						|
		validateActions func(t *testing.T, actions []clienttesting.Action)
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name: "present on get",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(addCondition(
 | 
						|
						newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
 | 
						|
						"the-condition", "status-value",
 | 
						|
					)), nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 1 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:  "handles no infos",
 | 
						|
			infos: []*resource.Info{},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				return dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
			},
 | 
						|
			timeout:     10 * time.Second,
 | 
						|
			expectedErr: errNoMatchingResources.Error(),
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 0 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles empty object name",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				return dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
			},
 | 
						|
			timeout:     10 * time.Second,
 | 
						|
			expectedErr: "resource name must be provided",
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 0 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "times out",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, addCondition(
 | 
						|
						newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
 | 
						|
						"some-other-condition", "status-value",
 | 
						|
					), nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 1 * time.Second,
 | 
						|
 | 
						|
			expectedErr: wait.ErrWaitTimeout.Error(),
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 2 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles watch close out",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					unstructuredObj := newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")
 | 
						|
					unstructuredObj.SetResourceVersion("123")
 | 
						|
					unstructuredList := newUnstructuredList(unstructuredObj)
 | 
						|
					unstructuredList.SetResourceVersion("234")
 | 
						|
					return true, unstructuredList, nil
 | 
						|
				})
 | 
						|
				count := 0
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					if count == 0 {
 | 
						|
						count++
 | 
						|
						fakeWatch := watch.NewRaceFreeFake()
 | 
						|
						go func() {
 | 
						|
							time.Sleep(100 * time.Millisecond)
 | 
						|
							fakeWatch.Stop()
 | 
						|
						}()
 | 
						|
						return true, fakeWatch, nil
 | 
						|
					}
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 3 * time.Second,
 | 
						|
 | 
						|
			expectedErr: wait.ErrWaitTimeout.Error(),
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 4 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") || actions[1].(clienttesting.WatchAction).GetWatchRestrictions().ResourceVersion != "234" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[2].Matches("list", "theresource") || actions[2].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[3].Matches("watch", "theresource") || actions[3].(clienttesting.WatchAction).GetWatchRestrictions().ResourceVersion != "234" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles watch condition change",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					fakeWatch.Action(watch.Modified, addCondition(
 | 
						|
						newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
 | 
						|
						"the-condition", "status-value",
 | 
						|
					))
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 2 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "handles watch created",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					fakeWatch.Action(watch.Added, addCondition(
 | 
						|
						newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
 | 
						|
						"the-condition", "status-value",
 | 
						|
					))
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 2 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name: "ignores watch error",
 | 
						|
			infos: []*resource.Info{
 | 
						|
				{
 | 
						|
					Mapping: &meta.RESTMapping{
 | 
						|
						Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "theresource"},
 | 
						|
					},
 | 
						|
					Name:      "name-foo",
 | 
						|
					Namespace: "ns-foo",
 | 
						|
				},
 | 
						|
			},
 | 
						|
			fakeClient: func() *dynamicfakeclient.FakeDynamicClient {
 | 
						|
				fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme)
 | 
						|
				fakeClient.PrependReactor("list", "theresource", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
 | 
						|
					return true, newUnstructuredList(newUnstructured("group/version", "TheKind", "ns-foo", "name-foo")), nil
 | 
						|
				})
 | 
						|
				count := 0
 | 
						|
				fakeClient.PrependWatchReactor("theresource", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
 | 
						|
					fakeWatch := watch.NewRaceFreeFake()
 | 
						|
					if count == 0 {
 | 
						|
						fakeWatch.Error(newUnstructuredStatus(&metav1.Status{
 | 
						|
							TypeMeta: metav1.TypeMeta{Kind: "Status", APIVersion: "v1"},
 | 
						|
							Status:   "Failure",
 | 
						|
							Code:     500,
 | 
						|
							Message:  "Bad",
 | 
						|
						}))
 | 
						|
						fakeWatch.Stop()
 | 
						|
					} else {
 | 
						|
						fakeWatch.Action(watch.Modified, addCondition(
 | 
						|
							newUnstructured("group/version", "TheKind", "ns-foo", "name-foo"),
 | 
						|
							"the-condition", "status-value",
 | 
						|
						))
 | 
						|
					}
 | 
						|
					count++
 | 
						|
					return true, fakeWatch, nil
 | 
						|
				})
 | 
						|
				return fakeClient
 | 
						|
			},
 | 
						|
			timeout: 10 * time.Second,
 | 
						|
 | 
						|
			validateActions: func(t *testing.T, actions []clienttesting.Action) {
 | 
						|
				if len(actions) != 4 {
 | 
						|
					t.Fatal(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[0].Matches("list", "theresource") || actions[0].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[1].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[2].Matches("list", "theresource") || actions[2].(clienttesting.ListAction).GetListRestrictions().Fields.String() != "metadata.name=name-foo" {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
				if !actions[3].Matches("watch", "theresource") {
 | 
						|
					t.Error(spew.Sdump(actions))
 | 
						|
				}
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, test := range tests {
 | 
						|
		t.Run(test.name, func(t *testing.T) {
 | 
						|
			fakeClient := test.fakeClient()
 | 
						|
			o := &WaitOptions{
 | 
						|
				ResourceFinder: genericclioptions.NewSimpleFakeResourceFinder(test.infos...),
 | 
						|
				DynamicClient:  fakeClient,
 | 
						|
				Timeout:        test.timeout,
 | 
						|
 | 
						|
				Printer:     printers.NewDiscardingPrinter(),
 | 
						|
				ConditionFn: ConditionalWait{conditionName: "the-condition", conditionStatus: "status-value", errOut: ioutil.Discard}.IsConditionMet,
 | 
						|
				IOStreams:   genericclioptions.NewTestIOStreamsDiscard(),
 | 
						|
			}
 | 
						|
			err := o.RunWait()
 | 
						|
			switch {
 | 
						|
			case err == nil && len(test.expectedErr) == 0:
 | 
						|
			case err != nil && len(test.expectedErr) == 0:
 | 
						|
				t.Fatal(err)
 | 
						|
			case err == nil && len(test.expectedErr) != 0:
 | 
						|
				t.Fatalf("missing: %q", test.expectedErr)
 | 
						|
			case err != nil && len(test.expectedErr) != 0:
 | 
						|
				if !strings.Contains(err.Error(), test.expectedErr) {
 | 
						|
					t.Fatalf("expected %q, got %q", test.expectedErr, err.Error())
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			test.validateActions(t, fakeClient.Actions())
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |