package appclient import ( "compress/gzip" "fmt" "net/http" "net/http/httptest" "net/url" "strings" "testing" "time" "github.com/gorilla/handlers" "github.com/ugorji/go/codec" "github.com/weaveworks/common/test" "github.com/weaveworks/scope/common/xfer" "github.com/weaveworks/scope/report" "github.com/weaveworks/scope/test/reflect" ) func dummyServer(t *testing.T, expectedToken, expectedID string, expectedVersion string, expectedReport report.Report, done chan struct{}) *httptest.Server { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if have := r.Header.Get("Authorization"); fmt.Sprintf("Scope-Probe token=%s", expectedToken) != have { t.Errorf("want %q, have %q", expectedToken, have) } if have := r.Header.Get(xfer.ScopeProbeIDHeader); expectedID != have { t.Errorf("want %q, have %q", expectedID, have) } if have := r.Header.Get(xfer.ScopeProbeVersionHeader); expectedVersion != have { t.Errorf("want %q, have %q", expectedVersion, have) } if have := r.Header.Get("user-agent"); "Scope_Probe/"+expectedVersion != have { t.Errorf("want %q, have %q", "Scope_Probe/"+expectedVersion, have) } var have report.Report reader := r.Body var err error if strings.Contains(r.Header.Get("Content-Encoding"), "gzip") { reader, err = gzip.NewReader(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } defer reader.Close() } decoder := codec.NewDecoder(reader, &codec.MsgpackHandle{}) if err := decoder.Decode(&have); err != nil { t.Error(err) return } if !reflect.DeepEqual(expectedReport, have) { t.Error(test.Diff(expectedReport, have)) return } w.WriteHeader(http.StatusOK) done <- struct{}{} }) return httptest.NewServer(handlers.CompressHandler(handler)) } func TestAppClientPublish(t *testing.T) { var ( token = "abcdefg" id = "1234567" version = "0.18" rpt = report.MakeReport() done = make(chan struct{}, 10) ) s := dummyServer(t, token, id, version, rpt, done) defer s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } pc := ProbeConfig{ Token: token, ProbeVersion: version, ProbeID: id, Insecure: false, } url, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } p, err := NewAppClient(pc, u.Host, *url, nil) if err != nil { t.Fatal(err) } defer p.Stop() // First few reports might be dropped as the client is spinning up. for i := 0; i < 10; i++ { buf, _ := rpt.WriteBinary() if err := p.Publish(buf, false); err != nil { t.Error(err) } time.Sleep(10 * time.Millisecond) } select { case <-done: case <-time.After(100 * time.Millisecond): t.Error("timeout") } } func TestAppClientDetails(t *testing.T) { var ( id = "foobarbaz" version = "imalittleteapot" want = xfer.Details{ID: id, Version: version} ) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { encoder := codec.NewEncoder(w, &codec.JsonHandle{}) if err := encoder.Encode(want); err != nil { t.Fatal(err) } }) s := httptest.NewServer(handlers.CompressHandler(handler)) defer s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } pc := ProbeConfig{ Token: "", ProbeID: "", Insecure: false, } url, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } p, err := NewAppClient(pc, u.Host, *url, nil) if err != nil { t.Fatal(err) } defer p.Stop() have, err := p.Details() if err != nil { t.Fatal(err) } if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) return } } // Make sure Stopping a client works even if the connection or the remote app // gets stuck for whatever reason. // See https://github.com/weaveworks/scope/issues/1576 func TestStop(t *testing.T) { var ( rpt = report.MakeReport() stopHanging = make(chan struct{}) receivedReport = make(chan struct{}) ) handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { close(receivedReport) <-stopHanging }) s := httptest.NewServer(handlers.CompressHandler(handler)) defer s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } pc := ProbeConfig{ Token: "", ProbeID: "", Insecure: false, } url, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } p, err := NewAppClient(pc, u.Host, *url, nil) if err != nil { t.Fatal(err) } // Make sure the app received our report and is stuck for done := false; !done; { select { case <-receivedReport: done = true default: buf, _ := rpt.WriteBinary() if err := p.Publish(buf, false); err != nil { t.Error(err) } time.Sleep(10 * time.Millisecond) } } // Close the client while the app is stuck p.Stop() // Let the server go so that the test can end close(stopHanging) }