hs-test: improved iperf testing

- set iperf to json output
- added iperf json parsing function
- we can now check if iperf transferred more than X megabytes
  (other asserts can be added)

Type: test

Change-Id: I560104a153456b46f22a1affee4301018063b99d
Signed-off-by: Adrian Villin <avillin@cisco.com>
This commit is contained in:
Adrian Villin 2024-12-06 16:00:25 +01:00 committed by Florin Coras
parent a661b90a4c
commit 8b2a67c8f3
4 changed files with 125 additions and 11 deletions

View File

@ -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

View File

@ -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")
}

View File

@ -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)
}

View File

@ -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))
}