summaryrefslogtreecommitdiffstats
path: root/extras/hs-test/utils.go
diff options
context:
space:
mode:
authorFilip Tehlar <ftehlar@cisco.com>2022-08-09 14:44:47 +0000
committerFlorin Coras <florin.coras@gmail.com>2022-09-19 21:00:18 +0000
commit229f5fcf188cf710f4a8fb269d92f1a1d04a99da (patch)
treebc2c85a49bac6aea4e5ef3304c356acb75ad9493 /extras/hs-test/utils.go
parent6cacc94de3984d9f0cf6d562a27d89a4ab0a89f9 (diff)
misc: add test framework for host stack
Type: feature Signed-off-by: Filip Tehlar <ftehlar@cisco.com> Change-Id: I5a64a2c095cae3a4d5f8fdc73e624b010339ec8e
Diffstat (limited to 'extras/hs-test/utils.go')
-rwxr-xr-xextras/hs-test/utils.go334
1 files changed, 334 insertions, 0 deletions
diff --git a/extras/hs-test/utils.go b/extras/hs-test/utils.go
new file mode 100755
index 00000000000..25303591a43
--- /dev/null
+++ b/extras/hs-test/utils.go
@@ -0,0 +1,334 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/edwarnicke/exechelper"
+)
+
+const configTemplate = `unix {
+ nodaemon
+ log %[1]s/var/log/vpp/vpp.log
+ full-coredump
+ cli-listen %[1]s/var/run/vpp/cli.sock
+ runtime-dir %[1]s/var/run
+ gid vpp
+}
+
+api-trace {
+ on
+}
+
+api-segment {
+ gid vpp
+}
+
+socksvr {
+ socket-name %[1]s/var/run/vpp/api.sock
+}
+
+statseg {
+ socket-name %[1]s/var/run/vpp/stats.sock
+}
+
+plugins {
+ plugin unittest_plugin.so { enable }
+ plugin dpdk_plugin.so { disable }
+ plugin crypto_aesni_plugin.so { enable }
+ plugin quic_plugin.so { enable }
+}
+
+`
+
+const TopologyDir string = "topo/"
+
+type Stanza struct {
+ content string
+ pad int
+}
+
+type ActionResult struct {
+ Err error
+ Desc string
+ ErrOutput string
+ StdOutput string
+}
+
+type JsonResult struct {
+ Code int
+ Desc string
+ ErrOutput string
+ StdOutput string
+}
+
+func StartServerApp(running chan error, done chan struct{}, env []string) {
+ cmd := exec.Command("iperf3", "-4", "-s")
+ if env != nil {
+ cmd.Env = env
+ }
+ err := cmd.Start()
+ if err != nil {
+ msg := fmt.Errorf("failed to start iperf server: %v", err)
+ running <- msg
+ return
+ }
+ running <- nil
+ <-done
+ cmd.Process.Kill()
+}
+
+func StartClientApp(env []string, clnCh chan error) {
+ defer func() {
+ clnCh <- nil
+ }()
+
+ nTries := 0
+
+ for {
+ cmd := exec.Command("iperf3", "-c", "10.10.10.1", "-u", "-l", "1460", "-b", "10g")
+ if env != nil {
+ cmd.Env = env
+ }
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ if nTries > 5 {
+ clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
+ return
+ }
+ time.Sleep(1 * time.Second)
+ nTries++
+ continue
+ } else {
+ fmt.Printf("Client output: %s", o)
+ }
+ break
+ }
+}
+
+// run vpphelper in docker
+func hstExec(args string, instance string) (string, error) {
+ syncFile := fmt.Sprintf("/tmp/%s/sync/rc", instance)
+ os.Remove(syncFile)
+
+ c := "docker exec -d " + instance + " /hs-test " + args
+ err := exechelper.Run(c)
+ if err != nil {
+ return "", err
+ }
+
+ res, err := waitForSyncFile(syncFile)
+
+ if err != nil {
+ return "", fmt.Errorf("failed to read sync file while executing './hs-test %s': %v", args, err)
+ }
+
+ o := res.StdOutput + res.ErrOutput
+ if res.Code != 0 {
+ return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
+ }
+ return o, err
+}
+
+func waitForSyncFile(fname string) (*JsonResult, error) {
+ var res JsonResult
+
+ for i := 0; i < 60; i++ {
+ f, err := os.Open(fname)
+ if err == nil {
+ defer f.Close()
+
+ data, err := ioutil.ReadFile(fname)
+ if err != nil {
+ return nil, fmt.Errorf("read error: %v", err)
+ }
+ err = json.Unmarshal(data, &res)
+ if err != nil {
+ return nil, fmt.Errorf("json unmarshal error: %v", err)
+ }
+ return &res, nil
+ }
+ time.Sleep(1 * time.Second)
+ }
+ return nil, fmt.Errorf("no sync file found")
+}
+
+func dockerRun(instance, args string) error {
+ exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", instance))
+ syncPath := fmt.Sprintf("-v /tmp/%s/sync:/tmp/sync", instance)
+ cmd := "docker run --cap-add=all -d --privileged --network host --rm "
+ cmd += syncPath
+ cmd += " " + args
+ cmd += " --name " + instance + " hs-test/vpp"
+ fmt.Println(cmd)
+ return exechelper.Run(cmd)
+}
+
+func assertFileSize(f1, f2 string) error {
+ fi1, err := os.Stat(f1)
+ if err != nil {
+ return err
+ }
+
+ fi2, err1 := os.Stat(f2)
+ if err1 != nil {
+ return err1
+ }
+
+ if fi1.Size() != fi2.Size() {
+ return fmt.Errorf("file sizes differ (%d vs %d)", fi1.Size(), fi2.Size())
+ }
+ return nil
+}
+
+func dockerExec(cmd string, instance string) ([]byte, error) {
+ c := "docker exec -d " + instance + " " + cmd
+ return exechelper.CombinedOutput(c)
+}
+
+func startEnvoy(ctx context.Context, dockerInstance string) <-chan error {
+ errCh := make(chan error)
+ wd, err := os.Getwd()
+ if err != nil {
+ errCh <- err
+ return errCh
+ }
+
+ c := []string{"docker", "run", "--rm", "--name", "envoy",
+ "-v", fmt.Sprintf("%s/envoy/proxy.yaml:/etc/envoy/envoy.yaml", wd),
+ "-v", fmt.Sprintf("shared-vol:/tmp/%s", dockerInstance),
+ "-v", fmt.Sprintf("%s/envoy:/tmp", wd),
+ "-e", "VCL_CONFIG=/tmp/vcl.conf",
+ "envoyproxy/envoy-contrib:v1.21-latest"}
+ fmt.Println(c)
+
+ go func(errCh chan error) {
+ count := 0
+ var cmd *exec.Cmd
+ for ; ; count++ {
+ cmd = NewCommand(c, "")
+ err = cmd.Start()
+ if err == nil {
+ break
+ }
+ if count > 5 {
+ errCh <- fmt.Errorf("Failed to start envoy docker after %d attempts", count)
+ return
+ }
+ }
+
+ err = cmd.Wait()
+ if err != nil {
+ errCh <- fmt.Errorf("failed to start docker: %v", err)
+ return
+ }
+ <-ctx.Done()
+ }(errCh)
+ return errCh
+}
+
+func setupEnvoy(t *testing.T, ctx context.Context, dockerInstance string) error {
+ errCh := startEnvoy(ctx, dockerInstance)
+ select {
+ case err := <-errCh:
+ return err
+ default:
+ }
+
+ go func(ctx context.Context, errCh <-chan error) {
+ for {
+ select {
+ // handle cancel() call from outside to gracefully stop the routine
+ case <-ctx.Done():
+ return
+ default:
+ select {
+ case err := <-errCh:
+ fmt.Printf("error while running envoy: %v", err)
+ default:
+ }
+ }
+ }
+ }(ctx, errCh)
+ return nil
+}
+
+func configureVppProxy() error {
+ _, err := dockerExec("vppctl test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666",
+ "vpp-proxy")
+ if err != nil {
+ return fmt.Errorf("error while configuring vpp proxy test: %v", err)
+ }
+ return nil
+}
+
+func startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
+ cmd := NewCommand([]string{"./http_server", addressPort}, netNs)
+ err := cmd.Start()
+ if err != nil {
+ fmt.Println("Failed to start http server")
+ return
+ }
+ running <- struct{}{}
+ <-done
+ cmd.Process.Kill()
+}
+
+func startWget(finished chan error, server_ip, port string, netNs string) {
+ fname := "test_file_10M"
+ defer func() {
+ finished <- errors.New("wget error")
+ }()
+
+ cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
+ netNs)
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ fmt.Printf("wget error: '%s'.\n%s", err, o)
+ return
+ }
+ fmt.Printf("Client output: %s", o)
+ finished <- nil
+}
+
+func (c *Stanza) NewStanza(name string) *Stanza {
+ c.Append("\n" + name + " {")
+ c.pad += 2
+ return c
+}
+
+func (c *Stanza) Append(name string) *Stanza {
+ c.content += strings.Repeat(" ", c.pad)
+ c.content += name + "\n"
+ return c
+}
+
+func (c *Stanza) Close() *Stanza {
+ c.content += "}\n"
+ c.pad -= 2
+ return c
+}
+
+func (s *Stanza) ToString() string {
+ return s.content
+}
+
+func (s *Stanza) SaveToFile(fileName string) error {
+ fo, err := os.Create(fileName)
+ if err != nil {
+ return err
+ }
+ defer fo.Close()
+
+ _, err = io.Copy(fo, strings.NewReader(s.content))
+ return err
+}