func init() {
RegisterVethTests(EchoBuiltinTest, EchoBuiltinBandwidthTest, EchoBuiltinEchobytesTest, EchoBuiltinRoundtripTest, EchoBuiltinTestbytesTest)
- RegisterSoloVethTests(TcpWithLossTest)
- RegisterVeth6Tests(TcpWithLoss6Test)
+ RegisterVethMWTests(TcpWithLossTest)
+ RegisterSoloVeth6Tests(TcpWithLoss6Test)
}
func EchoBuiltinTest(s *VethsSuite) {
s.AssertContains(o, " bytes out of 32768 sent (32768 target)")
}
-func TcpWithLossTest(s *VethsSuite) {
+func tcpWithoutLoss(s *VethsSuite) string {
serverVpp := s.Containers.ServerVpp.VppInstance
serverVpp.Vppctl("test echo server uri tcp://%s/"+s.Ports.Port1,
clientVpp := s.Containers.ClientVpp.VppInstance
- // Add loss of packets with Network Delay Simulator
- s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +
- " packet-size 1400 packets-per-drop 1000"))
-
- s.Log(clientVpp.Vppctl("nsim output-feature enable-disable host-" + s.Interfaces.Client.Name()))
-
// Do echo test from client-vpp container
- output := clientVpp.Vppctl("test echo client uri tcp://%s/%s verbose echo-bytes bytes 50m",
+ output := clientVpp.Vppctl("test echo client uri tcp://%s/%s verbose echo-bytes run-time 10 test-timeout 20",
s.Interfaces.Server.Ip4AddressString(), s.Ports.Port1)
s.Log(output)
s.AssertNotEqual(len(output), 0)
s.AssertNotContains(output, "failed", output)
+
+ return output
}
-func TcpWithLoss6Test(s *Veths6Suite) {
+func TcpWithLossTest(s *VethsSuite) {
+ s.CpusPerVppContainer = 2
+ s.CpusPerContainer = 1
+ s.SetupTest()
+ clientVpp := s.Containers.ClientVpp.VppInstance
serverVpp := s.Containers.ServerVpp.VppInstance
- serverVpp.Vppctl("test echo server uri tcp://%s/%s",
- s.Interfaces.Server.Ip6AddressString(), s.Ports.Port1)
+ s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 10 ms bandwidth 40 gbit"))
+ s.Log(clientVpp.Vppctl("nsim output-feature enable-disable host-" + s.Interfaces.Client.Name()))
- clientVpp := s.Containers.ClientVpp.VppInstance
+ s.Log(" * running TcpWithoutLoss")
+ output := tcpWithoutLoss(s)
+ baseline, err := s.ParseEchoClientTransfer(output)
+ s.AssertNil(err)
- // Add loss of packets with Network Delay Simulator
- s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +
- " packet-size 1400 packets-per-drop 1000"))
+ clientVpp.Disconnect()
+ clientVpp.Stop()
+ s.SetupClientVpp()
+ serverVpp.Disconnect()
+ serverVpp.Stop()
+ s.SetupServerVpp()
+ // Add loss of packets with Network Delay Simulator
+ s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 10 ms bandwidth 40 gbit" +
+ " packet-size 1400 drop-fraction 0.033"))
s.Log(clientVpp.Vppctl("nsim output-feature enable-disable host-" + s.Interfaces.Client.Name()))
+ s.Log(" * running TcpWithLoss")
+ output = tcpWithoutLoss(s)
+
+ withLoss, err := s.ParseEchoClientTransfer(output)
+ s.AssertNil(err)
+
+ if !s.CoverageRun {
+ s.Log("\nBaseline: %v gbit/s\nWith loss: %v gbit/s", baseline, withLoss)
+ s.AssertGreaterEqual(baseline, withLoss)
+ s.AssertGreaterEqual(withLoss, baseline*0.2)
+ }
+}
+
+func tcpWithoutLoss6(s *Veths6Suite) string {
+ serverVpp := s.Containers.ServerVpp.VppInstance
+
+ serverVpp.Vppctl("test echo server uri tcp://%s/"+s.Ports.Port1,
+ s.Interfaces.Server.Ip6AddressString())
+
+ clientVpp := s.Containers.ClientVpp.VppInstance
+
// Do echo test from client-vpp container
- output := clientVpp.Vppctl("test echo client uri tcp://%s/%s verbose echo-bytes bytes 50m",
+ output := clientVpp.Vppctl("test echo client uri tcp://%s/%s verbose echo-bytes run-time 10 test-timeout 20",
s.Interfaces.Server.Ip6AddressString(), s.Ports.Port1)
s.Log(output)
s.AssertNotEqual(len(output), 0)
s.AssertNotContains(output, "failed", output)
+
+ return output
+}
+
+func TcpWithLoss6Test(s *Veths6Suite) {
+ clientVpp := s.Containers.ClientVpp.VppInstance
+ serverVpp := s.Containers.ServerVpp.VppInstance
+ s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 10 ms bandwidth 40 gbit"))
+ s.Log(clientVpp.Vppctl("nsim output-feature enable-disable host-" + s.Interfaces.Client.Name()))
+
+ s.Log(" * running TcpWithoutLoss")
+ output := tcpWithoutLoss6(s)
+ baseline, err := s.ParseEchoClientTransfer(output)
+ s.AssertNil(err)
+
+ clientVpp.Disconnect()
+ clientVpp.Stop()
+ s.SetupClientVpp()
+ serverVpp.Disconnect()
+ serverVpp.Stop()
+ s.SetupServerVpp()
+
+ // Add loss of packets with Network Delay Simulator
+ s.Log(clientVpp.Vppctl("set nsim poll-main-thread delay 10 ms bandwidth 40 gbit" +
+ " packet-size 1400 drop-fraction 0.033"))
+
+ s.Log(clientVpp.Vppctl("nsim output-feature enable-disable host-" + s.Interfaces.Client.Name()))
+
+ s.Log(" * running TcpWithLoss")
+ output = tcpWithoutLoss6(s)
+
+ withLoss, err := s.ParseEchoClientTransfer(output)
+ s.AssertNil(err)
+
+ if !s.CoverageRun {
+ s.Log("Baseline: %v gbit/s\nWith loss: %v gbit/s", baseline, withLoss)
+ s.AssertGreaterEqual(baseline, withLoss)
+ s.AssertGreaterEqual(withLoss, baseline*0.2)
+ }
}
s.Log("Server response count: %d", replyCountInt)
s.AssertNotNil(o)
s.AssertNotContains(o, "error")
- s.AssertGreaterThan(replyCountInt, 15000)
+ s.AssertGreaterEqual(replyCountInt, 15000)
replyCount = ""
cmd = fmt.Sprintf("http client %s %s repeat %d header Hello:World uri %s",
s.Log(DumpHttpResp(resp, false))
s.AssertHttpStatus(resp, 200)
s.AssertHttpHeaderWithValue(resp, "Content-Type", "text/plain")
- s.AssertGreaterThan(resp.ContentLength, 0)
+ s.AssertGreaterEqual(resp.ContentLength, 0)
_, err = io.ReadAll(resp.Body)
s.AssertNil(err, fmt.Sprint(err))
}
s.AssertContains(log, "[64 bytes data]")
sizeHeader, err := strconv.Atoi(strings.ReplaceAll(writeOut, "\x00", ""))
s.AssertNil(err, fmt.Sprint(err))
- s.AssertGreaterThan(sizeHeader, 32768)
+ s.AssertGreaterEqual(sizeHeader, 32768)
}
func Http2ServerMemLeakTest(s *Http2Suite) {
o := s.Containers.ClientVpp.VppInstance.Vppctl("http client fifo-size 64k verbose save-to response.txt uri " + uri)
s.Log(o)
s.AssertContains(o, "HTTP/2 200 OK")
- s.AssertGreaterThan(strings.Count(o, "x"), 32768)
+ s.AssertGreaterEqual(strings.Count(o, "x"), 32768)
}
func Http2ClientMemLeakTest(s *Http2Suite) {
}
}
-func (s *HstCommon) AssertNil(object interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertNil(object any, msgAndArgs ...any) {
ExpectWithOffset(2, object).To(BeNil(), msgAndArgs...)
}
-func (s *HstCommon) AssertNotNil(object interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertNotNil(object any, msgAndArgs ...any) {
ExpectWithOffset(2, object).ToNot(BeNil(), msgAndArgs...)
}
-func (s *HstCommon) AssertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertEqual(expected, actual any, msgAndArgs ...any) {
ExpectWithOffset(2, actual).To(Equal(expected), msgAndArgs...)
}
-func (s *HstCommon) AssertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertNotEqual(expected, actual any, msgAndArgs ...any) {
ExpectWithOffset(2, actual).ToNot(Equal(expected), msgAndArgs...)
}
-func (s *HstCommon) AssertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertContains(testString, contains any, msgAndArgs ...any) {
ExpectWithOffset(2, strings.ToLower(fmt.Sprint(testString))).To(ContainSubstring(strings.ToLower(fmt.Sprint(contains))), msgAndArgs...)
}
-func (s *HstCommon) AssertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertNotContains(testString, contains any, msgAndArgs ...any) {
ExpectWithOffset(2, strings.ToLower(fmt.Sprint(testString))).ToNot(ContainSubstring(strings.ToLower(fmt.Sprint(contains))), msgAndArgs...)
}
-func (s *HstCommon) AssertEmpty(object interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertEmpty(object any, msgAndArgs ...any) {
ExpectWithOffset(2, object).To(BeEmpty(), msgAndArgs...)
}
-func (s *HstCommon) AssertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertNotEmpty(object any, msgAndArgs ...any) {
ExpectWithOffset(2, object).ToNot(BeEmpty(), msgAndArgs...)
}
-func (s *HstCommon) AssertMatchError(actual, expected error, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertMatchError(actual, expected error, msgAndArgs ...any) {
ExpectWithOffset(2, actual).To(MatchError(expected), msgAndArgs...)
}
-func (s *HstCommon) AssertGreaterThan(actual, expected interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertGreaterEqual(actual, expected any, msgAndArgs ...any) {
ExpectWithOffset(2, actual).Should(BeNumerically(">=", expected), msgAndArgs...)
}
-func (s *HstCommon) AssertEqualWithinThreshold(actual, expected, threshold interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertGreaterThan(actual, expected any, msgAndArgs ...any) {
+ ExpectWithOffset(2, actual).Should(BeNumerically(">", expected), msgAndArgs...)
+}
+
+func (s *HstCommon) AssertLessEqual(actual, expected any, msgAndArgs ...any) {
+ ExpectWithOffset(2, actual).Should(BeNumerically("<=", expected), msgAndArgs...)
+}
+
+func (s *HstCommon) AssertLessThan(actual, expected any, msgAndArgs ...any) {
+ ExpectWithOffset(2, actual).Should(BeNumerically("<", expected), msgAndArgs...)
+}
+
+func (s *HstCommon) AssertEqualWithinThreshold(actual, expected, threshold any, msgAndArgs ...any) {
ExpectWithOffset(2, actual).Should(BeNumerically("~", expected, threshold), msgAndArgs...)
}
-func (s *HstCommon) AssertTimeEqualWithinThreshold(actual, expected time.Time, threshold time.Duration, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertTimeEqualWithinThreshold(actual, expected time.Time, threshold time.Duration, msgAndArgs ...any) {
ExpectWithOffset(2, actual).Should(BeTemporally("~", expected, threshold), msgAndArgs...)
}
-func (s *HstCommon) AssertHttpStatus(resp *http.Response, expectedStatus int, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertHttpStatus(resp *http.Response, expectedStatus int, msgAndArgs ...any) {
ExpectWithOffset(2, resp).To(HaveHTTPStatus(expectedStatus), msgAndArgs...)
}
-func (s *HstCommon) AssertHttpHeaderWithValue(resp *http.Response, key string, value interface{}, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertHttpHeaderWithValue(resp *http.Response, key string, value any, msgAndArgs ...any) {
ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue(key, value), msgAndArgs...)
}
-func (s *HstCommon) AssertHttpHeaderNotPresent(resp *http.Response, key string, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertHttpHeaderNotPresent(resp *http.Response, key string, msgAndArgs ...any) {
ExpectWithOffset(2, resp.Header.Get(key)).To(BeEmpty(), msgAndArgs...)
}
-func (s *HstCommon) AssertHttpContentLength(resp *http.Response, expectedContentLen int64, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertHttpContentLength(resp *http.Response, expectedContentLen int64, msgAndArgs ...any) {
ExpectWithOffset(2, resp).To(HaveHTTPHeaderWithValue("Content-Length", strconv.FormatInt(expectedContentLen, 10)), msgAndArgs...)
}
-func (s *HstCommon) AssertHttpBody(resp *http.Response, expectedBody string, msgAndArgs ...interface{}) {
+func (s *HstCommon) AssertHttpBody(resp *http.Response, expectedBody string, msgAndArgs ...any) {
ExpectWithOffset(2, resp).To(HaveHTTPBody(expectedBody), msgAndArgs...)
}
return
}
if result.Start.Details.Protocol == "TCP" {
- s.AssertGreaterThan(result.End.TcpReceived.MBytes, minTransferred)
+ s.AssertGreaterEqual(result.End.TcpReceived.MBytes, minTransferred)
} else {
- s.AssertGreaterThan(result.End.Udp.MBytes, minTransferred)
+ s.AssertGreaterEqual(result.End.Udp.MBytes, minTransferred)
}
}
var vethTests = map[string][]func(s *VethsSuite){}
var vethSoloTests = map[string][]func(s *VethsSuite){}
+var vethMWTests = map[string][]func(s *VethsSuite){}
type VethsSuite struct {
HstSuite
func RegisterSoloVethTests(tests ...func(s *VethsSuite)) {
vethSoloTests[GetTestFilename()] = tests
}
+func RegisterVethMWTests(tests ...func(s *VethsSuite)) {
+ vethMWTests[GetTestFilename()] = tests
+}
func (s *VethsSuite) SetupSuite() {
time.Sleep(1 * time.Second)
s.AssertNotNil(clientVpp, fmt.Sprint(err))
s.SetupServerVpp()
- s.setupClientVpp()
+ s.SetupClientVpp()
if *DryRun {
s.LogStartedContainers()
s.Skip("Dry run mode = true")
s.AssertNotEqual(0, idx)
}
-func (s *VethsSuite) setupClientVpp() {
+func (s *VethsSuite) SetupClientVpp() {
clientVpp := s.GetContainerByName("client-vpp").VppInstance
s.AssertNil(clientVpp.Start())
}
}
})
+
+var _ = Describe("VethsSuiteMW", Ordered, ContinueOnFailure, Serial, func() {
+ var s VethsSuite
+ BeforeAll(func() {
+ s.SetupSuite()
+ })
+ BeforeEach(func() {
+ s.SkipIfNotEnoguhCpus = true
+ })
+ AfterAll(func() {
+ s.TeardownSuite()
+ })
+ AfterEach(func() {
+ s.TeardownTest()
+ })
+
+ // https://onsi.github.io/ginkgo/#dynamically-generating-specs
+ for filename, tests := range vethMWTests {
+ for _, test := range tests {
+ test := test
+ pc := reflect.ValueOf(test).Pointer()
+ funcValue := runtime.FuncForPC(pc)
+ testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
+ It(testName, Label("SOLO", "VPP Multi-Worker"), func(ctx SpecContext) {
+ s.Log(testName + ": BEGIN")
+ test(&s)
+ }, SpecTimeout(TestTimeout))
+ }
+ }
+})
s.AssertNotNil(clientVpp, fmt.Sprint(err))
s.SetupServerVpp()
- s.setupClientVpp()
+ s.SetupClientVpp()
if *DryRun {
s.LogStartedContainers()
s.Skip("Dry run mode = true")
s.AssertNotEqual(0, idx)
}
-func (s *Veths6Suite) setupClientVpp() {
+func (s *Veths6Suite) SetupClientVpp() {
clientVpp := s.GetContainerByName("client-vpp").VppInstance
s.AssertNil(clientVpp.Start())
s.Log("* started udp echo server " + addr + ":" + strconv.Itoa(port))
return conn
}
+
+// Parses transfer speed from the last line ("N gbit/second full-duplex")
+func (s *HstSuite) ParseEchoClientTransfer(stats string) (float64, error) {
+ lines := strings.Split(strings.TrimSpace(stats), "\n")
+ parts := strings.Fields(lines[len(lines)-1])
+ if len(parts) == 0 {
+ return 0, errors.New("check format of stats")
+ }
+ number, err := strconv.ParseFloat(parts[0], 64)
+ return number, err
+}
package main
import (
+ "errors"
+ "regexp"
+ "strconv"
"strings"
. "fd.io/hs-test/infra"
lines := strings.Split(o, "\n")
stats := lines[len(lines)-2]
s.Log(stats)
- s.AssertContains(stats, "10% packet loss")
+
+ re := regexp.MustCompile(`(\d+\.?\d*)\s*%\s*packet loss`)
+ matches := re.FindStringSubmatch(stats)
+ if len(matches) < 2 {
+ s.AssertNil(errors.New("Error when parsing stats."))
+ }
+ packetLossStr := matches[1]
+ packetLoss, err := strconv.ParseFloat(packetLossStr, 64)
+ s.AssertNil(err)
+ if !s.CoverageRun {
+ s.AssertEqual(packetLoss, float64(10), "Packet loss != 10%%")
+ }
}
report += fmt.Sprintf("Errors: timeout %d, read %d, write %d, invalid data received %d, connection %d\n", timeout.Load(), readError.Load(), writeError.Load(), invalidData.Load(), connectError.Load())
report += fmt.Sprintf("Successes ratio: %.2f%%\n", successRatio)
AddReportEntry(summary, report)
- s.AssertGreaterThan(successRatio, 90.0)
+ s.AssertGreaterEqual(successRatio, 90.0)
}
func VppConnectProxyStressTest(s *VppProxySuite) {
report += fmt.Sprintf("Errors: timeout %d, read %d, write %d, invalid data received %d, connection %d\n", timeout.Load(), readError.Load(), writeError.Load(), invalidData.Load(), connectError.Load())
report += fmt.Sprintf("Successes ratio: %.2f%%\n", successRatio)
AddReportEntry(summary, report)
- s.AssertGreaterThan(successRatio, 90.0)
+ s.AssertGreaterEqual(successRatio, 90.0)
}
func VppConnectUdpStressTest(s *VppUdpProxySuite) {