hs-test: transition to ginkgo test framework

Type: test

Change-Id: Ia38bf5549d20b22876f6082085b69a52a03d0142
Signed-off-by: Adrian Villin <avillin@cisco.com>
Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
Adrian Villin
2024-03-14 11:42:55 -04:00
parent 3a05db6264
commit cee15aa940
25 changed files with 762 additions and 230 deletions

View File

@ -23,6 +23,10 @@ ifeq ($(CPUS),)
CPUS=1
endif
ifeq ($(PARALLEL),)
PARALLEL=1
endif
ifeq ($(VPPSRC),)
VPPSRC=$(shell pwd)/../..
endif
@ -35,8 +39,8 @@ ifeq ($(ARCH),)
ARCH=$(shell dpkg --print-architecture)
endif
list_tests = @(grep -r ') Test' *_test.go | cut -d '*' -f2 | cut -d '(' -f1 | \
tr -d ' ' | tr ')' '/' | sed 's/Suite//')
list_tests = @go run github.com/onsi/ginkgo/v2/ginkgo --dry-run -v --no-color --seed=2 | head -n -1 | grep 'Test' | \
sed 's/^/* /; s/\(Suite\) /\1\//g'
.PHONY: help
help:
@ -60,6 +64,7 @@ help:
@echo " TEST=[test-name] - specific test to run"
@echo " CPUS=[n-cpus] - number of cpus to run with vpp"
@echo " VPPSRC=[path-to-vpp-src] - path to vpp source files (for gdb)"
@echo " PARALLEL=[n-cpus]" - number of test processes to spawn to run in parallel
@echo
@echo "List of all tests:"
$(call list_tests)
@ -78,7 +83,7 @@ build-vpp-debug:
test: .deps.ok .build.vpp
@bash ./test --persist=$(PERSIST) --verbose=$(VERBOSE) \
--unconfigure=$(UNCONFIGURE) --debug=$(DEBUG) --test=$(TEST) --cpus=$(CPUS) \
--vppsrc=$(VPPSRC)
--vppsrc=$(VPPSRC) --parallel=$(PARALLEL)
build-go:
go build ./tools/http_server

View File

