...

Source file src/github.com/go-openapi/runtime/client/request_test.go

Documentation: github.com/go-openapi/runtime/client

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package client
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/json"
    20  	"encoding/xml"
    21  	"errors"
    22  	"io"
    23  	"mime"
    24  	"mime/multipart"
    25  	"net/http"
    26  	"net/http/httptest"
    27  	"net/url"
    28  	"os"
    29  	"path/filepath"
    30  	"strings"
    31  	"testing"
    32  
    33  	"github.com/go-openapi/strfmt"
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  
    37  	"github.com/go-openapi/runtime"
    38  )
    39  
    40  var testProducers = map[string]runtime.Producer{
    41  	runtime.JSONMime: runtime.JSONProducer(),
    42  	runtime.XMLMime:  runtime.XMLProducer(),
    43  	runtime.TextMime: runtime.TextProducer(),
    44  }
    45  
    46  func TestBuildRequest_SetHeaders(t *testing.T) {
    47  	r := newRequest(http.MethodGet, "/flats/{id}/", nil)
    48  
    49  	// single value
    50  	_ = r.SetHeaderParam("X-Rate-Limit", "500")
    51  	assert.Equal(t, "500", r.header.Get("X-Rate-Limit"))
    52  	_ = r.SetHeaderParam("X-Rate-Limit", "400")
    53  	assert.Equal(t, "400", r.header.Get("X-Rate-Limit"))
    54  
    55  	// multi value
    56  	_ = r.SetHeaderParam("X-Accepts", "json", "xml", "yaml")
    57  	assert.EqualValues(t, []string{"json", "xml", "yaml"}, r.header["X-Accepts"])
    58  }
    59  
    60  func TestBuildRequest_SetPath(t *testing.T) {
    61  	r := newRequest(http.MethodGet, "/flats/{id}/?hello=world", nil)
    62  
    63  	_ = r.SetPathParam("id", "1345")
    64  	assert.Equal(t, "1345", r.pathParams["id"])
    65  }
    66  
    67  func TestBuildRequest_SetQuery(t *testing.T) {
    68  	r := newRequest(http.MethodGet, "/flats/{id}/", nil)
    69  
    70  	// single value
    71  	_ = r.SetQueryParam("hello", "there")
    72  	assert.Equal(t, "there", r.query.Get("hello"))
    73  
    74  	// multi value
    75  	_ = r.SetQueryParam("goodbye", "cruel", "world")
    76  	assert.Equal(t, []string{"cruel", "world"}, r.query["goodbye"])
    77  }
    78  
    79  func TestBuildRequest_SetForm(t *testing.T) {
    80  	// non-multipart
    81  	r := newRequest(http.MethodPost, "/flats", nil)
    82  	_ = r.SetFormParam("hello", "world")
    83  	assert.Equal(t, "world", r.formFields.Get("hello"))
    84  	_ = r.SetFormParam("goodbye", "cruel", "world")
    85  	assert.Equal(t, []string{"cruel", "world"}, r.formFields["goodbye"])
    86  }
    87  
    88  func TestBuildRequest_SetFile(t *testing.T) {
    89  	// needs to convert form to multipart
    90  	r := newRequest(http.MethodPost, "/flats/{id}/image", nil)
    91  
    92  	// error if it isn't there
    93  	err := r.SetFileParam("not there", os.NewFile(0, "./i-dont-exist"))
    94  	require.Error(t, err)
    95  
    96  	// error if it isn't a file
    97  	err = r.SetFileParam("directory", os.NewFile(0, "../client"))
    98  	require.Error(t, err)
    99  	// success adds it to the map
   100  	err = r.SetFileParam("file", mustGetFile("./runtime.go"))
   101  	require.NoError(t, err)
   102  	fl, ok := r.fileFields["file"]
   103  	require.True(t, ok)
   104  	assert.Equal(t, "runtime.go", filepath.Base(fl[0].Name()))
   105  
   106  	// success adds a file param with multiple files
   107  	err = r.SetFileParam("otherfiles", mustGetFile("./runtime.go"), mustGetFile("./request.go"))
   108  	require.NoError(t, err)
   109  	fl, ok = r.fileFields["otherfiles"]
   110  	require.True(t, ok)
   111  	assert.Equal(t, "runtime.go", filepath.Base(fl[0].Name()))
   112  	assert.Equal(t, "request.go", filepath.Base(fl[1].Name()))
   113  }
   114  
   115  func mustGetFile(path string) *os.File {
   116  	f, err := os.Open(path)
   117  	if err != nil {
   118  		panic(err)
   119  	}
   120  	return f
   121  }
   122  
   123  func TestBuildRequest_SetBody(t *testing.T) {
   124  	r := newRequest(http.MethodGet, "/flats/{id}/?hello=world", nil)
   125  
   126  	bd := []struct{ Name, Hobby string }{{"Tom", "Organ trail"}, {"John", "Bird watching"}}
   127  
   128  	_ = r.SetBodyParam(bd)
   129  	assert.Equal(t, bd, r.payload)
   130  }
   131  
   132  func TestBuildRequest_BuildHTTP_NoPayload(t *testing.T) {
   133  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   134  		_ = req.SetBodyParam(nil)
   135  		_ = req.SetQueryParam("hello", "world")
   136  		_ = req.SetPathParam("id", "1234")
   137  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   138  		return nil
   139  	})
   140  	r := newRequest(http.MethodPost, "/flats/{id}/", reqWrtr)
   141  
   142  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   143  	require.NoError(t, err)
   144  	require.NotNil(t, req)
   145  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   146  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   147  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   148  }
   149  
   150  func TestBuildRequest_BuildHTTP_Payload(t *testing.T) {
   151  	bd := []struct{ Name, Hobby string }{{"Tom", "Organ trail"}, {"John", "Bird watching"}}
   152  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   153  		_ = req.SetBodyParam(bd)
   154  		_ = req.SetQueryParam("hello", "world")
   155  		_ = req.SetPathParam("id", "1234")
   156  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   157  		return nil
   158  	})
   159  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   160  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
   161  
   162  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   163  	require.NoError(t, err)
   164  	require.NotNil(t, req)
   165  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   166  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   167  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   168  	expectedBody, err := json.Marshal(bd)
   169  	require.NoError(t, err)
   170  	actualBody, err := io.ReadAll(req.Body)
   171  	require.NoError(t, err)
   172  	assert.Equal(t, append(expectedBody, '\n'), actualBody)
   173  }
   174  
   175  func TestBuildRequest_BuildHTTP_SetsInAuth(t *testing.T) {
   176  	bd := []struct{ Name, Hobby string }{{"Tom", "Organ trail"}, {"John", "Bird watching"}}
   177  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   178  		_ = req.SetBodyParam(bd)
   179  		_ = req.SetQueryParam("hello", "wrong")
   180  		_ = req.SetPathParam("id", "wrong")
   181  		_ = req.SetHeaderParam("X-Rate-Limit", "wrong")
   182  		return nil
   183  	})
   184  
   185  	auth := runtime.ClientAuthInfoWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   186  		_ = req.SetBodyParam(bd)
   187  		_ = req.SetQueryParam("hello", "world")
   188  		_ = req.SetPathParam("id", "1234")
   189  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   190  		return nil
   191  	})
   192  
   193  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   194  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
   195  
   196  	req, err := r.buildHTTP(runtime.JSONMime, "", testProducers, nil, auth)
   197  	require.NoError(t, err)
   198  	require.NotNil(t, req)
   199  
   200  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   201  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   202  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   203  	expectedBody, err := json.Marshal(bd)
   204  	require.NoError(t, err)
   205  	actualBody, err := io.ReadAll(req.Body)
   206  	require.NoError(t, err)
   207  	assert.Equal(t, append(expectedBody, '\n'), actualBody)
   208  }
   209  
   210  func TestBuildRequest_BuildHTTP_XMLPayload(t *testing.T) {
   211  	bd := []struct {
   212  		XMLName xml.Name `xml:"person"`
   213  		Name    string   `xml:"name"`
   214  		Hobby   string   `xml:"hobby"`
   215  	}{{xml.Name{}, "Tom", "Organ trail"}, {xml.Name{}, "John", "Bird watching"}}
   216  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   217  		_ = req.SetBodyParam(bd)
   218  		_ = req.SetQueryParam("hello", "world")
   219  		_ = req.SetPathParam("id", "1234")
   220  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   221  		return nil
   222  	})
   223  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   224  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.XMLMime)
   225  
   226  	req, err := r.BuildHTTP(runtime.XMLMime, "", testProducers, nil)
   227  	require.NoError(t, err)
   228  	require.NotNil(t, req)
   229  
   230  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   231  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   232  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   233  	expectedBody, err := xml.Marshal(bd)
   234  	require.NoError(t, err)
   235  	actualBody, err := io.ReadAll(req.Body)
   236  	require.NoError(t, err)
   237  	assert.Equal(t, expectedBody, actualBody)
   238  }
   239  
   240  func TestBuildRequest_BuildHTTP_TextPayload(t *testing.T) {
   241  	const bd = "Tom: Organ trail; John: Bird watching"
   242  
   243  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   244  		_ = req.SetBodyParam(bd)
   245  		_ = req.SetQueryParam("hello", "world")
   246  		_ = req.SetPathParam("id", "1234")
   247  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   248  		return nil
   249  	})
   250  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   251  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.TextMime)
   252  
   253  	req, err := r.BuildHTTP(runtime.TextMime, "", testProducers, nil)
   254  	require.NoError(t, err)
   255  	require.NotNil(t, req)
   256  
   257  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   258  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   259  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   260  	expectedBody := []byte(bd)
   261  	actualBody, err := io.ReadAll(req.Body)
   262  	require.NoError(t, err)
   263  	assert.Equal(t, expectedBody, actualBody)
   264  }
   265  
   266  func TestBuildRequest_BuildHTTP_Form(t *testing.T) {
   267  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   268  		_ = req.SetFormParam("something", "some value")
   269  		_ = req.SetQueryParam("hello", "world")
   270  		_ = req.SetPathParam("id", "1234")
   271  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   272  		return nil
   273  	})
   274  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   275  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
   276  
   277  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   278  	require.NoError(t, err)
   279  	require.NotNil(t, req)
   280  
   281  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   282  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   283  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   284  	expected := []byte("something=some+value")
   285  	actual, _ := io.ReadAll(req.Body)
   286  	assert.Equal(t, expected, actual)
   287  }
   288  
   289  func TestBuildRequest_BuildHTTP_Form_URLEncoded(t *testing.T) {
   290  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   291  		_ = req.SetFormParam("something", "some value")
   292  		_ = req.SetQueryParam("hello", "world")
   293  		_ = req.SetPathParam("id", "1234")
   294  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   295  		return nil
   296  	})
   297  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   298  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.URLencodedFormMime)
   299  
   300  	req, err := r.BuildHTTP(runtime.URLencodedFormMime, "", testProducers, nil)
   301  	require.NoError(t, err)
   302  	require.NotNil(t, req)
   303  
   304  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   305  	assert.Equal(t, runtime.URLencodedFormMime, req.Header.Get(runtime.HeaderContentType))
   306  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   307  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   308  	expected := []byte("something=some+value")
   309  	actual, _ := io.ReadAll(req.Body)
   310  	assert.Equal(t, expected, actual)
   311  }
   312  
   313  func TestBuildRequest_BuildHTTP_Form_Content_Length(t *testing.T) {
   314  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   315  		_ = req.SetFormParam("something", "some value")
   316  		_ = req.SetQueryParam("hello", "world")
   317  		_ = req.SetPathParam("id", "1234")
   318  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   319  		return nil
   320  	})
   321  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   322  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.MultipartFormMime)
   323  
   324  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   325  	require.NoError(t, err)
   326  	require.NotNil(t, req)
   327  
   328  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   329  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   330  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   331  	assert.Condition(t, func() bool { return req.ContentLength > 0 },
   332  		"ContentLength must great than 0. got %d", req.ContentLength)
   333  	expected := []byte("something=some+value")
   334  	actual, _ := io.ReadAll(req.Body)
   335  	assert.Equal(t, expected, actual)
   336  }
   337  
   338  func TestBuildRequest_BuildHTTP_FormMultipart(t *testing.T) {
   339  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   340  		_ = req.SetFormParam("something", "some value")
   341  		_ = req.SetQueryParam("hello", "world")
   342  		_ = req.SetPathParam("id", "1234")
   343  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   344  		return nil
   345  	})
   346  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   347  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.MultipartFormMime)
   348  
   349  	req, err := r.BuildHTTP(runtime.MultipartFormMime, "", testProducers, nil)
   350  	require.NoError(t, err)
   351  	require.NotNil(t, req)
   352  
   353  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   354  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   355  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   356  	expected1 := []byte("Content-Disposition: form-data; name=\"something\"")
   357  	expected2 := []byte("some value")
   358  	actual, err := io.ReadAll(req.Body)
   359  	require.NoError(t, err)
   360  	actuallines := bytes.Split(actual, []byte("\r\n"))
   361  	assert.Len(t, actuallines, 6)
   362  	boundary := string(actuallines[0])
   363  	lastboundary := string(actuallines[4])
   364  	assert.True(t, strings.HasPrefix(boundary, "--"))
   365  	assert.True(t, strings.HasPrefix(lastboundary, "--") && strings.HasSuffix(lastboundary, "--"))
   366  	assert.Equal(t, lastboundary, boundary+"--")
   367  	assert.Equal(t, expected1, actuallines[1])
   368  	assert.Equal(t, expected2, actuallines[3])
   369  }
   370  
   371  func TestBuildRequest_BuildHTTP_FormMultiples(t *testing.T) {
   372  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   373  		_ = req.SetFormParam("something", "some value", "another value")
   374  		_ = req.SetQueryParam("hello", "world")
   375  		_ = req.SetPathParam("id", "1234")
   376  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   377  		return nil
   378  	})
   379  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   380  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.MultipartFormMime)
   381  
   382  	req, err := r.BuildHTTP(runtime.MultipartFormMime, "", testProducers, nil)
   383  	require.NoError(t, err)
   384  	require.NotNil(t, req)
   385  
   386  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   387  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   388  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   389  	expected1 := []byte("Content-Disposition: form-data; name=\"something\"")
   390  	expected2 := []byte("some value")
   391  	expected3 := []byte("another value")
   392  	actual, err := io.ReadAll(req.Body)
   393  	require.NoError(t, err)
   394  	actuallines := bytes.Split(actual, []byte("\r\n"))
   395  	assert.Len(t, actuallines, 10)
   396  	boundary := string(actuallines[0])
   397  	lastboundary := string(actuallines[8])
   398  	assert.True(t, strings.HasPrefix(boundary, "--"))
   399  	assert.True(t, strings.HasPrefix(lastboundary, "--") && strings.HasSuffix(lastboundary, "--"))
   400  	assert.Equal(t, lastboundary, boundary+"--")
   401  	assert.Equal(t, expected1, actuallines[1])
   402  	assert.Equal(t, expected2, actuallines[3])
   403  	assert.Equal(t, actuallines[0], actuallines[4])
   404  	assert.Equal(t, expected1, actuallines[5])
   405  	assert.Equal(t, expected3, actuallines[7])
   406  }
   407  
   408  func TestBuildRequest_BuildHTTP_Files(t *testing.T) {
   409  	cont, err := os.ReadFile("./runtime.go")
   410  	require.NoError(t, err)
   411  	cont2, err := os.ReadFile("./request.go")
   412  	require.NoError(t, err)
   413  	emptyFile, err := os.CreateTemp("", "empty")
   414  	require.NoError(t, err)
   415  
   416  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   417  		_ = req.SetFormParam("something", "some value")
   418  		_ = req.SetFileParam("file", mustGetFile("./runtime.go"))
   419  		_ = req.SetFileParam("otherfiles", mustGetFile("./runtime.go"), mustGetFile("./request.go"))
   420  		_ = req.SetFileParam("empty", emptyFile)
   421  		_ = req.SetQueryParam("hello", "world")
   422  		_ = req.SetPathParam("id", "1234")
   423  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   424  		return nil
   425  	})
   426  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   427  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
   428  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   429  	require.NoError(t, err)
   430  	require.NotNil(t, req)
   431  
   432  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   433  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   434  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   435  
   436  	mediaType, params, err := mime.ParseMediaType(req.Header.Get(runtime.HeaderContentType))
   437  	require.NoError(t, err)
   438  
   439  	assert.Equal(t, runtime.MultipartFormMime, mediaType)
   440  	boundary := params["boundary"]
   441  	mr := multipart.NewReader(req.Body, boundary)
   442  	defer req.Body.Close()
   443  	frm, err := mr.ReadForm(1 << 20)
   444  	require.NoError(t, err)
   445  
   446  	assert.Equal(t, "some value", frm.Value["something"][0])
   447  	fileverifier := func(name string, index int, filename string, content []byte) {
   448  		mpff := frm.File[name][index]
   449  		mpf, e := mpff.Open()
   450  		require.NoError(t, e)
   451  		defer mpf.Close()
   452  		assert.Equal(t, filename, mpff.Filename)
   453  		actual, e := io.ReadAll(mpf)
   454  		require.NoError(t, e)
   455  		assert.Equal(t, content, actual)
   456  	}
   457  	fileverifier("file", 0, "runtime.go", cont)
   458  
   459  	fileverifier("otherfiles", 0, "runtime.go", cont)
   460  	fileverifier("otherfiles", 1, "request.go", cont2)
   461  	fileverifier("empty", 0, filepath.Base(emptyFile.Name()), []byte{})
   462  }
   463  
   464  func TestBuildRequest_BuildHTTP_Files_URLEncoded(t *testing.T) {
   465  	cont, err := os.ReadFile("./runtime.go")
   466  	require.NoError(t, err)
   467  	cont2, err := os.ReadFile("./request.go")
   468  	require.NoError(t, err)
   469  
   470  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   471  		_ = req.SetFormParam("something", "some value")
   472  		_ = req.SetFileParam("file", mustGetFile("./runtime.go"))
   473  		_ = req.SetFileParam("otherfiles", mustGetFile("./runtime.go"), mustGetFile("./request.go"))
   474  		_ = req.SetQueryParam("hello", "world")
   475  		_ = req.SetPathParam("id", "1234")
   476  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   477  		return nil
   478  	})
   479  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   480  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.URLencodedFormMime)
   481  	req, err := r.BuildHTTP(runtime.URLencodedFormMime, "", testProducers, nil)
   482  	require.NoError(t, err)
   483  	require.NotNil(t, req)
   484  
   485  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   486  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   487  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   488  	mediaType, params, err := mime.ParseMediaType(req.Header.Get(runtime.HeaderContentType))
   489  	require.NoError(t, err)
   490  
   491  	assert.Equal(t, runtime.URLencodedFormMime, mediaType)
   492  	boundary := params["boundary"]
   493  	mr := multipart.NewReader(req.Body, boundary)
   494  	defer req.Body.Close()
   495  	frm, err := mr.ReadForm(1 << 20)
   496  	require.NoError(t, err)
   497  
   498  	assert.Equal(t, "some value", frm.Value["something"][0])
   499  	fileverifier := func(name string, index int, filename string, content []byte) {
   500  		mpff := frm.File[name][index]
   501  		mpf, e := mpff.Open()
   502  		require.NoError(t, e)
   503  		defer mpf.Close()
   504  		assert.Equal(t, filename, mpff.Filename)
   505  		actual, e := io.ReadAll(mpf)
   506  		require.NoError(t, e)
   507  		assert.Equal(t, content, actual)
   508  	}
   509  	fileverifier("file", 0, "runtime.go", cont)
   510  
   511  	fileverifier("otherfiles", 0, "runtime.go", cont)
   512  	fileverifier("otherfiles", 1, "request.go", cont2)
   513  }
   514  
   515  type contentTypeProvider struct {
   516  	runtime.NamedReadCloser
   517  	contentType string
   518  }
   519  
   520  func (p contentTypeProvider) ContentType() string {
   521  	return p.contentType
   522  }
   523  
   524  func TestBuildRequest_BuildHTTP_File_ContentType(t *testing.T) {
   525  	cont, err := os.ReadFile("./runtime.go")
   526  	require.NoError(t, err)
   527  	cont2, err := os.ReadFile("./request.go")
   528  	require.NoError(t, err)
   529  
   530  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   531  		_ = req.SetPathParam("id", "1234")
   532  		_ = req.SetFileParam("file1", contentTypeProvider{
   533  			NamedReadCloser: mustGetFile("./runtime.go"),
   534  			contentType:     "application/octet-stream",
   535  		})
   536  		_ = req.SetFileParam("file2", mustGetFile("./request.go"))
   537  
   538  		return nil
   539  	})
   540  	r := newRequest(http.MethodGet, "/flats/{id}/", reqWrtr)
   541  	_ = r.SetHeaderParam(runtime.HeaderContentType, runtime.JSONMime)
   542  	req, err := r.BuildHTTP(runtime.JSONMime, "", testProducers, nil)
   543  	require.NoError(t, err)
   544  	require.NotNil(t, req)
   545  
   546  	assert.Equal(t, "/flats/1234/", req.URL.Path)
   547  	mediaType, params, err := mime.ParseMediaType(req.Header.Get(runtime.HeaderContentType))
   548  	require.NoError(t, err)
   549  	assert.Equal(t, runtime.MultipartFormMime, mediaType)
   550  	boundary := params["boundary"]
   551  	mr := multipart.NewReader(req.Body, boundary)
   552  	defer req.Body.Close()
   553  	frm, err := mr.ReadForm(1 << 20)
   554  	require.NoError(t, err)
   555  
   556  	fileverifier := func(name string, index int, filename string, content []byte, contentType string) {
   557  		mpff := frm.File[name][index]
   558  		mpf, e := mpff.Open()
   559  		require.NoError(t, e)
   560  		defer mpf.Close()
   561  		assert.Equal(t, filename, mpff.Filename)
   562  		actual, e := io.ReadAll(mpf)
   563  		require.NoError(t, e)
   564  		assert.Equal(t, content, actual)
   565  		assert.Equal(t, mpff.Header.Get("Content-Type"), contentType)
   566  	}
   567  	fileverifier("file1", 0, "runtime.go", cont, "application/octet-stream")
   568  	fileverifier("file2", 0, "request.go", cont2, "text/plain; charset=utf-8")
   569  }
   570  
   571  func TestBuildRequest_BuildHTTP_BasePath(t *testing.T) {
   572  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   573  		_ = req.SetBodyParam(nil)
   574  		_ = req.SetQueryParam("hello", "world")
   575  		_ = req.SetPathParam("id", "1234")
   576  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   577  		return nil
   578  	})
   579  	r := newRequest(http.MethodPost, "/flats/{id}/", reqWrtr)
   580  
   581  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath", testProducers, nil)
   582  	require.NoError(t, err)
   583  	require.NotNil(t, req)
   584  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   585  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   586  	assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
   587  }
   588  
   589  func TestBuildRequest_BuildHTTP_EscapedPath(t *testing.T) {
   590  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   591  		_ = req.SetBodyParam(nil)
   592  		_ = req.SetQueryParam("hello", "world")
   593  		_ = req.SetPathParam("id", "1234/?*&^%")
   594  		_ = req.SetHeaderParam("X-Rate-Limit", "200")
   595  		return nil
   596  	})
   597  	r := newRequest(http.MethodPost, "/flats/{id}/", reqWrtr)
   598  
   599  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath", testProducers, nil)
   600  	require.NoError(t, err)
   601  	require.NotNil(t, req)
   602  
   603  	assert.Equal(t, "200", req.Header.Get("x-rate-limit"))
   604  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   605  	assert.Equal(t, "/basepath/flats/1234/?*&^%/", req.URL.Path)
   606  	assert.Equal(t, "/basepath/flats/1234%2F%3F%2A&%5E%25/", req.URL.RawPath)
   607  	assert.Equal(t, req.URL.RawPath, req.URL.EscapedPath())
   608  }
   609  
   610  func TestBuildRequest_BuildHTTP_BasePathWithQueryParameters(t *testing.T) {
   611  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   612  		_ = req.SetBodyParam(nil)
   613  		_ = req.SetQueryParam("hello", "world")
   614  		_ = req.SetPathParam("id", "1234")
   615  		return nil
   616  	})
   617  	r := newRequest(http.MethodPost, "/flats/{id}/", reqWrtr)
   618  
   619  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath?foo=bar", testProducers, nil)
   620  	require.NoError(t, err)
   621  	require.NotNil(t, req)
   622  
   623  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   624  	assert.Equal(t, "bar", req.URL.Query().Get("foo"))
   625  	assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
   626  }
   627  
   628  func TestBuildRequest_BuildHTTP_PathPatternWithQueryParameters(t *testing.T) {
   629  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   630  		_ = req.SetBodyParam(nil)
   631  		_ = req.SetQueryParam("hello", "world")
   632  		_ = req.SetPathParam("id", "1234")
   633  		return nil
   634  	})
   635  	r := newRequest(http.MethodPost, "/flats/{id}/?foo=bar", reqWrtr)
   636  
   637  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath", testProducers, nil)
   638  	require.NoError(t, err)
   639  	require.NotNil(t, req)
   640  
   641  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   642  	assert.Equal(t, "bar", req.URL.Query().Get("foo"))
   643  	assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
   644  }
   645  
   646  func TestBuildRequest_BuildHTTP_StaticParametersPathPatternPrevails(t *testing.T) {
   647  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   648  		_ = req.SetBodyParam(nil)
   649  		_ = req.SetPathParam("id", "1234")
   650  		return nil
   651  	})
   652  	r := newRequest(http.MethodPost, "/flats/{id}/?hello=world", reqWrtr)
   653  
   654  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath?hello=kitty", testProducers, nil)
   655  	require.NoError(t, err)
   656  	require.NotNil(t, req)
   657  
   658  	assert.Equal(t, "world", req.URL.Query().Get("hello"))
   659  	assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
   660  }
   661  
   662  func TestBuildRequest_BuildHTTP_StaticParametersConflictClientPrevails(t *testing.T) {
   663  	reqWrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   664  		_ = req.SetBodyParam(nil)
   665  		_ = req.SetQueryParam("hello", "there")
   666  		_ = req.SetPathParam("id", "1234")
   667  		return nil
   668  	})
   669  	r := newRequest(http.MethodPost, "/flats/{id}/?hello=world", reqWrtr)
   670  
   671  	req, err := r.BuildHTTP(runtime.JSONMime, "/basepath?hello=kitty", testProducers, nil)
   672  	require.NoError(t, err)
   673  	require.NotNil(t, req)
   674  
   675  	assert.Equal(t, "there", req.URL.Query().Get("hello"))
   676  	assert.Equal(t, "/basepath/flats/1234/", req.URL.Path)
   677  }
   678  
   679  type testReqFn func(*testing.T, *http.Request)
   680  
   681  type testRoundTripper struct {
   682  	tr          http.RoundTripper
   683  	testFn      testReqFn
   684  	testHarness *testing.T
   685  }
   686  
   687  func (t *testRoundTripper) RoundTrip(req *http.Request) (resp *http.Response, err error) {
   688  	t.testFn(t.testHarness, req)
   689  	return t.tr.RoundTrip(req)
   690  }
   691  
   692  func TestGetBodyCallsBeforeRoundTrip(t *testing.T) {
   693  	server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) {
   694  		rw.WriteHeader(http.StatusCreated)
   695  		_, err := rw.Write([]byte("test result"))
   696  		require.NoError(t, err)
   697  	}))
   698  	defer server.Close()
   699  	hu, err := url.Parse(server.URL)
   700  	require.NoError(t, err)
   701  
   702  	client := http.DefaultClient
   703  	transport := http.DefaultTransport
   704  
   705  	client.Transport = &testRoundTripper{
   706  		tr:          transport,
   707  		testHarness: t,
   708  		testFn: func(t *testing.T, req *http.Request) {
   709  			// Read the body once before sending the request
   710  			body, e := req.GetBody()
   711  			require.NoError(t, e)
   712  			bodyContent, e := io.ReadAll(io.Reader(body))
   713  			require.NoError(t, e)
   714  
   715  			require.Len(t, bodyContent, int(req.ContentLength))
   716  			require.EqualValues(t, "\"test body\"\n", string(bodyContent))
   717  
   718  			// Read the body a second time before sending the request
   719  			body, e = req.GetBody()
   720  			require.NoError(t, e)
   721  			bodyContent, e = io.ReadAll(io.Reader(body))
   722  			require.NoError(t, e)
   723  			require.Len(t, bodyContent, int(req.ContentLength))
   724  			require.EqualValues(t, "\"test body\"\n", string(bodyContent))
   725  		},
   726  	}
   727  
   728  	rwrtr := runtime.ClientRequestWriterFunc(func(req runtime.ClientRequest, _ strfmt.Registry) error {
   729  		return req.SetBodyParam("test body")
   730  	})
   731  
   732  	operation := &runtime.ClientOperation{
   733  		ID:          "getSites",
   734  		Method:      http.MethodPost,
   735  		PathPattern: "/",
   736  		Params:      rwrtr,
   737  		Client:      client,
   738  		Reader: runtime.ClientResponseReaderFunc(func(response runtime.ClientResponse, consumer runtime.Consumer) (interface{}, error) {
   739  			if response.Code() == http.StatusCreated {
   740  				var res string
   741  				if e := consumer.Consume(response.Body(), &res); e != nil {
   742  					return nil, e
   743  				}
   744  				return res, nil
   745  			}
   746  			return nil, errors.New("unexpected error code")
   747  		}),
   748  	}
   749  
   750  	openAPIClient := New(hu.Host, "/", []string{schemeHTTP})
   751  	res, err := openAPIClient.Submit(operation)
   752  	require.NoError(t, err)
   753  
   754  	actual := res.(string)
   755  	require.EqualValues(t, "test result", actual)
   756  }
   757  

View as plain text