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