@ -9,7 +9,10 @@ End-to-end tests often want multiple VPP instances, network namespaces, differen
and to execute external tools or commands. With such requirements the existing VPP test framework is not sufficient.
For this, ``Go`` was chosen as a high level language, allowing rapid development, with ``Docker`` and ``ip`` being the tools for creating required topology.
Go's package `testing`_ together with `go test`_ command form the base framework upon which the *hs-test* is built and run.
`Ginkgo`_ forms the base framework upon which the *hs-test* is built and run.
All tests are technically in a single suite because we are only using ``package main``. We simulate suite behavior by grouping tests by the topology they require.
This allows us to run those mentioned groups in parallel, but not individual tests in parallel.
Anatomy of a test case
----------------------
@ -24,15 +27,16 @@ Anatomy of a test case
**Action flow when running a test case**:
#. It starts with running ``make test``. Optional arguments are VERBOSE, PERSIST (topology configuration isn't cleaned up after test run),
and TEST=<test-name> to run specific test.
#. ``make list-tests`` (or ``make help``) shows all test names.
#. ``go test`` compiles package ``main`` along with any files with names matching the file pattern ``*_test.go``
and then runs the resulting test binaries
#. The go test framework runs each function matching :ref:`naming convention<test-convention>`. Each of these corresponds to a `test suite`_
#. Testify toolkit's ``suite.Run(t *testing.T, suite TestingSuite)`` function runs the suite and does the following:
TEST=<test-name> to run a specific test and PARALLEL=[n-cpus].
#. ``make list-tests`` (or ``make help``) shows all tests. The current `list of tests`_ is at the bottom of this document.
#. ``Ginkgo`` looks for a spec suite in the current directory and then compiles it to a .test binary
#. The Ginkgo test framework runs each function that was registered manually using ``registerMySuiteTest(s *MySuite)``. Each of these functions correspond to a suite
#. Ginkgo's ``RunSpecs(t, "Suite description")`` function is the entry point and does the following:
#. Ginkgo compiles the spec, builds a spec tree
#. ``Describe`` container nodes in suite\_\*_test.go files are run (in series by default, or in parallel with the argument PARALLEL=[n-cpus])
#. Suite is initialized. The topology is loaded and configured in this step
#. Test suite runs all the tests attached to it
#. Registered tests are run in generated ``It`` subject nodes
#. Execute tear-down functions, which currently consists of stopping running containers
and clean-up of test topology
@ -43,23 +47,25 @@ This describes adding a new test case to an existing suite.
For adding a new suite, please see `Modifying the framework`_ below.
#. To write a new test case, create a file whose name ends with ``_test.go`` or pick one that already exists
#. Declare method whose name starts with ``Test`` and specifies its receiver as a pointer to the suite's struct (defined in ``framework_test.go``)
#. Declare method whose name ends with ``Test`` and specifies its parameter as a pointer to the suite's struct (defined in ``suite_*_test.go``)
#. Implement test behaviour inside the test method. This typically includes the following:
#. Retrieve a running container in which to run some action. Method ``getContainerByName``
from ``HstSuite`` struct serves this purpose
#. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI
#. Run arbitrary commands inside the containers with ``exec`` method
#. Run other external tool with one of the preexisting functions in the ``utils.go`` file.
For example, use ``wget`` with ``startWget`` function
#. Use ``exechelper`` or just plain ``exec`` packages to run whatever else
#. Verify results of your tests using ``assert`` methods provided by the test suite,
implemented by HstSuite struct
#. Retrieve a running container in which to run some action. Method ``getContainerByName``
from ``HstSuite`` struct serves this purpose
#. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI
#. Run arbitrary commands inside the containers with ``exec`` method
#. Run other external tool with one of the preexisting functions in the ``utils.go`` file.
For example, use ``wget`` with ``startWget`` function
#. Use ``exechelper`` or just plain ``exec`` packages to run whatever else
#. Verify results of your tests using ``assert`` methods provided by the test suite, implemented by HstSuite struct or use ``Gomega`` assert functions.
#. Create an ``init()`` function and register the test using ``register*SuiteTests(testCaseFunction)``
**Example test case**
Assumed are two docker containers, each with its own VPP instance running. One VPP then pings the other.
This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./test -run TestMySuite/TestMyCase``.
This can be put in file ``extras/hs-test/my_test.go`` and run with command ``make test TEST=MyTest`` or ``ginkgo -v --trace --focus MyTest``.
::
@ -69,7 +75,11 @@ This can be put in file ``extras/hs-test/my_test.go`` and run with command ``./t
"fmt"
)
func (s *MySuite) TestMyCase() {
func init(){
registerMySuiteTest(MyTest)
}
func MyTest(s *MySuite) {
clientVpp := s.getContainerByName("client-vpp").vppInstance
serverVethAddress := s.netInterfaces["server-iface"].AddressString()
@ -86,8 +96,7 @@ Modifying the framework
.. _test-convention:
#. Adding a new suite takes place in ``framework_test.go`` and by creating a new file for the suite.
Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced
#. To add a new suite, create a new file. Naming convention for the suite files is ``suite_name_test.go`` where *name* will be replaced
by the actual name
#. Make a ``struct``, in the suite file, with at least ``HstSuite`` struct as its member.
@ -99,7 +108,17 @@ Modifying the framework
HstSuite
}
#. In suite file, implement ``SetupSuite`` method which testify runs once before starting any of the tests.
#. Create a new slice that will contain test functions with a pointer to the suite's struct: ``var myTests = []func(s *MySuite){}``
#. Then create a new function that will append test functions to that slice:
::
func registerMySuiteTests(tests ...func(s *MySuite)) {
nginxTests = append(myTests, tests...)
}
#. In suite file, implement ``SetupSuite`` method which Ginkgo runs once before starting any of the tests.
It's important here to call ``configureNetworkTopology`` method,
pass the topology name to the function in a form of file name of one of the *yaml* files in ``topo-network`` folder.
Without the extension. In this example, *myTopology* corresponds to file ``extras/hs-test/topo-network/myTopology.yaml``
@ -111,6 +130,8 @@ Modifying the framework
::
func (s *MySuite) SetupSuite() {
s.HstSuite.SetupSuite()
// Add custom setup code here
s.configureNetworkTopology("myTopology")
@ -123,19 +144,62 @@ Modifying the framework
::
func (s *MySuite) SetupTest() {
s.HstSuite.setupTest()
s.SetupVolumes()
s.SetupContainers()
}
#. In order for ``go test`` to run this suite, we need to create a normal test function and pass our suite to ``suite.Run``.
These functions are placed at the end of ``framework_test.go``
#. In order for ``Ginkgo`` to run this suite, we need to create a ``Describe`` container node with setup nodes and an ``It`` subject node.
Place them at the end of the suite file
* Declare a suite struct variable before anything else
* To use ``BeforeAll()`` and ``AfterAll()``, the container has to be marked as ``Ordered``
* Because the container is now marked as Ordered, if a test fails, all the subsequent tests are skipped.
To override this behavior, decorate the container node with ``ContinueOnFailure``
::
func TestMySuite(t *testing.T) {
var m MySuite
suite.Run(t, &m)
}
var _ = Describe("MySuite", Ordered, ContinueOnFailure, func() {
var s MySuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range mySuiteTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
#. Notice the loop - it will generate multiple ``It`` nodes, each running a different test.
``test := test`` is necessary, otherwise only the last test in a suite will run.
For a more detailed description, check Ginkgo's documentation: https://onsi.github.io/ginkgo/#dynamically-generating-specs\.
#. ``funcValue.Name()`` returns the full name of a function (e.g. ``fd.io/hs-test.MyTest``), however, we only need the test name (``MyTest``).
#. To run certain tests solo, create a new slice that will only contain tests that have to run solo and a new register function.
Add a ``Serial`` decorator to the container node and ``Label("SOLO")`` to the ``It`` subject node:
::
var _ = Describe("MySuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
...
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
})
#. Next step is to add test cases to the suite. For that, see section `Adding a test case`_ above
@ -186,14 +250,9 @@ Alternatively copy the executable from host system to the Docker image, similarl
**Skipping tests**
``HstSuite`` provides several methods that can be called in tests for skipping it conditionally or unconditionally such as:
``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``.
``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``. You can also use Ginkgo's ``Skip()``.
However the tests currently run under test suites which set up topology and containers before actual test is run. For the reason of saving
test run time it is not advisable to use aforementioned skip methods and instead prefix test name with ``Skip``:
::
func (s *MySuite) SkipTest(){
test run time it is not advisable to use aforementioned skip methods and instead, just don't register the test.
**Debugging a test**
@ -201,11 +260,11 @@ It is possible to debug VPP by attaching ``gdb`` before test execution by adding
::
$ make test TEST=TestVeths/TestLDPreloadIperfVpp DEBUG=true
$ make test TEST=LDPreloadIperfVppTest DEBUG=true
...
run following command in different terminal:
docker exec -it server-vpp gdb -ex "attach $(docker exec server-vpp pidof vpp)"
Afterwards press CTRL+C to continue
docker exec -it server-vpp2456109 gdb -ex "attach $(docker exec server-vpp2456109 pidof vpp)"
Afterwards press CTRL+\ to continue
If a test consists of more VPP instances then this is done for each of them.
@ -223,8 +282,38 @@ Generally, these will be updated on a per-need basis, for example when a bug is
or a new version incompatibility issue occurs.
.. _testing: https://pkg.go.dev/testing
.. _go test: https://pkg.go.dev/cmd/go#hdr-Test_packages
.. _test suite: https://github.com/stretchr/testify#suite-package
.. _ginkgo: https://onsi.github.io/ginkgo/
.. _volumes: https://docs.docker.com/storage/volumes/
**List of tests**
.. _list of tests:
Please update this list whenever you add a new test by pasting the output below.
* NsSuite/HttpTpsTest
* NsSuite/VppProxyHttpTcpTest
* NsSuite/VppProxyHttpTlsTest
* NsSuite/EnvoyProxyHttpTcpTest
* NginxSuite/MirroringTest
* VethsSuiteSolo TcpWithLossTest [SOLO]
* NoTopoSuiteSolo HttpStaticPromTest [SOLO]
* TapSuite/LinuxIperfTest
* NoTopoSuite/NginxHttp3Test
* NoTopoSuite/NginxAsServerTest
* NoTopoSuite/NginxPerfCpsTest
* NoTopoSuite/NginxPerfRpsTest
* NoTopoSuite/NginxPerfWrkTest
* VethsSuite/EchoBuiltinTest
* VethsSuite/HttpCliTest
* VethsSuite/LDPreloadIperfVppTest
* VethsSuite/VppEchoQuicTest
* VethsSuite/VppEchoTcpTest
* VethsSuite/VppEchoUdpTest
* VethsSuite/XEchoVclClientUdpTest
* VethsSuite/XEchoVclClientTcpTest
* VethsSuite/XEchoVclServerUdpTest
* VethsSuite/XEchoVclServerTcpTest
* VethsSuite/VclEchoTcpTest
* VethsSuite/VclEchoUdpTest
* VethsSuite/VclRetryAttachTest

View File

@ -12,7 +12,7 @@ import (
type AddressCounter = int
type Ip4AddressAllocator struct {
networks map[int]AddressCounter
networks map[int]AddressCounter
chosenOctet int
assignedIps []string
}
@ -47,7 +47,7 @@ func (a *Ip4AddressAllocator) NewIp4InterfaceAddress(inputNetworkNumber ...int)
// Creates a file every time an IP is assigned: used to keep track of addresses in use.
// If an address is not in use, 'counter' is then copied to 'chosenOctet' and it is used for the remaining tests.
// Also checks host IP addresses.
func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error){
func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) {
hostIps, _ := exechelper.CombinedOutput("ip a")
counter := 10
var address string
@ -56,7 +56,7 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
if a.chosenOctet != 0 {
address = fmt.Sprintf("10.%v.%v.%v", a.chosenOctet, networkNumber, numberOfAddresses)
file, err := os.Create(address)
if err != nil{
if err != nil {
return "", errors.New("unable to create file: " + fmt.Sprint(err))
}
file.Close()
@ -68,14 +68,14 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
counter++
} else if os.IsNotExist(err) {
file, err := os.Create(address)
if err != nil{
if err != nil {
return "", errors.New("unable to create file: " + fmt.Sprint(err))
}
}
file.Close()
a.chosenOctet = counter
break
} else {
return "", errors.New("an error occured while checking if a file exists: " + fmt.Sprint(err))
return "", errors.New("an error occurred while checking if a file exists: " + fmt.Sprint(err))
}
}
}
@ -84,8 +84,8 @@ func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddress
return address, nil
}
func (a *Ip4AddressAllocator) deleteIpAddresses(){
for ip := range a.assignedIps{
func (a *Ip4AddressAllocator) deleteIpAddresses() {
for ip := range a.assignedIps {
os.Remove(a.assignedIps[ip])
}
}

View File

@ -9,6 +9,7 @@ import (
"time"
"github.com/edwarnicke/exechelper"
. "github.com/onsi/ginkgo/v2"
)
const (
@ -38,7 +39,7 @@ type Container struct {
vppInstance *VppInstance
}
func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Container, error) {
func newContainer(suite *HstSuite, yamlInput ContainerConfig) (*Container, error) {
containerName := yamlInput["name"].(string)
if len(containerName) == 0 {
err := fmt.Errorf("container name must not be blank")
@ -48,7 +49,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont
var container = new(Container)
container.volumes = make(map[string]Volume)
container.envVars = make(map[string]string)
container.name = containerName + pid
container.name = containerName
container.suite = suite
if image, ok := yamlInput["image"]; ok {
@ -76,7 +77,7 @@ func newContainer(suite *HstSuite, yamlInput ContainerConfig, pid string) (*Cont
}
if _, ok := yamlInput["volumes"]; ok {
workingVolumeDir := logDir + container.suite.T().Name() + pid + volumeDir
workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + container.suite.pid + volumeDir
workDirReplacer := strings.NewReplacer("$HST_DIR", workDir)
volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir)
for _, volu := range yamlInput["volumes"].([]interface{}) {
@ -249,7 +250,7 @@ func (c *Container) copy(sourceFileName string, targetFileName string) error {
}
func (c *Container) createFile(destFileName string, content string) error {
f, err := os.CreateTemp("/tmp", "hst-config" + c.suite.pid)
f, err := os.CreateTemp("/tmp", "hst-config"+c.suite.pid)
if err != nil {
return err
}
@ -273,7 +274,7 @@ func (c *Container) execServer(command string, arguments ...any) {
serverCommand := fmt.Sprintf(command, arguments...)
containerExecCommand := "docker exec -d" + c.getEnvVarsAsCliOption() +
" " + c.name + " " + serverCommand
c.suite.T().Helper()
GinkgoHelper()
c.suite.log(containerExecCommand)
c.suite.assertNil(exechelper.Run(containerExecCommand))
}
@ -282,7 +283,7 @@ func (c *Container) exec(command string, arguments ...any) string {
cliCommand := fmt.Sprintf(command, arguments...)
containerExecCommand := "docker exec" + c.getEnvVarsAsCliOption() +
" " + c.name + " " + cliCommand
c.suite.T().Helper()
GinkgoHelper()
c.suite.log(containerExecCommand)
byteOutput, err := exechelper.CombinedOutput(containerExecCommand)
c.suite.assertNil(err, err)
@ -291,12 +292,12 @@ func (c *Container) exec(command string, arguments ...any) string {
func (c *Container) getLogDirPath() string {
testId := c.suite.getTestId()
testName := c.suite.T().Name()
testName := CurrentSpecReport().LeafNodeText
logDirPath := logDir + testName + "/" + testId + "/"
cmd := exec.Command("mkdir", "-p", logDirPath)
if err := cmd.Run(); err != nil {
c.suite.T().Fatalf("mkdir error: %v", err)
Fail("mkdir error: " + fmt.Sprint(err))
}
return logDirPath
@ -313,12 +314,12 @@ func (c *Container) saveLogs() {
cmd = exec.Command("docker", "logs", "--details", "-t", c.name)
output, err := cmd.CombinedOutput()
if err != nil {
c.suite.T().Fatalf("fetching logs error: %v", err)
Fail("fetching logs error: " + fmt.Sprint(err))
}
f, err := os.Create(testLogFilePath)
if err != nil {
c.suite.T().Fatalf("file create error: %v", err)
Fail("file create error: " + fmt.Sprint(err))
}
fmt.Fprint(f, string(output))
f.Close()

View File

@ -36,7 +36,7 @@ func (c *CpuAllocatorT) Allocate(nCpus int) (*CpuContext, error) {
return &cpuCtx, nil
}
func (c *CpuAllocatorT) readCpus(fname string) error {
func (c *CpuAllocatorT) readCpus() error {
var first, last int
file, err := os.Open(CPU_PATH)
if err != nil {
@ -60,7 +60,7 @@ func (c *CpuAllocatorT) readCpus(fname string) error {
func CpuAllocator() (*CpuAllocatorT, error) {
if cpuAllocator == nil {
cpuAllocator = new(CpuAllocatorT)
err := cpuAllocator.readCpus(CPU_PATH)
err := cpuAllocator.readCpus()
if err != nil {
return nil, err
}

View File

@ -16,6 +16,7 @@ COPY \
$DIR/unittest_plugin.so \
$DIR/quic_plugin.so \
$DIR/http_static_plugin.so \
$DIR/ping_plugin.so \
$DIR/prom_plugin.so \
$DIR/tlsopenssl_plugin.so \
/usr/lib/x86_64-linux-gnu/vpp_plugins/

View File

@ -1,6 +1,11 @@
package main
func (s *VethsSuite) TestEchoBuiltin() {
func init() {
registerVethTests(EchoBuiltinTest)
registerSoloVethTests(TcpWithLossTest)
}
func EchoBuiltinTest(s *VethsSuite) {
serverVpp := s.getContainerByName("server-vpp").vppInstance
serverVeth := s.getInterfaceByName(serverInterfaceName)
@ -16,7 +21,7 @@ func (s *VethsSuite) TestEchoBuiltin() {
s.assertNotContains(o, "failed:")
}
func (s *VethsSuite) TestTcpWithLoss() {
func TcpWithLossTest(s *VethsSuite) {
serverVpp := s.getContainerByName("server-vpp").vppInstance
serverVeth := s.getInterfaceByName(serverInterfaceName)
@ -25,9 +30,12 @@ func (s *VethsSuite) TestTcpWithLoss() {
clientVpp := s.getContainerByName("client-vpp").vppInstance
// TODO: investigate why this ping was here:
// ---------
// Ensure that VPP doesn't abort itself with NSIM enabled
// Warning: Removing this ping will make the test fail!
clientVpp.vppctl("ping %s", serverVeth.ip4AddressString())
// clientVpp.vppctl("ping %s", serverVeth.ip4AddressString())
// ---------
// Add loss of packets with Network Delay Simulator
clientVpp.vppctl("set nsim poll-main-thread delay 0.01 ms bandwidth 40 gbit" +

View File

@ -3,30 +3,11 @@ package main
import (
"testing"
"github.com/stretchr/testify/suite"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestTapSuite(t *testing.T) {
var m TapSuite
suite.Run(t, &m)
}
func TestNs(t *testing.T) {
var m NsSuite
suite.Run(t, &m)
}
func TestVeths(t *testing.T) {
var m VethsSuite
suite.Run(t, &m)
}
func TestNoTopo(t *testing.T) {
var m NoTopoSuite
suite.Run(t, &m)
}
func TestNginx(t *testing.T) {
var m NginxSuite
suite.Run(t, &m)
func TestHst(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "HST")
}

View File

@ -4,19 +4,28 @@ go 1.21
require (
github.com/edwarnicke/exechelper v1.0.3
github.com/stretchr/testify v1.8.4
go.fd.io/govpp v0.9.0
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.17.0 // indirect
)
require (
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
github.com/onsi/ginkgo/v2 v2.16.0
github.com/onsi/gomega v1.30.0
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/sys v0.16.0 // indirect

View File

@ -1,3 +1,6 @@
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@ -6,10 +9,19 @@ github.com/edwarnicke/exechelper v1.0.3 h1:OY2ocGAITTqnEDvZk0dRQSeMIQvyH0SyL/4nc
github.com/edwarnicke/exechelper v1.0.3/go.mod h1:R65OUPKns4bgeHkCmfSHbmqLBU8aHZxTgLmEyUBUk4U=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -18,6 +30,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc=
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg=
github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM=
github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -28,22 +42,27 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
go.fd.io/govpp v0.9.0 h1:EHUXhQ+dph2K2An4YMqmd/WBE3Fcqsg97KVmdLJoSoU=
go.fd.io/govpp v0.9.0/go.mod h1:9QoqjEbvfuuXNfjHS0A7YS+7QQVVaQ9cMioOWpSM4rY=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -5,14 +5,15 @@ import (
"errors"
"flag"
"fmt"
"log/slog"
"os"
"os/exec"
"strings"
"time"
"github.com/edwarnicke/exechelper"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"gopkg.in/yaml.v3"
)
@ -28,7 +29,6 @@ var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
var vppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory")
type HstSuite struct {
suite.Suite
containers map[string]*Container
volumes []string
netConfigs []NetConfig
@ -38,7 +38,7 @@ type HstSuite struct {
cpuAllocator *CpuAllocatorT
cpuContexts []*CpuContext
cpuPerVpp int
pid string
pid string
}
func (s *HstSuite) SetupSuite() {
@ -46,7 +46,7 @@ func (s *HstSuite) SetupSuite() {
s.pid = fmt.Sprint(os.Getpid())
s.cpuAllocator, err = CpuAllocator()
if err != nil {
s.FailNow("failed to init cpu allocator: %v", err)
Fail("failed to init cpu allocator: " + fmt.Sprint(err))
}
s.cpuPerVpp = *nConfiguredCpus
}
@ -85,6 +85,10 @@ func (s *HstSuite) skipIfUnconfiguring() {
}
func (s *HstSuite) SetupTest() {
RegisterFailHandler(func(message string, callerSkip ...int) {
s.hstFail()
Fail(message, callerSkip...)
})
s.skipIfUnconfiguring()
s.setupVolumes()
s.setupContainers()
@ -106,15 +110,15 @@ func (s *HstSuite) setupContainers() {
}
}
func logVppInstance(container *Container, maxLines int){
if container.vppInstance == nil{
func logVppInstance(container *Container, maxLines int) {
if container.vppInstance == nil {
return
}
logSource := container.getHostWorkDir() + defaultLogFilePath
file, err := os.Open(logSource)
if err != nil{
if err != nil {
return
}
defer file.Close()
@ -123,7 +127,7 @@ func logVppInstance(container *Container, maxLines int){
var lines []string
var counter int
for scanner.Scan(){
for scanner.Scan() {
lines = append(lines, scanner.Text())
counter++
if counter > maxLines {
@ -133,7 +137,7 @@ func logVppInstance(container *Container, maxLines int){
}
fmt.Println("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:")
for _, line := range lines{
for _, line := range lines {
fmt.Println(line)
}
fmt.Printf("^^^^^^^^^^^^^^^\n\n")
@ -141,73 +145,56 @@ func logVppInstance(container *Container, maxLines int){
func (s *HstSuite) hstFail() {
fmt.Println("Containers: " + fmt.Sprint(s.containers))
for _, container := range s.containers{
for _, container := range s.containers {
out, err := container.log(20)
if err != nil{
if err != nil {
fmt.Printf("An error occured while obtaining '%s' container logs: %s\n", container.name, fmt.Sprint(err))
break
}
fmt.Printf("\nvvvvvvvvvvvvvvv " +
container.name + ":\n" +
out +
"^^^^^^^^^^^^^^^\n\n")
container.name + ":\n" +
out +
"^^^^^^^^^^^^^^^\n\n")
logVppInstance(container, 20)
}
s.T().FailNow()
}
func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
if !assert.Nil(s.T(), object, msgAndArgs...) {
s.hstFail()
}
Expect(object).To(BeNil(), msgAndArgs...)
}
func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
if !assert.NotNil(s.T(), object, msgAndArgs...) {
s.hstFail()
}
Expect(object).ToNot(BeNil(), msgAndArgs...)
}
func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
s.hstFail()
}
Expect(actual).To(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
s.hstFail()
}
Expect(actual).ToNot(Equal(expected), msgAndArgs...)
}
func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
s.hstFail()
}
Expect(testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
s.hstFail()
}
Expect(testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
}
func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
s.hstFail()
}
Expect(object).ToNot(BeEmpty(), msgAndArgs...)
}
func (s *HstSuite) log(args ...any) {
func (s *HstSuite) log(arg any) {
if *isVerbose {
s.T().Helper()
s.T().Log(args...)
slog.Info(fmt.Sprint(arg))
}
}
func (s *HstSuite) skip(args ...any) {
s.log(args...)
s.T().SkipNow()
func (s *HstSuite) skip(args string) {
Skip(args)
}
func (s *HstSuite) SkipIfMultiWorker(args ...any) {
@ -249,11 +236,11 @@ func (s *HstSuite) getNetNamespaceByName(name string) string {
}
func (s *HstSuite) getInterfaceByName(name string) *NetInterface {
return s.netInterfaces[name + s.pid]
return s.netInterfaces[name+s.pid]
}
func (s *HstSuite) getContainerByName(name string) *Container {
return s.containers[name + s.pid]
return s.containers[name+s.pid]
}
/*
@ -261,25 +248,25 @@ func (s *HstSuite) getContainerByName(name string) *Container {
* are not able to modify the original container and affect other tests by doing that
*/
func (s *HstSuite) getTransientContainerByName(name string) *Container {
containerCopy := *s.containers[name + s.pid]
containerCopy := *s.containers[name+s.pid]
return &containerCopy
}
func (s *HstSuite) loadContainerTopology(topologyName string) {
data, err := os.ReadFile(containerTopologyDir + topologyName + ".yaml")
if err != nil {
s.T().Fatalf("read error: %v", err)
Fail("read error: " + fmt.Sprint(err))
}
var yamlTopo YamlTopology
err = yaml.Unmarshal(data, &yamlTopo)
if err != nil {
s.T().Fatalf("unmarshal error: %v", err)
Fail("unmarshal error: " + fmt.Sprint(err))
}
for _, elem := range yamlTopo.Volumes {
volumeMap := elem["volume"].(VolumeConfig)
hostDir := volumeMap["host-dir"].(string)
workingVolumeDir := logDir + s.T().Name() + s.pid + volumeDir
workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + s.pid + volumeDir
volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir)
hostDir = volDirReplacer.Replace(hostDir)
s.volumes = append(s.volumes, hostDir)
@ -287,10 +274,11 @@ func (s *HstSuite) loadContainerTopology(topologyName string) {
s.containers = make(map[string]*Container)
for _, elem := range yamlTopo.Containers {
newContainer, err := newContainer(s, elem, s.pid)
newContainer, err := newContainer(s, elem)
newContainer.suite = s
newContainer.name += newContainer.suite.pid
if err != nil {
s.T().Fatalf("container config error: %v", err)
Fail("container config error: " + fmt.Sprint(err))
}
s.containers[newContainer.name] = newContainer
}
@ -299,12 +287,12 @@ func (s *HstSuite) loadContainerTopology(topologyName string) {
func (s *HstSuite) loadNetworkTopology(topologyName string) {
data, err := os.ReadFile(networkTopologyDir + topologyName + ".yaml")
if err != nil {
s.T().Fatalf("read error: %v", err)
Fail("read error: " + fmt.Sprint(err))
}
var yamlTopo YamlTopology
err = yaml.Unmarshal(data, &yamlTopo)
if err != nil {
s.T().Fatalf("unmarshal error: %v", err)
Fail("unmarshal error: " + fmt.Sprint(err))
}
s.ip4AddrAllocator = NewIp4AddressAllocator()
@ -316,10 +304,10 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
}
if peer, ok := elem["peer"].(NetDevConfig); ok {
if peer["name"].(string) != ""{
if peer["name"].(string) != "" {
peer["name"] = peer["name"].(string) + s.pid
}
if _, ok := peer["netns"]; ok{
if _, ok := peer["netns"]; ok {
peer["netns"] = peer["netns"].(string) + s.pid
}
}
@ -341,7 +329,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
if namespace, err := newNetNamespace(elem); err == nil {
s.netConfigs = append(s.netConfigs, &namespace)
} else {
s.T().Fatalf("network config error: %v", err)
Fail("network config error: " + fmt.Sprint(err))
}
}
case Veth, Tap:
@ -350,7 +338,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
s.netConfigs = append(s.netConfigs, netIf)
s.netInterfaces[netIf.Name()] = netIf
} else {
s.T().Fatalf("network config error: %v", err)
Fail("network config error: " + fmt.Sprint(err))
}
}
case Bridge:
@ -358,7 +346,7 @@ func (s *HstSuite) loadNetworkTopology(topologyName string) {
if bridge, err := newBridge(elem); err == nil {
s.netConfigs = append(s.netConfigs, &bridge)
} else {
s.T().Fatalf("network config error: %v", err)
Fail("network config error: " + fmt.Sprint(err))
}
}
}
@ -374,7 +362,7 @@ func (s *HstSuite) configureNetworkTopology(topologyName string) {
for _, nc := range s.netConfigs {
if err := nc.configure(); err != nil {
s.T().Fatalf("network config error: %v", err)
Fail("Network config error: " + fmt.Sprint(err))
}
}
}
@ -389,7 +377,7 @@ func (s *HstSuite) unconfigureNetworkTopology() {
}
func (s *HstSuite) getTestId() string {
testName := s.T().Name()
testName := CurrentSpecReport().LeafNodeText
if s.testIds == nil {
s.testIds = map[string]string{}

View File

@ -4,9 +4,20 @@ import (
"fmt"
"os"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
func (s *NsSuite) TestHttpTps() {
func init() {
registerNsTests(HttpTpsTest)
registerVethTests(HttpCliTest)
registerNoTopoTests(NginxHttp3Test, NginxAsServerTest,
NginxPerfCpsTest, NginxPerfRpsTest, NginxPerfWrkTest)
registerNoTopoSoloTests(HttpStaticPromTest)
}
func HttpTpsTest(s *NsSuite) {
iface := s.getInterfaceByName(clientInterface)
client_ip := iface.ip4AddressString()
port := "8080"
@ -18,13 +29,16 @@ func (s *NsSuite) TestHttpTps() {
// configure vpp in the container
container.vppInstance.vppctl("http tps uri tcp://0.0.0.0/8080")
go s.startWget(finished, client_ip, port, "test_file_10M", clientNetns)
go func() {
defer GinkgoRecover()
s.startWget(finished, client_ip, port, "test_file_10M", clientNetns)
}()
// wait for client
err := <-finished
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
}
func (s *VethsSuite) TestHttpCli() {
func HttpCliTest(s *VethsSuite) {
serverContainer := s.getContainerByName("server-vpp")
clientContainer := s.getContainerByName("client-vpp")
@ -41,7 +55,7 @@ func (s *VethsSuite) TestHttpCli() {
s.assertContains(o, "<html>", "<html> not found in the result!")
}
func (s *NoTopoSuite) TestNginxHttp3() {
func NginxHttp3Test(s *NoTopoSuite) {
s.SkipUnlessExtendedTestsBuilt()
query := "index.html"
@ -57,23 +71,27 @@ func (s *NoTopoSuite) TestNginxHttp3() {
args := fmt.Sprintf("curl --noproxy '*' --local-port 55444 --http3-only -k https://%s:8443/%s", serverAddress, query)
curlCont.extraRunningArgs = args
o, err := curlCont.combinedOutput()
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.assertContains(o, "<http>", "<http> not found in the result!")
}
func (s *NoTopoSuite) TestHttpStaticProm() {
func HttpStaticPromTest(s *NoTopoSuite) {
finished := make(chan error, 1)
query := "stats.prom"
vpp := s.getContainerByName("vpp").vppInstance
serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
s.log(vpp.vppctl("http static server uri tcp://" + serverAddress + "/80 url-handlers"))
s.log(vpp.vppctl("prom enable"))
go s.startWget(finished, serverAddress, "80", query, "")
time.Sleep(time.Second * 5)
go func() {
defer GinkgoRecover()
s.startWget(finished, serverAddress, "80", query, "")
}()
err := <-finished
s.assertNil(err, err)
s.assertNil(err)
}
func (s *NoTopoSuite) TestNginxAsServer() {
func NginxAsServerTest(s *NoTopoSuite) {
query := "return_ok"
finished := make(chan error, 1)
@ -86,7 +104,10 @@ func (s *NoTopoSuite) TestNginxAsServer() {
serverAddress := s.getInterfaceByName(tapInterfaceName).peer.ip4AddressString()
defer func() { os.Remove(query) }()
go s.startWget(finished, serverAddress, "80", query, "")
go func() {
defer GinkgoRecover()
s.startWget(finished, serverAddress, "80", query, "")
}()
s.assertNil(<-finished)
}
@ -124,9 +145,11 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
args += " -r"
args += " http://" + serverAddress + ":80/64B.json"
abCont.extraRunningArgs = args
time.Sleep(time.Second * 10)
o, err := abCont.combinedOutput()
rps := parseString(o, "Requests per second:")
s.log(rps, err)
s.log(rps)
s.log(err)
s.assertNil(err, "err: '%s', output: '%s'", err, o)
} else {
wrkCont := s.getContainerByName("wrk")
@ -135,20 +158,21 @@ func runNginxPerf(s *NoTopoSuite, mode, ab_or_wrk string) error {
wrkCont.extraRunningArgs = args
o, err := wrkCont.combinedOutput()
rps := parseString(o, "requests")
s.log(rps, err)
s.log(rps)
s.log(err)
s.assertNil(err, "err: '%s', output: '%s'", err, o)
}
return nil
}
func (s *NoTopoSuite) TestNginxPerfCps() {
func NginxPerfCpsTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "cps", "ab"))
}
func (s *NoTopoSuite) TestNginxPerfRps() {
func NginxPerfRpsTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "rps", "ab"))
}
func (s *NoTopoSuite) TestNginxPerfWrk() {
func NginxPerfWrkTest(s *NoTopoSuite) {
s.assertNil(runNginxPerf(s, "", "wrk"))
}

View File

@ -3,9 +3,15 @@ package main
import (
"fmt"
"os"
. "github.com/onsi/ginkgo/v2"
)
func (s *VethsSuite) TestLDPreloadIperfVpp() {
func init() {
registerVethTests(LDPreloadIperfVppTest)
}
func LDPreloadIperfVppTest(s *VethsSuite) {
var clnVclConf, srvVclConf Stanza
serverContainer := s.getContainerByName("server-vpp")
@ -14,10 +20,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
clientContainer := s.getContainerByName("client-vpp")
clientVclFileName := clientContainer.getHostWorkDir() + "/vcl_cln.conf"
ldpreload := os.Getenv("HST_LDPRELOAD")
s.assertNotEqual("", ldpreload)
ldpreload = "LD_PRELOAD=" + ldpreload
ldpreload := "LD_PRELOAD=../../build-root/build-vpp-native/vpp/lib/x86_64-linux-gnu/libvcl_ldpreload.so"
stopServerCh := make(chan struct{}, 1)
srvCh := make(chan error, 1)
@ -36,7 +39,7 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
append("use-mq-eventfd").
append(clientAppSocketApi).close().
saveToFile(clientVclFileName)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
serverAppSocketApi := fmt.Sprintf("app-socket-api %s/var/run/app_ns_sockets/default",
serverContainer.getHostWorkDir())
@ -49,26 +52,32 @@ func (s *VethsSuite) TestLDPreloadIperfVpp() {
append("use-mq-eventfd").
append(serverAppSocketApi).close().
saveToFile(serverVclFileName)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.log("attaching server to vpp")
srvEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+serverVclFileName)
go s.startServerApp(srvCh, stopServerCh, srvEnv)
go func() {
defer GinkgoRecover()
s.startServerApp(srvCh, stopServerCh, srvEnv)
}()
err = <-srvCh
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.log("attaching client to vpp")
var clnRes = make(chan string, 1)
clnEnv := append(os.Environ(), ldpreload, "VCL_CONFIG="+clientVclFileName)
serverVethAddress := s.getInterfaceByName(serverInterfaceName).ip4AddressString()
go s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
go func() {
defer GinkgoRecover()
s.startClientApp(serverVethAddress, clnEnv, clnCh, clnRes)
}()
s.log(<-clnRes)
// wait for client's result
err = <-clnCh
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
// stop server
stopServerCh <- struct{}{}

View File

@ -1,6 +1,16 @@
package main
func (s *TapSuite) TestLinuxIperf() {
import (
"fmt"
. "github.com/onsi/ginkgo/v2"
)
func init() {
registerTapTests(LinuxIperfTest)
}
func LinuxIperfTest(s *TapSuite) {
clnCh := make(chan error)
stopServerCh := make(chan struct{})
srvCh := make(chan error, 1)
@ -9,13 +19,19 @@ func (s *TapSuite) TestLinuxIperf() {
stopServerCh <- struct{}{}
}()
go s.startServerApp(srvCh, stopServerCh, nil)
go func() {
defer GinkgoRecover()
s.startServerApp(srvCh, stopServerCh, nil)
}()
err := <-srvCh
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.log("server running")
ipAddress := s.getInterfaceByName(tapInterfaceName).ip4AddressString()
go s.startClientApp(ipAddress, nil, clnCh, clnRes)
go func() {
defer GinkgoRecover()
s.startClientApp(ipAddress, nil, clnCh, clnRes)
}()
s.log("client running")
s.log(<-clnRes)
err = <-clnCh

View File

@ -4,7 +4,11 @@ import (
"github.com/edwarnicke/exechelper"
)
func (s *NginxSuite) TestMirroring() {
func init() {
registerNginxTests(MirroringTest)
}
func MirroringTest(s *NginxSuite) {
proxyAddress := s.getInterfaceByName(mirroringClientInterfaceName).peer.ip4AddressString()
path := "/64B.json"

View File

@ -5,8 +5,13 @@ import (
"os"
"github.com/edwarnicke/exechelper"
. "github.com/onsi/ginkgo/v2"
)
func init() {
registerNsTests(VppProxyHttpTcpTest, VppProxyHttpTlsTest, EnvoyProxyHttpTcpTest)
}
func testProxyHttpTcp(s *NsSuite, proto string) error {
var outputFile string = "test" + s.pid + ".data"
var srcFilePid string = "httpTestFile" + s.pid
@ -19,12 +24,15 @@ func testProxyHttpTcp(s *NsSuite, proto string) error {
// create test file
err := exechelper.Run(fmt.Sprintf("ip netns exec %s truncate -s %s %s", serverNetns, fileSize, srcFilePid))
s.assertNil(err, "failed to run truncate command: " + fmt.Sprint(err))
s.assertNil(err, "failed to run truncate command: "+fmt.Sprint(err))
defer func() { os.Remove(srcFilePid) }()
s.log("test file created...")
go s.startHttpServer(serverRunning, stopServer, ":666", serverNetns)
go func() {
defer GinkgoRecover()
s.startHttpServer(serverRunning, stopServer, ":666", serverNetns)
}()
// TODO better error handling and recovery
<-serverRunning
@ -64,21 +72,21 @@ func configureVppProxy(s *NsSuite, proto string) {
clientVeth.ip4AddressString(),
serverVeth.peer.ip4AddressString(),
)
s.log("proxy configured...", output)
s.log("proxy configured: " + output)
}
func (s *NsSuite) TestVppProxyHttpTcp() {
func VppProxyHttpTcpTest(s *NsSuite) {
proto := "tcp"
configureVppProxy(s, proto)
err := testProxyHttpTcp(s, proto)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
}
func (s *NsSuite) TestVppProxyHttpTls() {
func VppProxyHttpTlsTest(s *NsSuite) {
proto := "tls"
configureVppProxy(s, proto)
err := testProxyHttpTcp(s, proto)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
}
func configureEnvoyProxy(s *NsSuite) {
@ -100,8 +108,8 @@ func configureEnvoyProxy(s *NsSuite) {
s.assertNil(envoyContainer.start())
}
func (s *NsSuite) TestEnvoyProxyHttpTcp() {
func EnvoyProxyHttpTcpTest(s *NsSuite) {
configureEnvoyProxy(s)
err := testProxyHttpTcp(s, "tcp")
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
}

View File

@ -1,15 +1,20 @@
package main
func (s *VethsSuite) TestVppEchoQuic() {
func init() {
registerVethTests(VppEchoQuicTest, VppEchoTcpTest, VppEchoUdpTest)
}
func VppEchoQuicTest(s *VethsSuite) {
s.testVppEcho("quic")
}
// udp echo currently broken in vpp, skipping
func (s *VethsSuite) SkipTestVppEchoUdp() {
func VppEchoUdpTest(s *VethsSuite) {
s.skip("Broken")
s.testVppEcho("udp")
}
func (s *VethsSuite) TestVppEchoTcp() {
func VppEchoTcpTest(s *VethsSuite) {
s.testVppEcho("tcp")
}

View File

@ -1,18 +1,37 @@
package main
import (
"reflect"
"runtime"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
// These correspond to names used in yaml config
const (
vppProxyContainerName = "vpp-proxy"
nginxProxyContainerName = "nginx-proxy"
nginxServerContainerName = "nginx-server"
vppProxyContainerName = "vpp-proxy"
nginxProxyContainerName = "nginx-proxy"
nginxServerContainerName = "nginx-server"
mirroringClientInterfaceName = "hstcln"
mirroringServerInterfaceName = "hstsrv"
)
var nginxTests = []func(s *NginxSuite){}
var nginxSoloTests = []func(s *NginxSuite){}
type NginxSuite struct {
HstSuite
}
func registerNginxTests(tests ...func(s *NginxSuite)) {
nginxTests = append(nginxTests, tests...)
}
func registerNginxSoloTests(tests ...func(s *NginxSuite)) {
nginxSoloTests = append(nginxSoloTests, tests...)
}
func (s *NginxSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.loadNetworkTopology("2taps")
@ -60,3 +79,51 @@ func (s *NginxSuite) SetupTest() {
proxyVpp.waitForApp("nginx-", 5)
}
var _ = Describe("NginxSuite", Ordered, ContinueOnFailure, func() {
var s NginxSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range nginxTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
var _ = Describe("NginxSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
var s NginxSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range nginxSoloTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})

View File

@ -1,15 +1,34 @@
package main
const (
singleTopoContainerVpp = "vpp"
singleTopoContainerNginx = "nginx"
tapInterfaceName = "htaphost"
import (
"reflect"
"runtime"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
const (
singleTopoContainerVpp = "vpp"
singleTopoContainerNginx = "nginx"
tapInterfaceName = "htaphost"
)
var noTopoTests = []func(s *NoTopoSuite){}
var noTopoSoloTests = []func(s *NoTopoSuite){}
type NoTopoSuite struct {
HstSuite
}
func registerNoTopoTests(tests ...func(s *NoTopoSuite)) {
noTopoTests = append(noTopoTests, tests...)
}
func registerNoTopoSoloTests(tests ...func(s *NoTopoSuite)) {
noTopoSoloTests = append(noTopoSoloTests, tests...)
}
func (s *NoTopoSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.loadNetworkTopology("tap")
@ -35,3 +54,53 @@ func (s *NoTopoSuite) SetupTest() {
s.assertNil(vpp.createTap(tapInterface), "failed to create tap interface")
}
var _ = Describe("NoTopoSuite", Ordered, ContinueOnFailure, func() {
var s NoTopoSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range noTopoTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
var _ = Describe("NoTopoSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
var s NoTopoSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range noTopoSoloTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})

View File

@ -1,15 +1,35 @@
package main
import (
"fmt"
"reflect"
"runtime"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
// These correspond to names used in yaml config
const (
clientInterface = "hclnvpp"
serverInterface = "hsrvvpp"
)
var nsTests = []func(s *NsSuite){}
var nsSoloTests = []func(s *NsSuite){}
type NsSuite struct {
HstSuite
}
func registerNsTests(tests ...func(s *NsSuite)) {
nsTests = append(nsTests, tests...)
}
func registerNsSoloTests(tests ...func(s *NsSuite)) {
nsSoloTests = append(nsSoloTests, tests...)
}
func (s *NsSuite) SetupSuite() {
s.HstSuite.SetupSuite()
s.configureNetworkTopology("ns")
@ -34,12 +54,62 @@ func (s *NsSuite) SetupTest() {
s.assertNil(vpp.start())
idx, err := vpp.createAfPacket(s.getInterfaceByName(serverInterface))
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
idx, err = vpp.createAfPacket(s.getInterfaceByName(clientInterface))
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
container.exec("chmod 777 -R %s", container.getContainerWorkDir())
}
var _ = Describe("NsSuite", Ordered, ContinueOnFailure, func() {
var s NsSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range nsTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
var _ = Describe("NsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
var s NsSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range nsSoloTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})

View File

@ -1,15 +1,80 @@
package main
import (
"reflect"
"runtime"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
type TapSuite struct {
HstSuite
}
var tapTests = []func(s *TapSuite){}
var tapSoloTests = []func(s *TapSuite){}
func registerTapTests(tests ...func(s *TapSuite)) {
tapTests = append(tapTests, tests...)
}
func registerTapSoloTests(tests ...func(s *TapSuite)) {
tapSoloTests = append(tapSoloTests, tests...)
}
func (s *TapSuite) SetupSuite() {
time.Sleep(1 * time.Second)
s.HstSuite.SetupSuite()
s.configureNetworkTopology("tap")
}
var _ = Describe("TapSuite", Ordered, ContinueOnFailure, func() {
var s TapSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range tapTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
var _ = Describe("TapSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
var s TapSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
for _, test := range tapSoloTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})

View File

@ -1,7 +1,13 @@
package main
import (
"fmt"
"reflect"
"runtime"
"strings"
"time"
. "github.com/onsi/ginkgo/v2"
)
// These correspond to names used in yaml config
@ -10,10 +16,20 @@ const (
clientInterfaceName = "cln"
)
var vethTests = []func(s *VethsSuite){}
var vethSoloTests = []func(s *VethsSuite){}
type VethsSuite struct {
HstSuite
}
func registerVethTests(tests ...func(s *VethsSuite)) {
vethTests = append(vethTests, tests...)
}
func registerSoloVethTests(tests ...func(s *VethsSuite)) {
vethSoloTests = append(vethSoloTests, tests...)
}
func (s *VethsSuite) SetupSuite() {
time.Sleep(1 * time.Second)
s.HstSuite.SetupSuite()
@ -36,7 +52,7 @@ func (s *VethsSuite) SetupTest() {
cpus := s.AllocateCpus()
serverVpp, err := serverContainer.newVppInstance(cpus, sessionConfig)
s.assertNotNil(serverVpp, err)
s.assertNotNil(serverVpp, fmt.Sprint(err))
s.setupServerVpp()
@ -45,7 +61,7 @@ func (s *VethsSuite) SetupTest() {
cpus = s.AllocateCpus()
clientVpp, err := clientContainer.newVppInstance(cpus, sessionConfig)
s.assertNotNil(clientVpp, err)
s.assertNotNil(clientVpp, fmt.Sprint(err))
s.setupClientVpp()
}
@ -56,7 +72,7 @@ func (s *VethsSuite) setupServerVpp() {
serverVeth := s.getInterfaceByName(serverInterfaceName)
idx, err := serverVpp.createAfPacket(serverVeth)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
}
@ -66,6 +82,60 @@ func (s *VethsSuite) setupClientVpp() {
clientVeth := s.getInterfaceByName(clientInterfaceName)
idx, err := clientVpp.createAfPacket(clientVeth)
s.assertNil(err, err)
s.assertNil(err, fmt.Sprint(err))
s.assertNotEqual(0, idx)
}
var _ = Describe("VethsSuite", Ordered, ContinueOnFailure, func() {
var s VethsSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
// https://onsi.github.io/ginkgo/#dynamically-generating-specs
for _, test := range vethTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})
var _ = Describe("VethsSuiteSolo", Ordered, ContinueOnFailure, Serial, func() {
var s VethsSuite
BeforeAll(func() {
s.SetupSuite()
})
BeforeEach(func() {
s.SetupTest()
})
AfterAll(func() {
s.TearDownSuite()
})
AfterEach(func() {
s.TearDownTest()
})
// https://onsi.github.io/ginkgo/#dynamically-generating-specs
for _, test := range vethSoloTests {
test := test
pc := reflect.ValueOf(test).Pointer()
funcValue := runtime.FuncForPC(pc)
It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) {
test(&s)
}, SpecTimeout(time.Minute*5))
}
})

View File

@ -8,6 +8,8 @@ persist_set=0
unconfigure_set=0
debug_set=0
vppsrc=
ginkgo_args=
parallel=
for i in "$@"
do
@ -49,8 +51,14 @@ case "${i}" in
tc_name="${i#*=}"
if [ $tc_name != "all" ]; then
single_test=1
args="$args -run $tc_name -verbose"
ginkgo_args="$ginkgo_args --focus $tc_name -vv"
args="$args -verbose"
else
ginkgo_args="$ginkgo_args -v"
fi
;;
--parallel=*)
ginkgo_args="$ginkgo_args -procs=${i#*=}"
esac
done
@ -74,4 +82,4 @@ if [ $single_test -eq 0 ] && [ $debug_set -eq 1 ]; then
exit 1
fi
sudo -E go test -timeout=20m -buildvcs=false -v $args
sudo -E go run github.com/onsi/ginkgo/v2/ginkgo --trace $ginkgo_args -- $args

View File

@ -5,6 +5,11 @@ import (
"time"
)
func init() {
registerVethTests(XEchoVclClientUdpTest, XEchoVclClientTcpTest, XEchoVclServerUdpTest,
XEchoVclServerTcpTest, VclEchoTcpTest, VclEchoUdpTest, VclRetryAttachTest)
}
func getVclConfig(c *Container, ns_id_optional ...string) string {
var s Stanza
ns_id := "default"
@ -23,11 +28,11 @@ func getVclConfig(c *Container, ns_id_optional ...string) string {
return s.close().toString()
}
func (s *VethsSuite) TestXEchoVclClientUdp() {
func XEchoVclClientUdpTest(s *VethsSuite) {
s.testXEchoVclClient("udp")
}
func (s *VethsSuite) TestXEchoVclClientTcp() {
func XEchoVclClientTcpTest(s *VethsSuite) {
s.testXEchoVclClient("tcp")
}
@ -49,11 +54,11 @@ func (s *VethsSuite) testXEchoVclClient(proto string) {
s.assertContains(o, "CLIENT RESULTS")
}
func (s *VethsSuite) TestXEchoVclServerUdp() {
func XEchoVclServerUdpTest(s *VethsSuite) {
s.testXEchoVclServer("udp")
}
func (s *VethsSuite) TestXEchoVclServerTcp() {
func XEchoVclServerTcpTest(s *VethsSuite) {
s.testXEchoVclServer("tcp")
}
@ -97,16 +102,15 @@ func (s *VethsSuite) testVclEcho(proto string) {
s.log(o)
}
func (s *VethsSuite) TestVclEchoTcp() {
func VclEchoTcpTest(s *VethsSuite) {
s.testVclEcho("tcp")
}
func (s *VethsSuite) TestVclEchoUdp() {
func VclEchoUdpTest(s *VethsSuite) {
s.testVclEcho("udp")
}
// this test takes too long, for now it's being skipped
func (s *VethsSuite) SkipTestVclRetryAttach() {
func VclRetryAttachTest(s *VethsSuite) {
s.testRetryAttach("tcp")
}

View File

@ -11,6 +11,7 @@ import (
"time"
"github.com/edwarnicke/exechelper"
. "github.com/onsi/ginkgo/v2"
"go.fd.io/govpp"
"go.fd.io/govpp/api"
@ -59,6 +60,7 @@ plugins {
plugin http_static_plugin.so { enable }
plugin prom_plugin.so { enable }
plugin tlsopenssl_plugin.so { enable }
plugin ping_plugin.so { enable }
}
logging {
@ -131,9 +133,10 @@ func (vpp *VppInstance) start() error {
vpp.container.createFile(vppcliFileName, cliContent)
vpp.container.exec("chmod 0755 " + vppcliFileName)
vpp.getSuite().log("starting vpp")
if *isVppDebug {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT)
signal.Notify(sig, syscall.SIGQUIT)
cont := make(chan bool, 1)
go func() {
<-sig
@ -143,7 +146,7 @@ func (vpp *VppInstance) start() error {
vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
fmt.Println("run following command in different terminal:")
fmt.Println("docker exec -it " + vpp.container.name + " gdb -ex \"attach $(docker exec " + vpp.container.name + " pidof vpp)\"")
fmt.Println("Afterwards press CTRL+C to continue")
fmt.Println("Afterwards press CTRL+\\ to continue")
<-cont
fmt.Println("continuing...")
} else {
@ -151,6 +154,7 @@ func (vpp *VppInstance) start() error {
vpp.container.execServer("su -c \"vpp -c " + startupFileName + " &> /proc/1/fd/1\"")
}
vpp.getSuite().log("connecting to vpp")
// Connect to VPP and store the connection
sockAddress := vpp.container.getHostWorkDir() + defaultApiSocketFilePath
conn, connEv, err := govpp.AsyncConnect(
@ -207,7 +211,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int {
tokens := strings.Split(strings.TrimSpace(line), " ")
val, err := strconv.Atoi(tokens[0])
if err != nil {
vpp.getSuite().FailNow("failed to parse stat value %s", err)
Fail("failed to parse stat value %s" + fmt.Sprint(err))
return 0
}
return val
@ -217,6 +221,7 @@ func (vpp *VppInstance) GetSessionStat(stat string) int {
}
func (vpp *VppInstance) waitForApp(appName string, timeout int) {
vpp.getSuite().log("waiting for app " + appName)
for i := 0; i < timeout; i++ {
o := vpp.vppctl("show app")
if strings.Contains(o, appName) {
@ -240,6 +245,7 @@ func (vpp *VppInstance) createAfPacket(
}
createReply := &af_packet.AfPacketCreateV2Reply{}
vpp.getSuite().log("create af-packet interface " + veth.Name())
if err := vpp.apiChannel.SendRequest(createReq).ReceiveReply(createReply); err != nil {
return 0, err
}
@ -252,6 +258,7 @@ func (vpp *VppInstance) createAfPacket(
}
upReply := &interfaces.SwInterfaceSetFlagsReply{}
vpp.getSuite().log("set af-packet interface " + veth.Name() + " up")
if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil {
return 0, err
}
@ -273,6 +280,7 @@ func (vpp *VppInstance) createAfPacket(
}
addressReply := &interfaces.SwInterfaceAddDelAddressReply{}
vpp.getSuite().log("af-packet interface " + veth.Name() + " add address " + veth.ip4Address)
if err := vpp.apiChannel.SendRequest(addressReq).ReceiveReply(addressReply); err != nil {
return 0, err
}
@ -292,6 +300,7 @@ func (vpp *VppInstance) addAppNamespace(
}
reply := &session.AppNamespaceAddDelV2Reply{}
vpp.getSuite().log("add app namespace " + namespaceId)
if err := vpp.apiChannel.SendRequest(req).ReceiveReply(reply); err != nil {
return err
}
@ -301,6 +310,7 @@ func (vpp *VppInstance) addAppNamespace(
}
sessionReply := &session.SessionEnableDisableReply{}
vpp.getSuite().log("enable app namespace " + namespaceId)
if err := vpp.apiChannel.SendRequest(sessionReq).ReceiveReply(sessionReply); err != nil {
return err
}
@ -325,6 +335,7 @@ func (vpp *VppInstance) createTap(
}
createTapReply := &tapv2.TapCreateV2Reply{}
vpp.getSuite().log("create tap interface " + tap.Name())
// Create tap interface
if err := vpp.apiChannel.SendRequest(createTapReq).ReceiveReply(createTapReply); err != nil {
return err
@ -338,6 +349,7 @@ func (vpp *VppInstance) createTap(
}
addAddressReply := &interfaces.SwInterfaceAddDelAddressReply{}
vpp.getSuite().log("tap interface " + tap.Name() + " add address " + tap.peer.ip4Address)
if err := vpp.apiChannel.SendRequest(addAddressReq).ReceiveReply(addAddressReply); err != nil {
return err
}
@ -349,6 +361,7 @@ func (vpp *VppInstance) createTap(
}
upReply := &interfaces.SwInterfaceSetFlagsReply{}
vpp.getSuite().log("set tap interface " + tap.Name() + " up")
if err := vpp.apiChannel.SendRequest(upReq).ReceiveReply(upReply); err != nil {
return err
}
@ -360,7 +373,6 @@ func (vpp *VppInstance) saveLogs() {
logTarget := vpp.container.getLogDirPath() + "vppinstance-" + vpp.container.name + ".log"
logSource := vpp.container.getHostWorkDir() + defaultLogFilePath
cmd := exec.Command("cp", logSource, logTarget)
vpp.getSuite().T().Helper()
vpp.getSuite().log(cmd.String())
cmd.Run()
}