func watchBody(events ...watch.Event) string { buf := &bytes.Buffer{} enc := watchjson.NewEncoder(buf, latest.Codec) for _, e := range events { enc.Encode(&e) } return buf.String() }
// ServeHTTP serves a series of JSON encoded events via straight HTTP with // Transfer-Encoding: chunked. func (self *WatchServer) ServeHTTP(w http.ResponseWriter, req *http.Request) { loggedW := httplog.LogOf(req, w) w = httplog.Unlogged(w) timeoutCh, cleanup := self.t.TimeoutCh() defer cleanup() defer self.watching.Stop() cn, ok := w.(http.CloseNotifier) if !ok { loggedW.Addf("unable to get CloseNotifier") http.NotFound(w, req) return } flusher, ok := w.(http.Flusher) if !ok { loggedW.Addf("unable to get Flusher") http.NotFound(w, req) return } w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) flusher.Flush() encoder := watchjson.NewEncoder(w, self.codec) for { select { case <-cn.CloseNotify(): return case <-timeoutCh: return case event, ok := <-self.watching.ResultChan(): if !ok { // End of results. return } self.fixup(event.Object) if err := encoder.Encode(&event); err != nil { // Client disconnect. return } flusher.Flush() } } }
func TestWatch(t *testing.T) { var table = []struct { t watch.EventType obj runtime.Object }{ {watch.Added, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "first"}}}, {watch.Modified, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "second"}}}, {watch.Deleted, &api.Pod{ObjectMeta: api.ObjectMeta{Name: "last"}}}, } auth := &Config{Username: "******", Password: "******"} testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { checkAuth(t, auth, r) flusher, ok := w.(http.Flusher) if !ok { panic("need flusher!") } w.Header().Set("Transfer-Encoding", "chunked") w.WriteHeader(http.StatusOK) flusher.Flush() encoder := watchjson.NewEncoder(w, latest.Codec) for _, item := range table { if err := encoder.Encode(&watch.Event{item.t, item.obj}); err != nil { panic(err) } flusher.Flush() } })) s, err := New(&Config{ Host: testServer.URL, Version: testapi.Version(), Username: "******", Password: "******", }) if err != nil { t.Fatalf("unexpected error: %v", err) } watching, err := s.Get().Prefix("path/to/watch/thing").Watch() if err != nil { t.Fatalf("Unexpected error") } for _, item := range table { got, ok := <-watching.ResultChan() if !ok { t.Fatalf("Unexpected early close") } if e, a := item.t, got.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } if e, a := item.obj, got.Object; !api.Semantic.DeepDerivative(e, a) { t.Errorf("Expected %v, got %v", e, a) } } _, ok := <-watching.ResultChan() if ok { t.Fatal("Unexpected non-close") } }