diff --git a/extras/hs-test/infra/hst_suite.go b/extras/hs-test/infra/hst_suite.go index 0513e86e47b..9a3a3c9c8f6 100644 --- a/extras/hs-test/infra/hst_suite.go +++ b/extras/hs-test/infra/hst_suite.go @@ -364,6 +364,15 @@ func (s *HstSuite) AssertChannelClosed(timeout time.Duration, channel chan error EventuallyWithOffset(2, channel).WithTimeout(timeout).Should(BeClosed()) } +// Pass the parsed result struct and the minimum amount of data transferred in MB +func (s *HstSuite) AssertIperfMinTransfer(result IPerfResult, minTransferred int) { + if result.Start.Details.Protocol == "TCP" { + s.AssertGreaterThan(result.End.TcpReceived.MBytes, minTransferred) + } else { + s.AssertGreaterThan(result.End.Udp.MBytes, minTransferred) + } +} + func (s *HstSuite) CreateLogger() { suiteName := s.GetCurrentSuiteName() var err error diff --git a/extras/hs-test/infra/utils.go b/extras/hs-test/infra/utils.go index 16a6a8c1dab..a7c2f13625e 100644 --- a/extras/hs-test/infra/utils.go +++ b/extras/hs-test/infra/utils.go @@ -2,6 +2,7 @@ package hst import ( "crypto/tls" + "encoding/json" "errors" "fmt" "io" @@ -36,6 +37,43 @@ type JsonResult struct { StdOutput string } +type IPerfResult struct { + Start struct { + Timestamp struct { + Time string `json:"time"` + } `json:"timestamp"` + Connected []struct { + Socket int `json:"socket"` + LocalHost string `json:"local_host"` + LocalPort int `json:"local_port"` + RemoteHost string `json:"remote_host"` + RemotePort int `json:"remote_port"` + } `json:"connected"` + Version string `json:"version"` + Details struct { + Protocol string `json:"protocol"` + } `json:"test_start"` + } `json:"start"` + End struct { + TcpSent *struct { + MbitsPerSecond float64 `json:"bits_per_second"` + MBytes float64 `json:"bytes"` + } `json:"sum_sent,omitempty"` + TcpReceived *struct { + MbitsPerSecond float64 `json:"bits_per_second"` + MBytes float64 `json:"bytes"` + } `json:"sum_received,omitempty"` + Udp *struct { + MbitsPerSecond float64 `json:"bits_per_second"` + JitterMs float64 `json:"jitter_ms,omitempty"` + LostPackets int `json:"lost_packets,omitempty"` + Packets int `json:"packets,omitempty"` + LostPercent float64 `json:"lost_percent,omitempty"` + MBytes float64 `json:"bytes"` + } `json:"sum,omitempty"` + } `json:"end"` +} + func AssertFileSize(f1, f2 string) error { fi1, err := os.Stat(f1) if err != nil { @@ -286,7 +324,7 @@ func (s *HstSuite) StartServerApp(c *Container, processName string, cmd string, } func (s *HstSuite) StartClientApp(c *Container, cmd string, - clnCh chan error, clnRes chan string) { + clnCh chan error, clnRes chan []byte) { defer func() { close(clnCh) close(clnRes) @@ -301,10 +339,71 @@ func (s *HstSuite) StartClientApp(c *Container, cmd string, if err != nil { s.Log(err) s.Log(string(o)) - clnRes <- "" + clnRes <- nil clnCh <- fmt.Errorf("failed to start client app '%s'", err) s.AssertNil(err, fmt.Sprint(err)) } else { - clnRes <- fmt.Sprintf("Client output: %s", o) + clnRes <- o } } + +func (s *HstSuite) ParseJsonIperfOutput(jsonResult []byte) IPerfResult { + var result IPerfResult + // remove iperf warning line if present + if strings.Contains(string(jsonResult), "warning") { + index := strings.Index(string(jsonResult), "\n") + jsonResult = jsonResult[index+1:] + } + + err := json.Unmarshal(jsonResult, &result) + s.AssertNil(err) + + if result.Start.Details.Protocol == "TCP" { + result.End.TcpSent.MbitsPerSecond = result.End.TcpSent.MbitsPerSecond / 1000000 + result.End.TcpSent.MBytes = result.End.TcpSent.MBytes / 1000000 + result.End.TcpReceived.MbitsPerSecond = result.End.TcpReceived.MbitsPerSecond / 1000000 + result.End.TcpReceived.MBytes = result.End.TcpReceived.MBytes / 1000000 + } else { + result.End.Udp.MBytes = result.End.Udp.MBytes / 1000000 + result.End.Udp.MbitsPerSecond = result.End.Udp.MbitsPerSecond / 1000000 + } + + return result +} + +func (s *HstSuite) LogJsonIperfOutput(result IPerfResult) { + s.Log("\n*******************************************\n"+ + "%s\n"+ + "[%s] %s:%d connected to %s:%d\n"+ + "Started: %s\n", + result.Start.Version, + result.Start.Details.Protocol, + result.Start.Connected[0].LocalHost, result.Start.Connected[0].LocalPort, + result.Start.Connected[0].RemoteHost, result.Start.Connected[0].RemotePort, + result.Start.Timestamp.Time) + + if result.Start.Details.Protocol == "TCP" { + s.Log("Transfer (sent): %.2f MBytes\n"+ + "Bitrate (sent): %.2f Mbits/sec\n"+ + "Transfer (received): %.2f MBytes\n"+ + "Bitrate (received): %.2f Mbits/sec", + result.End.TcpSent.MBytes, + result.End.TcpSent.MbitsPerSecond, + result.End.TcpReceived.MBytes, + result.End.TcpReceived.MbitsPerSecond) + } else { + s.Log("Transfer: %.2f MBytes\n"+ + "Bitrate: %.2f Mbits/sec\n"+ + "Jitter: %.3f ms\n"+ + "Packets: %d\n"+ + "Packets lost: %d\n"+ + "Percent lost: %.2f%%", + result.End.Udp.MBytes, + result.End.Udp.MbitsPerSecond, + result.End.Udp.JitterMs, + result.End.Udp.Packets, + result.End.Udp.LostPackets, + result.End.Udp.LostPercent) + } + s.Log("*******************************************\n") +} diff --git a/extras/hs-test/iperf_linux_test.go b/extras/hs-test/iperf_linux_test.go index ff1467c48eb..0a59f6a4e0f 100644 --- a/extras/hs-test/iperf_linux_test.go +++ b/extras/hs-test/iperf_linux_test.go @@ -21,7 +21,7 @@ func IperfUdpLinuxTest(s *IperfSuite) { clnCh := make(chan error) stopServerCh := make(chan struct{}) srvCh := make(chan error, 1) - clnRes := make(chan string, 1) + clnRes := make(chan []byte, 1) defer func() { stopServerCh <- struct{}{} @@ -39,9 +39,12 @@ func IperfUdpLinuxTest(s *IperfSuite) { go func() { defer GinkgoRecover() cmd := "iperf3 -c " + serverIpAddress + " -B " + clientIpAddress + - " -u -l 1460 -b 10g -p " + s.GetPortFromPpid() + " -u -l 1460 -b 10g -J -p " + s.GetPortFromPpid() s.StartClientApp(clientContainer, cmd, clnCh, clnRes) }() s.AssertChannelClosed(time.Minute*3, clnCh) - s.Log(<-clnRes) + output := <-clnRes + result := s.ParseJsonIperfOutput(output) + s.LogJsonIperfOutput(result) + s.AssertIperfMinTransfer(result, 800) } diff --git a/extras/hs-test/ldp_test.go b/extras/hs-test/ldp_test.go index 32473d54afd..76bc3669fb6 100644 --- a/extras/hs-test/ldp_test.go +++ b/extras/hs-test/ldp_test.go @@ -48,7 +48,7 @@ func ldPreloadIperfVpp(s *LdpSuite, useUdp bool) { stopServerCh := make(chan struct{}, 1) srvCh := make(chan error, 1) clnCh := make(chan error) - clnRes := make(chan string, 1) + clnRes := make(chan []byte, 1) defer func() { stopServerCh <- struct{}{} @@ -65,12 +65,15 @@ func ldPreloadIperfVpp(s *LdpSuite, useUdp bool) { go func() { defer GinkgoRecover() - cmd := "iperf3 -c " + serverVethAddress + " -l 1460 -b 10g -p " + s.GetPortFromPpid() + protocol + cmd := "iperf3 -c " + serverVethAddress + " -l 1460 -b 10g -J -p " + s.GetPortFromPpid() + protocol s.StartClientApp(clientContainer, cmd, clnCh, clnRes) }() s.AssertChannelClosed(time.Minute*3, clnCh) - s.Log(<-clnRes) + output := <-clnRes + result := s.ParseJsonIperfOutput(output) + s.LogJsonIperfOutput(result) + s.AssertIperfMinTransfer(result, 400) } func RedisBenchmarkTest(s *LdpSuite) { @@ -83,7 +86,7 @@ func RedisBenchmarkTest(s *LdpSuite) { runningSrv := make(chan error) doneSrv := make(chan struct{}) clnCh := make(chan error) - clnRes := make(chan string, 1) + clnRes := make(chan []byte, 1) defer func() { doneSrv <- struct{}{} @@ -112,5 +115,5 @@ func RedisBenchmarkTest(s *LdpSuite) { // 4.5 minutes s.AssertChannelClosed(time.Second*270, clnCh) - s.Log(<-clnRes) + s.Log(string(<-clnRes)) }