diff options
author | Matus Fabian <matfabia@cisco.com> | 2024-07-31 16:08:40 +0200 |
---|---|---|
committer | Florin Coras <florin.coras@gmail.com> | 2024-08-06 16:01:02 +0000 |
commit | d46e674abc5605b58584bbf9a0607ef621ca0eee (patch) | |
tree | 4f42d19311c0036726d72d5d17af97082a05bed0 /extras | |
parent | fc3464dac99c9e3e56616e6c6bc6d10886b2f567 (diff) |
http: client POST method
Type: improvement
Change-Id: Iaa70abcee02866f9a6426a6e8e4709eeba0e8114
Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'extras')
-rw-r--r-- | extras/hs-test/http_test.go | 153 | ||||
-rw-r--r-- | extras/hs-test/infra/hst_suite.go | 20 |
2 files changed, 162 insertions, 11 deletions
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index 75db60d43ae..c45f7c2d57c 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -10,6 +10,7 @@ import ( "net/http" "net/http/httptrace" "os" + "strconv" "sync" "time" @@ -27,9 +28,10 @@ func init() { HttpContentLengthTest, HttpStaticBuildInUrlGetIfListTest, HttpStaticBuildInUrlGetVersionTest, HttpStaticMacTimeTest, HttpStaticBuildInUrlGetVersionVerboseTest, HttpVersionNotSupportedTest, HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathTraversalTest, HttpUriDecodeTest, - HttpHeadersTest, HttpStaticFileHandler, HttpClientTest, HttpClientErrRespTest) - RegisterNoTopoSoloTests(HttpStaticPromTest, HttpTpsTest, HttpTpsInterruptModeTest, PromConcurrentConnections, - PromMemLeakTest) + HttpHeadersTest, HttpStaticFileHandlerTest, HttpClientTest, HttpClientErrRespTest, HttpClientPostFormTest, + HttpClientPostFileTest, HttpClientPostFilePtrTest) + RegisterNoTopoSoloTests(HttpStaticPromTest, HttpTpsTest, HttpTpsInterruptModeTest, PromConcurrentConnectionsTest, + PromMemLeakTest, HttpClientPostMemLeakTest) } const wwwRootPath = "/tmp/www_root" @@ -46,6 +48,7 @@ func httpDownloadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data in defer resp.Body.Close() s.AssertEqual(200, resp.StatusCode) _, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) duration := time.Since(t) experiment.RecordValue("Download Speed", (float64(resp.ContentLength)/1024/1024)/duration.Seconds(), gmeasure.Units("MB/s"), gmeasure.Precision(2)) } @@ -114,7 +117,6 @@ func HttpPersistentConnectionTest(s *NoTopoSuite) { body, err = io.ReadAll(resp.Body) s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), "some data") - s.AssertNil(err, fmt.Sprint(err)) o2 := vpp.Vppctl("show session verbose proto http state ready") s.Log(o2) s.AssertContains(o2, "ESTABLISHED") @@ -196,6 +198,7 @@ func HttpClientTest(s *NoTopoSuite) { server.HTTPTestServer.Listener = l server.AppendHandlers( ghttp.CombineHandlers( + s.LogHttpReq(true), ghttp.VerifyRequest("GET", "/test"), ghttp.VerifyHeader(http.Header{"User-Agent": []string{"http_cli_client"}}), ghttp.VerifyHeader(http.Header{"Accept": []string{"text / html"}}), @@ -220,6 +223,7 @@ func HttpClientErrRespTest(s *NoTopoSuite) { server.HTTPTestServer.Listener = l server.AppendHandlers( ghttp.CombineHandlers( + s.LogHttpReq(true), ghttp.VerifyRequest("GET", "/test"), ghttp.RespondWith(http.StatusNotFound, "404: Not Found"), )) @@ -233,6 +237,74 @@ func HttpClientErrRespTest(s *NoTopoSuite) { s.AssertContains(o, "404: Not Found", "error not found in the result!") } +func HttpClientPostFormTest(s *NoTopoSuite) { + serverAddress := s.GetInterfaceByName(TapInterfaceName).Ip4AddressString() + body := "field1=value1&field2=value2" + + server := ghttp.NewUnstartedServer() + l, err := net.Listen("tcp", serverAddress+":80") + s.AssertNil(err, fmt.Sprint(err)) + server.HTTPTestServer.Listener = l + server.AppendHandlers( + ghttp.CombineHandlers( + s.LogHttpReq(true), + ghttp.VerifyRequest("POST", "/test"), + ghttp.VerifyContentType("application / x-www-form-urlencoded"), + ghttp.VerifyBody([]byte(body)), + ghttp.RespondWith(http.StatusOK, nil), + )) + server.Start() + defer server.Close() + + uri := "http://" + serverAddress + "/80" + vpp := s.GetContainerByName("vpp").VppInstance + o := vpp.Vppctl("http post uri " + uri + " target /test data " + body) + + s.Log(o) + s.AssertNotContains(o, "error") +} + +func httpClientPostFile(s *NoTopoSuite, usePtr bool, fileSize int) { + serverAddress := s.GetInterfaceByName(TapInterfaceName).Ip4AddressString() + vpp := s.GetContainerByName("vpp").VppInstance + fileName := "/tmp/test_file.txt" + s.Log(vpp.Container.Exec("fallocate -l " + strconv.Itoa(fileSize) + " " + fileName)) + s.Log(vpp.Container.Exec("ls -la " + fileName)) + + server := ghttp.NewUnstartedServer() + l, err := net.Listen("tcp", serverAddress+":80") + s.AssertNil(err, fmt.Sprint(err)) + server.HTTPTestServer.Listener = l + server.AppendHandlers( + ghttp.CombineHandlers( + s.LogHttpReq(false), + ghttp.VerifyRequest("POST", "/test"), + ghttp.VerifyHeader(http.Header{"Content-Length": []string{strconv.Itoa(fileSize)}}), + ghttp.VerifyContentType("application / octet - stream"), + ghttp.RespondWith(http.StatusOK, nil), + )) + server.Start() + defer server.Close() + + uri := "http://" + serverAddress + "/80" + cmd := "http post uri " + uri + " target /test file " + fileName + if usePtr { + cmd += " use-ptr" + } + o := vpp.Vppctl(cmd) + + s.Log(o) + s.AssertNotContains(o, "error") +} + +func HttpClientPostFileTest(s *NoTopoSuite) { + httpClientPostFile(s, false, 32768) +} + +func HttpClientPostFilePtrTest(s *NoTopoSuite) { + httpClientPostFile(s, true, 131072) +} + func HttpStaticPromTest(s *NoTopoSuite) { query := "stats.prom" vpp := s.GetContainerByName("vpp").VppInstance @@ -252,6 +324,7 @@ func HttpStaticPromTest(s *NoTopoSuite) { s.AssertContains(resp.Header.Get("Content-Type"), "plain") s.AssertNotEqual(int64(0), resp.ContentLength) _, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) } func promReq(s *NoTopoSuite, url string) { @@ -263,6 +336,7 @@ func promReq(s *NoTopoSuite, url string) { defer resp.Body.Close() s.AssertEqual(200, resp.StatusCode) _, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) } func promReqWg(s *NoTopoSuite, url string, wg *sync.WaitGroup) { @@ -271,7 +345,7 @@ func promReqWg(s *NoTopoSuite, url string, wg *sync.WaitGroup) { promReq(s, url) } -func PromConcurrentConnections(s *NoTopoSuite) { +func PromConcurrentConnectionsTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString() url := "http://" + serverAddress + ":80/stats.prom" @@ -341,6 +415,9 @@ func HttpClientGetMemLeakTest(s *VethsSuite) { /* warmup request (FIB) */ clientContainer.Vppctl("http cli client uri " + uri + " query /show/version") + /* let's give it some time to clean up sessions, so local port can be reused and we have less noise */ + time.Sleep(time.Second * 12) + clientContainer.EnableMemoryTrace() traces1, err := clientContainer.GetMemoryTrace() s.AssertNil(err, fmt.Sprint(err)) @@ -355,13 +432,64 @@ func HttpClientGetMemLeakTest(s *VethsSuite) { clientContainer.MemLeakCheck(traces1, traces2) } -func HttpStaticFileHandler(s *NoTopoSuite) { +func HttpClientPostMemLeakTest(s *NoTopoSuite) { + s.SkipUnlessLeakCheck() + + serverAddress := s.GetInterfaceByName(TapInterfaceName).Ip4AddressString() + body := "field1=value1&field2=value2" + + uri := "http://" + serverAddress + "/80" + vpp := s.GetContainerByName("vpp").VppInstance + + /* no goVPP less noise */ + vpp.Disconnect() + + server := ghttp.NewUnstartedServer() + l, err := net.Listen("tcp", serverAddress+":80") + s.AssertNil(err, fmt.Sprint(err)) + server.HTTPTestServer.Listener = l + server.AppendHandlers( + ghttp.CombineHandlers( + ghttp.VerifyRequest("POST", "/test"), + ghttp.RespondWith(http.StatusOK, nil), + ), + ghttp.CombineHandlers( + ghttp.VerifyRequest("POST", "/test"), + ghttp.RespondWith(http.StatusOK, nil), + ), + ) + server.Start() + defer server.Close() + + /* warmup request (FIB) */ + vpp.Vppctl("http post uri " + uri + " target /test data " + body) + + /* let's give it some time to clean up sessions, so local port can be reused and we have less noise */ + time.Sleep(time.Second * 12) + + vpp.EnableMemoryTrace() + traces1, err := vpp.GetMemoryTrace() + s.AssertNil(err, fmt.Sprint(err)) + + vpp.Vppctl("http post uri " + uri + " target /test data " + body) + + /* let's give it some time to clean up sessions */ + time.Sleep(time.Second * 12) + + traces2, err := vpp.GetMemoryTrace() + s.AssertNil(err, fmt.Sprint(err)) + vpp.MemLeakCheck(traces1, traces2) +} + +func HttpStaticFileHandlerTest(s *NoTopoSuite) { content := "<html><body><p>Hello</p></body></html>" content2 := "<html><body><p>Page</p></body></html>" vpp := s.GetContainerByName("vpp").VppInstance vpp.Container.Exec("mkdir -p " + wwwRootPath) - vpp.Container.CreateFile(wwwRootPath+"/index.html", content) - vpp.Container.CreateFile(wwwRootPath+"/page.html", content2) + err := vpp.Container.CreateFile(wwwRootPath+"/index.html", content) + s.AssertNil(err, fmt.Sprint(err)) + err = vpp.Container.CreateFile(wwwRootPath+"/page.html", content2) + s.AssertNil(err, fmt.Sprint(err)) serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug cache-size 2m")) @@ -377,6 +505,7 @@ func HttpStaticFileHandler(s *NoTopoSuite) { s.AssertContains(resp.Header.Get("Cache-Control"), "max-age=") s.AssertEqual(int64(len([]rune(content))), resp.ContentLength) body, err := io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content) o := vpp.Vppctl("show http static server cache verbose") s.Log(o) @@ -392,6 +521,7 @@ func HttpStaticFileHandler(s *NoTopoSuite) { s.AssertContains(resp.Header.Get("Cache-Control"), "max-age=") s.AssertEqual(int64(len([]rune(content))), resp.ContentLength) body, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content) req, err = http.NewRequest("GET", "http://"+serverAddress+":80/page.html", nil) @@ -405,6 +535,7 @@ func HttpStaticFileHandler(s *NoTopoSuite) { s.AssertContains(resp.Header.Get("Cache-Control"), "max-age=") s.AssertEqual(int64(len([]rune(content2))), resp.ContentLength) body, err = io.ReadAll(resp.Body) + s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(string(body), content2) o = vpp.Vppctl("show http static server cache verbose") s.Log(o) @@ -416,7 +547,8 @@ func HttpStaticPathTraversalTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance vpp.Container.Exec("mkdir -p " + wwwRootPath) vpp.Container.Exec("mkdir -p " + "/tmp/secret_folder") - vpp.Container.CreateFile("/tmp/secret_folder/secret_file.txt", "secret") + err := vpp.Container.CreateFile("/tmp/secret_folder/secret_file.txt", "secret") + s.AssertNil(err, fmt.Sprint(err)) serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) @@ -436,7 +568,8 @@ func HttpStaticPathTraversalTest(s *NoTopoSuite) { func HttpStaticMovedTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance vpp.Container.Exec("mkdir -p " + wwwRootPath + "/tmp.aaa") - vpp.Container.CreateFile(wwwRootPath+"/tmp.aaa/index.html", "<html><body><p>Hello</p></body></html>") + err := vpp.Container.CreateFile(wwwRootPath+"/tmp.aaa/index.html", "<html><body><p>Hello</p></body></html>") + s.AssertNil(err, fmt.Sprint(err)) serverAddress := s.GetInterfaceByName(TapInterfaceName).Peer.Ip4AddressString() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go index 028ab0bef1f..ff5b02eb95b 100644 --- a/extras/hs-test/infra/hst_suite.go +++ b/extras/hs-test/infra/hst_suite.go @@ -7,6 +7,8 @@ import ( "fmt" "io" "log" + "net/http" + "net/http/httputil" "os" "os/exec" "path/filepath" @@ -561,7 +563,7 @@ func (s *HstSuite) StartWget(finished chan error, server_ip, port, query, netNs } /* -runBenchmark creates Gomega's experiment with the passed-in name and samples the passed-in callback repeatedly (samplesNum times), +RunBenchmark creates Gomega's experiment with the passed-in name and samples the passed-in callback repeatedly (samplesNum times), passing in suite context, experiment and your data. You can also instruct runBenchmark to run with multiple concurrent workers. @@ -578,3 +580,19 @@ func (s *HstSuite) RunBenchmark(name string, samplesNum, parallelNum int, callba }, gmeasure.SamplingConfig{N: samplesNum, NumParallel: parallelNum}) AddReportEntry(experiment.Name, experiment) } + +/* +LogHttpReq is Gomega's ghttp server handler which logs received HTTP request. + +You should put it at the first place, so request is logged always. +*/ +func (s *HstSuite) LogHttpReq(body bool) http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + dump, err := httputil.DumpRequest(req, body) + if err == nil { + s.Log("\n> Received request (" + req.RemoteAddr + "):\n" + + string(dump) + + "\n------------------------------\n") + } + } +} |