mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
136 lines
3.6 KiB
Go
136 lines
3.6 KiB
Go
// Copyright 2017 go-dockerclient authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build !windows
|
|
|
|
package docker
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"reflect"
|
|
"sort"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestClientDoConcurrentStress(t *testing.T) {
|
|
t.Parallel()
|
|
var reqs []*http.Request
|
|
var mu sync.Mutex
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
mu.Lock()
|
|
reqs = append(reqs, r)
|
|
mu.Unlock()
|
|
})
|
|
var nativeSrvs []*httptest.Server
|
|
for i := 0; i < 3; i++ {
|
|
srv, cleanup, err := newNativeServer(handler)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer cleanup()
|
|
nativeSrvs = append(nativeSrvs, srv)
|
|
}
|
|
var tests = []struct {
|
|
testCase string
|
|
srv *httptest.Server
|
|
scheme string
|
|
withTimeout bool
|
|
withTLSServer bool
|
|
withTLSClient bool
|
|
}{
|
|
{testCase: "http server", srv: httptest.NewUnstartedServer(handler), scheme: "http"},
|
|
{testCase: "native server", srv: nativeSrvs[0], scheme: nativeProtocol},
|
|
{testCase: "http with timeout", srv: httptest.NewUnstartedServer(handler), scheme: "http", withTimeout: true},
|
|
{testCase: "native with timeout", srv: nativeSrvs[1], scheme: nativeProtocol, withTimeout: true},
|
|
{testCase: "http with tls", srv: httptest.NewUnstartedServer(handler), scheme: "https", withTLSServer: true, withTLSClient: true},
|
|
{testCase: "native with client-only tls", srv: nativeSrvs[2], scheme: nativeProtocol, withTLSServer: false, withTLSClient: nativeProtocol == unixProtocol}, // TLS client only works with unix protocol
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.testCase, func(t *testing.T) {
|
|
reqs = nil
|
|
var client *Client
|
|
var err error
|
|
endpoint := tt.scheme + "://" + tt.srv.Listener.Addr().String()
|
|
if tt.withTLSServer {
|
|
tt.srv.StartTLS()
|
|
} else {
|
|
tt.srv.Start()
|
|
}
|
|
defer tt.srv.Close()
|
|
if tt.withTLSClient {
|
|
certPEMBlock, certErr := ioutil.ReadFile("testing/data/cert.pem")
|
|
if certErr != nil {
|
|
t.Fatal(certErr)
|
|
}
|
|
keyPEMBlock, certErr := ioutil.ReadFile("testing/data/key.pem")
|
|
if certErr != nil {
|
|
t.Fatal(certErr)
|
|
}
|
|
client, err = NewTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, nil)
|
|
} else {
|
|
client, err = NewClient(endpoint)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if tt.withTimeout {
|
|
client.SetTimeout(time.Minute)
|
|
}
|
|
n := 50
|
|
wg := sync.WaitGroup{}
|
|
var paths []string
|
|
errsCh := make(chan error, 3*n)
|
|
waiters := make(chan CloseWaiter, n)
|
|
for i := 0; i < n; i++ {
|
|
path := fmt.Sprintf("/%05d", i)
|
|
paths = append(paths, "GET"+path)
|
|
paths = append(paths, "POST"+path)
|
|
paths = append(paths, "HEAD"+path)
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
_, clientErr := client.do("GET", path, doOptions{})
|
|
if clientErr != nil {
|
|
errsCh <- clientErr
|
|
}
|
|
clientErr = client.stream("POST", path, streamOptions{})
|
|
if clientErr != nil {
|
|
errsCh <- clientErr
|
|
}
|
|
cw, clientErr := client.hijack("HEAD", path, hijackOptions{})
|
|
if clientErr != nil {
|
|
errsCh <- clientErr
|
|
} else {
|
|
waiters <- cw
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
close(errsCh)
|
|
close(waiters)
|
|
for cw := range waiters {
|
|
cw.Wait()
|
|
cw.Close()
|
|
}
|
|
for err = range errsCh {
|
|
t.Error(err)
|
|
}
|
|
var reqPaths []string
|
|
for _, r := range reqs {
|
|
reqPaths = append(reqPaths, r.Method+r.URL.Path)
|
|
}
|
|
sort.Strings(paths)
|
|
sort.Strings(reqPaths)
|
|
if !reflect.DeepEqual(reqPaths, paths) {
|
|
t.Fatalf("expected server request paths to equal %v, got: %v", paths, reqPaths)
|
|
}
|
|
})
|
|
}
|
|
}
|