blob: ba40beedeafb9d4d71cea9282c433b76da8b36a7 [file] [log] [blame]
Filip Tehlar229f5fc2022-08-09 14:44:47 +00001package main
2
3import (
4 "context"
5 "encoding/json"
6 "errors"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "os"
11 "os/exec"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/edwarnicke/exechelper"
17)
18
19const configTemplate = `unix {
20 nodaemon
21 log %[1]s/var/log/vpp/vpp.log
22 full-coredump
23 cli-listen %[1]s/var/run/vpp/cli.sock
24 runtime-dir %[1]s/var/run
25 gid vpp
26}
27
28api-trace {
29 on
30}
31
32api-segment {
33 gid vpp
34}
35
36socksvr {
37 socket-name %[1]s/var/run/vpp/api.sock
38}
39
40statseg {
41 socket-name %[1]s/var/run/vpp/stats.sock
42}
43
44plugins {
45 plugin unittest_plugin.so { enable }
46 plugin dpdk_plugin.so { disable }
47 plugin crypto_aesni_plugin.so { enable }
48 plugin quic_plugin.so { enable }
49}
50
51`
52
53const TopologyDir string = "topo/"
54
55type Stanza struct {
56 content string
57 pad int
58}
59
60type ActionResult struct {
61 Err error
62 Desc string
63 ErrOutput string
64 StdOutput string
65}
66
67type JsonResult struct {
68 Code int
69 Desc string
70 ErrOutput string
71 StdOutput string
72}
73
74func StartServerApp(running chan error, done chan struct{}, env []string) {
75 cmd := exec.Command("iperf3", "-4", "-s")
76 if env != nil {
77 cmd.Env = env
78 }
79 err := cmd.Start()
80 if err != nil {
81 msg := fmt.Errorf("failed to start iperf server: %v", err)
82 running <- msg
83 return
84 }
85 running <- nil
86 <-done
87 cmd.Process.Kill()
88}
89
90func StartClientApp(env []string, clnCh chan error) {
91 defer func() {
92 clnCh <- nil
93 }()
94
95 nTries := 0
96
97 for {
98 cmd := exec.Command("iperf3", "-c", "10.10.10.1", "-u", "-l", "1460", "-b", "10g")
99 if env != nil {
100 cmd.Env = env
101 }
102 o, err := cmd.CombinedOutput()
103 if err != nil {
104 if nTries > 5 {
105 clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
106 return
107 }
108 time.Sleep(1 * time.Second)
109 nTries++
110 continue
111 } else {
112 fmt.Printf("Client output: %s", o)
113 }
114 break
115 }
116}
117
118// run vpphelper in docker
119func hstExec(args string, instance string) (string, error) {
120 syncFile := fmt.Sprintf("/tmp/%s/sync/rc", instance)
121 os.Remove(syncFile)
122
123 c := "docker exec -d " + instance + " /hs-test " + args
124 err := exechelper.Run(c)
125 if err != nil {
126 return "", err
127 }
128
129 res, err := waitForSyncFile(syncFile)
130
131 if err != nil {
132 return "", fmt.Errorf("failed to read sync file while executing './hs-test %s': %v", args, err)
133 }
134
135 o := res.StdOutput + res.ErrOutput
136 if res.Code != 0 {
137 return o, fmt.Errorf("cmd resulted in non-zero value %d: %s", res.Code, res.Desc)
138 }
139 return o, err
140}
141
142func waitForSyncFile(fname string) (*JsonResult, error) {
143 var res JsonResult
144
145 for i := 0; i < 60; i++ {
146 f, err := os.Open(fname)
147 if err == nil {
148 defer f.Close()
149
150 data, err := ioutil.ReadFile(fname)
151 if err != nil {
152 return nil, fmt.Errorf("read error: %v", err)
153 }
154 err = json.Unmarshal(data, &res)
155 if err != nil {
156 return nil, fmt.Errorf("json unmarshal error: %v", err)
157 }
158 return &res, nil
159 }
160 time.Sleep(1 * time.Second)
161 }
162 return nil, fmt.Errorf("no sync file found")
163}
164
165func dockerRun(instance, args string) error {
166 exechelper.Run(fmt.Sprintf("mkdir -p /tmp/%s/sync", instance))
167 syncPath := fmt.Sprintf("-v /tmp/%s/sync:/tmp/sync", instance)
168 cmd := "docker run --cap-add=all -d --privileged --network host --rm "
169 cmd += syncPath
170 cmd += " " + args
171 cmd += " --name " + instance + " hs-test/vpp"
172 fmt.Println(cmd)
173 return exechelper.Run(cmd)
174}
175
176func assertFileSize(f1, f2 string) error {
177 fi1, err := os.Stat(f1)
178 if err != nil {
179 return err
180 }
181
182 fi2, err1 := os.Stat(f2)
183 if err1 != nil {
184 return err1
185 }
186
187 if fi1.Size() != fi2.Size() {
188 return fmt.Errorf("file sizes differ (%d vs %d)", fi1.Size(), fi2.Size())
189 }
190 return nil
191}
192
193func dockerExec(cmd string, instance string) ([]byte, error) {
194 c := "docker exec -d " + instance + " " + cmd
195 return exechelper.CombinedOutput(c)
196}
197
198func startEnvoy(ctx context.Context, dockerInstance string) <-chan error {
199 errCh := make(chan error)
200 wd, err := os.Getwd()
201 if err != nil {
202 errCh <- err
203 return errCh
204 }
205
206 c := []string{"docker", "run", "--rm", "--name", "envoy",
207 "-v", fmt.Sprintf("%s/envoy/proxy.yaml:/etc/envoy/envoy.yaml", wd),
208 "-v", fmt.Sprintf("shared-vol:/tmp/%s", dockerInstance),
209 "-v", fmt.Sprintf("%s/envoy:/tmp", wd),
Maros Ondrejickaeeaf6c82022-10-13 15:38:17 +0200210 "-e", "ENVOY_UID=0",
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000211 "-e", "VCL_CONFIG=/tmp/vcl.conf",
212 "envoyproxy/envoy-contrib:v1.21-latest"}
213 fmt.Println(c)
214
215 go func(errCh chan error) {
216 count := 0
217 var cmd *exec.Cmd
218 for ; ; count++ {
219 cmd = NewCommand(c, "")
220 err = cmd.Start()
221 if err == nil {
222 break
223 }
224 if count > 5 {
Maros Ondrejickaeeaf6c82022-10-13 15:38:17 +0200225 errCh <- fmt.Errorf("failed to start envoy docker after %d attempts", count)
Filip Tehlar229f5fc2022-08-09 14:44:47 +0000226 return
227 }
228 }
229
230 err = cmd.Wait()
231 if err != nil {
232 errCh <- fmt.Errorf("failed to start docker: %v", err)
233 return
234 }
235 <-ctx.Done()
236 }(errCh)
237 return errCh
238}
239
240func setupEnvoy(t *testing.T, ctx context.Context, dockerInstance string) error {
241 errCh := startEnvoy(ctx, dockerInstance)
242 select {
243 case err := <-errCh:
244 return err
245 default:
246 }
247
248 go func(ctx context.Context, errCh <-chan error) {
249 for {
250 select {
251 // handle cancel() call from outside to gracefully stop the routine
252 case <-ctx.Done():
253 return
254 default:
255 select {
256 case err := <-errCh:
257 fmt.Printf("error while running envoy: %v", err)
258 default:
259 }
260 }
261 }
262 }(ctx, errCh)
263 return nil
264}
265
266func configureVppProxy() error {
267 _, err := dockerExec("vppctl test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666",
268 "vpp-proxy")
269 if err != nil {
270 return fmt.Errorf("error while configuring vpp proxy test: %v", err)
271 }
272 return nil
273}
274
275func startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
276 cmd := NewCommand([]string{"./http_server", addressPort}, netNs)
277 err := cmd.Start()
278 if err != nil {
279 fmt.Println("Failed to start http server")
280 return
281 }
282 running <- struct{}{}
283 <-done
284 cmd.Process.Kill()
285}
286
287func startWget(finished chan error, server_ip, port string, netNs string) {
288 fname := "test_file_10M"
289 defer func() {
290 finished <- errors.New("wget error")
291 }()
292
293 cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
294 netNs)
295 o, err := cmd.CombinedOutput()
296 if err != nil {
297 fmt.Printf("wget error: '%s'.\n%s", err, o)
298 return
299 }
300 fmt.Printf("Client output: %s", o)
301 finished <- nil
302}
303
304func (c *Stanza) NewStanza(name string) *Stanza {
305 c.Append("\n" + name + " {")
306 c.pad += 2
307 return c
308}
309
310func (c *Stanza) Append(name string) *Stanza {
311 c.content += strings.Repeat(" ", c.pad)
312 c.content += name + "\n"
313 return c
314}
315
316func (c *Stanza) Close() *Stanza {
317 c.content += "}\n"
318 c.pad -= 2
319 return c
320}
321
322func (s *Stanza) ToString() string {
323 return s.content
324}
325
326func (s *Stanza) SaveToFile(fileName string) error {
327 fo, err := os.Create(fileName)
328 if err != nil {
329 return err
330 }
331 defer fo.Close()
332
333 _, err = io.Copy(fo, strings.NewReader(s.content))
334 return err
335}