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