hs-test: add nginx test

Type: test

Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
Change-Id: Idd5352f254df0d1f36c1270e73440c9287247b81
diff --git a/extras/hs-test/Dockerfile.nginx b/extras/hs-test/Dockerfile.nginx
new file mode 100644
index 0000000..ece7376
--- /dev/null
+++ b/extras/hs-test/Dockerfile.nginx
@@ -0,0 +1,8 @@
+FROM nginx:1.22.1
+
+COPY vpp-data/lib/* /usr/lib/
+COPY resources/nginx/vcl.conf /vcl.conf
+COPY resources/nginx/nginx.conf /nginx.conf
+COPY resources/nginx/start.sh /start.sh
+
+ENTRYPOINT ["/start.sh"]
diff --git a/extras/hs-test/actions.go b/extras/hs-test/actions.go
index 34096df..279589b 100755
--- a/extras/hs-test/actions.go
+++ b/extras/hs-test/actions.go
@@ -15,6 +15,7 @@
 	"github.com/edwarnicke/govpp/binapi/interface_types"
 	ip_types "github.com/edwarnicke/govpp/binapi/ip_types"
 	"github.com/edwarnicke/govpp/binapi/session"
+	"github.com/edwarnicke/govpp/binapi/tapv2"
 	"github.com/edwarnicke/govpp/binapi/vlib"
 	"github.com/edwarnicke/vpphelper"
 )
@@ -347,3 +348,62 @@
 	<-ctx.Done()
 	return nil
 }
+
+func (a *Actions) ConfigureTap(args []string) *ActionResult {
+	var startup Stanza
+	startup.
+		NewStanza("session").
+		Append("enable").
+		Append("use-app-socket-api").Close()
+
+	ctx, cancel := newVppContext()
+	defer cancel()
+	con, vppErrCh := vpphelper.StartAndDialContext(ctx,
+		vpphelper.WithRootDir(workDir),
+		vpphelper.WithVppConfig(configTemplate+startup.ToString()))
+	exitOnErrCh(ctx, cancel, vppErrCh)
+	ifaceClient := interfaces.NewServiceClient(con)
+
+	pref, err := ip_types.ParseIP4Prefix("10.10.10.2/24")
+	if err != nil {
+		return NewActionResult(err, ActionResultWithDesc("failed to parse ip4 address"))
+	}
+	createTapReply, err := tapv2.NewServiceClient(con).TapCreateV2(ctx, &tapv2.TapCreateV2{
+		HostIfNameSet:    true,
+		HostIfName:       "tap0",
+		HostIP4PrefixSet: true,
+		HostIP4Prefix:    ip_types.IP4AddressWithPrefix(pref),
+	})
+	if err != nil {
+		return NewActionResult(err, ActionResultWithDesc("failed to configure tap"))
+	}
+	ipPrefix, err := ip_types.ParseAddressWithPrefix("10.10.10.1/24")
+	if err != nil {
+		return NewActionResult(err, ActionResultWithDesc("parsing ip address failed"))
+	}
+	ipAddress := &interfaces.SwInterfaceAddDelAddress{
+		IsAdd:     true,
+		SwIfIndex: createTapReply.SwIfIndex,
+		Prefix:    ipPrefix,
+	}
+	_, errx := ifaceClient.SwInterfaceAddDelAddress(ctx, ipAddress)
+	if errx != nil {
+		return NewActionResult(err, ActionResultWithDesc("configuring ip address failed"))
+	}
+	_, err = ifaceClient.SwInterfaceSetFlags(ctx, &interfaces.SwInterfaceSetFlags{
+		SwIfIndex: createTapReply.SwIfIndex,
+		Flags:     interface_types.IF_STATUS_API_FLAG_ADMIN_UP,
+	})
+	if err != nil {
+		return NewActionResult(err, ActionResultWithDesc("failed to set interface state"))
+	}
+	_, err = session.NewServiceClient(con).SessionEnableDisable(ctx, &session.SessionEnableDisable{
+		IsEnable: true,
+	})
+	if err != nil {
+		return NewActionResult(err, ActionResultWithDesc("configuration failed"))
+	}
+	writeSyncFile(OkResult())
+	<-ctx.Done()
+	return nil
+}
diff --git a/extras/hs-test/framework_test.go b/extras/hs-test/framework_test.go
index cd43cfe..056be13 100755
--- a/extras/hs-test/framework_test.go
+++ b/extras/hs-test/framework_test.go
@@ -178,3 +178,8 @@
 	var m VethsSuite
 	suite.Run(t, &m)
 }
+
+func TestNoTopo(t *testing.T) {
+	var m NoTopoSuite
+	suite.Run(t, &m)
+}
diff --git a/extras/hs-test/http_test.go b/extras/hs-test/http_test.go
index ae1c8b8..665a3e4 100755
--- a/extras/hs-test/http_test.go
+++ b/extras/hs-test/http_test.go
@@ -1,5 +1,10 @@
 package main
 
+import (
+	"os"
+	"time"
+)
+
 func (s *NsSuite) TestHttpTps() {
 	finished := make(chan error, 1)
 	server_ip := "10.0.0.2"
@@ -13,7 +18,7 @@
 	_, err := container.execAction("ConfigureHttpTps")
 	s.assertNil(err)
 
-	go startWget(finished, server_ip, port, "client")
+	go startWget(finished, server_ip, port, "test_file_10M", "client")
 	// wait for client
 	err = <-finished
 	s.assertNil(err)
@@ -41,3 +46,21 @@
 
 	s.assertContains(o, "<html>", "<html> not found in the result!")
 }
+
+func (s *NoTopoSuite) TestNginx() {
+	query := "return_ok"
+	finished := make(chan error, 1)
+	vppCont := s.getContainerByName("vpp")
+	vppInst := NewVppInstance(vppCont)
+	vppInst.actionFuncName = "ConfigureTap"
+	s.assertNil(vppInst.start(), "failed to start vpp")
+
+	nginxCont := s.getContainerByName("nginx")
+	s.assertNil(nginxCont.run())
+
+	time.Sleep(3 * time.Second)
+
+	defer func() { os.Remove(query) }()
+	go startWget(finished, "10.10.10.1", "80", query, "")
+	s.assertNil(<-finished)
+}
diff --git a/extras/hs-test/resources/nginx/nginx.conf b/extras/hs-test/resources/nginx/nginx.conf
new file mode 100644
index 0000000..ec83aa9
--- /dev/null
+++ b/extras/hs-test/resources/nginx/nginx.conf
@@ -0,0 +1,26 @@
+master_process on;
+worker_rlimit_nofile 10240;
+worker_processes 2;
+daemon off;
+
+events {
+  use epoll;
+  worker_connections  10240;
+  accept_mutex       off;
+  multi_accept       off;
+}
+
+http {
+  keepalive_timeout 300s;
+  keepalive_requests 1000000;
+  sendfile on;
+  server {
+    listen 80;
+    root /usr/share/nginx;
+    index index.html index.htm;
+    location /return_ok
+    {
+      return 200 '';
+    }
+  }
+}
diff --git a/extras/hs-test/resources/nginx/start.sh b/extras/hs-test/resources/nginx/start.sh
new file mode 100755
index 0000000..29e4902
--- /dev/null
+++ b/extras/hs-test/resources/nginx/start.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+LDP_PATH=/usr/lib/libvcl_ldpreload.so
+VCL_CFG=/vcl.conf
+LD_PRELOAD=$LDP_PATH VCL_CONFIG=$VCL_CFG nginx -c /nginx.conf
+tail -f /dev/null
diff --git a/extras/hs-test/resources/nginx/vcl.conf b/extras/hs-test/resources/nginx/vcl.conf
new file mode 100644
index 0000000..737b8a8
--- /dev/null
+++ b/extras/hs-test/resources/nginx/vcl.conf
@@ -0,0 +1,10 @@
+vcl {
+  heapsize 64M
+  segment-size 4000000000
+  add-segment-size 4000000000
+  rx-fifo-size 4000000
+  tx-fifo-size 4000000
+
+  use-mq-eventfd
+  app-socket-api /tmp/nginx/var/run/app_ns_sockets/default
+}
diff --git a/extras/hs-test/script/build.sh b/extras/hs-test/script/build.sh
index d80823b..b8962ec 100755
--- a/extras/hs-test/script/build.sh
+++ b/extras/hs-test/script/build.sh
@@ -11,3 +11,4 @@
 cp -r ${VPP_WS}/build-root/build-vpp_debug-native/vpp/lib/x86_64-linux-gnu/* ${lib}
 
 docker build -t hs-test/vpp -f Dockerfile.vpp .
+docker build -t hs-test/nginx-ldp -f Dockerfile.nginx .
diff --git a/extras/hs-test/suite_no_topo_test.go b/extras/hs-test/suite_no_topo_test.go
new file mode 100644
index 0000000..421decc
--- /dev/null
+++ b/extras/hs-test/suite_no_topo_test.go
@@ -0,0 +1,10 @@
+package main
+
+type NoTopoSuite struct {
+	HstSuite
+}
+
+func (s *NoTopoSuite) SetupSuite() {
+	s.teardownSuite = func() {}
+	s.loadContainerTopology("single")
+}
diff --git a/extras/hs-test/topo-containers/single.yaml b/extras/hs-test/topo-containers/single.yaml
new file mode 100644
index 0000000..e0fea70
--- /dev/null
+++ b/extras/hs-test/topo-containers/single.yaml
@@ -0,0 +1,17 @@
+---
+volumes:
+  - shared-vol
+
+containers:
+  - name: "vpp"
+    volumes:
+      - host-dir: "shared-vol"
+        container-dir: "/tmp/vpp"
+        is-default-work-dir: true
+  - name: "nginx"
+    volumes:
+      - host-dir: "shared-vol"
+        container-dir: "/tmp/nginx"
+        is-default-work-dir: true
+    image: "hs-test/nginx-ldp"
+    is-optional: true
\ No newline at end of file
diff --git a/extras/hs-test/utils.go b/extras/hs-test/utils.go
index 583dc4a..e23ea81 100755
--- a/extras/hs-test/utils.go
+++ b/extras/hs-test/utils.go
@@ -176,17 +176,16 @@
 	cmd.Process.Kill()
 }
 
-func startWget(finished chan error, server_ip, port string, netNs string) {
-	fname := "test_file_10M"
+func startWget(finished chan error, server_ip, port, query, netNs string) {
 	defer func() {
 		finished <- errors.New("wget error")
 	}()
 
-	cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
+	cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
 		netNs)
 	o, err := cmd.CombinedOutput()
 	if err != nil {
-		finished <- errors.New(fmt.Sprintf("wget error: '%s'.\n%s", err, o))
+		finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
 		return
 	}
 	finished <- nil