func TestMatchPod(t *testing.T) { testCases := []struct { in *api.Pod fieldSelector fields.Selector expectMatch bool }{ { in: &api.Pod{ Spec: api.PodSpec{NodeName: "nodeA"}, }, fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=nodeA"), expectMatch: true, }, { in: &api.Pod{ Spec: api.PodSpec{NodeName: "nodeB"}, }, fieldSelector: fields.ParseSelectorOrDie("spec.nodeName=nodeA"), expectMatch: false, }, { in: &api.Pod{ Spec: api.PodSpec{RestartPolicy: api.RestartPolicyAlways}, }, fieldSelector: fields.ParseSelectorOrDie("spec.restartPolicy=Always"), expectMatch: true, }, { in: &api.Pod{ Spec: api.PodSpec{RestartPolicy: api.RestartPolicyAlways}, }, fieldSelector: fields.ParseSelectorOrDie("spec.restartPolicy=Never"), expectMatch: false, }, { in: &api.Pod{ Status: api.PodStatus{Phase: api.PodRunning}, }, fieldSelector: fields.ParseSelectorOrDie("status.phase=Running"), expectMatch: true, }, { in: &api.Pod{ Status: api.PodStatus{Phase: api.PodRunning}, }, fieldSelector: fields.ParseSelectorOrDie("status.phase=Pending"), expectMatch: false, }, } for _, testCase := range testCases { m := MatchPod(labels.Everything(), testCase.fieldSelector) result, err := m.Matches(testCase.in) if err != nil { t.Errorf("Unexpected error %v", err) } if result != testCase.expectMatch { t.Errorf("Result %v, Expected %v, Selector: %v, Pod: %v", result, testCase.expectMatch, testCase.fieldSelector.String(), testCase.in) } } }
func TestGetToList(t *testing.T) { ctx, store, cluster := testSetup(t) defer cluster.Terminate(t) key, storedObj := testPropogateStore(ctx, t, store, &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}) tests := []struct { key string pred storage.SelectionPredicate expectedOut []*api.Pod }{{ // test GetToList on existing key key: key, pred: storage.Everything, expectedOut: []*api.Pod{storedObj}, }, { // test GetToList on non-existing key key: "/non-existing", pred: storage.Everything, expectedOut: nil, }, { // test GetToList 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.(*api.Pod) return nil, fields.Set{"metadata.name": pod.Name}, nil }, }, expectedOut: nil, }} for i, tt := range tests { out := &api.PodList{} err := store.GetToList(ctx, tt.key, "", tt.pred, out) if err != nil { t.Fatalf("GetToList failed: %v", err) } 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) { cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1}) defer cluster.Terminate(t) store := newStore(cluster.RandClient(), false, testapi.Default.Codec(), "") ctx := context.Background() // Setup storage with the following structure: // / // - one-level/ // | - test // | // - two-level/ // - 1/ // | - test // | // - 2/ // - test preset := []struct { key string obj *api.Pod storedObj *api.Pod }{{ key: "/one-level/test", obj: &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, }, { key: "/two-level/1/test", obj: &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}, }, { key: "/two-level/2/test", obj: &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}}, }} for i, ps := range preset { preset[i].storedObj = &api.Pod{} err := store.Create(ctx, ps.key, ps.obj, preset[i].storedObj, 0) if err != nil { t.Fatalf("Set failed: %v", err) } } tests := []struct { prefix string pred storage.SelectionPredicate expectedOut []*api.Pod }{{ // test List on existing key prefix: "/one-level/", pred: storage.Everything, expectedOut: []*api.Pod{preset[0].storedObj}, }, { // test List on non-existing key prefix: "/non-existing/", pred: storage.Everything, expectedOut: nil, }, { // test List with pod name matching prefix: "/one-level/", pred: storage.SelectionPredicate{ Label: labels.Everything(), Field: fields.ParseSelectorOrDie("metadata.name!=" + preset[0].storedObj.Name), GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod := obj.(*api.Pod) return nil, fields.Set{"metadata.name": pod.Name}, nil }, }, expectedOut: nil, }, { // test List with multiple levels of directories and expect flattened result prefix: "/two-level/", pred: storage.Everything, expectedOut: []*api.Pod{preset[1].storedObj, preset[2].storedObj}, }} for i, tt := range tests { out := &api.PodList{} err := store.List(ctx, tt.prefix, "0", tt.pred, out) if err != nil { t.Fatalf("List failed: %v", err) } if len(tt.expectedOut) != len(out.Items) { 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) } } } }
// It tests that // - first occurrence of objects should notify Add event // - update should trigger Modified event // - update that gets filtered should trigger Deleted event func testWatch(t *testing.T, recursive bool) { ctx, store, cluster := testSetup(t) defer cluster.Terminate(t) podFoo := &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}} podBar := &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "bar"}} tests := []struct { key string pred storage.SelectionPredicate watchTests []*testWatchStruct }{{ // create a key key: "/somekey-1", watchTests: []*testWatchStruct{{podFoo, true, watch.Added}}, pred: storage.Everything, }, { // create a key but obj gets filtered. Then update it with unfiltered obj key: "/somekey-3", watchTests: []*testWatchStruct{{podFoo, false, ""}, {podBar, true, watch.Added}}, pred: storage.SelectionPredicate{ Label: labels.Everything(), Field: fields.ParseSelectorOrDie("metadata.name=bar"), GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod := obj.(*api.Pod) return nil, fields.Set{"metadata.name": pod.Name}, nil }, }, }, { // update key: "/somekey-4", watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Modified}}, pred: storage.Everything, }, { // delete because of being filtered key: "/somekey-5", watchTests: []*testWatchStruct{{podFoo, true, watch.Added}, {podBar, true, watch.Deleted}}, pred: storage.SelectionPredicate{ Label: labels.Everything(), Field: fields.ParseSelectorOrDie("metadata.name!=bar"), GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { pod := obj.(*api.Pod) return nil, fields.Set{"metadata.name": pod.Name}, nil }, }, }} for i, tt := range tests { w, err := store.watch(ctx, tt.key, "0", tt.pred, recursive) if err != nil { t.Fatalf("Watch failed: %v", err) } var prevObj *api.Pod for _, watchTest := range tt.watchTests { out := &api.Pod{} key := tt.key if recursive { key = key + "/item" } err := store.GuaranteedUpdate(ctx, key, out, true, nil, storage.SimpleUpdate( func(runtime.Object) (runtime.Object, error) { return watchTest.obj, nil })) if err != nil { t.Fatalf("GuaranteedUpdate failed: %v", err) } if watchTest.expectEvent { expectObj := out if watchTest.watchType == watch.Deleted { expectObj = prevObj expectObj.ResourceVersion = out.ResourceVersion } testCheckResult(t, i, watchTest.watchType, w, expectObj) } prevObj = out } w.Stop() testCheckStop(t, i, w) } }
// Returns a cache.ListWatch that gets all changes to replicasets. func (factory *ConfigFactory) createReplicaSetLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.client.Extensions().RESTClient(), "replicasets", v1.NamespaceAll, fields.ParseSelectorOrDie("")) }
// Returns a cache.ListWatch that gets all changes to controllers. func (factory *ConfigFactory) createControllerLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.client.Core().RESTClient(), "replicationControllers", v1.NamespaceAll, fields.ParseSelectorOrDie("")) }
// Returns a cache.ListWatch that gets all changes to services. func (factory *ConfigFactory) createServiceLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.client.Core().RESTClient(), "services", v1.NamespaceAll, fields.ParseSelectorOrDie("")) }
// createPersistentVolumeClaimLW returns a cache.ListWatch that gets all changes to persistentVolumeClaims. func (factory *ConfigFactory) createPersistentVolumeClaimLW() *cache.ListWatch { return cache.NewListWatchFromClient(factory.client.Core().RESTClient(), "persistentVolumeClaims", v1.NamespaceAll, fields.ParseSelectorOrDie("")) }
// createNodeLW returns a cache.ListWatch that gets all changes to nodes. func (factory *ConfigFactory) createNodeLW() *cache.ListWatch { // all nodes are considered to ensure that the scheduler cache has access to all nodes for lookups // the NodeCondition is used to filter out the nodes that are not ready or unschedulable // the filtered list is used as the super set of nodes to consider for scheduling return cache.NewListWatchFromClient(factory.client.Core().RESTClient(), "nodes", v1.NamespaceAll, fields.ParseSelectorOrDie("")) }
// Returns a cache.ListWatch that finds all pods that are // already scheduled. // TODO: return a ListerWatcher interface instead? func (factory *ConfigFactory) createAssignedNonTerminatedPodLW() *cache.ListWatch { selector := fields.ParseSelectorOrDie("spec.nodeName!=" + "" + ",status.phase!=" + string(v1.PodSucceeded) + ",status.phase!=" + string(v1.PodFailed)) return cache.NewListWatchFromClient(factory.client.Core().RESTClient(), "pods", v1.NamespaceAll, selector) }