diff --git a/cmd/syncthing/gui_test.go b/cmd/syncthing/gui_test.go index 0d9a112a..9517728c 100644 --- a/cmd/syncthing/gui_test.go +++ b/cmd/syncthing/gui_test.go @@ -9,10 +9,14 @@ package main import ( "bytes" "compress/gzip" + "fmt" "io/ioutil" + "net" "net/http" "net/http/httptest" + "strings" "testing" + "time" "github.com/d4l3k/messagediff" "github.com/syncthing/syncthing/lib/config" @@ -176,7 +180,7 @@ func TestDirNames(t *testing.T) { } } -func TestInstantiateAPIService(t *testing.T) { +func TestAPIServiceRequests(t *testing.T) { model := new(mockedModel) cfg := new(mockedConfig) httpsCertFile := "../../test/h1/https-cert.pem" @@ -188,10 +192,95 @@ func TestInstantiateAPIService(t *testing.T) { errorLog := new(mockedLoggerRecorder) systemLog := new(mockedLoggerRecorder) + // Instantiate the API service svc, err := newAPIService(protocol.LocalDeviceID, cfg, httpsCertFile, httpsKeyFile, assetDir, model, eventSub, discoverer, relayService, errorLog, systemLog) if err != nil { t.Fatal(err) } _ = svc + + // Make sure the API service is listening, and get the URL to use. + addr := svc.listener.Addr() + if addr == nil { + t.Fatal("Nil listening address from API service") + } + tcpAddr, err := net.ResolveTCPAddr("tcp", addr.String()) + if err != nil { + t.Fatal("Weird address from API service:", err) + } + baseURL := fmt.Sprintf("http://127.0.0.1:%d", tcpAddr.Port) + + // Actually start the API service + supervisor := suture.NewSimple("API test") + supervisor.Add(svc) + supervisor.ServeBackground() + + // Try requests to common URLs, all of which should succeed and return + // some sort of JSON object. + urls := []string{ + "/rest/system/status", + "/rest/system/config", + "/rest/system/config/insync", + // "/rest/system/connections", does not return an object in the empty case ("null"), should be fixed + "/rest/system/discovery", + "/rest/system/error?since=0", + "/rest/system/ping", + // "/rest/system/upgrade", depends on Github API, not good for testing + "/rest/system/version", + "/rest/system/debug", + "/rest/system/log?since=0", + } + for _, url := range urls { + t.Log("Testing", url, "...") + testHTTPJSONObject(t, baseURL+url) + } +} + +// testHTTPJSONObject tries the given URL and verifies that the HTTP request +// succeeds and that a JSON object (something beginning with "{") is +// returned. Returns the object data, or nil on failure. +func testHTTPJSONObject(t *testing.T, url string) []byte { + resp := testHTTPRequest(t, url) + if resp == nil { + return nil + } + + ct := resp.Header.Get("Content-Type") + if !strings.HasPrefix(ct, "application/json") { + t.Errorf("The content type on %s should be application/json, not %q", url, ct) + return nil + } + + defer resp.Body.Close() + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("Unexpected error reading %s: %v", url, err) + return nil + } + + if !bytes.HasPrefix(data, []byte("{")) { + t.Errorf("Returned data from %s does not look like a JSON object: %s", url, data) + return nil + } + return data +} + +// testHTTPRequest performs a HTTP GET request and verifies that the +// response is successfull (code 200). Returns the *http.Response or nil on +// failure. +func testHTTPRequest(t *testing.T, url string) *http.Response { + cli := &http.Client{ + Timeout: time.Second, + } + resp, err := cli.Get(url) + if err != nil { + t.Errorf("Unexpected error requesting %s: %v", url, err) + return nil + } + if resp.StatusCode != 200 { + t.Errorf("Get on %s should have returned status code 200, not %s", url, resp.Status) + return nil + } + return resp } diff --git a/cmd/syncthing/mocked_logger_test.go b/cmd/syncthing/mocked_logger_test.go index a2a42e6e..19ad99b2 100644 --- a/cmd/syncthing/mocked_logger_test.go +++ b/cmd/syncthing/mocked_logger_test.go @@ -15,7 +15,12 @@ import ( type mockedLoggerRecorder struct{} func (r *mockedLoggerRecorder) Since(t time.Time) []logger.Line { - select {} + return []logger.Line{ + { + When: time.Now(), + Message: "Test message", + }, + } } func (r *mockedLoggerRecorder) Clear() {}