func TestRunUntil(t *testing.T) { stopCh := make(chan struct{}) store := NewStore(MetaNamespaceKeyFunc) r := NewReflector(&testLW{}, &api.Pod{}, store, 0) fw := watch.NewFake() r.listerWatcher = &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { return fw, nil }, ListFunc: func() (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil }, } r.RunUntil(stopCh) // Synchronously add a dummy pod into the watch channel so we // know the RunUntil go routine is in the watch handler. fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}) stopCh <- struct{}{} select { case _, ok := <-fw.ResultChan(): if ok { t.Errorf("Watch channel left open after stopping the watch") } case <-time.After(util.ForeverTestTimeout): t.Errorf("the cancellation is at least %s late", util.ForeverTestTimeout.String()) break } }
func TestReflectorForWatchCache(t *testing.T) { store := newWatchCache(5) { _, version := store.ListWithVersion() if version != 0 { t.Errorf("unexpected resource version: %d", version) } } lw := &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { fw := watch.NewFake() go fw.Stop() return fw, nil }, ListFunc: func() (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "10"}}, nil }, } r := cache.NewReflector(lw, &api.Pod{}, store, 0) r.ListAndWatch(util.NeverStop) { _, version := store.ListWithVersion() if version != 10 { t.Errorf("unexpected resource version: %d", version) } } }
func TestReflector_ListAndWatch(t *testing.T) { createdFakes := make(chan *watch.FakeWatcher) // The ListFunc says that it's at revision 1. Therefore, we expect our WatchFunc // to get called at the beginning of the watch with 1, and again with 3 when we // inject an error. expectedRVs := []string{"1", "3"} lw := &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { fw := watch.NewFake() if e, a := expectedRVs[0], rv; e != a { t.Errorf("Expected rv %v, but got %v", e, a) } expectedRVs = expectedRVs[1:] // channel is not buffered because the for loop below needs to block. But // we don't want to block here, so report the new fake via a go routine. go func() { createdFakes <- fw }() return fw, nil }, ListFunc: func() (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil }, } s := NewFIFO(MetaNamespaceKeyFunc) r := NewReflector(lw, &api.Pod{}, s, 0) go r.ListAndWatch(util.NeverStop) ids := []string{"foo", "bar", "baz", "qux", "zoo"} var fw *watch.FakeWatcher for i, id := range ids { if fw == nil { fw = <-createdFakes } sendingRV := strconv.FormatUint(uint64(i+2), 10) fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: sendingRV}}) if sendingRV == "3" { // Inject a failure. fw.Stop() fw = nil } } // Verify we received the right ids with the right resource versions. for i, id := range ids { pod := s.Pop().(*api.Pod) if e, a := id, pod.Name; e != a { t.Errorf("%v: Expected %v, got %v", i, e, a) } if e, a := strconv.FormatUint(uint64(i+2), 10), pod.ResourceVersion; e != a { t.Errorf("%v: Expected %v, got %v", i, e, a) } } if len(expectedRVs) != 0 { t.Error("called watchStarter an unexpected number of times") } }
func TestReflector_watchHandler(t *testing.T) { s := NewStore(MetaNamespaceKeyFunc) g := NewReflector(&testLW{}, &api.Pod{}, s, 0) fw := watch.NewFake() s.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}) s.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}}) go func() { fw.Add(&api.Service{ObjectMeta: api.ObjectMeta{Name: "rejected"}}) fw.Delete(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}) fw.Modify(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar", ResourceVersion: "55"}}) fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "baz", ResourceVersion: "32"}}) fw.Stop() }() var resumeRV string err := g.watchHandler(fw, &resumeRV, neverExitWatch, util.NeverStop) if err != nil { t.Errorf("unexpected error %v", err) } mkPod := func(id string, rv string) *api.Pod { return &api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: rv}} } table := []struct { Pod *api.Pod exists bool }{ {mkPod("foo", ""), false}, {mkPod("rejected", ""), false}, {mkPod("bar", "55"), true}, {mkPod("baz", "32"), true}, } for _, item := range table { obj, exists, _ := s.Get(item.Pod) if e, a := item.exists, exists; e != a { t.Errorf("%v: expected %v, got %v", item.Pod, e, a) } if !exists { continue } if e, a := item.Pod.ResourceVersion, obj.(*api.Pod).ResourceVersion; e != a { t.Errorf("%v: expected %v, got %v", item.Pod, e, a) } } // RV should send the last version we see. if e, a := "32", resumeRV; e != a { t.Errorf("expected %v, got %v", e, a) } // last sync resource version should be the last version synced with store if e, a := "32", g.LastSyncResourceVersion(); e != a { t.Errorf("expected %v, got %v", e, a) } }
func TestReflector_watchHandlerTimeout(t *testing.T) { s := NewStore(MetaNamespaceKeyFunc) g := NewReflector(&testLW{}, &api.Pod{}, s, 0) fw := watch.NewFake() var resumeRV string exit := make(chan time.Time, 1) exit <- time.Now() err := g.watchHandler(fw, &resumeRV, exit, util.NeverStop) if err != errorResyncRequested { t.Errorf("expected timeout error, but got %q", err) } }
func TestReflectorStopWatch(t *testing.T) { s := NewStore(MetaNamespaceKeyFunc) g := NewReflector(&testLW{}, &api.Pod{}, s, 0) fw := watch.NewFake() var resumeRV string stopWatch := make(chan struct{}, 1) stopWatch <- struct{}{} err := g.watchHandler(fw, &resumeRV, neverExitWatch, stopWatch) if err != errorStopRequested { t.Errorf("expected stop error, got %q", err) } }
func TestWatchHTTPTimeout(t *testing.T) { watcher := watch.NewFake() timeoutCh := make(chan time.Time) done := make(chan struct{}) // Setup a new watchserver watchServer := &WatchServer{ watcher, newCodec, func(obj runtime.Object) {}, &fakeTimeoutFactory{timeoutCh, done}, } s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { watchServer.ServeHTTP(w, req) })) defer s.Close() // Setup a client dest, _ := url.Parse(s.URL) dest.Path = "/api/" + newVersion + "/simple" dest.RawQuery = "watch=true" req, _ := http.NewRequest("GET", dest.String(), nil) client := http.Client{} resp, err := client.Do(req) watcher.Add(&Simple{TypeMeta: unversioned.TypeMeta{APIVersion: newVersion}}) // Make sure we can actually watch an endpoint decoder := json.NewDecoder(resp.Body) var got watchJSON err = decoder.Decode(&got) if err != nil { t.Fatalf("Unexpected error: %v", err) } // Timeout and check for leaks close(timeoutCh) select { case <-done: if !watcher.Stopped { t.Errorf("Leaked watch on timeout") } case <-time.After(util.ForeverTestTimeout): t.Errorf("Failed to stop watcher after %s of timeout signal", util.ForeverTestTimeout.String()) } // Make sure we can't receive any more events through the timeout watch err = decoder.Decode(&got) if err != io.EOF { t.Errorf("Unexpected non-error") } }
func TestUpdatePods(t *testing.T) { fakeWatch := watch.NewFake() client := &testclient.Fake{} client.AddWatchReactor("*", testclient.DefaultWatchReactor(fakeWatch, nil)) manager := NewReplicationManager(client, controller.NoResyncPeriodFunc, BurstReplicas) manager.podStoreSynced = alwaysReady received := make(chan string) manager.syncHandler = func(key string) error { obj, exists, err := manager.rcStore.Store.GetByKey(key) if !exists || err != nil { t.Errorf("Expected to find controller under key %v", key) } received <- obj.(*api.ReplicationController).Name return nil } stopCh := make(chan struct{}) defer close(stopCh) go util.Until(manager.worker, 10*time.Millisecond, stopCh) // Put 2 rcs and one pod into the controller's stores testControllerSpec1 := newReplicationController(1) manager.rcStore.Store.Add(testControllerSpec1) testControllerSpec2 := *testControllerSpec1 testControllerSpec2.Spec.Selector = map[string]string{"bar": "foo"} testControllerSpec2.Name = "barfoo" manager.rcStore.Store.Add(&testControllerSpec2) // Put one pod in the podStore pod1 := newPodList(manager.podStore.Store, 1, api.PodRunning, testControllerSpec1).Items[0] pod2 := pod1 pod2.Labels = testControllerSpec2.Spec.Selector // Send an update of the same pod with modified labels, and confirm we get a sync request for // both controllers manager.updatePod(&pod1, &pod2) expected := sets.NewString(testControllerSpec1.Name, testControllerSpec2.Name) for _, name := range expected.List() { t.Logf("Expecting update for %+v", name) select { case got := <-received: if !expected.Has(got) { t.Errorf("Expected keys %#v got %v", expected, got) } case <-time.After(util.ForeverTestTimeout): t.Errorf("Expected update notifications for controllers within 100ms each") } } }
func TestReflector_watchHandlerError(t *testing.T) { s := NewStore(MetaNamespaceKeyFunc) g := NewReflector(&testLW{}, &api.Pod{}, s, 0) fw := watch.NewFake() go func() { fw.Stop() }() var resumeRV string err := g.watchHandler(fw, &resumeRV, neverExitWatch, util.NeverStop) if err == nil { t.Errorf("unexpected non-error") } }
// NewSimpleFake returns a client that will respond with the provided objects func NewSimpleFake(objects ...runtime.Object) *Fake { o := NewObjects(api.Scheme, api.Scheme) for _, obj := range objects { if err := o.Add(obj); err != nil { panic(err) } } fakeClient := &Fake{} fakeClient.AddReactor("*", "*", ObjectReaction(o, api.RESTMapper)) fakeClient.AddWatchReactor("*", DefaultWatchReactor(watch.NewFake(), nil)) return fakeClient }
func NewMockPodsListWatch(initialPodList api.PodList) *MockPodsListWatch { lw := MockPodsListWatch{ fakeWatcher: watch.NewFake(), list: initialPodList, } lw.ListWatch = cache.ListWatch{ WatchFunc: func(resourceVersion string) (watch.Interface, error) { return lw.fakeWatcher, nil }, ListFunc: func() (runtime.Object, error) { return &lw.list, nil }, } return &lw }
func TestWatchPods(t *testing.T) { fakeWatch := watch.NewFake() client := &testclient.Fake{} client.AddWatchReactor("*", testclient.DefaultWatchReactor(fakeWatch, nil)) manager := NewJobController(client, controller.NoResyncPeriodFunc) manager.podStoreSynced = alwaysReady // Put one job and one pod into the store testJob := newJob(2, 2) manager.jobStore.Store.Add(testJob) received := make(chan string) // The pod update sent through the fakeWatcher should figure out the managing job and // send it into the syncHandler. manager.syncHandler = func(key string) error { obj, exists, err := manager.jobStore.Store.GetByKey(key) if !exists || err != nil { t.Errorf("Expected to find job under key %v", key) } job := obj.(*extensions.Job) if !api.Semantic.DeepDerivative(job, testJob) { t.Errorf("\nExpected %#v,\nbut got %#v", testJob, job) } close(received) return nil } // Start only the pod watcher and the workqueue, send a watch event, // and make sure it hits the sync method for the right job. stopCh := make(chan struct{}) defer close(stopCh) go manager.podController.Run(stopCh) go util.Until(manager.worker, 10*time.Millisecond, stopCh) pods := newPodList(1, api.PodRunning, testJob) testPod := pods[0] testPod.Status.Phase = api.PodFailed fakeWatch.Add(&testPod) select { case <-received: case <-time.After(controllerTimeout): t.Errorf("Expected 1 call but got 0") } }
func NewMockPodsListWatch(initialPodList api.PodList) *MockPodsListWatch { lw := MockPodsListWatch{ fakeWatcher: watch.NewFake(), list: initialPodList, } lw.ListWatch = cache.ListWatch{ WatchFunc: func(resourceVersion string) (watch.Interface, error) { return lw.fakeWatcher, nil }, ListFunc: func() (runtime.Object, error) { lw.lock.Lock() defer lw.lock.Unlock() listCopy, err := api.Scheme.DeepCopy(&lw.list) return listCopy.(*api.PodList), err }, } return &lw }
func TestWatchControllers(t *testing.T) { fakeWatch := watch.NewFake() client := &testclient.Fake{} client.AddWatchReactor("*", testclient.DefaultWatchReactor(fakeWatch, nil)) manager := NewReplicationManager(client, controller.NoResyncPeriodFunc, BurstReplicas) manager.podStoreSynced = alwaysReady var testControllerSpec api.ReplicationController received := make(chan string) // The update sent through the fakeWatcher should make its way into the workqueue, // and eventually into the syncHandler. The handler validates the received controller // and closes the received channel to indicate that the test can finish. manager.syncHandler = func(key string) error { obj, exists, err := manager.rcStore.Store.GetByKey(key) if !exists || err != nil { t.Errorf("Expected to find controller under key %v", key) } controllerSpec := *obj.(*api.ReplicationController) if !api.Semantic.DeepDerivative(controllerSpec, testControllerSpec) { t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec) } close(received) return nil } // Start only the rc watcher and the workqueue, send a watch event, // and make sure it hits the sync method. stopCh := make(chan struct{}) defer close(stopCh) go manager.rcController.Run(stopCh) go util.Until(manager.worker, 10*time.Millisecond, stopCh) testControllerSpec.Name = "foo" fakeWatch.Add(&testControllerSpec) select { case <-received: case <-time.After(util.ForeverTestTimeout): t.Errorf("Expected 1 call but got 0") } }
func TestNewSourceApiserver_TwoNamespacesSameName(t *testing.T) { pod1 := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "p", Namespace: "one"}, Spec: api.PodSpec{Containers: []api.Container{{Image: "image/one"}}}} pod2 := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "p", Namespace: "two"}, Spec: api.PodSpec{Containers: []api.Container{{Image: "image/blah"}}}} // Setup fake api client. fakeWatch := watch.NewFake() lw := fakePodLW{ listResp: &api.PodList{Items: []api.Pod{pod1, pod2}}, watchResp: fakeWatch, } ch := make(chan interface{}) newSourceApiserverFromLW(lw, ch) got, ok := <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update := got.(kubelet.PodUpdate) // Make sure that we get both pods. Catches bug #2294. if !(len(update.Pods) == 2) { t.Errorf("Expected %d, Got %d", 2, len(update.Pods)) } // Delete pod1 fakeWatch.Delete(&pod1) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update = got.(kubelet.PodUpdate) if !(len(update.Pods) == 1) { t.Errorf("Expected %d, Got %d", 1, len(update.Pods)) } }
func TestNewSourceApiserverInitialEmptySendsEmptyPodUpdate(t *testing.T) { // Setup fake api client. fakeWatch := watch.NewFake() lw := fakePodLW{ listResp: &api.PodList{Items: []api.Pod{}}, watchResp: fakeWatch, } ch := make(chan interface{}) newSourceApiserverFromLW(lw, ch) got, ok := <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update := got.(kubelet.PodUpdate) expected := CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource) if !api.Semantic.DeepEqual(expected, update) { t.Errorf("Expected %#v; Got %#v", expected, update) } }
func TestReflectorResync(t *testing.T) { s := NewStore(MetaNamespaceKeyFunc) currentTime := time.Time{} now = func() time.Time { return currentTime } iteration := 0 lw := &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { if iteration == 0 { // Move time, but do not force resync. currentTime = currentTime.Add(30 * time.Second) } else if iteration == 1 { // Move time to force resync. currentTime = currentTime.Add(28 * time.Second) } else if iteration >= 2 { t.Fatalf("should have forced resync earlier") } iteration++ fw := watch.NewFake() // Send something to the watcher to avoid "watch too short" errors. go func() { fw.Add(&api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: strconv.Itoa(iteration)}}) fw.Stop() }() return fw, nil }, ListFunc: func() (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "0"}}, nil }, } resyncPeriod := time.Minute r := NewReflector(lw, &api.Pod{}, s, resyncPeriod) r.ListAndWatch(util.NeverStop) if iteration != 2 { t.Errorf("exactly 2 iterations were expected, got: %v", iteration) } }
func TestCloseWatchChannelOnError(t *testing.T) { r := NewReflector(&testLW{}, &api.Pod{}, NewStore(MetaNamespaceKeyFunc), 0) pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "bar"}} fw := watch.NewFake() r.listerWatcher = &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { return fw, nil }, ListFunc: func() (runtime.Object, error) { return &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: "1"}}, nil }, } go r.ListAndWatch(util.NeverStop) fw.Error(pod) select { case _, ok := <-fw.ResultChan(): if ok { t.Errorf("Watch channel left open after cancellation") } case <-time.After(util.ForeverTestTimeout): t.Errorf("the cancellation is at least %s late", util.ForeverTestTimeout.String()) break } }
func TestNewSourceApiserver_UpdatesAndMultiplePods(t *testing.T) { pod1v1 := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "p"}, Spec: api.PodSpec{Containers: []api.Container{{Image: "image/one"}}}} pod1v2 := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "p"}, Spec: api.PodSpec{Containers: []api.Container{{Image: "image/two"}}}} pod2 := &api.Pod{ ObjectMeta: api.ObjectMeta{Name: "q"}, Spec: api.PodSpec{Containers: []api.Container{{Image: "image/blah"}}}} // Setup fake api client. fakeWatch := watch.NewFake() lw := fakePodLW{ listResp: &api.PodList{Items: []api.Pod{*pod1v1}}, watchResp: fakeWatch, } ch := make(chan interface{}) newSourceApiserverFromLW(lw, ch) got, ok := <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update := got.(kubelet.PodUpdate) expected := CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod1v1) if !api.Semantic.DeepEqual(expected, update) { t.Errorf("Expected %#v; Got %#v", expected, update) } // Add another pod fakeWatch.Add(pod2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update = got.(kubelet.PodUpdate) // Could be sorted either of these two ways: expectedA := CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod1v1, pod2) expectedB := CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod2, pod1v1) if !api.Semantic.DeepEqual(expectedA, update) && !api.Semantic.DeepEqual(expectedB, update) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, update) } // Modify pod1 fakeWatch.Modify(pod1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update = got.(kubelet.PodUpdate) expectedA = CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod1v2, pod2) expectedB = CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod2, pod1v2) if !api.Semantic.DeepEqual(expectedA, update) && !api.Semantic.DeepEqual(expectedB, update) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, update) } // Delete pod1 fakeWatch.Delete(pod1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update = got.(kubelet.PodUpdate) expected = CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource, pod2) if !api.Semantic.DeepEqual(expected, update) { t.Errorf("Expected %#v, Got %#v", expected, update) } // Delete pod2 fakeWatch.Delete(pod2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } update = got.(kubelet.PodUpdate) expected = CreatePodUpdate(kubelet.SET, kubelet.ApiserverSource) if !api.Semantic.DeepEqual(expected, update) { t.Errorf("Expected %#v, Got %#v", expected, update) } }
// TestAdmission func TestAdmission(t *testing.T) { namespaceObj := &api.Namespace{ ObjectMeta: api.ObjectMeta{ Name: "test", Namespace: "", }, Status: api.NamespaceStatus{ Phase: api.NamespaceActive, }, } var namespaceLock sync.RWMutex store := cache.NewStore(cache.MetaNamespaceKeyFunc) store.Add(namespaceObj) fakeWatch := watch.NewFake() mockClient := &testclient.Fake{} mockClient.AddWatchReactor("*", testclient.DefaultWatchReactor(fakeWatch, nil)) mockClient.AddReactor("get", "namespaces", func(action testclient.Action) (bool, runtime.Object, error) { namespaceLock.RLock() defer namespaceLock.RUnlock() if getAction, ok := action.(testclient.GetAction); ok && getAction.GetName() == namespaceObj.Name { return true, namespaceObj, nil } return true, nil, fmt.Errorf("No result for action %v", action) }) mockClient.AddReactor("list", "namespaces", func(action testclient.Action) (bool, runtime.Object, error) { namespaceLock.RLock() defer namespaceLock.RUnlock() return true, &api.NamespaceList{Items: []api.Namespace{*namespaceObj}}, nil }) lfhandler := NewLifecycle(mockClient).(*lifecycle) lfhandler.store = store handler := admission.NewChainHandler(lfhandler) pod := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "123", Namespace: namespaceObj.Name}, Spec: api.PodSpec{ Volumes: []api.Volume{{Name: "vol"}}, Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, } badPod := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "456", Namespace: "doesnotexist"}, Spec: api.PodSpec{ Volumes: []api.Volume{{Name: "vol"}}, Containers: []api.Container{{Name: "ctr", Image: "image"}}, }, } err := handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Create, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // change namespace state to terminating namespaceLock.Lock() namespaceObj.Status.Phase = api.NamespaceTerminating namespaceLock.Unlock() store.Add(namespaceObj) // verify create operations in the namespace cause an error err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Create, nil)) if err == nil { t.Errorf("Expected error rejecting creates in a namespace when it is terminating") } // verify update operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(&pod, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Update, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete operations in the namespace can proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Pod", pod.Namespace, pod.Name, "pods", "", admission.Delete, nil)) if err != nil { t.Errorf("Unexpected error returned from admission handler: %v", err) } // verify delete of namespace default can never proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Namespace", "", api.NamespaceDefault, "namespaces", "", admission.Delete, nil)) if err == nil { t.Errorf("Expected an error that this namespace can never be deleted") } // verify delete of namespace other than default can proceed err = handler.Admit(admission.NewAttributesRecord(nil, "Namespace", "", "other", "namespaces", "", admission.Delete, nil)) if err != nil { t.Errorf("Did not expect an error %v", err) } // verify create/update/delete of object in non-existant namespace throws error err = handler.Admit(admission.NewAttributesRecord(&badPod, "Pod", badPod.Namespace, badPod.Name, "pods", "", admission.Create, nil)) if err == nil { t.Errorf("Expected an aerror that objects cannot be created in non-existant namespaces", err) } err = handler.Admit(admission.NewAttributesRecord(&badPod, "Pod", badPod.Namespace, badPod.Name, "pods", "", admission.Update, nil)) if err == nil { t.Errorf("Expected an aerror that objects cannot be updated in non-existant namespaces", err) } err = handler.Admit(admission.NewAttributesRecord(&badPod, "Pod", badPod.Namespace, badPod.Name, "pods", "", admission.Delete, nil)) if err == nil { t.Errorf("Expected an aerror that objects cannot be deleted in non-existant namespaces", err) } }
func TestReflector_ListAndWatchWithErrors(t *testing.T) { mkPod := func(id string, rv string) *api.Pod { return &api.Pod{ObjectMeta: api.ObjectMeta{Name: id, ResourceVersion: rv}} } mkList := func(rv string, pods ...*api.Pod) *api.PodList { list := &api.PodList{ListMeta: unversioned.ListMeta{ResourceVersion: rv}} for _, pod := range pods { list.Items = append(list.Items, *pod) } return list } table := []struct { list *api.PodList listErr error events []watch.Event watchErr error }{ { list: mkList("1"), events: []watch.Event{ {watch.Added, mkPod("foo", "2")}, {watch.Added, mkPod("bar", "3")}, }, }, { list: mkList("3", mkPod("foo", "2"), mkPod("bar", "3")), events: []watch.Event{ {watch.Deleted, mkPod("foo", "4")}, {watch.Added, mkPod("qux", "5")}, }, }, { listErr: fmt.Errorf("a list error"), }, { list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")), watchErr: fmt.Errorf("a watch error"), }, { list: mkList("5", mkPod("bar", "3"), mkPod("qux", "5")), events: []watch.Event{ {watch.Added, mkPod("baz", "6")}, }, }, { list: mkList("6", mkPod("bar", "3"), mkPod("qux", "5"), mkPod("baz", "6")), }, } s := NewFIFO(MetaNamespaceKeyFunc) for line, item := range table { if item.list != nil { // Test that the list is what currently exists in the store. current := s.List() checkMap := map[string]string{} for _, item := range current { pod := item.(*api.Pod) checkMap[pod.Name] = pod.ResourceVersion } for _, pod := range item.list.Items { if e, a := pod.ResourceVersion, checkMap[pod.Name]; e != a { t.Errorf("%v: expected %v, got %v for pod %v", line, e, a, pod.Name) } } if e, a := len(item.list.Items), len(checkMap); e != a { t.Errorf("%v: expected %v, got %v", line, e, a) } } watchRet, watchErr := item.events, item.watchErr lw := &testLW{ WatchFunc: func(rv string) (watch.Interface, error) { if watchErr != nil { return nil, watchErr } watchErr = fmt.Errorf("second watch") fw := watch.NewFake() go func() { for _, e := range watchRet { fw.Action(e.Type, e.Object) } fw.Stop() }() return fw, nil }, ListFunc: func() (runtime.Object, error) { return item.list, item.listErr }, } r := NewReflector(lw, &api.Pod{}, s, 0) r.ListAndWatch(util.NeverStop) } }
func TestNewEndpointsSourceApi_UpdatesAndMultipleEndpoints(t *testing.T) { endpoints1v1 := &api.Endpoints{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "e1"}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{ {IP: "1.2.3.4"}, }, Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, } endpoints1v2 := &api.Endpoints{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "e1"}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{ {IP: "1.2.3.4"}, {IP: "4.3.2.1"}, }, Ports: []api.EndpointPort{{Port: 8080, Protocol: "TCP"}}, }}, } endpoints2 := &api.Endpoints{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "e2"}, Subsets: []api.EndpointSubset{{ Addresses: []api.EndpointAddress{ {IP: "5.6.7.8"}, }, Ports: []api.EndpointPort{{Port: 80, Protocol: "TCP"}}, }}, } // Setup fake api client. fakeWatch := watch.NewFake() lw := fakeLW{ listResp: &api.EndpointsList{Items: []api.Endpoints{}}, watchResp: fakeWatch, } ch := make(chan EndpointsUpdate) newEndpointsSourceApiFromLW(lw, 30*time.Second, ch) got, ok := <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected := EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v; Got %#v", expected, got) } // Add the first endpoints fakeWatch.Add(endpoints1v1) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints1v1}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v; Got %#v", expected, got) } // Add another endpoints fakeWatch.Add(endpoints2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } // Could be sorted either of these two ways: expectedA := EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints1v1, *endpoints2}} expectedB := EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints2, *endpoints1v1}} if !api.Semantic.DeepEqual(expectedA, got) && !api.Semantic.DeepEqual(expectedB, got) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, got) } // Modify endpoints1 fakeWatch.Modify(endpoints1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expectedA = EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints1v2, *endpoints2}} expectedB = EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints2, *endpoints1v2}} if !api.Semantic.DeepEqual(expectedA, got) && !api.Semantic.DeepEqual(expectedB, got) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, got) } // Delete endpoints1 fakeWatch.Delete(endpoints1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{*endpoints2}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v, Got %#v", expected, got) } // Delete endpoints2 fakeWatch.Delete(endpoints2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = EndpointsUpdate{Op: SET, Endpoints: []api.Endpoints{}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v, Got %#v", expected, got) } }
func TestWatchJobs(t *testing.T) { fakeWatch := watch.NewFake() client := &testclient.Fake{} client.AddWatchReactor("*", testclient.DefaultWatchReactor(fakeWatch, nil)) manager := NewJobController(client, controller.NoResyncPeriodFunc) manager.podStoreSynced = alwaysReady var testJob extensions.Job received := make(chan string) // The update sent through the fakeWatcher should make its way into the workqueue, // and eventually into the syncHandler. manager.syncHandler = func(key string) error { obj, exists, err := manager.jobStore.Store.GetByKey(key) if !exists || err != nil { t.Errorf("Expected to find job under key %v", key) } job := *obj.(*extensions.Job) if !api.Semantic.DeepDerivative(job, testJob) { t.Errorf("Expected %#v, but got %#v", testJob, job) } received <- key return nil } // Start only the job watcher and the workqueue, send a watch event, // and make sure it hits the sync method. stopCh := make(chan struct{}) defer close(stopCh) go manager.jobController.Run(stopCh) go util.Until(manager.worker, 10*time.Millisecond, stopCh) // We're sending new job to see if it reaches syncHandler. testJob.Name = "foo" fakeWatch.Add(&testJob) select { case <-received: case <-time.After(controllerTimeout): t.Errorf("Expected 1 call but got 0") } // We're sending fake finished job, to see if it reaches syncHandler - it should not, // since we're filtering out finished jobs. testJobv2 := extensions.Job{ ObjectMeta: api.ObjectMeta{Name: "foo"}, Status: extensions.JobStatus{ Conditions: []extensions.JobCondition{{ Type: extensions.JobComplete, Status: api.ConditionTrue, LastProbeTime: unversioned.Now(), LastTransitionTime: unversioned.Now(), }}, }, } fakeWatch.Modify(&testJobv2) select { case <-received: t.Errorf("Expected 0 call but got 1") case <-time.After(controllerTimeout): } }
func TestNewServicesSourceApi_UpdatesAndMultipleServices(t *testing.T) { service1v1 := &api.Service{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "s1"}, Spec: api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 10}}}} service1v2 := &api.Service{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "s1"}, Spec: api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 20}}}} service2 := &api.Service{ ObjectMeta: api.ObjectMeta{Namespace: "testnamespace", Name: "s2"}, Spec: api.ServiceSpec{Ports: []api.ServicePort{{Protocol: "TCP", Port: 30}}}} // Setup fake api client. fakeWatch := watch.NewFake() lw := fakeLW{ listResp: &api.ServiceList{Items: []api.Service{}}, watchResp: fakeWatch, } ch := make(chan ServiceUpdate) newServicesSourceApiFromLW(lw, 30*time.Second, ch) got, ok := <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected := ServiceUpdate{Op: SET, Services: []api.Service{}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v; Got %#v", expected, got) } // Add the first service fakeWatch.Add(service1v1) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = ServiceUpdate{Op: SET, Services: []api.Service{*service1v1}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v; Got %#v", expected, got) } // Add another service fakeWatch.Add(service2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } // Could be sorted either of these two ways: expectedA := ServiceUpdate{Op: SET, Services: []api.Service{*service1v1, *service2}} expectedB := ServiceUpdate{Op: SET, Services: []api.Service{*service2, *service1v1}} if !api.Semantic.DeepEqual(expectedA, got) && !api.Semantic.DeepEqual(expectedB, got) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, got) } // Modify service1 fakeWatch.Modify(service1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expectedA = ServiceUpdate{Op: SET, Services: []api.Service{*service1v2, *service2}} expectedB = ServiceUpdate{Op: SET, Services: []api.Service{*service2, *service1v2}} if !api.Semantic.DeepEqual(expectedA, got) && !api.Semantic.DeepEqual(expectedB, got) { t.Errorf("Expected %#v or %#v, Got %#v", expectedA, expectedB, got) } // Delete service1 fakeWatch.Delete(service1v2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = ServiceUpdate{Op: SET, Services: []api.Service{*service2}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v, Got %#v", expected, got) } // Delete service2 fakeWatch.Delete(service2) got, ok = <-ch if !ok { t.Errorf("Unable to read from channel when expected") } expected = ServiceUpdate{Op: SET, Services: []api.Service{}} if !api.Semantic.DeepEqual(expected, got) { t.Errorf("Expected %#v, Got %#v", expected, got) } }