blob: 25d8519cb8a03b1ec644a49cd62db720038ea594 [file] [log] [blame]
Adrian Villin4677d922024-06-14 09:32:39 +02001package hst
Filip Tehlar229f5fc2022-08-09 14:44:47 +00002
3import (
Adrian Villind01a63a2024-08-15 12:53:53 +02004 "errors"
Filip Tehlar229f5fc2022-08-09 14:44:47 +00005 "fmt"
6 "io"
Matus Fabian82ad9662024-06-04 19:00:00 +02007 "net"
Matus Fabian5409d332024-05-28 13:39:13 +02008 "net/http"
Matus Fabian8ca6ce62024-06-20 17:08:26 +02009 "net/http/httputil"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000010 "os"
Matus Fabian8792e5c2024-08-14 12:38:20 +020011 "os/exec"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000012 "strings"
Matus Fabian5409d332024-05-28 13:39:13 +020013 "time"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000014)
15
Maros Ondrejickae7625d02023-02-28 16:55:01 +010016const networkTopologyDir string = "topo-network/"
17const containerTopologyDir string = "topo-containers/"
Filip Tehlar229f5fc2022-08-09 14:44:47 +000018
19type Stanza struct {
20 content string
21 pad int
22}
23
24type ActionResult struct {
25 Err error
26 Desc string
27 ErrOutput string
28 StdOutput string
29}
30
31type JsonResult struct {
32 Code int
33 Desc string
34 ErrOutput string
35 StdOutput string
36}
37
Adrian Villin4677d922024-06-14 09:32:39 +020038func AssertFileSize(f1, f2 string) error {
Filip Tehlar229f5fc2022-08-09 14:44:47 +000039 fi1, err := os.Stat(f1)
40 if err != nil {
41 return err
42 }
43
44 fi2, err1 := os.Stat(f2)
45 if err1 != nil {
46 return err1
47 }
48
49 if fi1.Size() != fi2.Size() {
50 return fmt.Errorf("file sizes differ (%d vs %d)", fi1.Size(), fi2.Size())
51 }
52 return nil
53}
54
Adrian Villin4677d922024-06-14 09:32:39 +020055func (c *Stanza) NewStanza(name string) *Stanza {
56 c.Append("\n" + name + " {")
Filip Tehlar229f5fc2022-08-09 14:44:47 +000057 c.pad += 2
58 return c
59}
60
Adrian Villin4677d922024-06-14 09:32:39 +020061func (c *Stanza) Append(name string) *Stanza {
Filip Tehlar229f5fc2022-08-09 14:44:47 +000062 c.content += strings.Repeat(" ", c.pad)
63 c.content += name + "\n"
64 return c
65}
66
Adrian Villin4677d922024-06-14 09:32:39 +020067func (c *Stanza) Close() *Stanza {
Filip Tehlar229f5fc2022-08-09 14:44:47 +000068 c.content += "}\n"
69 c.pad -= 2
70 return c
71}
72
Adrian Villin4677d922024-06-14 09:32:39 +020073func (s *Stanza) ToString() string {
Filip Tehlar229f5fc2022-08-09 14:44:47 +000074 return s.content
75}
76
Adrian Villin4677d922024-06-14 09:32:39 +020077func (s *Stanza) SaveToFile(fileName string) error {
Filip Tehlar229f5fc2022-08-09 14:44:47 +000078 fo, err := os.Create(fileName)
79 if err != nil {
80 return err
81 }
82 defer fo.Close()
83
84 _, err = io.Copy(fo, strings.NewReader(s.content))
85 return err
86}
Matus Fabian5409d332024-05-28 13:39:13 +020087
Adrian Villin4677d922024-06-14 09:32:39 +020088// NewHttpClient creates [http.Client] with disabled proxy and redirects, it also sets timeout to 30seconds.
89func NewHttpClient() *http.Client {
Matus Fabian5409d332024-05-28 13:39:13 +020090 transport := http.DefaultTransport
91 transport.(*http.Transport).Proxy = nil
92 transport.(*http.Transport).DisableKeepAlives = true
93 client := &http.Client{
94 Transport: transport,
95 Timeout: time.Second * 30,
96 CheckRedirect: func(req *http.Request, via []*http.Request) error {
97 return http.ErrUseLastResponse
98 }}
99 return client
100}
Matus Fabian82ad9662024-06-04 19:00:00 +0200101
Matus Fabian8ca6ce62024-06-20 17:08:26 +0200102func DumpHttpResp(resp *http.Response, body bool) string {
103 dump, err := httputil.DumpResponse(resp, body)
104 if err != nil {
105 return ""
106 }
107 return string(dump)
108}
109
Adrian Villin4677d922024-06-14 09:32:39 +0200110func TcpSendReceive(address, data string) (string, error) {
Matus Fabian82ad9662024-06-04 19:00:00 +0200111 conn, err := net.DialTimeout("tcp", address, time.Second*30)
112 if err != nil {
113 return "", err
114 }
115 defer conn.Close()
116 err = conn.SetDeadline(time.Now().Add(time.Second * 30))
117 if err != nil {
118 return "", err
119 }
120 _, err = conn.Write([]byte(data))
121 if err != nil {
122 return "", err
123 }
124 reply := make([]byte, 1024)
125 _, err = conn.Read(reply)
126 if err != nil {
127 return "", err
128 }
129 return string(reply), nil
130}
Matus Fabian8792e5c2024-08-14 12:38:20 +0200131
132/*
133RunCurlContainer execute curl command with given args.
134Container with name "curl" must be available.
135Curl runs in verbose mode and progress meter switch off by default.
136*/
137func (s *HstSuite) RunCurlContainer(args string) (string, string) {
138 curlCont := s.GetContainerByName("curl")
139 cmd := fmt.Sprintf("curl -v -s %s", args)
140 s.Log(cmd)
141 curlCont.ExtraRunningArgs = cmd
142 curlCont.Run()
143 stdout, stderr := curlCont.GetOutput()
144 s.Log(stderr)
145 s.Log(stdout)
146 return stdout, stderr
147}
148
149/*
150CollectNginxLogs save access and error logs to the test execution directory.
151Nginx logging need to be set following way:
152
153 - error_log <default-work-dir>/{{.LogPrefix}}-error.log;
154 - access_log <default-work-dir>/{{.LogPrefix}}-access.log;
155
156where LogPrefix is set to nginxContainer.Name
157*/
158func (s *HstSuite) CollectNginxLogs(containerName string) {
159 nginxContainer := s.GetContainerByName(containerName)
Matus Fabian56f5bd92024-08-22 09:35:59 +0200160 targetDir := nginxContainer.Suite.getLogDirPath()
Matus Fabian8792e5c2024-08-14 12:38:20 +0200161 source := nginxContainer.GetHostWorkDir() + "/" + nginxContainer.Name + "-"
162 cmd := exec.Command("cp", "-t", targetDir, source+"error.log", source+"access.log")
163 s.Log(cmd.String())
164 err := cmd.Run()
165 if err != nil {
166 s.Log(fmt.Sprint(err))
167 }
168}
169
170/*
171CollectEnvoyLogs save access logs to the test execution directory.
172Envoy access log path need to be set following way:
173<default-work-dir>/{{.LogPrefix}}-access.log
174where LogPrefix is set to envoyContainer.Name
175*/
176func (s *HstSuite) CollectEnvoyLogs(containerName string) {
177 envoyContainer := s.GetContainerByName(containerName)
Matus Fabian56f5bd92024-08-22 09:35:59 +0200178 targetDir := envoyContainer.Suite.getLogDirPath()
Matus Fabian8792e5c2024-08-14 12:38:20 +0200179 source := envoyContainer.GetHostWorkDir() + "/" + envoyContainer.Name + "-"
180 cmd := exec.Command("cp", "-t", targetDir, source+"access.log")
181 s.Log(cmd.String())
182 err := cmd.Run()
183 if err != nil {
184 s.Log(fmt.Sprint(err))
185 }
186}
Adrian Villind01a63a2024-08-15 12:53:53 +0200187
188func (s *HstSuite) StartIperfServerApp(running chan error, done chan struct{}, env []string) {
189 cmd := exec.Command("iperf3", "-4", "-s", "-p", s.GetPortFromPpid())
190 if env != nil {
191 cmd.Env = env
192 }
193 s.Log(cmd)
194 err := cmd.Start()
195 if err != nil {
196 msg := fmt.Errorf("failed to start iperf server: %v", err)
197 running <- msg
198 return
199 }
200 running <- nil
201 <-done
202 cmd.Process.Kill()
203}
204
205func (s *HstSuite) StartIperfClientApp(ipAddress string, env []string, clnCh chan error, clnRes chan string) {
206 defer func() {
207 clnCh <- nil
208 }()
209
210 nTries := 0
211
212 for {
213 cmd := exec.Command("iperf3", "-c", ipAddress, "-u", "-l", "1460", "-b", "10g", "-p", s.GetPortFromPpid())
214 if env != nil {
215 cmd.Env = env
216 }
217 s.Log(cmd)
218 o, err := cmd.CombinedOutput()
219 if err != nil {
220 if nTries > 5 {
221 clnRes <- ""
222 clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
223 return
224 }
225 time.Sleep(1 * time.Second)
226 nTries++
227 continue
228 } else {
229 clnRes <- fmt.Sprintf("Client output: %s", o)
230 }
231 break
232 }
233}
234
235func (s *HstSuite) StartHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
236 cmd := newCommand([]string{"./http_server", addressPort, s.Ppid, s.ProcessIndex}, netNs)
237 err := cmd.Start()
238 s.Log(cmd)
239 if err != nil {
240 s.Log("Failed to start http server: " + fmt.Sprint(err))
241 return
242 }
243 running <- struct{}{}
244 <-done
245 cmd.Process.Kill()
246}
247
248func (s *HstSuite) StartWget(finished chan error, server_ip, port, query, netNs string) {
249 defer func() {
250 finished <- errors.New("wget error")
251 }()
252
253 cmd := newCommand([]string{"wget", "--timeout=10", "--no-proxy", "--tries=5", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
254 netNs)
255 s.Log(cmd)
256 o, err := cmd.CombinedOutput()
257 if err != nil {
258 finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
259 return
260 } else if !strings.Contains(string(o), "200 OK") {
261 finished <- fmt.Errorf("wget error: response not 200 OK")
262 return
263 }
264 finished <- nil
265}
266
267// Start a server app. 'processName' is used to check whether the app started correctly.
268func (s *HstSuite) StartServerApp(c *Container, processName string, cmd string,
269 running chan error, done chan struct{}) {
270
271 s.Log("starting server")
272 c.ExecServer(cmd)
273 cmd2 := exec.Command("docker", "exec", c.Name, "pidof", processName)
274 err := cmd2.Run()
275 if err != nil {
276 msg := fmt.Errorf("failed to start server app: %v", err)
277 running <- msg
278 <-done
279 return
280 }
281 running <- nil
282 <-done
283}
284
285func (s *HstSuite) StartClientApp(c *Container, cmd string,
286 clnCh chan error, clnRes chan string) {
287 defer func() {
288 close(clnCh)
289 close(clnRes)
290 }()
291
292 s.Log("starting client app, please wait")
293
294 nTries := 0
295 for {
296 // exec.Cmd can only be used once, which is why it's in the loop
297 cmd2 := exec.Command("/bin/sh", "-c", "docker exec "+c.getEnvVarsAsCliOption()+" "+
298 c.Name+" "+cmd)
299 s.Log(cmd2)
300 o, err := cmd2.CombinedOutput()
301 if err != nil {
302 s.Log(err)
303 if nTries > 5 {
304 clnRes <- ""
305 clnCh <- fmt.Errorf("failed to start client app '%s'", err)
306 s.AssertNil(err, fmt.Sprint(err))
307 break
308 }
309 time.Sleep(1 * time.Second)
310 nTries++
311 } else {
312 clnRes <- fmt.Sprintf("Client output: %s", o)
313 break
314 }
315 }
316}