From d24da571a98411e59f6de8afb0c3478f51a8aaa3 Mon Sep 17 00:00:00 2001 From: Benjamin Grandfond Date: Thu, 4 Apr 2024 13:03:55 +0200 Subject: [PATCH] Fix url creation to handle query params when using HTTP wait strategy --- wait/http.go | 9 ++--- wait/http_test.go | 81 +++++++++++++++++++++++++++++++++++++++++++ wait/testdata/main.go | 11 ++++++ 3 files changed, 97 insertions(+), 4 deletions(-) diff --git a/wait/http.go b/wait/http.go index 7b92eb6a15..89e4f092d2 100644 --- a/wait/http.go +++ b/wait/http.go @@ -264,11 +264,12 @@ func (ws *HTTPStrategy) WaitUntilReady(ctx context.Context, target StrategyTarge client := http.Client{Transport: tripper, Timeout: time.Second} address := net.JoinHostPort(ipAddress, strconv.Itoa(mappedPort.Int())) - endpoint := url.URL{ - Scheme: proto, - Host: address, - Path: ws.Path, + endpoint, err := url.Parse(ws.Path) + if err != nil { + return err } + endpoint.Scheme = proto + endpoint.Host = address if ws.UserInfo != nil { endpoint.User = ws.UserInfo diff --git a/wait/http_test.go b/wait/http_test.go index 8966e6968e..e9e065ab33 100644 --- a/wait/http_test.go +++ b/wait/http_test.go @@ -300,6 +300,87 @@ func TestHTTPStrategyWaitUntilReady(t *testing.T) { } } +func TestHTTPStrategyWaitUntilReadyWithQueryString(t *testing.T) { + workdir, err := os.Getwd() + if err != nil { + t.Error(err) + return + } + + capath := filepath.Join(workdir, "testdata", "root.pem") + cafile, err := os.ReadFile(capath) + if err != nil { + t.Errorf("can't load ca file: %v", err) + return + } + + certpool := x509.NewCertPool() + if !certpool.AppendCertsFromPEM(cafile) { + t.Errorf("the ca file isn't valid") + return + } + + tlsconfig := &tls.Config{RootCAs: certpool, ServerName: "testcontainer.go.test"} + dockerReq := testcontainers.ContainerRequest{ + FromDockerfile: testcontainers.FromDockerfile{ + Context: filepath.Join(workdir, "testdata"), + }, + + ExposedPorts: []string{"6443/tcp"}, + WaitingFor: wait.NewHTTPStrategy("/query-params-ping?v=pong").WithTLS(true, tlsconfig). + WithStartupTimeout(time.Second * 10).WithPort("6443/tcp"). + WithResponseMatcher(func(body io.Reader) bool { + data, _ := io.ReadAll(body) + return bytes.Equal(data, []byte("pong")) + }), + } + + container, err := testcontainers.GenericContainer(context.Background(), + testcontainers.GenericContainerRequest{ContainerRequest: dockerReq, Started: true}) + if err != nil { + t.Error(err) + return + } + defer container.Terminate(context.Background()) // nolint: errcheck + + host, err := container.Host(context.Background()) + if err != nil { + t.Error(err) + return + } + port, err := container.MappedPort(context.Background(), "6443/tcp") + if err != nil { + t.Error(err) + return + } + client := http.Client{ + Transport: &http.Transport{ + TLSClientConfig: tlsconfig, + Proxy: http.ProxyFromEnvironment, + DialContext: (&net.Dialer{ + Timeout: time.Second, + KeepAlive: 30 * time.Second, + DualStack: true, + }).DialContext, + ForceAttemptHTTP2: true, + MaxIdleConns: 100, + IdleConnTimeout: 90 * time.Second, + TLSHandshakeTimeout: 10 * time.Second, + ExpectContinueTimeout: 1 * time.Second, + }, + } + resp, err := client.Get(fmt.Sprintf("https://%s:%s", host, port.Port())) + if err != nil { + t.Error(err) + return + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + t.Errorf("status code isn't ok: %s", resp.Status) + return + } +} + func TestHTTPStrategyWaitUntilReadyNoBasicAuth(t *testing.T) { workdir, err := os.Getwd() if err != nil { diff --git a/wait/testdata/main.go b/wait/testdata/main.go index 9ed936731a..95baa2f5b7 100644 --- a/wait/testdata/main.go +++ b/wait/testdata/main.go @@ -45,6 +45,17 @@ func main() { w.WriteHeader(http.StatusUnauthorized) }) + mux.HandleFunc("/query-params-ping", func(w http.ResponseWriter, req *http.Request) { + v := req.URL.Query().Get("v") + if v == "" { + w.WriteHeader(http.StatusBadRequest) + return + } + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("pong")) + }) + mux.HandleFunc("/headers", func(w http.ResponseWriter, req *http.Request) { h := req.Header.Get("X-request-header") if h != "" {