api/internal/endpoint/handler/http/proxy/handler_bench_test.go
Peter Kurfer d70ba748f5 Introduce Lifecycle for every endpoint and manage listeners in the renamed Orchestrator
- merge packages to get a more concise layout because plugins are no more and therefore there's not a lot to be exported
- fix test logger
- rework config parsing to be easier and more transparent
- remove unnecessary APIs because dynamic endpoint handling is rather a won't implement
2021-02-10 20:26:45 +00:00

167 lines
3.8 KiB
Go

package proxy_test
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
"net/url"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"github.com/docker/go-connections/nat"
"github.com/testcontainers/testcontainers-go"
"gitlab.com/inetmock/inetmock/internal/test/integration"
)
const (
charSet = "abcdedfghijklmnopqrstABCDEFGHIJKLMNOP"
)
var (
availableExtensions = []string{"gif", "html", "ico", "jpg", "png", "txt"}
)
func init() {
rand.Seed(time.Now().Unix())
}
func Benchmark_httpProxy(b *testing.B) {
type benchmark struct {
name string
port string
scheme string
}
benchmarks := []benchmark{
{
name: "HTTP",
port: "3128/tcp",
scheme: "http",
},
{
name: "HTTPS",
port: "3128/tcp",
scheme: "https",
},
}
scenario := func(bm benchmark) func(bm *testing.B) {
return func(b *testing.B) {
var err error
var endpoint string
if endpoint, err = setupContainer(b, bm.port); err != nil {
b.Errorf("setupContainer() error = %v", err)
}
var httpClient *http.Client
if httpClient, err = setupHTTPClient(fmt.Sprintf("http://%s", endpoint), fmt.Sprintf("https://%s", endpoint)); err != nil {
return
}
time.Sleep(500 * time.Millisecond)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
extension := availableExtensions[rand.Intn(len(availableExtensions))]
reqUrl, _ := url.Parse(fmt.Sprintf("%s://%s/%s.%s", bm.scheme, endpoint, randomString(15), extension))
req := &http.Request{
Method: http.MethodGet,
URL: reqUrl,
Close: false,
Host: "www.inetmock.com",
}
if resp, err := httpClient.Do(req); err != nil {
b.Error(err)
} else if resp.StatusCode != 200 {
b.Errorf("Got status code %d", resp.StatusCode)
}
}
})
}
}
for _, bm := range benchmarks {
b.Run(bm.name, scenario(bm))
}
}
func randomString(length int) (result string) {
buffer := strings.Builder{}
for i := 0; i < length; i++ {
buffer.WriteByte(charSet[rand.Intn(len(charSet))])
}
return buffer.String()
}
func setupContainer(b *testing.B, port string) (httpEndpoint string, err error) {
b.Helper()
startupCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
var inetMockContainer testcontainers.Container
if inetMockContainer, err = integration.SetupINetMockContainer(startupCtx, b, port); err != nil {
return
}
httpEndpoint, err = inetMockContainer.PortEndpoint(startupCtx, nat.Port(port), "")
return
}
func setupHTTPClient(httpEndpoint, httpsEndpoint string) (client *http.Client, err error) {
_, fileName, _, _ := runtime.Caller(0)
var repoRoot string
if repoRoot, err = filepath.Abs(filepath.Join(filepath.Dir(fileName), "..", "..", "..", "..", "..")); err != nil {
return
}
var demoCABytes []byte
if demoCABytes, err = ioutil.ReadFile(filepath.Join(repoRoot, "assets", "demoCA", "ca.pem")); err != nil {
return
}
rootCaPool := x509.NewCertPool()
if !rootCaPool.AppendCertsFromPEM(demoCABytes) {
err = errors.New("failed to add CA key")
return
}
client = &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
switch req.URL.Scheme {
case "http":
return url.Parse(httpEndpoint)
case "https":
return url.Parse(httpsEndpoint)
default:
return nil, errors.New("unknown scheme")
}
},
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
TLSClientConfig: &tls.Config{
RootCAs: rootCaPool,
},
ForceAttemptHTTP2: true,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
return
}