diff options
Diffstat (limited to 'extras')
47 files changed, 885 insertions, 529 deletions
diff --git a/extras/hs-test/Makefile b/extras/hs-test/Makefile index 2a501580e53..7d1242e08d8 100644 --- a/extras/hs-test/Makefile +++ b/extras/hs-test/Makefile @@ -74,7 +74,6 @@ help: @echo @echo "'make build' arguments:" @echo " UBUNTU_VERSION - ubuntu version for docker image" - @echo " HST_EXTENDED_TESTS - build extended tests" @echo @echo "'make test' arguments:" @echo " PERSIST=[true|false] - whether clean up topology and dockers after test" @@ -87,6 +86,7 @@ help: @echo " PARALLEL=[n-cpus] - number of test processes to spawn to run in parallel" @echo " REPEAT=[n] - repeat tests up to N times or until a failure occurs" @echo " CPU0=[true|false] - use cpu0" + @echo " DRYRUN=[true|false] - set up containers but don't run tests" @echo @echo "List of all tests:" @$(MAKE) list-tests @@ -121,7 +121,8 @@ build-vpp-gcov: test: .deps.ok .build.ok @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --cpu0=$(CPU0); \ + --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --cpu0=$(CPU0) \ + --dryrun=$(DRYRUN); \ ./script/compress.sh $$? @@ -130,14 +131,14 @@ test-debug: .deps.ok .build_debug.ok @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \ --vppsrc=$(VPPSRC) --parallel=$(PARALLEL) --repeat=$(REPEAT) --debug_build=true \ - --cpu0=$(CPU0); \ + --cpu0=$(CPU0) --dryrun=$(DRYRUN); \ ./script/compress.sh $$? .PHONY: test-cov test-cov: .deps.ok .build.cov.ok @bash ./hs_test.sh --persist=$(PERSIST) --verbose=$(VERBOSE) \ --unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST-HS) --cpus=$(CPUS) \ - --vppsrc=$(VPPSRC) --cpu0=$(CPU0); \ + --vppsrc=$(VPPSRC) --cpu0=$(CPU0) --dryrun=$(DRYRUN); \ ./script/compress.sh $$? .PHONY: test-leak @@ -184,10 +185,19 @@ install-deps: @apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin @touch .deps.ok +.goimports.ok: + @rm -f .goimports.ok + go install golang.org/x/tools/cmd/goimports@v0.25.0 + @touch .goimports.ok + .PHONY: checkstyle-go -checkstyle-go: - @output=$$(gofmt -d $${WS_ROOT}); \ - if [ -z "$$output" ]; then \ +checkstyle-go: .goimports.ok + $(eval GOPATH := $(shell go env GOPATH)) + @output=$$($(GOPATH)/bin/goimports -d $${WS_ROOT}); \ + status=$$?; \ + if [ $$status -ne 0 ]; then \ + exit $$status; \ + elif [ -z "$$output" ]; then \ echo "*******************************************************************"; \ echo "Checkstyle OK."; \ echo "*******************************************************************"; \ @@ -200,9 +210,10 @@ checkstyle-go: fi .PHONY: fixstyle-go -fixstyle-go: +fixstyle-go: .goimports.ok + $(eval GOPATH := $(shell go env GOPATH)) @echo "Modified files:" - @gofmt -w -l $(WS_ROOT) + @$(GOPATH)/bin/goimports -w -l $(WS_ROOT) @go mod tidy @echo "*******************************************************************" @echo "Fixstyle done." diff --git a/extras/hs-test/README.rst b/extras/hs-test/README.rst index 6a4cea187c4..c62be5a84aa 100644 --- a/extras/hs-test/README.rst +++ b/extras/hs-test/README.rst @@ -27,7 +27,7 @@ Anatomy of a test case **Action flow when running a test case**: #. It starts with running ``make test``. Optional arguments are VERBOSE, PERSIST (topology configuration isn't cleaned up after test run, use ``make cleanup-hst`` to clean up), - TEST=<test-name> to run a specific test and PARALLEL=[n-cpus]. + TEST=<test-name> to run a specific test and PARALLEL=[n-cpus]. If you want to run multiple specific tests, separate their names with a comma. #. ``make list-tests`` (or ``make help``) shows all tests. #. ``Ginkgo`` looks for a spec suite in the current directory and then compiles it to a .test binary. #. The Ginkgo test framework runs each function that was registered manually using ``Register[SuiteName]Test()``. Each of these functions correspond to a suite. @@ -167,8 +167,8 @@ Modifying the framework // Add custom setup code here - s.ConfigureNetworkTopology("myTopology") - s.LoadContainerTopology("2peerVeth") + s.ConfigureNetworkTopology("myNetworkTopology") + s.LoadContainerTopology("myContainerTopology") } #. In suite file, implement ``SetupTest`` method which gets executed before each test. Starting containers and @@ -216,7 +216,7 @@ Modifying the framework It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -237,7 +237,7 @@ Modifying the framework It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(time.Minute*5)) + }, SpecTimeout(TestTimeout)) }) #. Next step is to add test cases to the suite. For that, see section `Adding a test case`_ above diff --git a/extras/hs-test/docker/Dockerfile.curl b/extras/hs-test/docker/Dockerfile.curl index cbb0bbe734f..0722068b2f7 100644 --- a/extras/hs-test/docker/Dockerfile.curl +++ b/extras/hs-test/docker/Dockerfile.curl @@ -3,13 +3,12 @@ ARG UBUNTU_VERSION FROM ubuntu:${UBUNTU_VERSION} RUN apt-get update \ - && apt-get install -y gcc git make autoconf libtool pkg-config cmake ninja-build golang \ + && apt-get install -y xz-utils wget \ && rm -rf /var/lib/apt/lists/* COPY script/build_curl.sh /build_curl.sh COPY resources/curl/* /tmp/ RUN fallocate -l 10MB /tmp/testFile -RUN apt-get update && apt-get install wget RUN /build_curl.sh CMD ["/bin/sh"] diff --git a/extras/hs-test/docker/Dockerfile.envoy b/extras/hs-test/docker/Dockerfile.envoy new file mode 100644 index 00000000000..cadb9b14a76 --- /dev/null +++ b/extras/hs-test/docker/Dockerfile.envoy @@ -0,0 +1,6 @@ +FROM envoyproxy/envoy-contrib:v1.31-latest + +RUN chmod go+r /etc/envoy/envoy.yaml +RUN chown envoy:envoy /dev/stdout /dev/stderr + +ENTRYPOINT ["/bin/sh", "-c", "envoy --log-format [%t][%l][%g:%#]%_ --concurrency 2 -c /etc/envoy/envoy.yaml"]
\ No newline at end of file diff --git a/extras/hs-test/docker/Dockerfile.nginx b/extras/hs-test/docker/Dockerfile.nginx index 386f8e90016..78a75d44a31 100644 --- a/extras/hs-test/docker/Dockerfile.nginx +++ b/extras/hs-test/docker/Dockerfile.nginx @@ -7,11 +7,10 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* COPY vpp-data/lib/* /usr/lib/ -COPY resources/nginx/vcl.conf /vcl.conf COPY resources/nginx/nginx.conf /nginx.conf COPY script/nginx_ldp.sh /usr/bin/nginx_ldp.sh -ENV VCL_CONFIG=/vcl.conf +ENV VCL_CONFIG=/tmp/nginx/vcl.conf ENV LDP=/usr/lib/libvcl_ldpreload.so ENV LDP_DEBUG=0 ENV VCL_DEBUG=0 diff --git a/extras/hs-test/docker/Dockerfile.nginx-http3 b/extras/hs-test/docker/Dockerfile.nginx-http3 index 8b2f8406d38..fc905376986 100644 --- a/extras/hs-test/docker/Dockerfile.nginx-http3 +++ b/extras/hs-test/docker/Dockerfile.nginx-http3 @@ -3,16 +3,16 @@ ARG UBUNTU_VERSION FROM ubuntu:${UBUNTU_VERSION} RUN apt-get update \ - && apt-get install -y gcc git make autoconf libtool pkg-config cmake ninja-build golang \ - && rm -rf /var/lib/apt/lists/* + && apt-get install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring libunwind-dev +RUN curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ +| tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null +RUN echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ + http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \ + | tee /etc/apt/sources.list.d/nginx.list +RUN bash -c 'echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \ +| tee /etc/apt/preferences.d/99nginx' -COPY script/build_boringssl.sh /build_boringssl.sh -RUN git clone https://boringssl.googlesource.com/boringssl -RUN ./build_boringssl.sh - -COPY script/build_nginx.sh /build_nginx.sh -RUN git clone https://github.com/nginx/nginx -RUN ./build_nginx.sh +RUN apt update && apt install -y nginx=1.26.2-1~jammy COPY vpp-data/lib/* /usr/lib/ COPY resources/nginx/vcl.conf /vcl.conf @@ -27,4 +27,4 @@ ENV LDP_DEBUG=0 ENV VCL_DEBUG=0 ENV LDP_SID_BIT=8 -ENTRYPOINT ["nginx_ldp.sh", "/usr/local/nginx/sbin/nginx", "-c", "/nginx.conf"] +ENTRYPOINT ["nginx_ldp.sh", "nginx", "-c", "/nginx.conf"] diff --git a/extras/hs-test/docker/Dockerfile.vpp b/extras/hs-test/docker/Dockerfile.vpp index 82a1a1a73d3..5f5d41ce610 100644 --- a/extras/hs-test/docker/Dockerfile.vpp +++ b/extras/hs-test/docker/Dockerfile.vpp @@ -13,6 +13,7 @@ COPY \ $DIR/af_packet_plugin.so \ $DIR/hs_apps_plugin.so \ $DIR/http_plugin.so \ + $DIR/http_unittest_plugin.so \ $DIR/unittest_plugin.so \ $DIR/quic_plugin.so \ $DIR/http_static_plugin.so \ diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go index 91cb1032bba..a578fb15573 100644 --- a/extras/hs-test/framework_test.go +++ b/extras/hs-test/framework_test.go @@ -15,9 +15,9 @@ import ( func TestHst(t *testing.T) { if *IsVppDebug { // 30 minute timeout so that the framework won't timeout while debugging - SuiteTimeout = time.Minute * 30 + TestTimeout = time.Minute * 30 } else { - SuiteTimeout = time.Minute * 5 + TestTimeout = time.Minute * 5 } output, err := os.ReadFile("/sys/devices/system/node/online") @@ -33,4 +33,8 @@ func TestHst(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "HST") + if *DryRun || *IsPersistent { + fmt.Println("\033[36m" + "Use 'make cleanup-hst' to remove IP files, " + + "namespaces and containers. \nPPID: " + ppid + "\033[0m") + } } diff --git a/extras/hs-test/hs_test.sh b/extras/hs-test/hs_test.sh index 85c0dd72705..59edf57afc2 100644 --- a/extras/hs-test/hs_test.sh +++ b/extras/hs-test/hs_test.sh @@ -3,14 +3,16 @@ source vars args= -single_test=0 +focused_test=0 persist_set=0 +dryrun_set=0 unconfigure_set=0 debug_set=0 leak_check_set=0 debug_build= ginkgo_args= -tc_name= +tc_names=() +dryrun= for i in "$@" do @@ -55,13 +57,12 @@ case "${i}" in args="$args -vppsrc ${i#*=}" ;; --test=*) - tc_name="${i#*=}" - if [ "$tc_name" != "all" ]; then - single_test=1 - ginkgo_args="$ginkgo_args --focus $tc_name -vv" + tc_list="${i#*=}" + ginkgo_args="$ginkgo_args -v" + if [ "$tc_list" != "all" ]; then + focused_test=1 + IFS=',' read -r -a tc_names <<< "$tc_list" args="$args -verbose" - else - ginkgo_args="$ginkgo_args -v" fi ;; --parallel=*) @@ -76,6 +77,13 @@ case "${i}" in args="$args -cpu0" fi ;; + --dryrun=*) + dryrun="${i#*=}" + if [ "$dryrun" = "true" ]; then + args="$args -dryrun" + dryrun_set=1 + fi + ;; --leak_check=*) leak_check="${i#*=}" if [ "$leak_check" = "true" ]; then @@ -86,32 +94,41 @@ case "${i}" in esac done -if [ $single_test -eq 0 ] && [ $persist_set -eq 1 ]; then - echo "persist flag is not supported while running all tests!" - exit 1 +if [ ${#tc_names[@]} -gt 1 ] +then + focused_test=0 +fi + +for name in "${tc_names[@]}"; do + ginkgo_args="$ginkgo_args --focus $name" +done + +if [ $focused_test -eq 0 ] && { [ $persist_set -eq 1 ] || [ $dryrun_set -eq 1 ]; }; then + echo -e "\e[1;31mpersist/dryrun flag is not supported while running all tests!\e[1;0m" + exit 2 fi -if [ $unconfigure_set -eq 1 ] && [ $single_test -eq 0 ]; then - echo "a single test has to be specified when unconfigure is set" - exit 1 +if [ $unconfigure_set -eq 1 ] && [ $focused_test -eq 0 ]; then + echo -e "\e[1;31ma single test has to be specified when unconfigure is set\e[1;0m" + exit 2 fi if [ $persist_set -eq 1 ] && [ $unconfigure_set -eq 1 ]; then - echo "setting persist flag and unconfigure flag is not allowed" - exit 1 + echo -e "\e[1;31msetting persist flag and unconfigure flag is not allowed\e[1;0m" + exit 2 fi -if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then - echo "VPP debug flag is not supported while running all tests!" - exit 1 +if [ $focused_test -eq 0 ] && [ $debug_set -eq 1 ]; then + echo -e "\e[1;31mVPP debug flag is not supported while running all tests!\e[1;0m" + exit 2 fi if [ $leak_check_set -eq 1 ]; then - if [ $single_test -eq 0 ]; then - echo "a single test has to be specified when leak_check is set" - exit 1 + if [ $focused_test -eq 0 ]; then + echo -e "\e[1;31ma single test has to be specified when leak_check is set\e[1;0m" + exit 2 fi - ginkgo_args="--focus $tc_name" + ginkgo_args="--focus ${tc_names[0]}" sudo -E go run github.com/onsi/ginkgo/v2/ginkgo $ginkgo_args -- $args exit 0 fi diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go index bfd2d34483c..902d6efacfc 100644 --- a/extras/hs-test/http_test.go +++ b/extras/hs-test/http_test.go @@ -3,8 +3,6 @@ package main import ( "bytes" "fmt" - "github.com/onsi/gomega/ghttp" - "github.com/onsi/gomega/gmeasure" "io" "math/rand" "net" @@ -12,9 +10,13 @@ import ( "net/http/httptrace" "os" "strconv" + "strings" "sync" "time" + "github.com/onsi/gomega/ghttp" + "github.com/onsi/gomega/gmeasure" + . "fd.io/hs-test/infra" . "github.com/onsi/ginkgo/v2" ) @@ -29,18 +31,22 @@ func init() { HttpContentLengthTest, HttpStaticBuildInUrlGetIfListTest, HttpStaticBuildInUrlGetVersionTest, HttpStaticMacTimeTest, HttpStaticBuildInUrlGetVersionVerboseTest, HttpVersionNotSupportedTest, HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathTraversalTest, HttpUriDecodeTest, - HttpHeadersTest, HttpStaticFileHandlerTest, HttpStaticFileHandlerDefaultMaxAgeTest, HttpClientTest, HttpClientErrRespTest, HttpClientPostFormTest, - HttpClientPostFileTest, HttpClientPostFilePtrTest, AuthorityFormTargetTest, HttpRequestLineTest) + HttpHeadersTest, HttpStaticFileHandlerTest, HttpStaticFileHandlerDefaultMaxAgeTest, HttpClientTest, + HttpClientErrRespTest, HttpClientPostFormTest, HttpClientGet128kbResponseTest, HttpClientGetResponseBodyTest, + HttpClientGetNoResponseBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, HttpUnitTest, + HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest) RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest, - PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest) + PromMemLeakTest, HttpClientPostMemLeakTest, HttpInvalidClientRequestMemLeakTest, HttpPostTpsTest, HttpPostTpsInterruptModeTest, + PromConsecutiveConnectionsTest) } const wwwRootPath = "/tmp/www_root" +const defaultHttpTimeout = time.Second * 10 func httpDownloadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data interface{}) { url, isValid := data.(string) s.AssertEqual(true, isValid) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", url, nil) s.AssertNil(err, fmt.Sprint(err)) t := time.Now() @@ -73,7 +79,7 @@ func httpUploadBenchmark(s *HstSuite, experiment *gmeasure.Experiment, data inte s.AssertEqual(true, isValid) body := make([]byte, 10485760) _, err := rand.Read(body) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("POST", url, bytes.NewBuffer(body)) s.AssertNil(err, fmt.Sprint(err)) t := time.Now() @@ -130,7 +136,7 @@ func HttpPersistentConnectionTest(s *NoTopoSuite) { s.AssertHttpContentLength(resp, int64(0)) o1 := vpp.Vppctl("show session verbose proto http state ready") s.Log(o1) - s.AssertContains(o1, "ESTABLISHED") + s.AssertContains(o1, "established") req, err = http.NewRequest("GET", "http://"+serverAddress+":80/test1", nil) s.AssertNil(err, fmt.Sprint(err)) @@ -148,7 +154,7 @@ func HttpPersistentConnectionTest(s *NoTopoSuite) { s.AssertHttpBody(resp, "hello") o2 := vpp.Vppctl("show session verbose proto http state ready") s.Log(o2) - s.AssertContains(o2, "ESTABLISHED") + s.AssertContains(o2, "established") s.AssertEqual(o1, o2) req, err = http.NewRequest("GET", "http://"+serverAddress+":80/test2", nil) @@ -162,9 +168,8 @@ func HttpPersistentConnectionTest(s *NoTopoSuite) { s.AssertHttpBody(resp, "some data") o2 = vpp.Vppctl("show session verbose proto http state ready") s.Log(o2) - s.AssertContains(o2, "ESTABLISHED") + s.AssertContains(o2, "established") s.AssertEqual(o1, o2) - } func HttpPipeliningTest(s *NoTopoSuite) { @@ -192,7 +197,7 @@ func HttpPipeliningTest(s *NoTopoSuite) { s.AssertNil(err, fmt.Sprint(err)) s.AssertEqual(n, len([]rune(req2))) reply := make([]byte, 1024) - n, err = conn.Read(reply) + _, err = conn.Read(reply) s.AssertNil(err, fmt.Sprint(err)) s.Log(string(reply)) s.AssertContains(string(reply), "delayed data", "first request response not received") @@ -293,6 +298,7 @@ func HttpClientPostFormTest(s *NoTopoSuite) { s.LogHttpReq(true), ghttp.VerifyRequest("POST", "/test"), ghttp.VerifyContentType("application/x-www-form-urlencoded"), + ghttp.VerifyHeaderKV("Hello", "World"), ghttp.VerifyBody([]byte(body)), ghttp.RespondWith(http.StatusOK, nil), )) @@ -301,18 +307,100 @@ func HttpClientPostFormTest(s *NoTopoSuite) { uri := "http://" + serverAddress + "/80" vpp := s.GetContainerByName("vpp").VppInstance - o := vpp.Vppctl("http post uri " + uri + " target /test data " + body) + o := vpp.Vppctl("http client post verbose header Hello:World uri " + uri + " target /test data " + body) s.Log(o) - s.AssertNotContains(o, "error") + s.AssertContains(o, "200 OK") +} + +func HttpClientGetResponseBodyTest(s *NoTopoSuite) { + response := "<body>hello world</body>" + size := len(response) + httpClientGet(s, response, size) +} + +func HttpClientGet128kbResponseTest(s *NoTopoSuite) { + response := strings.Repeat("a", 128*1024) + size := len(response) + httpClientGet(s, response, size) +} + +func HttpClientGetNoResponseBodyTest(s *NoTopoSuite) { + response := "" + httpClientGet(s, response, 0) +} + +func httpClientGet(s *NoTopoSuite, response string, size int) { + serverAddress := s.HostAddr() + vpp := s.GetContainerByName("vpp").VppInstance + + 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("GET", "/test"), + ghttp.VerifyHeaderKV("Hello", "World"), + ghttp.VerifyHeaderKV("Test-H2", "Test-K2"), + ghttp.RespondWith(http.StatusOK, string(response), http.Header{"Content-Length": {strconv.Itoa(size)}}), + )) + server.Start() + defer server.Close() + + uri := "http://" + serverAddress + "/80" + cmd := "http client use-ptr verbose header Hello:World header Test-H2:Test-K2 save-to response.txt uri " + uri + " target /test" + + o := vpp.Vppctl(cmd) + outputLen := len(o) + if outputLen > 500 { + s.Log(o[:500]) + s.Log("* HST Framework: output limited to 500 chars to avoid flooding the console. Output length: " + fmt.Sprint(outputLen)) + } else { + s.Log(o) + } + s.AssertContains(o, "200 OK") + s.AssertContains(o, response) + s.AssertContains(o, "Content-Length: "+strconv.Itoa(size)) + + file_contents := vpp.Container.Exec(false, "cat /tmp/response.txt") + s.AssertContains(file_contents, response) +} + +func HttpClientGetTimeout(s *NoTopoSuite) { + serverAddress := s.HostAddr() + vpp := s.GetContainerByName("vpp").VppInstance + + server := ghttp.NewUnstartedServer() + l, err := net.Listen("tcp", serverAddress+":"+s.GetPortFromPpid()) + s.AssertNil(err, fmt.Sprint(err)) + server.HTTPTestServer.Listener = l + server.AppendHandlers( + ghttp.CombineHandlers( + s.LogHttpReq(false), + ghttp.VerifyRequest("GET", "/timeout"), + http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + time.Sleep(5 * time.Second) + }), + ghttp.RespondWith(http.StatusOK, nil), + )) + server.Start() + defer server.Close() + uri := "http://" + serverAddress + "/" + s.GetPortFromPpid() + cmd := "http client verbose timeout 1 uri " + uri + " target /timeout" + + o := vpp.Vppctl(cmd) + s.Log(o) + s.AssertContains(o, "error: timeout") } func httpClientPostFile(s *NoTopoSuite, usePtr bool, fileSize int) { serverAddress := s.HostAddr() 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)) + s.Log(vpp.Container.Exec(false, "fallocate -l "+strconv.Itoa(fileSize)+" "+fileName)) + s.Log(vpp.Container.Exec(false, "ls -la "+fileName)) server := ghttp.NewUnstartedServer() l, err := net.Listen("tcp", serverAddress+":80") @@ -330,14 +418,14 @@ func httpClientPostFile(s *NoTopoSuite, usePtr bool, fileSize int) { defer server.Close() uri := "http://" + serverAddress + "/80" - cmd := "http post uri " + uri + " target /test file " + fileName + cmd := "http client post verbose uri " + uri + " target /test file " + fileName if usePtr { cmd += " use-ptr" } o := vpp.Vppctl(cmd) s.Log(o) - s.AssertNotContains(o, "error") + s.AssertContains(o, "200 OK") } func HttpClientPostFileTest(s *NoTopoSuite) { @@ -348,24 +436,11 @@ func HttpClientPostFilePtrTest(s *NoTopoSuite) { httpClientPostFile(s, true, 131072) } -func cliTestAuthority(s *NoTopoSuite, authority string) { - o := s.GetContainerByName("vpp").VppInstance.Vppctl("test http authority-form " + authority) - s.AssertNotContains(o, "error") - s.AssertContains(o, authority) -} - -func cliTestAuthorityError(s *NoTopoSuite, authority string) { - o := s.GetContainerByName("vpp").VppInstance.Vppctl("test http authority-form " + authority) - s.AssertContains(o, "error") -} - -func AuthorityFormTargetTest(s *NoTopoSuite) { - cliTestAuthority(s, "10.10.2.45:20") - cliTestAuthority(s, "[dead:beef::1234]:443") - cliTestAuthorityError(s, "example.com:80") - cliTestAuthorityError(s, "10.10.2.45") - cliTestAuthorityError(s, "1000.10.2.45:20") - cliTestAuthorityError(s, "[xyz0::1234]:443") +func HttpUnitTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + o := vpp.Vppctl("test http all") + s.Log(o) + s.AssertNotContains(o, "FAIL") } func HttpStaticPromTest(s *NoTopoSuite) { @@ -375,7 +450,7 @@ func HttpStaticPromTest(s *NoTopoSuite) { s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers")) s.Log(vpp.Vppctl("prom enable")) time.Sleep(time.Second * 5) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/"+query, nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -389,8 +464,8 @@ func HttpStaticPromTest(s *NoTopoSuite) { s.AssertNil(err, fmt.Sprint(err)) } -func promReq(s *NoTopoSuite, url string) { - client := NewHttpClient() +func promReq(s *NoTopoSuite, url string, timeout time.Duration) { + client := NewHttpClient(timeout) req, err := http.NewRequest("GET", url, nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -404,7 +479,7 @@ func promReq(s *NoTopoSuite, url string) { func promReqWg(s *NoTopoSuite, url string, wg *sync.WaitGroup) { defer GinkgoRecover() defer wg.Done() - promReq(s, url) + promReq(s, url, defaultHttpTimeout) } func PromConcurrentConnectionsTest(s *NoTopoSuite) { @@ -425,6 +500,20 @@ func PromConcurrentConnectionsTest(s *NoTopoSuite) { s.Log(vpp.Vppctl("show session verbose proto http")) } +func PromConsecutiveConnectionsTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + serverAddress := s.VppAddr() + url := "http://" + serverAddress + ":80/stats.prom" + + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers")) + s.Log(vpp.Vppctl("prom enable")) + time.Sleep(time.Second * 5) + + for i := 0; i < 1000; i++ { + promReq(s, url, time.Millisecond*500) + } +} + func PromMemLeakTest(s *NoTopoSuite) { s.SkipUnlessLeakCheck() @@ -440,7 +529,7 @@ func PromMemLeakTest(s *NoTopoSuite) { time.Sleep(time.Second * 3) /* warmup request (FIB) */ - promReq(s, url) + promReq(s, url, defaultHttpTimeout) vpp.EnableMemoryTrace() traces1, err := vpp.GetMemoryTrace() @@ -449,7 +538,7 @@ func PromMemLeakTest(s *NoTopoSuite) { /* collect stats couple of times */ for i := 0; i < 5; i++ { time.Sleep(time.Second * 1) - promReq(s, url) + promReq(s, url, defaultHttpTimeout) } /* let's give it some time to clean up sessions */ @@ -577,6 +666,39 @@ func HttpInvalidClientRequestMemLeakTest(s *NoTopoSuite) { } +func runWrkPerf(s *NoTopoSuite) { + nConnections := 1000 + serverAddress := s.VppAddr() + + wrkCont := s.GetContainerByName("wrk") + args := fmt.Sprintf("-c %d -t 2 -d 30s http://%s:80/64B", nConnections, serverAddress) + wrkCont.ExtraRunningArgs = args + wrkCont.Run() + s.Log("Please wait for 30s, test is running.") + o, err := wrkCont.GetOutput() + s.Log(o) + s.AssertEmpty(err, "err: '%s'", err) +} + +func HttpStaticFileHandlerWrkTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + serverAddress := s.VppAddr() + vpp.Container.Exec(false, "mkdir -p "+wwwRootPath) + content := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + err := vpp.Container.CreateFile(wwwRootPath+"/64B", content) + s.AssertNil(err, fmt.Sprint(err)) + s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 private-segment-size 256m")) + runWrkPerf(s) +} + +func HttpStaticUrlHandlerWrkTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + serverAddress := s.VppAddr() + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers private-segment-size 256m")) + s.Log(vpp.Vppctl("test-url-handler enable")) + runWrkPerf(s) +} + func HttpStaticFileHandlerDefaultMaxAgeTest(s *NoTopoSuite) { HttpStaticFileHandlerTestFunction(s, "default") } @@ -598,7 +720,7 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { content2 := "<html><body><p>Page</p></body></html>" vpp := s.GetContainerByName("vpp").VppInstance - vpp.Container.Exec("mkdir -p " + wwwRootPath) + vpp.Container.Exec(false, "mkdir -p "+wwwRootPath) err := vpp.Container.CreateFile(wwwRootPath+"/index.html", content) s.AssertNil(err, fmt.Sprint(err)) err = vpp.Container.CreateFile(wwwRootPath+"/page.html", content2) @@ -606,7 +728,7 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug cache-size 2m " + maxAgeFormatted)) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/index.html", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -654,14 +776,14 @@ func HttpStaticFileHandlerTestFunction(s *NoTopoSuite, max_age string) { 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.Exec(false, "mkdir -p "+wwwRootPath) + vpp.Container.Exec(false, "mkdir -p "+"/tmp/secret_folder") err := vpp.Container.CreateFile("/tmp/secret_folder/secret_file.txt", "secret") s.AssertNil(err, fmt.Sprint(err)) serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/../secret_folder/secret_file.txt", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -676,13 +798,13 @@ func HttpStaticPathTraversalTest(s *NoTopoSuite) { func HttpStaticMovedTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance - vpp.Container.Exec("mkdir -p " + wwwRootPath + "/tmp.aaa") + vpp.Container.Exec(false, "mkdir -p "+wwwRootPath+"/tmp.aaa") err := vpp.Container.CreateFile(wwwRootPath+"/tmp.aaa/index.html", "<html><body><p>Hello</p></body></html>") s.AssertNil(err, fmt.Sprint(err)) serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/tmp.aaa", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -698,11 +820,11 @@ func HttpStaticMovedTest(s *NoTopoSuite) { func HttpStaticNotFoundTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance - vpp.Container.Exec("mkdir -p " + wwwRootPath) + vpp.Container.Exec(false, "mkdir -p "+wwwRootPath) serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server www-root " + wwwRootPath + " uri tcp://" + serverAddress + "/80 debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/notfound.html", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -720,7 +842,7 @@ func HttpCliMethodNotAllowedTest(s *NoTopoSuite) { serverAddress := s.VppAddr() vpp.Vppctl("http cli server") - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("POST", "http://"+serverAddress+":80/test", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -738,7 +860,7 @@ func HttpCliBadRequestTest(s *NoTopoSuite) { serverAddress := s.VppAddr() vpp.Vppctl("http cli server") - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -753,10 +875,10 @@ func HttpCliBadRequestTest(s *NoTopoSuite) { func HttpStaticBuildInUrlGetVersionTest(s *NoTopoSuite) { vpp := s.GetContainerByName("vpp").VppInstance serverAddress := s.VppAddr() - s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) + s.Log(vpp.Vppctl("http static server uri tls://" + serverAddress + "/80 url-handlers debug")) - client := NewHttpClient() - req, err := http.NewRequest("GET", "http://"+serverAddress+":80/version.json", nil) + client := NewHttpClient(defaultHttpTimeout) + req, err := http.NewRequest("GET", "https://"+serverAddress+":80/version.json", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) s.AssertNil(err, fmt.Sprint(err)) @@ -779,7 +901,7 @@ func HttpStaticBuildInUrlGetVersionVerboseTest(s *NoTopoSuite) { serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/version.json?verbose=true", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -803,7 +925,7 @@ func HttpStaticBuildInUrlGetIfListTest(s *NoTopoSuite) { serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/interface_list.json", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -823,7 +945,7 @@ func HttpStaticBuildInUrlGetIfStatsTest(s *NoTopoSuite) { serverAddress := s.VppAddr() s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/interface_stats.json", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -852,7 +974,7 @@ func HttpStaticBuildInUrlPostIfStatsTest(s *NoTopoSuite) { s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) body := []byte(s.VppIfName()) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("POST", "http://"+serverAddress+":80/interface_stats.json", bytes.NewBuffer(body)) s.AssertNil(err, fmt.Sprint(err)) @@ -873,7 +995,7 @@ func HttpStaticMacTimeTest(s *NoTopoSuite) { s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug")) s.Log(vpp.Vppctl("mactime enable-disable " + s.VppIfName())) - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/mactime.json", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -1044,7 +1166,7 @@ func HttpMethodNotImplementedTest(s *NoTopoSuite) { serverAddress := s.VppAddr() vpp.Vppctl("http cli server") - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("OPTIONS", "http://"+serverAddress+":80/show/version", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -1071,7 +1193,7 @@ func HttpUriDecodeTest(s *NoTopoSuite) { serverAddress := s.VppAddr() vpp.Vppctl("http cli server") - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/sh%6fw%20versio%6E%20verbose", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -1143,7 +1265,7 @@ func HeaderServerTest(s *NoTopoSuite) { serverAddress := s.VppAddr() vpp.Vppctl("http cli server") - client := NewHttpClient() + client := NewHttpClient(defaultHttpTimeout) req, err := http.NewRequest("GET", "http://"+serverAddress+":80/show/version", nil) s.AssertNil(err, fmt.Sprint(err)) resp, err := client.Do(req) @@ -1154,3 +1276,33 @@ func HeaderServerTest(s *NoTopoSuite) { s.AssertHttpHeaderWithValue(resp, "Server", "http_cli_server") s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/html") } + +func HttpConnTimeoutTest(s *NoTopoSuite) { + vpp := s.GetContainerByName("vpp").VppInstance + serverAddress := s.VppAddr() + s.Log(vpp.Vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers debug keepalive-timeout 2")) + + req := "GET /version.json HTTP/1.1\r\nHost:" + serverAddress + ":80\r\nUser-Agent:test\r\n\r\n" + conn, err := net.DialTimeout("tcp", serverAddress+":80", time.Second*30) + s.AssertNil(err, fmt.Sprint(err)) + defer conn.Close() + err = conn.SetDeadline(time.Now().Add(time.Second * 30)) + s.AssertNil(err, fmt.Sprint(err)) + _, err = conn.Write([]byte(req)) + s.AssertNil(err, fmt.Sprint(err)) + reply := make([]byte, 1024) + _, err = conn.Read(reply) + s.AssertNil(err, fmt.Sprint(err)) + s.AssertContains(string(reply), "HTTP/1.1 200 OK") + s.Log(vpp.Vppctl("show session verbose 2")) + + s.Log("waiting for close on the server side") + time.Sleep(time.Second * 5) + s.Log(vpp.Vppctl("show session verbose 2")) + + _, err = conn.Write([]byte(req)) + s.AssertNil(err, fmt.Sprint(err)) + reply = make([]byte, 1024) + _, err = conn.Read(reply) + s.AssertMatchError(err, io.EOF, "connection not closed by server") +} diff --git a/extras/hs-test/infra/container.go b/extras/hs-test/infra/container.go index 974d1547c03..cc79a5cbb18 100644 --- a/extras/hs-test/infra/container.go +++ b/extras/hs-test/infra/container.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "fmt" - "github.com/docker/go-units" "os" "os/exec" "regexp" @@ -14,6 +13,8 @@ import ( "text/template" "time" + "github.com/docker/go-units" + "github.com/cilium/cilium/pkg/sysctl" containerTypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -328,9 +329,13 @@ func (c *Container) getVolumesAsSlice() []string { core_pattern, err := sysctl.Read("kernel.core_pattern") if err == nil { - index := strings.LastIndex(core_pattern, "/") - core_pattern = core_pattern[:index] - volumeSlice = append(volumeSlice, c.Suite.getLogDirPath()+":"+core_pattern) + if len(core_pattern) > 0 && core_pattern[0] != '|' { + index := strings.LastIndex(core_pattern, "/") + core_pattern = core_pattern[:index] + volumeSlice = append(volumeSlice, c.Suite.getLogDirPath()+":"+core_pattern) + } else { + c.Suite.Log(fmt.Sprintf("core_pattern \"%s\" starts with pipe, ignoring", core_pattern)) + } } else { c.Suite.Log(err) } @@ -415,6 +420,19 @@ func (c *Container) CreateFile(destFileName string, content string) error { return nil } +func (c *Container) CreateFileInWorkDir(fileName string, contents string) error { + file, err := os.Create(c.GetHostWorkDir() + "/" + fileName) + if err != nil { + return err + } + defer file.Close() + _, err = file.Write([]byte(contents)) + if err != nil { + return err + } + return nil +} + func (c *Container) GetFile(sourceFileName, targetFileName string) error { cmd := exec.Command("docker", "cp", c.Name+":"+sourceFileName, targetFileName) return cmd.Run() @@ -424,19 +442,29 @@ func (c *Container) GetFile(sourceFileName, targetFileName string) error { * Executes in detached mode so that the started application can continue to run * without blocking execution of test */ -func (c *Container) ExecServer(command string, arguments ...any) { +func (c *Container) ExecServer(useEnvVars bool, command string, arguments ...any) { + var envVars string serverCommand := fmt.Sprintf(command, arguments...) - containerExecCommand := "docker exec -d" + c.getEnvVarsAsCliOption() + - " " + c.Name + " " + serverCommand + if useEnvVars { + envVars = c.getEnvVarsAsCliOption() + } else { + envVars = "" + } + containerExecCommand := fmt.Sprintf("docker exec -d %s %s %s", envVars, c.Name, serverCommand) GinkgoHelper() c.Suite.Log(containerExecCommand) c.Suite.AssertNil(exechelper.Run(containerExecCommand)) } -func (c *Container) Exec(command string, arguments ...any) string { - cliCommand := fmt.Sprintf(command, arguments...) - containerExecCommand := "docker exec" + c.getEnvVarsAsCliOption() + - " " + c.Name + " " + cliCommand +func (c *Container) Exec(useEnvVars bool, command string, arguments ...any) string { + var envVars string + serverCommand := fmt.Sprintf(command, arguments...) + if useEnvVars { + envVars = c.getEnvVarsAsCliOption() + } else { + envVars = "" + } + containerExecCommand := fmt.Sprintf("docker exec %s %s %s", envVars, c.Name, serverCommand) GinkgoHelper() c.Suite.Log(containerExecCommand) byteOutput, err := exechelper.CombinedOutput(containerExecCommand) @@ -513,7 +541,7 @@ func (c *Container) stop() error { return nil } -func (c *Container) CreateConfig(targetConfigName string, templateName string, values any) { +func (c *Container) CreateConfigFromTemplate(targetConfigName string, templateName string, values any) { template := template.Must(template.ParseFiles(templateName)) f, err := os.CreateTemp(logDir, "hst-config") diff --git a/extras/hs-test/infra/cpu.go b/extras/hs-test/infra/cpu.go index a1682819a2f..615f8a3f87d 100644 --- a/extras/hs-test/infra/cpu.go +++ b/extras/hs-test/infra/cpu.go @@ -4,11 +4,12 @@ import ( "bufio" "errors" "fmt" - . "github.com/onsi/ginkgo/v2" "os" "os/exec" "strconv" "strings" + + . "github.com/onsi/ginkgo/v2" ) var CgroupPath = "/sys/fs/cgroup/" diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go index ed8da3fe244..3aeeb24d14e 100644 --- a/extras/hs-test/infra/hst_suite.go +++ b/extras/hs-test/infra/hst_suite.go @@ -4,7 +4,6 @@ import ( "bufio" "flag" "fmt" - "github.com/edwarnicke/exechelper" "io" "log" "net/http" @@ -17,6 +16,8 @@ import ( "strings" "time" + "github.com/edwarnicke/exechelper" + containerTypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" "github.com/onsi/gomega/gmeasure" @@ -40,8 +41,9 @@ var IsDebugBuild = flag.Bool("debug_build", false, "some paths are different wit var UseCpu0 = flag.Bool("cpu0", false, "use cpu0") var IsLeakCheck = flag.Bool("leak_check", false, "run leak-check tests") var ParallelTotal = flag.Lookup("ginkgo.parallel.total") +var DryRun = flag.Bool("dryrun", false, "set up containers but don't run tests") var NumaAwareCpuAlloc bool -var SuiteTimeout time.Duration +var TestTimeout time.Duration type HstSuite struct { Containers map[string]*Container @@ -61,6 +63,18 @@ type HstSuite struct { Docker *client.Client } +type colors struct { + grn string + pur string + rst string +} + +var Colors = colors{ + grn: "\033[32m", + pur: "\033[35m", + rst: "\033[0m", +} + // used for colorful ReportEntry type StringerStruct struct { Label string @@ -103,8 +117,8 @@ func (s *HstSuite) newDockerClient() { func (s *HstSuite) SetupSuite() { s.CreateLogger() + s.Log("[* SUITE SETUP]") s.newDockerClient() - s.Log("Suite Setup") RegisterFailHandler(func(message string, callerSkip ...int) { s.HstFail() Fail(message, callerSkip...) @@ -138,21 +152,28 @@ func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) { func (s *HstSuite) TearDownSuite() { defer s.LogFile.Close() defer s.Docker.Close() - s.Log("Suite Teardown") + if *IsPersistent || *DryRun { + return + } + s.Log("[* SUITE TEARDOWN]") s.UnconfigureNetworkTopology() } func (s *HstSuite) TearDownTest() { - s.Log("Test Teardown") - if *IsPersistent { + s.Log("[* TEST TEARDOWN]") + if *IsPersistent || *DryRun { return } - s.WaitForCoreDump() + coreDump := s.WaitForCoreDump() s.ResetContainers() if s.Ip4AddrAllocator != nil { s.Ip4AddrAllocator.DeleteIpAddresses() } + + if coreDump { + Fail("VPP crashed") + } } func (s *HstSuite) SkipIfUnconfiguring() { @@ -162,7 +183,7 @@ func (s *HstSuite) SkipIfUnconfiguring() { } func (s *HstSuite) SetupTest() { - s.Log("Test Setup") + s.Log("[* TEST SETUP]") s.StartedContainers = s.StartedContainers[:0] s.SkipIfUnconfiguring() s.SetupContainers() @@ -289,6 +310,10 @@ func (s *HstSuite) AssertHttpBody(resp *http.Response, expectedBody string, msgA ExpectWithOffset(2, resp).To(HaveHTTPBody(expectedBody), msgAndArgs...) } +func (s *HstSuite) AssertChannelClosed(timeout time.Duration, channel chan error) { + EventuallyWithOffset(2, channel).WithTimeout(timeout).Should(BeClosed()) +} + func (s *HstSuite) CreateLogger() { suiteName := s.GetCurrentSuiteName() var err error @@ -301,13 +326,20 @@ func (s *HstSuite) CreateLogger() { // Logs to files by default, logs to stdout when VERBOSE=true with GinkgoWriter // to keep console tidy -func (s *HstSuite) Log(arg any) { - logs := strings.Split(fmt.Sprint(arg), "\n") +func (s *HstSuite) Log(log any, arg ...any) { + var logStr string + if len(arg) == 0 { + logStr = fmt.Sprint(log) + } else { + logStr = fmt.Sprintf(fmt.Sprint(log), arg...) + } + logs := strings.Split(logStr, "\n") + for _, line := range logs { s.Logger.Println(line) } if *IsVerbose { - GinkgoWriter.Println(arg) + GinkgoWriter.Println(logStr) } } @@ -321,33 +353,24 @@ func (s *HstSuite) SkipIfMultiWorker(args ...any) { } } -func (s *HstSuite) SkipIfNotEnoughAvailableCpus() bool { - var MaxRequestedCpu int +func (s *HstSuite) SkipIfNotEnoughAvailableCpus() { + var maxRequestedCpu int + availableCpus := len(s.CpuAllocator.cpus) - 1 - if s.CpuAllocator.runningInCi { - MaxRequestedCpu = ((s.CpuAllocator.buildNumber + 1) * s.CpuAllocator.maxContainerCount * s.CpuCount) - } else { - MaxRequestedCpu = (GinkgoParallelProcess() * s.CpuAllocator.maxContainerCount * s.CpuCount) + if *UseCpu0 { + availableCpus++ } - if len(s.CpuAllocator.cpus)-1 < MaxRequestedCpu { - s.Skip(fmt.Sprintf("test case cannot allocate requested cpus (%d cpus * %d containers)", s.CpuCount, s.CpuAllocator.maxContainerCount)) + if s.CpuAllocator.runningInCi { + maxRequestedCpu = ((s.CpuAllocator.buildNumber + 1) * s.CpuAllocator.maxContainerCount * s.CpuCount) + } else { + maxRequestedCpu = (GinkgoParallelProcess() * s.CpuAllocator.maxContainerCount * s.CpuCount) } - return true -} - -func (s *HstSuite) SkipUnlessExtendedTestsBuilt() { - imageName := "hs-test/nginx-http3" - - cmd := exec.Command("docker", "images", imageName) - byteOutput, err := cmd.CombinedOutput() - if err != nil { - s.Log("error while searching for docker image") - return - } - if !strings.Contains(string(byteOutput), imageName) { - s.Skip("extended tests not built") + if availableCpus < maxRequestedCpu { + s.Skip(fmt.Sprintf("Test case cannot allocate requested cpus "+ + "(%d cpus * %d containers, %d available). Try using 'CPU0=true'", + s.CpuCount, s.CpuAllocator.maxContainerCount, availableCpus)) } } @@ -357,19 +380,19 @@ func (s *HstSuite) SkipUnlessLeakCheck() { } } -func (s *HstSuite) WaitForCoreDump() { +func (s *HstSuite) WaitForCoreDump() bool { var filename string dir, err := os.Open(s.getLogDirPath()) if err != nil { s.Log(err) - return + return false } defer dir.Close() files, err := dir.Readdirnames(0) if err != nil { s.Log(err) - return + return false } for _, file := range files { if strings.Contains(file, "core") { @@ -386,7 +409,7 @@ func (s *HstSuite) WaitForCoreDump() { fileInfo, err := os.Stat(corePath) if err != nil { s.Log("Error while reading file info: " + fmt.Sprint(err)) - return + return true } currSize := fileInfo.Size() s.Log(fmt.Sprintf("Waiting %ds/%ds...", i, timeout)) @@ -413,10 +436,11 @@ func (s *HstSuite) WaitForCoreDump() { s.Log(err) } } - return + return true } } } + return false } func (s *HstSuite) ResetContainers() { @@ -480,6 +504,13 @@ func (s *HstSuite) LoadContainerTopology(topologyName string) { } s.Containers[newContainer.Name] = newContainer } + + if *DryRun { + s.Log(Colors.pur + "* Containers used by this suite (some might already be running):" + Colors.rst) + for name := range s.Containers { + s.Log("%sdocker start %s && docker exec -it %s bash%s", Colors.pur, name, name, Colors.rst) + } + } } func (s *HstSuite) LoadNetworkTopology(topologyName string) { @@ -567,14 +598,18 @@ func (s *HstSuite) ConfigureNetworkTopology(topologyName string) { } func (s *HstSuite) UnconfigureNetworkTopology() { - if *IsPersistent { - return - } for _, nc := range s.NetConfigs { nc.unconfigure() } } +func (s *HstSuite) LogStartedContainers() { + s.Log("%s* Started containers:%s", Colors.grn, Colors.rst) + for _, container := range s.StartedContainers { + s.Log(Colors.grn + container.Name + Colors.rst) + } +} + func (s *HstSuite) GetTestId() string { testName := s.GetCurrentTestName() diff --git a/extras/hs-test/infra/suite_cpu_pinning.go b/extras/hs-test/infra/suite_cpu_pinning.go index e829efa950b..57efbe7f4f0 100644 --- a/extras/hs-test/infra/suite_cpu_pinning.go +++ b/extras/hs-test/infra/suite_cpu_pinning.go @@ -2,10 +2,11 @@ package hst import ( "fmt" - . "github.com/onsi/ginkgo/v2" "reflect" "runtime" "strings" + + . "github.com/onsi/ginkgo/v2" ) var cpuPinningTests = map[string][]func(s *CpuPinningSuite){} @@ -41,6 +42,11 @@ func (s *CpuPinningSuite) SetupTest() { container := s.GetContainerByName(SingleTopoContainerVpp) vpp, err := container.newVppInstance(container.AllocatedCpus) s.AssertNotNil(vpp, fmt.Sprint(err)) + + if *DryRun { + s.LogStartedContainers() + s.Skip("Dry run mode = true") + } } func (s *CpuPinningSuite) TearDownTest() { @@ -77,7 +83,7 @@ var _ = Describe("CpuPinningSuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -106,7 +112,7 @@ var _ = Describe("CpuPinningSuiteSolo", Ordered, ContinueOnFailure, Serial, func It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_envoy_proxy.go b/extras/hs-test/infra/suite_envoy_proxy.go index 80715214cac..50ffd11898e 100644 --- a/extras/hs-test/infra/suite_envoy_proxy.go +++ b/extras/hs-test/infra/suite_envoy_proxy.go @@ -7,10 +7,12 @@ package hst import ( "fmt" - . "github.com/onsi/ginkgo/v2" "reflect" "runtime" "strings" + "time" + + . "github.com/onsi/ginkgo/v2" ) const ( @@ -63,12 +65,8 @@ func (s *EnvoyProxySuite) SetupTest() { vppContainer := s.GetContainerByName(VppContainerName) vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(vpp, fmt.Sprint(err)) - s.AssertNil(vpp.Start()) clientInterface := s.GetInterfaceByName(ClientTapInterfaceName) - s.AssertNil(vpp.createTap(clientInterface, 1)) serverInterface := s.GetInterfaceByName(ServerTapInterfaceName) - s.AssertNil(vpp.createTap(serverInterface, 2)) - vppContainer.Exec("chmod 777 -R %s", vppContainer.GetContainerWorkDir()) // nginx HTTP server nginxContainer := s.GetTransientContainerByName(NginxServerContainerName) @@ -85,16 +83,16 @@ func (s *EnvoyProxySuite) SetupTest() { Port: s.nginxPort, Timeout: s.maxTimeout, } - nginxContainer.CreateConfig( + nginxContainer.CreateConfigFromTemplate( "/nginx.conf", "./resources/nginx/nginx_server.conf", nginxSettings, ) - s.AssertNil(nginxContainer.Start()) // Envoy envoyContainer := s.GetContainerByName(EnvoyProxyContainerName) s.AssertNil(envoyContainer.Create()) + s.proxyPort = 8080 envoySettings := struct { LogPrefix string @@ -107,19 +105,35 @@ func (s *EnvoyProxySuite) SetupTest() { ServerPort: s.nginxPort, ProxyPort: s.proxyPort, } - envoyContainer.CreateConfig( + envoyContainer.CreateConfigFromTemplate( "/etc/envoy/envoy.yaml", "resources/envoy/proxy.yaml", envoySettings, ) - s.AssertNil(envoyContainer.Start()) + + s.AssertNil(vpp.Start()) + // wait for VPP to start + time.Sleep(time.Second * 1) + s.AssertNil(vpp.createTap(clientInterface, 1)) + s.AssertNil(vpp.createTap(serverInterface, 2)) + vppContainer.Exec(false, "chmod 777 -R %s", vppContainer.GetContainerWorkDir()) // Add Ipv4 ARP entry for nginx HTTP server, otherwise first request fail (HTTP error 503) arp := fmt.Sprintf("set ip neighbor %s %s %s", serverInterface.Peer.Name(), serverInterface.Ip4AddressString(), serverInterface.HwAddress) + + if *DryRun { + vpp.AppendToCliConfig(arp) + s.LogStartedContainers() + s.Log("%s* Proxy IP used in tests: %s:%d%s", Colors.pur, s.ProxyAddr(), s.ProxyPort(), Colors.rst) + s.Skip("Dry run mode = true") + } + vppContainer.VppInstance.Vppctl(arp) + s.AssertNil(nginxContainer.Start()) + s.AssertNil(envoyContainer.Start()) } func (s *EnvoyProxySuite) TearDownTest() { @@ -177,7 +191,7 @@ var _ = Describe("EnvoyProxySuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -206,7 +220,7 @@ var _ = Describe("EnvoyProxySuiteSolo", Ordered, ContinueOnFailure, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_iperf_linux.go b/extras/hs-test/infra/suite_iperf_linux.go index 728429b505f..fb685f9ad96 100644 --- a/extras/hs-test/infra/suite_iperf_linux.go +++ b/extras/hs-test/infra/suite_iperf_linux.go @@ -61,7 +61,7 @@ var _ = Describe("IperfSuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -90,7 +90,7 @@ var _ = Describe("IperfSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_ldp.go b/extras/hs-test/infra/suite_ldp.go index 15b45f710ef..6294fab0dd6 100644 --- a/extras/hs-test/infra/suite_ldp.go +++ b/extras/hs-test/infra/suite_ldp.go @@ -60,24 +60,34 @@ func (s *LdpSuite) SetupTest() { serverVpp, err := serverContainer.newVppInstance(serverContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(serverVpp, fmt.Sprint(err)) - s.SetupServerVpp() - // ... For client clientContainer := s.GetContainerByName("client-vpp") clientVpp, err := clientContainer.newVppInstance(clientContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(clientVpp, fmt.Sprint(err)) - s.setupClientVpp() - - serverContainer.AddEnvVar("VCL_CONFIG", serverContainer.GetContainerWorkDir()+"/vcl_srv.conf") - clientContainer.AddEnvVar("VCL_CONFIG", clientContainer.GetContainerWorkDir()+"/vcl_cln.conf") + serverContainer.AddEnvVar("VCL_CONFIG", serverContainer.GetContainerWorkDir()+"/vcl.conf") + clientContainer.AddEnvVar("VCL_CONFIG", clientContainer.GetContainerWorkDir()+"/vcl.conf") for _, container := range s.StartedContainers { container.AddEnvVar("LD_PRELOAD", "/usr/lib/libvcl_ldpreload.so") container.AddEnvVar("LDP_DEBUG", "0") container.AddEnvVar("VCL_DEBUG", "0") } + + s.CreateVclConfig(serverContainer) + s.CreateVclConfig(clientContainer) + s.SetupServerVpp(serverContainer) + s.setupClientVpp(clientContainer) + + if *DryRun { + s.LogStartedContainers() + s.Log("\n%s* LD_PRELOAD and VCL_CONFIG server/client paths:", Colors.grn) + s.Log("LD_PRELOAD=/usr/lib/libvcl_ldpreload.so") + s.Log("VCL_CONFIG=%s/vcl.conf", serverContainer.GetContainerWorkDir()) + s.Log("VCL_CONFIG=%s/vcl.conf%s\n", clientContainer.GetContainerWorkDir(), Colors.rst) + s.Skip("Dry run mode = true") + } } func (s *LdpSuite) TearDownTest() { @@ -89,36 +99,35 @@ func (s *LdpSuite) TearDownTest() { } -func (s *LdpSuite) SetupServerVpp() { - var srvVclConf Stanza - serverContainer := s.GetContainerByName("server-vpp") - serverVclFileName := serverContainer.GetHostWorkDir() + "/vcl_srv.conf" - serverVpp := serverContainer.VppInstance - s.AssertNil(serverVpp.Start()) +func (s *LdpSuite) CreateVclConfig(container *Container) { + var vclConf Stanza + vclFileName := container.GetHostWorkDir() + "/vcl.conf" - serverVeth := s.GetInterfaceByName(ServerInterfaceName) - idx, err := serverVpp.createAfPacket(serverVeth) - s.AssertNil(err, fmt.Sprint(err)) - s.AssertNotEqual(0, idx) - - serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", - serverContainer.GetContainerWorkDir()) - err = srvVclConf. + appSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", + container.GetContainerWorkDir()) + err := vclConf. NewStanza("vcl"). Append("rx-fifo-size 4000000"). Append("tx-fifo-size 4000000"). Append("app-scope-local"). Append("app-scope-global"). Append("use-mq-eventfd"). - Append(serverAppSocketApi).Close(). - SaveToFile(serverVclFileName) + Append(appSocketApi).Close(). + SaveToFile(vclFileName) s.AssertNil(err, fmt.Sprint(err)) } -func (s *LdpSuite) setupClientVpp() { - var clnVclConf Stanza - clientContainer := s.GetContainerByName("client-vpp") - clientVclFileName := clientContainer.GetHostWorkDir() + "/vcl_cln.conf" +func (s *LdpSuite) SetupServerVpp(serverContainer *Container) { + serverVpp := serverContainer.VppInstance + s.AssertNil(serverVpp.Start()) + + serverVeth := s.GetInterfaceByName(ServerInterfaceName) + idx, err := serverVpp.createAfPacket(serverVeth) + s.AssertNil(err, fmt.Sprint(err)) + s.AssertNotEqual(0, idx) +} + +func (s *LdpSuite) setupClientVpp(clientContainer *Container) { clientVpp := clientContainer.VppInstance s.AssertNil(clientVpp.Start()) @@ -126,19 +135,6 @@ func (s *LdpSuite) setupClientVpp() { idx, err := clientVpp.createAfPacket(clientVeth) s.AssertNil(err, fmt.Sprint(err)) s.AssertNotEqual(0, idx) - - clientAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", - clientContainer.GetContainerWorkDir()) - err = clnVclConf. - NewStanza("vcl"). - Append("rx-fifo-size 4000000"). - Append("tx-fifo-size 4000000"). - Append("app-scope-local"). - Append("app-scope-global"). - Append("use-mq-eventfd"). - Append(clientAppSocketApi).Close(). - SaveToFile(clientVclFileName) - s.AssertNil(err, fmt.Sprint(err)) } var _ = Describe("LdpSuite", Ordered, ContinueOnFailure, func() { @@ -167,7 +163,7 @@ var _ = Describe("LdpSuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -197,7 +193,7 @@ var _ = Describe("LdpSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_nginx_proxy.go b/extras/hs-test/infra/suite_nginx_proxy.go index 75215cfc78d..9d81f70720c 100644 --- a/extras/hs-test/infra/suite_nginx_proxy.go +++ b/extras/hs-test/infra/suite_nginx_proxy.go @@ -58,33 +58,13 @@ func (s *NginxProxySuite) SetupTest() { vppContainer := s.GetContainerByName(VppContainerName) vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(vpp, fmt.Sprint(err)) - s.AssertNil(vpp.Start()) clientInterface := s.GetInterfaceByName(MirroringClientInterfaceName) - s.AssertNil(vpp.createTap(clientInterface, 1)) serverInterface := s.GetInterfaceByName(MirroringServerInterfaceName) - s.AssertNil(vpp.createTap(serverInterface, 2)) // nginx proxy - nginxProxyContainer := s.GetTransientContainerByName(NginxProxyContainerName) + nginxProxyContainer := s.GetContainerByName(NginxProxyContainerName) s.AssertNil(nginxProxyContainer.Create()) s.proxyPort = 80 - values := struct { - LogPrefix string - Proxy string - Server string - Port uint16 - }{ - LogPrefix: nginxProxyContainer.Name, - Proxy: clientInterface.Peer.Ip4AddressString(), - Server: serverInterface.Ip4AddressString(), - Port: s.proxyPort, - } - nginxProxyContainer.CreateConfig( - "/nginx.conf", - "./resources/nginx/nginx_proxy_mirroring.conf", - values, - ) - s.AssertNil(nginxProxyContainer.Start()) // nginx HTTP server nginxServerContainer := s.GetTransientContainerByName(NginxServerContainerName) @@ -98,14 +78,24 @@ func (s *NginxProxySuite) SetupTest() { Address: serverInterface.Ip4AddressString(), Timeout: s.maxTimeout, } - nginxServerContainer.CreateConfig( + nginxServerContainer.CreateConfigFromTemplate( "/nginx.conf", "./resources/nginx/nginx_server_mirroring.conf", nginxSettings, ) - s.AssertNil(nginxServerContainer.Start()) - vpp.WaitForApp("nginx-", 5) + s.AssertNil(vpp.Start()) + s.AssertNil(vpp.createTap(clientInterface, 1)) + s.AssertNil(vpp.createTap(serverInterface, 2)) + + if *DryRun { + s.LogStartedContainers() + s.Log("%s* Proxy IP used in tests: %s:%d%s", Colors.pur, s.ProxyAddr(), s.ProxyPort(), Colors.rst) + s.Skip("Dry run mode = true") + } + + s.AssertNil(nginxProxyContainer.Start()) + s.AssertNil(nginxServerContainer.Start()) } func (s *NginxProxySuite) TearDownTest() { @@ -116,6 +106,35 @@ func (s *NginxProxySuite) TearDownTest() { s.HstSuite.TearDownTest() } +func (s *NginxProxySuite) CreateNginxProxyConfig(container *Container, multiThreadWorkers bool) { + clientInterface := s.GetInterfaceByName(MirroringClientInterfaceName) + serverInterface := s.GetInterfaceByName(MirroringServerInterfaceName) + var workers uint8 + if multiThreadWorkers { + workers = 2 + } else { + workers = 1 + } + values := struct { + Workers uint8 + LogPrefix string + Proxy string + Server string + Port uint16 + }{ + Workers: workers, + LogPrefix: container.Name, + Proxy: clientInterface.Peer.Ip4AddressString(), + Server: serverInterface.Ip4AddressString(), + Port: s.proxyPort, + } + container.CreateConfigFromTemplate( + "/nginx.conf", + "./resources/nginx/nginx_proxy_mirroring.conf", + values, + ) +} + func (s *NginxProxySuite) ProxyPort() uint16 { return s.proxyPort } @@ -132,6 +151,31 @@ func (s *NginxProxySuite) CurlDownloadResource(uri string) { s.AssertNotContains(log, "Operation timed out") } +func (s *NginxProxySuite) AddVclConfig(container *Container, multiThreadWorkers bool) { + var vclConf Stanza + vclFileName := container.GetHostWorkDir() + "/vcl.conf" + + appSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", + container.GetContainerWorkDir()) + + vclConf. + NewStanza("vcl"). + Append("heapsize 64M"). + Append("rx-fifo-size 4000000"). + Append("tx-fifo-size 4000000"). + Append("segment-size 4000000000"). + Append("add-segment-size 4000000000"). + Append("event-queue-size 100000"). + Append("use-mq-eventfd"). + Append(appSocketApi) + if multiThreadWorkers { + vclConf.Append("multi-thread-workers") + } + + err := vclConf.Close().SaveToFile(vclFileName) + s.AssertNil(err, fmt.Sprint(err)) +} + var _ = Describe("NginxProxySuite", Ordered, ContinueOnFailure, func() { var s NginxProxySuite BeforeAll(func() { @@ -156,7 +200,7 @@ var _ = Describe("NginxProxySuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -185,7 +229,7 @@ var _ = Describe("NginxProxySuiteSolo", Ordered, ContinueOnFailure, Serial, func It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_no_topo.go b/extras/hs-test/infra/suite_no_topo.go index 9b4998a77a1..068c43b14d0 100644 --- a/extras/hs-test/infra/suite_no_topo.go +++ b/extras/hs-test/infra/suite_no_topo.go @@ -1,6 +1,7 @@ package hst import ( + "fmt" "reflect" "runtime" "strings" @@ -12,6 +13,7 @@ const ( SingleTopoContainerVpp = "vpp" SingleTopoContainerNginx = "nginx" TapInterfaceName = "htaphost" + NginxHttp3ContainerName = "nginx-http3" ) var noTopoTests = map[string][]func(s *NoTopoSuite){} @@ -53,11 +55,66 @@ func (s *NoTopoSuite) SetupTest() { container := s.GetContainerByName(SingleTopoContainerVpp) vpp, _ := container.newVppInstance(container.AllocatedCpus, sessionConfig) - s.AssertNil(vpp.Start()) + s.AssertNil(vpp.Start()) tapInterface := s.GetInterfaceByName(TapInterfaceName) - s.AssertNil(vpp.createTap(tapInterface), "failed to create tap interface") + + if *DryRun { + s.LogStartedContainers() + s.Skip("Dry run mode = true") + } +} + +func (s *NoTopoSuite) TearDownTest() { + if CurrentSpecReport().Failed() { + s.CollectNginxLogs(NginxHttp3ContainerName) + } + s.HstSuite.TearDownTest() +} + +func (s *NoTopoSuite) CreateNginxConfig(container *Container, multiThreadWorkers bool) { + var workers uint8 + if multiThreadWorkers { + workers = 2 + } else { + workers = 1 + } + values := struct { + Workers uint8 + }{ + Workers: workers, + } + container.CreateConfigFromTemplate( + "/nginx.conf", + "./resources/nginx/nginx.conf", + values, + ) +} + +func (s *NoTopoSuite) AddNginxVclConfig(multiThreadWorkers bool) { + nginxCont := s.GetContainerByName(SingleTopoContainerNginx) + vclFileName := nginxCont.GetHostWorkDir() + "/vcl.conf" + appSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default", + nginxCont.GetContainerWorkDir()) + + var vclConf Stanza + vclConf. + NewStanza("vcl"). + Append("heapsize 64M"). + Append("rx-fifo-size 4000000"). + Append("tx-fifo-size 4000000"). + Append("segment-size 4000000000"). + Append("add-segment-size 4000000000"). + Append("event-queue-size 100000"). + Append("use-mq-eventfd"). + Append(appSocketApi) + if multiThreadWorkers { + vclConf.Append("multi-thread-workers") + } + + err := vclConf.Close().SaveToFile(vclFileName) + s.AssertNil(err, fmt.Sprint(err)) } func (s *NoTopoSuite) VppAddr() string { @@ -72,6 +129,19 @@ func (s *NoTopoSuite) HostAddr() string { return s.GetInterfaceByName(TapInterfaceName).Ip4AddressString() } +func (s *NoTopoSuite) CreateNginxHttp3Config(container *Container) { + nginxSettings := struct { + LogPrefix string + }{ + LogPrefix: container.Name, + } + container.CreateConfigFromTemplate( + "/nginx.conf", + "./resources/nginx/nginx_http3.conf", + nginxSettings, + ) +} + var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() { var s NoTopoSuite BeforeAll(func() { @@ -96,7 +166,7 @@ var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -125,7 +195,7 @@ var _ = Describe("NoTopoSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_ns.go b/extras/hs-test/infra/suite_ns.go deleted file mode 100644 index 601ec22a8a9..00000000000 --- a/extras/hs-test/infra/suite_ns.go +++ /dev/null @@ -1,127 +0,0 @@ -package hst - -import ( - "fmt" - "reflect" - "runtime" - "strings" - - . "github.com/onsi/ginkgo/v2" -) - -// These correspond to names used in yaml config -const ( - ClientInterface = "hclnvpp" - ServerInterface = "hsrvvpp" -) - -var nsTests = map[string][]func(s *NsSuite){} -var nsSoloTests = map[string][]func(s *NsSuite){} - -type NsSuite struct { - HstSuite -} - -func RegisterNsTests(tests ...func(s *NsSuite)) { - nsTests[getTestFilename()] = tests -} -func RegisterNsSoloTests(tests ...func(s *NsSuite)) { - nsSoloTests[getTestFilename()] = tests -} - -func (s *NsSuite) SetupSuite() { - s.HstSuite.SetupSuite() - s.ConfigureNetworkTopology("ns") - s.LoadContainerTopology("ns") -} - -func (s *NsSuite) SetupTest() { - s.HstSuite.SetupTest() - - // Setup test conditions - var sessionConfig Stanza - sessionConfig. - NewStanza("session"). - Append("enable"). - Append("use-app-socket-api"). - Append("evt_qs_memfd_seg"). - Append("event-queue-length 100000") - - if strings.Contains(CurrentSpecReport().LeafNodeText, "InterruptMode") { - sessionConfig.Append("use-private-rx-mqs").Close() - } else { - sessionConfig.Close() - } - - container := s.GetContainerByName("vpp") - vpp, _ := container.newVppInstance(container.AllocatedCpus, sessionConfig) - s.AssertNil(vpp.Start()) - - idx, err := vpp.createAfPacket(s.GetInterfaceByName(ServerInterface)) - s.AssertNil(err, fmt.Sprint(err)) - s.AssertNotEqual(0, idx) - - idx, err = vpp.createAfPacket(s.GetInterfaceByName(ClientInterface)) - s.AssertNil(err, fmt.Sprint(err)) - s.AssertNotEqual(0, idx) - - container.Exec("chmod 777 -R %s", container.GetContainerWorkDir()) -} - -var _ = Describe("NsSuite", Ordered, ContinueOnFailure, func() { - var s NsSuite - BeforeAll(func() { - s.SetupSuite() - }) - BeforeEach(func() { - s.SetupTest() - }) - AfterAll(func() { - s.TearDownSuite() - }) - AfterEach(func() { - s.TearDownTest() - }) - - for filename, tests := range nsTests { - for _, test := range tests { - test := test - pc := reflect.ValueOf(test).Pointer() - funcValue := runtime.FuncForPC(pc) - testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] - It(testName, func(ctx SpecContext) { - s.Log(testName + ": BEGIN") - test(&s) - }, SpecTimeout(SuiteTimeout)) - } - } -}) - -var _ = Describe("NsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { - var s NsSuite - BeforeAll(func() { - s.SetupSuite() - }) - BeforeEach(func() { - s.SetupTest() - }) - AfterAll(func() { - s.TearDownSuite() - }) - AfterEach(func() { - s.TearDownTest() - }) - - for filename, tests := range nsSoloTests { - for _, test := range tests { - test := test - pc := reflect.ValueOf(test).Pointer() - funcValue := runtime.FuncForPC(pc) - testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2] - It(testName, Label("SOLO"), func(ctx SpecContext) { - s.Log(testName + ": BEGIN") - test(&s) - }, SpecTimeout(SuiteTimeout)) - } - } -}) diff --git a/extras/hs-test/infra/suite_veth.go b/extras/hs-test/infra/suite_veth.go index f7b1c3da7d8..cbbd7ee2694 100644 --- a/extras/hs-test/infra/suite_veth.go +++ b/extras/hs-test/infra/suite_veth.go @@ -60,15 +60,18 @@ func (s *VethsSuite) SetupTest() { serverVpp, err := serverContainer.newVppInstance(serverContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(serverVpp, fmt.Sprint(err)) - s.SetupServerVpp() - // ... For client clientContainer := s.GetContainerByName("client-vpp") clientVpp, err := clientContainer.newVppInstance(clientContainer.AllocatedCpus, sessionConfig) s.AssertNotNil(clientVpp, fmt.Sprint(err)) + s.SetupServerVpp() s.setupClientVpp() + if *DryRun { + s.LogStartedContainers() + s.Skip("Dry run mode = true") + } } func (s *VethsSuite) SetupServerVpp() { @@ -117,7 +120,7 @@ var _ = Describe("VethsSuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -147,7 +150,7 @@ var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/suite_vpp_proxy.go b/extras/hs-test/infra/suite_vpp_proxy.go index 21e81e0581e..16c6115bc23 100644 --- a/extras/hs-test/infra/suite_vpp_proxy.go +++ b/extras/hs-test/infra/suite_vpp_proxy.go @@ -7,10 +7,11 @@ package hst import ( "fmt" - . "github.com/onsi/ginkgo/v2" "reflect" "runtime" "strings" + + . "github.com/onsi/ginkgo/v2" ) // These correspond to names used in yaml config @@ -57,11 +58,9 @@ func (s *VppProxySuite) SetupTest() { vppContainer := s.GetContainerByName(VppProxyContainerName) vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus) s.AssertNotNil(vpp, fmt.Sprint(err)) - s.AssertNil(vpp.Start()) + clientInterface := s.GetInterfaceByName(ClientTapInterfaceName) - s.AssertNil(vpp.createTap(clientInterface, 1)) serverInterface := s.GetInterfaceByName(ServerTapInterfaceName) - s.AssertNil(vpp.createTap(serverInterface, 2)) // nginx HTTP server nginxContainer := s.GetTransientContainerByName(NginxServerContainerName) @@ -78,12 +77,21 @@ func (s *VppProxySuite) SetupTest() { Port: s.nginxPort, Timeout: s.maxTimeout, } - nginxContainer.CreateConfig( + nginxContainer.CreateConfigFromTemplate( "/nginx.conf", "./resources/nginx/nginx_server.conf", nginxSettings, ) s.AssertNil(nginxContainer.Start()) + + s.AssertNil(vpp.Start()) + s.AssertNil(vpp.createTap(clientInterface, 1)) + s.AssertNil(vpp.createTap(serverInterface, 2)) + + if *DryRun { + s.LogStartedContainers() + s.Skip("Dry run mode = true") + } } func (s *VppProxySuite) TearDownTest() { @@ -176,7 +184,7 @@ var _ = Describe("VppProxySuite", Ordered, ContinueOnFailure, func() { It(testName, func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) @@ -205,7 +213,7 @@ var _ = Describe("VppProxySuiteSolo", Ordered, ContinueOnFailure, func() { It(testName, Label("SOLO"), func(ctx SpecContext) { s.Log(testName + ": BEGIN") test(&s) - }, SpecTimeout(SuiteTimeout)) + }, SpecTimeout(TestTimeout)) } } }) diff --git a/extras/hs-test/infra/utils.go b/extras/hs-test/infra/utils.go index 25d8519cb8a..30abb6ac715 100644 --- a/extras/hs-test/infra/utils.go +++ b/extras/hs-test/infra/utils.go @@ -1,6 +1,7 @@ package hst import ( + "crypto/tls" "errors" "fmt" "io" @@ -86,13 +87,14 @@ func (s *Stanza) SaveToFile(fileName string) error { } // NewHttpClient creates [http.Client] with disabled proxy and redirects, it also sets timeout to 30seconds. -func NewHttpClient() *http.Client { +func NewHttpClient(timeout time.Duration) *http.Client { transport := http.DefaultTransport transport.(*http.Transport).Proxy = nil transport.(*http.Transport).DisableKeepAlives = true + transport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} client := &http.Client{ Transport: transport, - Timeout: time.Second * 30, + Timeout: timeout, CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }} @@ -254,6 +256,7 @@ func (s *HstSuite) StartWget(finished chan error, server_ip, port, query, netNs netNs) s.Log(cmd) o, err := cmd.CombinedOutput() + s.Log(string(o)) if err != nil { finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o) return @@ -269,7 +272,7 @@ func (s *HstSuite) StartServerApp(c *Container, processName string, cmd string, running chan error, done chan struct{}) { s.Log("starting server") - c.ExecServer(cmd) + c.ExecServer(true, cmd) cmd2 := exec.Command("docker", "exec", c.Name, "pidof", processName) err := cmd2.Run() if err != nil { diff --git a/extras/hs-test/infra/vppinstance.go b/extras/hs-test/infra/vppinstance.go index b3ae995870f..d40fbffe63c 100644 --- a/extras/hs-test/infra/vppinstance.go +++ b/extras/hs-test/infra/vppinstance.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "go.fd.io/govpp/binapi/ethernet_types" "io" "net" "os" @@ -15,6 +14,8 @@ import ( "syscall" "time" + "go.fd.io/govpp/binapi/ethernet_types" + "github.com/edwarnicke/exechelper" . "github.com/onsi/ginkgo/v2" "github.com/sirupsen/logrus" @@ -36,6 +37,7 @@ const vppConfigTemplate = `unix { coredump-size unlimited cli-listen %[1]s%[2]s runtime-dir %[1]s/var/run + %[5]s } api-trace { @@ -58,6 +60,7 @@ plugins { plugin af_packet_plugin.so { enable } plugin hs_apps_plugin.so { enable } plugin http_plugin.so { enable } + plugin http_unittest_plugin.so { enable } plugin http_static_plugin.so { enable } plugin prom_plugin.so { enable } plugin tlsopenssl_plugin.so { enable } @@ -121,18 +124,27 @@ func (vpp *VppInstance) getEtcDir() string { return vpp.Container.GetContainerWorkDir() + "/etc/vpp" } +// Appends a string to '[host-work-dir]/cli-config.conf'. +// Creates the conf file if it doesn't exist. Used for dry-run mode. +func (vpp *VppInstance) AppendToCliConfig(vppCliConfig string) { + f, err := os.OpenFile(vpp.Container.GetHostWorkDir()+"/cli-config.conf", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + vpp.getSuite().AssertNil(err) + _, err = f.Write([]byte(vppCliConfig)) + vpp.getSuite().AssertNil(err) + err = f.Close() + vpp.getSuite().AssertNil(err) +} + func (vpp *VppInstance) Start() error { - maxReconnectAttempts := 3 - // Replace default logger in govpp with our own - govppLogger := logrus.New() - govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().Logger.Writer(), GinkgoWriter)) - core.SetLogger(govppLogger) - // Create folders containerWorkDir := vpp.Container.GetContainerWorkDir() + var cliConfig string + if *DryRun { + cliConfig = fmt.Sprintf("exec %s/cli-config.conf", containerWorkDir) + } - vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getRunDir()) - vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getLogDir()) - vpp.Container.Exec("mkdir --mode=0700 -p " + vpp.getEtcDir()) + vpp.Container.Exec(false, "mkdir --mode=0700 -p "+vpp.getRunDir()) + vpp.Container.Exec(false, "mkdir --mode=0700 -p "+vpp.getLogDir()) + vpp.Container.Exec(false, "mkdir --mode=0700 -p "+vpp.getEtcDir()) // Create startup.conf inside the container configContent := fmt.Sprintf( @@ -141,6 +153,7 @@ func (vpp *VppInstance) Start() error { defaultCliSocketFilePath, defaultApiSocketFilePath, defaultLogFilePath, + cliConfig, ) configContent += vpp.generateVPPCpuConfig() for _, c := range vpp.AdditionalConfig { @@ -153,7 +166,20 @@ func (vpp *VppInstance) Start() error { cliContent := "#!/usr/bin/bash\nvppctl -s " + vpp.getRunDir() + "/cli.sock" vppcliFileName := "/usr/bin/vppcli" vpp.Container.CreateFile(vppcliFileName, cliContent) - vpp.Container.Exec("chmod 0755 " + vppcliFileName) + vpp.Container.Exec(false, "chmod 0755 "+vppcliFileName) + + if *DryRun { + vpp.getSuite().Log("%s* Commands to start VPP and VPPCLI:", Colors.pur) + vpp.getSuite().Log("vpp -c %s/startup.conf", vpp.getEtcDir()) + vpp.getSuite().Log("vppcli (= vppctl -s %s/cli.sock)%s\n", vpp.getRunDir(), Colors.rst) + return nil + } + + maxReconnectAttempts := 3 + // Replace default logger in govpp with our own + govppLogger := logrus.New() + govppLogger.SetOutput(io.MultiWriter(vpp.getSuite().Logger.Writer(), GinkgoWriter)) + core.SetLogger(govppLogger) vpp.getSuite().Log("starting vpp") if *IsVppDebug { @@ -167,7 +193,7 @@ func (vpp *VppInstance) Start() error { cont <- true }() - vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"") + vpp.Container.ExecServer(false, "su -c \"vpp -c "+startupFileName+" &> /proc/1/fd/1\"") fmt.Println("run following command in different terminal:") fmt.Println("docker exec -it " + vpp.Container.Name + " gdb -ex \"attach $(docker exec " + vpp.Container.Name + " pidof vpp)\"") fmt.Println("Afterwards press CTRL+\\ to continue") @@ -175,7 +201,7 @@ func (vpp *VppInstance) Start() error { fmt.Println("continuing...") } else { // Start VPP - vpp.Container.ExecServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"") + vpp.Container.ExecServer(false, "su -c \"vpp -c "+startupFileName+" &> /proc/1/fd/1\"") } vpp.getSuite().Log("connecting to vpp") @@ -255,6 +281,23 @@ func (vpp *VppInstance) WaitForApp(appName string, timeout int) { func (vpp *VppInstance) createAfPacket( veth *NetInterface, ) (interface_types.InterfaceIndex, error) { + if *DryRun { + if ip4Address, err := veth.Ip4AddrAllocator.NewIp4InterfaceAddress(veth.Peer.NetworkNumber); err == nil { + veth.Ip4Address = ip4Address + } else { + return 0, err + } + vppCliConfig := fmt.Sprintf( + "create host-interface name %s\n"+ + "set int state host-%s up\n"+ + "set int ip addr host-%s %s\n", + veth.Name(), + veth.Name(), + veth.Name(), veth.Ip4Address) + vpp.AppendToCliConfig(vppCliConfig) + vpp.getSuite().Log("%s* Interface added:\n%s%s", Colors.grn, vppCliConfig, Colors.rst) + return 1, nil + } createReq := &af_packet.AfPacketCreateV3{ Mode: 1, UseRandomHwAddr: true, @@ -381,14 +424,28 @@ func (vpp *VppInstance) addAppNamespace( return nil } -func (vpp *VppInstance) createTap( - tap *NetInterface, - tapId ...uint32, -) error { +func (vpp *VppInstance) createTap(tap *NetInterface, tapId ...uint32) error { var id uint32 = 1 if len(tapId) > 0 { id = tapId[0] } + + if *DryRun { + vppCliConfig := fmt.Sprintf("create tap id %d host-if-name %s host-ip4-addr %s\n"+ + "set int ip addr tap%d %s\n"+ + "set int state tap%d up\n", + id, + tap.name, + tap.Ip4Address, + id, + tap.Peer.Ip4Address, + id, + ) + vpp.AppendToCliConfig(vppCliConfig) + vpp.getSuite().Log("%s* Interface added:\n%s%s", Colors.grn, vppCliConfig, Colors.rst) + return nil + } + createTapReq := &tapv2.TapCreateV3{ ID: id, HostIfNameSet: true, diff --git a/extras/hs-test/iperf_linux_test.go b/extras/hs-test/iperf_linux_test.go index 14422fe5efa..b2b52a758ed 100644 --- a/extras/hs-test/iperf_linux_test.go +++ b/extras/hs-test/iperf_linux_test.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" . "fd.io/hs-test/infra" . "github.com/onsi/ginkgo/v2" @@ -41,8 +42,6 @@ func IperfLinuxTest(s *IperfSuite) { " -u -l 1460 -b 10g -p " + s.GetPortFromPpid() s.StartClientApp(clientContainer, cmd, clnCh, clnRes) }() - + s.AssertChannelClosed(time.Minute*3, clnCh) s.Log(<-clnRes) - err = <-clnCh - s.AssertNil(err, "err: '%s'", err) } diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go index 03636b11191..e72fac4fbba 100644 --- a/extras/hs-test/ldp_test.go +++ b/extras/hs-test/ldp_test.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "time" . "fd.io/hs-test/infra" . "github.com/onsi/ginkgo/v2" @@ -24,6 +25,10 @@ func LDPreloadIperfVppTest(s *LdpSuite) { clnCh := make(chan error) clnRes := make(chan string, 1) + defer func() { + stopServerCh <- struct{}{} + }() + go func() { defer GinkgoRecover() cmd := "iperf3 -4 -s -p " + s.GetPortFromPpid() @@ -39,14 +44,9 @@ func LDPreloadIperfVppTest(s *LdpSuite) { cmd := "iperf3 -c " + serverVethAddress + " -u -l 1460 -b 10g -p " + s.GetPortFromPpid() s.StartClientApp(clientContainer, cmd, clnCh, clnRes) }() - s.Log(<-clnRes) - - // wait for client's result - err = <-clnCh - s.AssertNil(err, fmt.Sprint(err)) - // stop server - stopServerCh <- struct{}{} + s.AssertChannelClosed(time.Minute*3, clnCh) + s.Log(<-clnRes) } func RedisBenchmarkTest(s *LdpSuite) { @@ -61,6 +61,10 @@ func RedisBenchmarkTest(s *LdpSuite) { clnCh := make(chan error) clnRes := make(chan string, 1) + defer func() { + doneSrv <- struct{}{} + }() + go func() { defer GinkgoRecover() cmd := "redis-server --daemonize yes --protected-mode no --bind " + serverVethAddress @@ -79,12 +83,10 @@ func RedisBenchmarkTest(s *LdpSuite) { cmd = "redis-benchmark --threads " + fmt.Sprint(*NConfiguredCpus) + "-h " + serverVethAddress } s.StartClientApp(clientContainer, cmd, clnCh, clnRes) + }() + // 4.5 minutes + s.AssertChannelClosed(time.Second*270, clnCh) s.Log(<-clnRes) - // wait for client's result - err = <-clnCh - s.AssertNil(err, fmt.Sprint(err)) - // stop server - doneSrv <- struct{}{} } diff --git a/extras/hs-test/mem_leak_test.go b/extras/hs-test/mem_leak_test.go index 76966ae968a..0d8831d2bbc 100644 --- a/extras/hs-test/mem_leak_test.go +++ b/extras/hs-test/mem_leak_test.go @@ -1,8 +1,9 @@ package main import ( - . "fd.io/hs-test/infra" "fmt" + + . "fd.io/hs-test/infra" ) func init() { diff --git a/extras/hs-test/nginx_test.go b/extras/hs-test/nginx_test.go index fa6afda58fc..7a6f5b3c182 100644 --- a/extras/hs-test/nginx_test.go +++ b/extras/hs-test/nginx_test.go @@ -1,24 +1,27 @@ package main import ( - . "fd.io/hs-test/infra" "fmt" - . "github.com/onsi/ginkgo/v2" "os" "strings" + + . "fd.io/hs-test/infra" + . "github.com/onsi/ginkgo/v2" ) func init() { RegisterNoTopoTests(NginxHttp3Test, NginxAsServerTest, NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest, NginxPerfCpsInterruptModeTest, NginxPerfRpsInterruptModeTest, NginxPerfWrkInterruptModeTest) + RegisterNoTopoSoloTests(NginxPerfRpsMultiThreadTest, NginxPerfCpsMultiThreadTest) } func NginxHttp3Test(s *NoTopoSuite) { - s.SkipUnlessExtendedTestsBuilt() - query := "index.html" - nginxCont := s.GetContainerByName("nginx-http3") - nginxCont.Run() + nginxCont := s.GetContainerByName(NginxHttp3ContainerName) + + nginxCont.Create() + s.CreateNginxHttp3Config(nginxCont) + nginxCont.Start() vpp := s.GetContainerByName("vpp").VppInstance vpp.WaitForApp("nginx-", 5) @@ -29,17 +32,23 @@ func NginxHttp3Test(s *NoTopoSuite) { args := fmt.Sprintf("curl --noproxy '*' --local-port 55444 --http3-only -k https://%s:8443/%s", serverAddress, query) curlCont.ExtraRunningArgs = args curlCont.Run() - o, err := curlCont.GetOutput() - s.Log(o) - s.AssertEmpty(err) - s.AssertContains(o, "<http>", "<http> not found in the result!") + body, stats := curlCont.GetOutput() + s.Log(body) + s.Log(stats) + s.AssertNotContains(stats, "refused") + s.AssertContains(stats, "100") + s.AssertContains(body, "<http>", "<http> not found in the result!") } + func NginxAsServerTest(s *NoTopoSuite) { query := "return_ok" finished := make(chan error, 1) nginxCont := s.GetContainerByName("nginx") - nginxCont.Run() + nginxCont.Create() + s.CreateNginxConfig(nginxCont, false) + s.AddNginxVclConfig(false) + nginxCont.Start() vpp := s.GetContainerByName("vpp").VppInstance vpp.WaitForApp("nginx-", 5) @@ -64,7 +73,7 @@ func parseString(s, pattern string) string { return "" } -func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { +func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string, multiThreadWorkers bool) error { nRequests := 1000000 nClients := 1000 @@ -73,7 +82,10 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { vpp := s.GetContainerByName("vpp").VppInstance nginxCont := s.GetContainerByName(SingleTopoContainerNginx) - nginxCont.Run() + nginxCont.Create() + s.AddNginxVclConfig(multiThreadWorkers) + s.CreateNginxConfig(nginxCont, multiThreadWorkers) + nginxCont.Start() vpp.WaitForApp("nginx-", 5) if ab_or_wrk == "ab" { @@ -88,6 +100,7 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error { args += " -r" args += " http://" + serverAddress + ":80/64B.json" abCont.ExtraRunningArgs = args + s.Log("Test might take up to 2 minutes to finish. Please wait") abCont.Run() o, err := abCont.GetOutput() rps := parseString(o, "Requests per second:") @@ -113,18 +126,24 @@ func NginxPerfCpsInterruptModeTest(s *NoTopoSuite) { NginxPerfCpsTest(s) } -// unstable with multiple workers +func NginxPerfCpsMultiThreadTest(s *NoTopoSuite) { + s.AssertNil(runNginxPerf(s, "cps", "ab", true)) +} + func NginxPerfCpsTest(s *NoTopoSuite) { - s.SkipIfMultiWorker() - s.AssertNil(runNginxPerf(s, "cps", "ab")) + s.AssertNil(runNginxPerf(s, "cps", "ab", false)) } func NginxPerfRpsInterruptModeTest(s *NoTopoSuite) { NginxPerfRpsTest(s) } +func NginxPerfRpsMultiThreadTest(s *NoTopoSuite) { + s.AssertNil(runNginxPerf(s, "rps", "ab", true)) +} + func NginxPerfRpsTest(s *NoTopoSuite) { - s.AssertNil(runNginxPerf(s, "rps", "ab")) + s.AssertNil(runNginxPerf(s, "rps", "ab", false)) } func NginxPerfWrkInterruptModeTest(s *NoTopoSuite) { @@ -132,5 +151,5 @@ func NginxPerfWrkInterruptModeTest(s *NoTopoSuite) { } func NginxPerfWrkTest(s *NoTopoSuite) { - s.AssertNil(runNginxPerf(s, "", "wrk")) + s.AssertNil(runNginxPerf(s, "", "wrk", false)) } diff --git a/extras/hs-test/proxy_test.go b/extras/hs-test/proxy_test.go index 7ec97c76c02..5ca151f6228 100644 --- a/extras/hs-test/proxy_test.go +++ b/extras/hs-test/proxy_test.go @@ -1,26 +1,26 @@ package main import ( - . "fd.io/hs-test/infra" "fmt" + + . "fd.io/hs-test/infra" ) func init() { - RegisterVppProxyTests(VppProxyHttpGetTcpTest, VppProxyHttpGetTlsTest, VppProxyHttpPutTcpTest, VppProxyHttpPutTlsTest) + RegisterVppProxyTests(VppProxyHttpGetTcpTest, VppProxyHttpGetTlsTest, VppProxyHttpPutTcpTest, VppProxyHttpPutTlsTest, + VppConnectProxyGetTest, VppConnectProxyPutTest) RegisterEnvoyProxyTests(EnvoyProxyHttpGetTcpTest, EnvoyProxyHttpPutTcpTest) RegisterNginxProxyTests(NginxMirroringTest) + RegisterNginxProxySoloTests(MirrorMultiThreadTest) } func configureVppProxy(s *VppProxySuite, proto string, proxyPort uint16) { vppProxy := s.GetContainerByName(VppProxyContainerName).VppInstance - output := vppProxy.Vppctl( - "test proxy server server-uri %s://%s/%d client-uri tcp://%s/%d", - proto, - s.VppProxyAddr(), - proxyPort, - s.NginxAddr(), - s.NginxPort(), - ) + cmd := fmt.Sprintf("test proxy server fifo-size 512k server-uri %s://%s/%d", proto, s.VppProxyAddr(), proxyPort) + if proto != "http" { + cmd += fmt.Sprintf(" client-uri tcp://%s/%d", s.NginxAddr(), s.NginxPort()) + } + output := vppProxy.Vppctl(cmd) s.Log("proxy configured: " + output) } @@ -62,9 +62,42 @@ func EnvoyProxyHttpPutTcpTest(s *EnvoyProxySuite) { s.CurlUploadResource(uri, CurlContainerTestFile) } -// broken when CPUS > 1 +func MirrorMultiThreadTest(s *NginxProxySuite) { + nginxMirroring(s, true) +} + func NginxMirroringTest(s *NginxProxySuite) { - s.SkipIfMultiWorker() + nginxMirroring(s, false) +} + +func nginxMirroring(s *NginxProxySuite, multiThreadWorkers bool) { + nginxProxyContainer := s.GetContainerByName(NginxProxyContainerName) + vpp := s.GetContainerByName(VppContainerName).VppInstance + + s.AddVclConfig(nginxProxyContainer, multiThreadWorkers) + s.CreateNginxProxyConfig(nginxProxyContainer, multiThreadWorkers) + nginxProxyContainer.Start() + vpp.WaitForApp("nginx-", 5) uri := fmt.Sprintf("http://%s:%d/httpTestFile", s.ProxyAddr(), s.ProxyPort()) s.CurlDownloadResource(uri) } + +func VppConnectProxyGetTest(s *VppProxySuite) { + var proxyPort uint16 = 8080 + + configureVppProxy(s, "http", proxyPort) + + targetUri := fmt.Sprintf("http://%s:%d/httpTestFile", s.NginxAddr(), s.NginxPort()) + proxyUri := fmt.Sprintf("http://%s:%d", s.VppProxyAddr(), proxyPort) + s.CurlDownloadResourceViaTunnel(targetUri, proxyUri) +} + +func VppConnectProxyPutTest(s *VppProxySuite) { + var proxyPort uint16 = 8080 + + configureVppProxy(s, "http", proxyPort) + + proxyUri := fmt.Sprintf("http://%s:%d", s.VppProxyAddr(), proxyPort) + targetUri := fmt.Sprintf("http://%s:%d/upload/testFile", s.NginxAddr(), s.NginxPort()) + s.CurlUploadResourceViaTunnel(targetUri, proxyUri, CurlContainerTestFile) +} diff --git a/extras/hs-test/raw_session_test.go b/extras/hs-test/raw_session_test.go index 438b7ba03a5..822ee5c68e3 100644 --- a/extras/hs-test/raw_session_test.go +++ b/extras/hs-test/raw_session_test.go @@ -29,7 +29,7 @@ func testVppEcho(s *VethsSuite, proto string) { " use-app-socket-api" + " uri " + uri s.Log(serverCommand) - echoSrvContainer.ExecServer(serverCommand) + echoSrvContainer.ExecServer(true, serverCommand) echoClnContainer := s.GetContainerByName("client-app") @@ -37,6 +37,6 @@ func testVppEcho(s *VethsSuite, proto string) { " socket-name " + echoClnContainer.GetContainerWorkDir() + "/var/run/app_ns_sockets/default" + " use-app-socket-api uri " + uri s.Log(clientCommand) - o := echoClnContainer.Exec(clientCommand) + o := echoClnContainer.Exec(true, clientCommand) s.Log(o) } diff --git a/extras/hs-test/resources/nginx/nginx.conf b/extras/hs-test/resources/nginx/nginx.conf index 99073aab1ab..956a13138eb 100644 --- a/extras/hs-test/resources/nginx/nginx.conf +++ b/extras/hs-test/resources/nginx/nginx.conf @@ -1,6 +1,6 @@ master_process on; worker_rlimit_nofile 10240; -worker_processes 2; +worker_processes {{.Workers}}; daemon off; events { diff --git a/extras/hs-test/resources/nginx/nginx_http3.conf b/extras/hs-test/resources/nginx/nginx_http3.conf index 2a01f714111..e048b17044b 100644 --- a/extras/hs-test/resources/nginx/nginx_http3.conf +++ b/extras/hs-test/resources/nginx/nginx_http3.conf @@ -2,6 +2,8 @@ master_process on; worker_processes 2; daemon off; +error_log /tmp/nginx/{{.LogPrefix}}-error.log info; + events { use epoll; accept_mutex off; @@ -12,12 +14,11 @@ http { quic_gso on; quic_retry on; - access_log logs/access.log; + access_log /tmp/nginx/{{.LogPrefix}}-access.log; keepalive_timeout 300s; sendfile on; server { listen 0.0.0.0:8443 quic; - #listen 0.0.0.0:8443 ssl; root /usr/share/nginx; ssl_certificate /etc/nginx/ssl/localhost.crt; ssl_certificate_key /etc/nginx/ssl/localhost.key; diff --git a/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf b/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf index 7f6b09c6050..d834a27288a 100644 --- a/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf +++ b/extras/hs-test/resources/nginx/nginx_proxy_mirroring.conf @@ -1,5 +1,5 @@ master_process on; -worker_processes 4; +worker_processes {{.Workers}}; worker_rlimit_nofile 102400; daemon off; diff --git a/extras/hs-test/resources/nginx/vcl.conf b/extras/hs-test/resources/nginx/vcl.conf index cfcd5d2e959..27699248bcf 100644 --- a/extras/hs-test/resources/nginx/vcl.conf +++ b/extras/hs-test/resources/nginx/vcl.conf @@ -5,7 +5,6 @@ vcl { rx-fifo-size 4000000 tx-fifo-size 4000000 event-queue-size 100000 - use-mq-eventfd app-socket-api /tmp/nginx/var/run/app_ns_sockets/default } diff --git a/extras/hs-test/script/build_boringssl.sh b/extras/hs-test/script/build_boringssl.sh deleted file mode 100755 index cca4e4a31d1..00000000000 --- a/extras/hs-test/script/build_boringssl.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -cd boringssl || exit 1 -cmake -GNinja -B build -ninja -C build diff --git a/extras/hs-test/script/build_hst.sh b/extras/hs-test/script/build_hst.sh index 9b11f5f0272..a072abdb29d 100755 --- a/extras/hs-test/script/build_hst.sh +++ b/extras/hs-test/script/build_hst.sh @@ -85,9 +85,8 @@ docker_build hs-test/vpp vpp docker_build hs-test/nginx-ldp nginx docker_build hs-test/nginx-server nginx-server docker_build hs-test/curl curl -if [ "$HST_EXTENDED_TESTS" = true ] ; then - docker_build hs-test/nginx-http3 nginx-http3 -fi +docker_build hs-test/envoy envoy +docker_build hs-test/nginx-http3 nginx-http3 # cleanup detached images images=$(docker images --filter "dangling=true" -q --no-trunc) diff --git a/extras/hs-test/script/build_nginx.sh b/extras/hs-test/script/build_nginx.sh deleted file mode 100755 index f21201c4297..00000000000 --- a/extras/hs-test/script/build_nginx.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -cd nginx || exit 1 -./auto/configure --with-debug --with-http_v3_module --with-cc-opt="-I../boringssl/include" --with-ld-opt="-L../boringssl/build/ssl -L../boringssl/build/crypto" --without-http_rewrite_module --without-http_gzip_module -make -make install diff --git a/extras/hs-test/script/compress.sh b/extras/hs-test/script/compress.sh index 09db9b6720d..ebc60d25779 100755 --- a/extras/hs-test/script/compress.sh +++ b/extras/hs-test/script/compress.sh @@ -1,12 +1,17 @@ #!/usr/bin/env bash +if [ $1 == 2 ] +then + exit 1 +fi + # if failed-summary.log is not empty, exit status = 1 if [ -s "${HS_ROOT}/summary/failed-summary.log" ] then if [ -n "${WORKSPACE}" ] then echo -n "Copying docker logs..." - dirs=$(jq -r '.[0] | .SpecReports[] | select(.State == "failed") | .LeafNodeText | split("/")[1]' ${HS_ROOT}/summary/report.json) + dirs=$(jq -r '.[0] | .SpecReports[] | select((.State == "failed") or (.State == "timedout") or (.State == "panicked")) | .LeafNodeText | split("/")[1]' ${HS_ROOT}/summary/report.json) for dirName in $dirs; do logDir=/tmp/hs-test/$dirName if [ -d "$logDir" ]; then diff --git a/extras/hs-test/topo-containers/envoyProxy.yaml b/extras/hs-test/topo-containers/envoyProxy.yaml index 92dd9b93c47..cbb00d868db 100644 --- a/extras/hs-test/topo-containers/envoyProxy.yaml +++ b/extras/hs-test/topo-containers/envoyProxy.yaml @@ -20,9 +20,8 @@ containers: - name: "ENVOY_UID" value: "0" - name: "VCL_CONFIG" - value: "/tmp/vcl.conf" - image: "envoyproxy/envoy-contrib:v1.30-latest" - extra-args: "--log-format [%t][%l][%g:%#]%_ --concurrency 2 -c /etc/envoy/envoy.yaml" + value: /tmp/vcl.conf + image: "hs-test/envoy" is-optional: true - name: "nginx-server" volumes: diff --git a/extras/hs-test/topo-containers/ns.yaml b/extras/hs-test/topo-containers/ns.yaml deleted file mode 100644 index 3de5af59569..00000000000 --- a/extras/hs-test/topo-containers/ns.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -volumes: - - volume: &shared-vol - host-dir: "$HST_VOLUME_DIR/shared-vol" - -# $HST_DIR will be replaced during runtime by path to hs-test directory -containers: - - name: "vpp" - volumes: - - <<: *shared-vol - container-dir: "/tmp/vpp" - is-default-work-dir: true - - name: "envoy" - volumes: - - <<: *shared-vol - container-dir: "/tmp/vpp-envoy" - is-default-work-dir: true - - host-dir: "$HST_DIR/resources/envoy" - container-dir: "/tmp" - vars: - - name: "ENVOY_UID" - value: "0" - - name: "VCL_CONFIG" - value: "/tmp/vcl.conf" - image: "envoyproxy/envoy-contrib:v1.30-latest" - extra-args: "--concurrency 2 -c /etc/envoy/envoy.yaml" - is-optional: true diff --git a/extras/hs-test/vcl_test.go b/extras/hs-test/vcl_test.go index 81da0c533b9..68ca9d02097 100644 --- a/extras/hs-test/vcl_test.go +++ b/extras/hs-test/vcl_test.go @@ -51,7 +51,7 @@ func testXEchoVclClient(s *VethsSuite, proto string) { testClientCommand := "vcl_test_client -N 100 -p " + proto + " " + serverVeth.Ip4AddressString() + " " + port s.Log(testClientCommand) echoClnContainer.AddEnvVar("VCL_CONFIG", "/vcl.conf") - o := echoClnContainer.Exec(testClientCommand) + o := echoClnContainer.Exec(true, testClientCommand) s.Log(o) s.AssertContains(o, "CLIENT RESULTS") } @@ -72,7 +72,7 @@ func testXEchoVclServer(s *VethsSuite, proto string) { srvAppCont.CreateFile("/vcl.conf", getVclConfig(srvVppCont)) srvAppCont.AddEnvVar("VCL_CONFIG", "/vcl.conf") vclSrvCmd := fmt.Sprintf("vcl_test_server -p %s %s", proto, port) - srvAppCont.ExecServer(vclSrvCmd) + srvAppCont.ExecServer(true, vclSrvCmd) serverVeth := s.GetInterfaceByName(ServerInterfaceName) serverVethAddress := serverVeth.Ip4AddressString() @@ -90,7 +90,7 @@ func testVclEcho(s *VethsSuite, proto string) { srvAppCont.CreateFile("/vcl.conf", getVclConfig(srvVppCont)) srvAppCont.AddEnvVar("VCL_CONFIG", "/vcl.conf") - srvAppCont.ExecServer("vcl_test_server -p " + proto + " " + port) + srvAppCont.ExecServer(true, "vcl_test_server -p "+proto+" "+port) serverVeth := s.GetInterfaceByName(ServerInterfaceName) serverVethAddress := serverVeth.Ip4AddressString() @@ -100,7 +100,7 @@ func testVclEcho(s *VethsSuite, proto string) { testClientCommand := "vcl_test_client -p " + proto + " " + serverVethAddress + " " + port echoClnContainer.AddEnvVar("VCL_CONFIG", "/vcl.conf") - o := echoClnContainer.Exec(testClientCommand) + o := echoClnContainer.Exec(true, testClientCommand) s.Log(o) } @@ -128,7 +128,7 @@ func testRetryAttach(s *VethsSuite, proto string) { echoSrvContainer.CreateFile("/vcl.conf", getVclConfig(echoSrvContainer)) echoSrvContainer.AddEnvVar("VCL_CONFIG", "/vcl.conf") - echoSrvContainer.ExecServer("vcl_test_server -p " + proto + " 12346") + echoSrvContainer.ExecServer(true, "vcl_test_server -p "+proto+" 12346") s.Log("This whole test case can take around 3 minutes to run. Please be patient.") s.Log("... Running first echo client test, before disconnect.") @@ -141,14 +141,14 @@ func testRetryAttach(s *VethsSuite, proto string) { testClientCommand := "vcl_test_client -U -p " + proto + " " + serverVethAddress + " 12346" echoClnContainer.AddEnvVar("VCL_CONFIG", "/vcl.conf") - o := echoClnContainer.Exec(testClientCommand) + o := echoClnContainer.Exec(true, testClientCommand) s.Log(o) s.Log("... First test ended. Stopping VPP server now.") // Stop server-vpp-instance, start it again and then run vcl-test-client once more srvVppContainer.VppInstance.Disconnect() stopVppCommand := "/bin/bash -c 'ps -C vpp_main -o pid= | xargs kill -9'" - srvVppContainer.Exec(stopVppCommand) + srvVppContainer.Exec(false, stopVppCommand) s.SetupServerVpp() @@ -156,7 +156,7 @@ func testRetryAttach(s *VethsSuite, proto string) { time.Sleep(30 * time.Second) // Wait a moment for the re-attachment to happen s.Log("... Running second echo client test, after disconnect and re-attachment.") - o = echoClnContainer.Exec(testClientCommand) + o = echoClnContainer.Exec(true, testClientCommand) s.Log(o) s.Log("Done.") } diff --git a/extras/scripts/crcchecker.py b/extras/scripts/crcchecker.py index 7dcdb681e18..4a8f9b16669 100755 --- a/extras/scripts/crcchecker.py +++ b/extras/scripts/crcchecker.py @@ -40,10 +40,13 @@ def crc_from_apigen(revision, filename): if returncode.returncode != 0: print( f"vppapigen failed for {revision}:{filename} with " - "command\n {apigen}\n error: {rv}", - returncode.stderr.decode("ascii"), + f"command:\n {apigen}\n error: {returncode.returncode}", file=sys.stderr, ) + if returncode.stderr: + print(f"stderr: {returncode.stderr.decode('ascii')}", file=sys.stderr) + if returncode.stdout: + print(f"stdout: {returncode.stdout.decode('ascii')}", file=sys.stderr) sys.exit(-2) return json.loads(returncode.stdout) diff --git a/extras/vpp_if_stats/apimock.go b/extras/vpp_if_stats/apimock.go index 77363344090..25e76ed1d31 100755 --- a/extras/vpp_if_stats/apimock.go +++ b/extras/vpp_if_stats/apimock.go @@ -5,10 +5,11 @@ package main import ( - api "git.fd.io/govpp.git/api" - gomock "github.com/golang/mock/gomock" reflect "reflect" time "time" + + api "git.fd.io/govpp.git/api" + gomock "github.com/golang/mock/gomock" ) // MockChannel is a mock of Channel interface diff --git a/extras/vpp_if_stats/json_structs.go b/extras/vpp_if_stats/json_structs.go index a42b6d815b2..8e73337418e 100755 --- a/extras/vpp_if_stats/json_structs.go +++ b/extras/vpp_if_stats/json_structs.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "git.fd.io/govpp.git/examples/bin_api/vpe" ) diff --git a/extras/vpp_if_stats/statsmock.go b/extras/vpp_if_stats/statsmock.go index 72528f53d9a..172176fa744 100755 --- a/extras/vpp_if_stats/statsmock.go +++ b/extras/vpp_if_stats/statsmock.go @@ -5,9 +5,10 @@ package main import ( + reflect "reflect" + adapter "git.fd.io/govpp.git/adapter" gomock "github.com/golang/mock/gomock" - reflect "reflect" ) // MockStatsAPI is a mock of StatsAPI interface diff --git a/extras/vpp_if_stats/vpp_if_stats.go b/extras/vpp_if_stats/vpp_if_stats.go index 90c1700430c..751bbe5d5a9 100644 --- a/extras/vpp_if_stats/vpp_if_stats.go +++ b/extras/vpp_if_stats/vpp_if_stats.go @@ -3,6 +3,8 @@ package main import ( "flag" "fmt" + "log" + "git.fd.io/govpp.git" "git.fd.io/govpp.git/adapter" "git.fd.io/govpp.git/adapter/vppapiclient" @@ -10,7 +12,6 @@ import ( "git.fd.io/govpp.git/core" "git.fd.io/govpp.git/examples/bin_api/interfaces" "git.fd.io/govpp.git/examples/bin_api/vpe" - "log" ) ////////////////////////////////////// diff --git a/extras/vpp_if_stats/vpp_if_stats_test.go b/extras/vpp_if_stats/vpp_if_stats_test.go index 3c22ce85d75..53c990c4158 100644 --- a/extras/vpp_if_stats/vpp_if_stats_test.go +++ b/extras/vpp_if_stats/vpp_if_stats_test.go @@ -1,15 +1,16 @@ package main import ( + "math/rand" + "testing" + "time" + "git.fd.io/govpp.git/adapter" "git.fd.io/govpp.git/api" "git.fd.io/govpp.git/examples/bin_api/interfaces" "git.fd.io/govpp.git/examples/bin_api/vpe" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "math/rand" - "testing" - "time" ) var ( |