blob: 25303591a430c6bf9dc833075d1a90daedb030cb [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),
210 "-e", "VCL_CONFIG=/tmp/vcl.conf",
211 "envoyproxy/envoy-contrib:v1.21-latest"}
212 fmt.Println(c)
213
214 go func(errCh chan error) {
215 count := 0
216 var cmd *exec.Cmd
217 for ; ; count++ {
218 cmd = NewCommand(c, "")
219 err = cmd.Start()
220 if err == nil {
221 break
222 }
223 if count > 5 {
224 errCh <- fmt.Errorf("Failed to start envoy docker after %d attempts", count)
225 return
226 }
227 }
228
229 err = cmd.Wait()
230 if err != nil {
231 errCh <- fmt.Errorf("failed to start docker: %v", err)
232 return
233 }
234 <-ctx.Done()
235 }(errCh)
236 return errCh
237}
238
239func setupEnvoy(t *testing.T, ctx context.Context, dockerInstance string) error {
240 errCh := startEnvoy(ctx, dockerInstance)
241 select {
242 case err := <-errCh:
243 return err
244 default:
245 }
246
247 go func(ctx context.Context, errCh <-chan error) {
248 for {
249 select {
250 // handle cancel() call from outside to gracefully stop the routine
251 case <-ctx.Done():
252 return
253 default:
254 select {
255 case err := <-errCh:
256 fmt.Printf("error while running envoy: %v", err)
257 default:
258 }
259 }
260 }
261 }(ctx, errCh)
262 return nil
263}
264
265func configureVppProxy() error {
266 _, err := dockerExec("vppctl test proxy server server-uri tcp://10.0.0.2/555 client-uri tcp://10.0.1.1/666",
267 "vpp-proxy")
268 if err != nil {
269 return fmt.Errorf("error while configuring vpp proxy test: %v", err)
270 }
271 return nil
272}
273
274func startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
275 cmd := NewCommand([]string{"./http_server", addressPort}, netNs)
276 err := cmd.Start()
277 if err != nil {
278 fmt.Println("Failed to start http server")
279 return
280 }
281 running <- struct{}{}
282 <-done
283 cmd.Process.Kill()
284}
285
286func startWget(finished chan error, server_ip, port string, netNs string) {
287 fname := "test_file_10M"
288 defer func() {
289 finished <- errors.New("wget error")
290 }()
291
292 cmd := NewCommand([]string{"wget", "--tries=5", "-q", "-O", "/dev/null", server_ip + ":" + port + "/" + fname},
293 netNs)
294 o, err := cmd.CombinedOutput()
295 if err != nil {
296 fmt.Printf("wget error: '%s'.\n%s", err, o)
297 return
298 }
299 fmt.Printf("Client output: %s", o)
300 finished <- nil
301}
302
303func (c *Stanza) NewStanza(name string) *Stanza {
304 c.Append("\n" + name + " {")
305 c.pad += 2
306 return c
307}
308
309func (c *Stanza) Append(name string) *Stanza {
310 c.content += strings.Repeat(" ", c.pad)
311 c.content += name + "\n"
312 return c
313}
314
315func (c *Stanza) Close() *Stanza {
316 c.content += "}\n"
317 c.pad -= 2
318 return c
319}
320
321func (s *Stanza) ToString() string {
322 return s.content
323}
324
325func (s *Stanza) SaveToFile(fileName string) error {
326 fo, err := os.Create(fileName)
327 if err != nil {
328 return err
329 }
330 defer fo.Close()
331
332 _, err = io.Copy(fo, strings.NewReader(s.content))
333 return err
334}