diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index 4abad9f9f..19395b6b2 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -158,7 +158,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro srv := http.Server{ Handler: handler, - ReadTimeout: 2 * time.Second, + ReadTimeout: 10 * time.Second, } go func() { diff --git a/test/httpstress_test.go b/test/httpstress_test.go index 6855bd1d3..1370f8549 100644 --- a/test/httpstress_test.go +++ b/test/httpstress_test.go @@ -49,6 +49,8 @@ func TestStressHTTP(t *testing.T) { t.Fatal(err) } + // Create a client with reasonable timeouts on all stages of the request. + tc := &tls.Config{InsecureSkipVerify: true} tr := &http.Transport{ TLSClientConfig: tc, @@ -60,72 +62,101 @@ func TestStressHTTP(t *testing.T) { Transport: tr, Timeout: 10 * time.Second, } + + var ( + requestsOK = map[string]int{} + requestsError = map[string]int{} + firstError error + lock sync.Mutex + ) + + gotError := func(ctx string, err error) { + lock.Lock() + requestsError[ctx]++ + if firstError == nil { + firstError = err + } + lock.Unlock() + } + + requestOK := func(ctx string) { + lock.Lock() + requestsOK[ctx]++ + lock.Unlock() + } + + log.Println("Testing...") + var wg sync.WaitGroup t0 := time.Now() - var counter int - var lock sync.Mutex - - errChan := make(chan error, 2) - // One thread with immediately closed connections wg.Add(1) go func() { + defer wg.Done() for time.Since(t0).Seconds() < 30 { conn, err := net.Dial("tcp", "localhost:8082") if err != nil { - log.Println(err) - errChan <- err - return + gotError("Dial", err) + } else { + requestOK("Dial") + conn.Close() } - conn.Close() + + // At most 100 connects/sec + time.Sleep(10 * time.Millisecond) } - wg.Done() }() - // 50 threads doing HTTP and HTTPS requests + // 50 threads doing mixed HTTP and HTTPS requests for i := 0; i < 50; i++ { i := i wg.Add(1) go func() { + defer wg.Done() for time.Since(t0).Seconds() < 30 { proto := "http" if i%2 == 0 { proto = "https" } - resp, err := client.Get(proto + "://localhost:8082/") + url := proto + "://localhost:8082/" + resp, err := client.Get(url) + if err != nil { - errChan <- err - return - } - bs, _ := ioutil.ReadAll(resp.Body) - resp.Body.Close() - if !bytes.Contains(bs, []byte("")) { - log.Printf("%s", bs) - errChan <- errors.New("Incorrect response") - return + gotError("Get "+proto, err) + continue } - lock.Lock() - counter++ - lock.Unlock() + bs, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + + if err != nil { + gotError("Read "+proto, err) + continue + } + + if !bytes.Contains(bs, []byte("")) { + err := errors.New("Incorrect response") + gotError("Get "+proto, err) + continue + } + + requestOK(url) + + // At most 100 requests/sec + time.Sleep(10 * time.Millisecond) } - wg.Done() }() } - go func() { - wg.Wait() - errChan <- nil - }() + wg.Wait() + t.Logf("OK: %v reqs", requestsOK) + t.Logf("Err: %v reqs", requestsError) - err = <-errChan - if err != nil { - t.Error(err) + if firstError != nil { + t.Error(firstError) } - t.Logf("%.01f reqs/sec", float64(counter)/time.Since(t0).Seconds()) - err = sender.stop() if err != nil { t.Error(err)