Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 1 | Host stack test framework |
| 2 | ========================= |
| 3 | |
| 4 | Overview |
| 5 | -------- |
| 6 | |
| 7 | The goal of the Host stack test framework (**hs-test**) is to ease writing and running end-to-end tests for VPP's Host Stack. |
| 8 | End-to-end tests often want multiple VPP instances, network namespaces, different types of interfaces |
| 9 | and to execute external tools or commands. With such requirements the existing VPP test framework is not sufficient. |
| 10 | For this, ``Go`` was chosen as a high level language, allowing rapid development, with ``Docker`` and ``ip`` being the tools for creating required topology. |
| 11 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 12 | `Ginkgo`_ forms the base framework upon which the *hs-test* is built and run. |
| 13 | 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. |
| 14 | This allows us to run those mentioned groups in parallel, but not individual tests in parallel. |
| 15 | |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 16 | |
| 17 | Anatomy of a test case |
| 18 | ---------------------- |
| 19 | |
| 20 | **Prerequisites**: |
| 21 | |
Filip Tehlar | 671cf51 | 2023-01-31 10:34:18 +0100 | [diff] [blame] | 22 | * Install hs-test dependencies with ``make install-deps`` |
| 23 | * Tests use *hs-test*'s own docker image, so building it before starting tests is a prerequisite. Run ``make build[-debug]`` to do so |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 24 | * Docker has to be installed and Go has to be in path of both the running user and root |
| 25 | * Root privileges are required to run tests as it uses Linux ``ip`` command for configuring topology |
| 26 | |
| 27 | **Action flow when running a test case**: |
| 28 | |
Filip Tehlar | 671cf51 | 2023-01-31 10:34:18 +0100 | [diff] [blame] | 29 | #. It starts with running ``make test``. Optional arguments are VERBOSE, PERSIST (topology configuration isn't cleaned up after test run), |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 30 | TEST=<test-name> to run a specific test and PARALLEL=[n-cpus]. |
| 31 | #. ``make list-tests`` (or ``make help``) shows all tests. The current `list of tests`_ is at the bottom of this document. |
| 32 | #. ``Ginkgo`` looks for a spec suite in the current directory and then compiles it to a .test binary |
| 33 | #. The Ginkgo test framework runs each function that was registered manually using ``registerMySuiteTest(s *MySuite)``. Each of these functions correspond to a suite |
| 34 | #. Ginkgo's ``RunSpecs(t, "Suite description")`` function is the entry point and does the following: |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 35 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 36 | #. Ginkgo compiles the spec, builds a spec tree |
| 37 | #. ``Describe`` container nodes in suite\_\*_test.go files are run (in series by default, or in parallel with the argument PARALLEL=[n-cpus]) |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 38 | #. Suite is initialized. The topology is loaded and configured in this step |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 39 | #. Registered tests are run in generated ``It`` subject nodes |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 40 | #. Execute tear-down functions, which currently consists of stopping running containers |
| 41 | and clean-up of test topology |
| 42 | |
| 43 | Adding a test case |
| 44 | ------------------ |
| 45 | |
| 46 | This describes adding a new test case to an existing suite. |
| 47 | For adding a new suite, please see `Modifying the framework`_ below. |
| 48 | |
| 49 | #. To write a new test case, create a file whose name ends with ``_test.go`` or pick one that already exists |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 50 | #. Declare method whose name ends with ``Test`` and specifies its parameter as a pointer to the suite's struct (defined in ``suite_*_test.go``) |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 51 | #. Implement test behaviour inside the test method. This typically includes the following: |
| 52 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 53 | #. Retrieve a running container in which to run some action. Method ``getContainerByName`` |
| 54 | from ``HstSuite`` struct serves this purpose |
| 55 | #. Interact with VPP through the ``VppInstance`` struct embedded in container. It provides ``vppctl`` method to access debug CLI |
| 56 | #. Run arbitrary commands inside the containers with ``exec`` method |
| 57 | #. Run other external tool with one of the preexisting functions in the ``utils.go`` file. |
| 58 | For example, use ``wget`` with ``startWget`` function |
| 59 | #. Use ``exechelper`` or just plain ``exec`` packages to run whatever else |
| 60 | #. Verify results of your tests using ``assert`` methods provided by the test suite, implemented by HstSuite struct or use ``Gomega`` assert functions. |
| 61 | |
| 62 | #. Create an ``init()`` function and register the test using ``register*SuiteTests(testCaseFunction)`` |
| 63 | |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 64 | |
| 65 | **Example test case** |
| 66 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 67 | Assumed are two docker containers, each with its own VPP instance running. One VPP then pings the other. |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 68 | 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``. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 69 | |
| 70 | :: |
| 71 | |
| 72 | package main |
| 73 | |
| 74 | import ( |
| 75 | "fmt" |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 76 | ) |
| 77 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 78 | func init(){ |
| 79 | registerMySuiteTest(MyTest) |
| 80 | } |
| 81 | |
| 82 | func MyTest(s *MySuite) { |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 83 | clientVpp := s.getContainerByName("client-vpp").vppInstance |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 84 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 85 | serverVethAddress := s.netInterfaces["server-iface"].AddressString() |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 86 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 87 | result := clientVpp.vppctl("ping " + serverVethAddress) |
| 88 | s.assertNotNil(result) |
| 89 | s.log(result) |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 90 | } |
| 91 | |
| 92 | Modifying the framework |
| 93 | ----------------------- |
| 94 | |
| 95 | **Adding a test suite** |
| 96 | |
| 97 | .. _test-convention: |
| 98 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 99 | #. 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 |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 100 | by the actual name |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 101 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 102 | #. Make a ``struct``, in the suite file, with at least ``HstSuite`` struct as its member. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 103 | HstSuite provides functionality that can be shared for all suites, like starting containers |
| 104 | |
| 105 | :: |
| 106 | |
| 107 | type MySuite struct { |
| 108 | HstSuite |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 109 | } |
| 110 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 111 | #. Create a new slice that will contain test functions with a pointer to the suite's struct: ``var myTests = []func(s *MySuite){}`` |
| 112 | |
| 113 | #. Then create a new function that will append test functions to that slice: |
| 114 | |
| 115 | :: |
| 116 | |
| 117 | func registerMySuiteTests(tests ...func(s *MySuite)) { |
| 118 | nginxTests = append(myTests, tests...) |
| 119 | } |
| 120 | |
| 121 | #. In suite file, implement ``SetupSuite`` method which Ginkgo runs once before starting any of the tests. |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 122 | It's important here to call ``configureNetworkTopology`` method, |
| 123 | pass the topology name to the function in a form of file name of one of the *yaml* files in ``topo-network`` folder. |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 124 | Without the extension. In this example, *myTopology* corresponds to file ``extras/hs-test/topo-network/myTopology.yaml`` |
| 125 | This will ensure network topology, such as network interfaces and namespaces, will be created. |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 126 | Another important method to call is ``loadContainerTopology()`` which will load |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 127 | containers and shared volumes used by the suite. This time the name passed to method corresponds |
| 128 | to file in ``extras/hs-test/topo-containers`` folder |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 129 | |
| 130 | :: |
| 131 | |
| 132 | func (s *MySuite) SetupSuite() { |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 133 | s.HstSuite.SetupSuite() |
| 134 | |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 135 | // Add custom setup code here |
| 136 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 137 | s.configureNetworkTopology("myTopology") |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 138 | s.loadContainerTopology("2peerVeth") |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 139 | } |
| 140 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 141 | #. In suite file, implement ``SetupTest`` method which gets executed before each test. Starting containers and |
| 142 | configuring VPP is usually placed here |
| 143 | |
| 144 | :: |
| 145 | |
| 146 | func (s *MySuite) SetupTest() { |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 147 | s.HstSuite.setupTest() |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 148 | s.SetupVolumes() |
| 149 | s.SetupContainers() |
| 150 | } |
| 151 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 152 | #. In order for ``Ginkgo`` to run this suite, we need to create a ``Describe`` container node with setup nodes and an ``It`` subject node. |
| 153 | Place them at the end of the suite file |
| 154 | |
| 155 | * Declare a suite struct variable before anything else |
| 156 | * To use ``BeforeAll()`` and ``AfterAll()``, the container has to be marked as ``Ordered`` |
| 157 | * Because the container is now marked as Ordered, if a test fails, all the subsequent tests are skipped. |
| 158 | To override this behavior, decorate the container node with ``ContinueOnFailure`` |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 159 | |
| 160 | :: |
| 161 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 162 | var _ = Describe("MySuite", Ordered, ContinueOnFailure, func() { |
| 163 | var s MySuite |
| 164 | BeforeAll(func() { |
| 165 | s.SetupSuite() |
| 166 | }) |
| 167 | BeforeEach(func() { |
| 168 | s.SetupTest() |
| 169 | }) |
| 170 | AfterAll(func() { |
| 171 | s.TearDownSuite() |
| 172 | }) |
| 173 | AfterEach(func() { |
| 174 | s.TearDownTest() |
| 175 | }) |
| 176 | for _, test := range mySuiteTests { |
| 177 | test := test |
| 178 | pc := reflect.ValueOf(test).Pointer() |
| 179 | funcValue := runtime.FuncForPC(pc) |
| 180 | It(strings.Split(funcValue.Name(), ".")[2], func(ctx SpecContext) { |
| 181 | test(&s) |
| 182 | }, SpecTimeout(time.Minute*5)) |
| 183 | } |
| 184 | }) |
| 185 | |
| 186 | #. Notice the loop - it will generate multiple ``It`` nodes, each running a different test. |
| 187 | ``test := test`` is necessary, otherwise only the last test in a suite will run. |
| 188 | For a more detailed description, check Ginkgo's documentation: https://onsi.github.io/ginkgo/#dynamically-generating-specs\. |
| 189 | |
| 190 | #. ``funcValue.Name()`` returns the full name of a function (e.g. ``fd.io/hs-test.MyTest``), however, we only need the test name (``MyTest``). |
| 191 | |
| 192 | #. To run certain tests solo, create a new slice that will only contain tests that have to run solo and a new register function. |
| 193 | Add a ``Serial`` decorator to the container node and ``Label("SOLO")`` to the ``It`` subject node: |
| 194 | |
| 195 | :: |
| 196 | |
| 197 | var _ = Describe("MySuiteSolo", Ordered, ContinueOnFailure, Serial, func() { |
| 198 | ... |
| 199 | It(strings.Split(funcValue.Name(), ".")[2], Label("SOLO"), func(ctx SpecContext) { |
| 200 | test(&s) |
| 201 | }, SpecTimeout(time.Minute*5)) |
| 202 | }) |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 203 | |
| 204 | #. Next step is to add test cases to the suite. For that, see section `Adding a test case`_ above |
| 205 | |
| 206 | **Adding a topology element** |
| 207 | |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 208 | Topology configuration exists as ``yaml`` files in the ``extras/hs-test/topo-network`` and |
| 209 | ``extras/hs-test/topo-containers`` folders. Processing of a network topology file for a particular test suite |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 210 | is started by the ``configureNetworkTopology`` method depending on which file's name is passed to it. |
| 211 | Specified file is loaded and converted into internal data structures which represent various elements of the topology. |
| 212 | After parsing the configuration, framework loops over the elements and configures them one by one on the host system. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 213 | |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 214 | These are currently supported types of network elements. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 215 | |
| 216 | * ``netns`` - network namespace |
| 217 | * ``veth`` - veth network interface, optionally with target network namespace or IPv4 address |
| 218 | * ``bridge`` - ethernet bridge to connect created interfaces, optionally with target network namespace |
| 219 | * ``tap`` - tap network interface with IP address |
| 220 | |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 221 | Similarly, container topology is started by ``loadContainerTopology()``, configuration file is processed |
| 222 | so that test suite retains map of defined containers and uses that to start them at the beginning |
| 223 | of each test case and stop containers after the test finishes. Container configuration can specify |
| 224 | also volumes which allow to share data between containers or between host system and containers. |
| 225 | |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 226 | Supporting a new type of topology element requires adding code to recognize the new element type during loading. |
Maros Ondrejicka | db823ed | 2022-12-14 16:30:04 +0100 | [diff] [blame] | 227 | And adding code to set up the element in the host system with some Linux tool, such as *ip*. |
| 228 | This should be implemented in ``netconfig.go`` for network and in ``container.go`` for containers and volumes. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 229 | |
| 230 | **Communicating between containers** |
| 231 | |
| 232 | When two VPP instances or other applications, each in its own Docker container, |
| 233 | want to communicate there are typically two ways this can be done within *hs-test*. |
| 234 | |
| 235 | * Network interfaces. Containers are being created with ``-d --network host`` options, |
| 236 | so they are connected with interfaces created in host system |
| 237 | * Shared folders. Containers are being created with ``-v`` option to create shared `volumes`_ between host system and containers |
| 238 | or just between containers |
| 239 | |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 240 | Host system connects to VPP instances running in containers using a shared folder |
| 241 | where binary API socket is accessible by both sides. |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 242 | |
| 243 | **Adding an external tool** |
| 244 | |
| 245 | If an external program should be executed as part of a test case, it might be useful to wrap its execution in its own function. |
| 246 | These types of functions are placed in the ``utils.go`` file. If the external program is not available by default in Docker image, |
| 247 | add its installation to ``extras/hs-test/Dockerfile.vpp`` in ``apt-get install`` command. |
| 248 | Alternatively copy the executable from host system to the Docker image, similarly how the VPP executables and libraries are being copied. |
| 249 | |
Filip Tehlar | 9418143 | 2024-01-15 13:11:28 +0100 | [diff] [blame] | 250 | **Skipping tests** |
| 251 | |
| 252 | ``HstSuite`` provides several methods that can be called in tests for skipping it conditionally or unconditionally such as: |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 253 | ``skip()``, ``SkipIfMultiWorker()``, ``SkipUnlessExtendedTestsBuilt()``. You can also use Ginkgo's ``Skip()``. |
Filip Tehlar | 9418143 | 2024-01-15 13:11:28 +0100 | [diff] [blame] | 254 | However the tests currently run under test suites which set up topology and containers before actual test is run. For the reason of saving |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 255 | test run time it is not advisable to use aforementioned skip methods and instead, just don't register the test. |
Filip Tehlar | 9418143 | 2024-01-15 13:11:28 +0100 | [diff] [blame] | 256 | |
Filip Tehlar | f34b680 | 2024-01-24 15:11:27 +0100 | [diff] [blame] | 257 | **Debugging a test** |
| 258 | |
| 259 | It is possible to debug VPP by attaching ``gdb`` before test execution by adding ``DEBUG=true`` like follows: |
| 260 | |
| 261 | :: |
| 262 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 263 | $ make test TEST=LDPreloadIperfVppTest DEBUG=true |
Filip Tehlar | f34b680 | 2024-01-24 15:11:27 +0100 | [diff] [blame] | 264 | ... |
| 265 | run following command in different terminal: |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 266 | docker exec -it server-vpp2456109 gdb -ex "attach $(docker exec server-vpp2456109 pidof vpp)" |
| 267 | Afterwards press CTRL+\ to continue |
Filip Tehlar | f34b680 | 2024-01-24 15:11:27 +0100 | [diff] [blame] | 268 | |
| 269 | If a test consists of more VPP instances then this is done for each of them. |
| 270 | |
| 271 | |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 272 | **Eternal dependencies** |
| 273 | |
| 274 | * Linux tools ``ip``, ``brctl`` |
| 275 | * Standalone programs ``wget``, ``iperf3`` - since these are downloaded when Docker image is made, |
| 276 | they are reasonably up-to-date automatically |
Maros Ondrejicka | 56bfc63 | 2023-02-21 13:42:35 +0100 | [diff] [blame] | 277 | * Programs in Docker images - ``envoyproxy/envoy-contrib`` and ``nginx`` |
| 278 | * ``http_server`` - homegrown application that listens on specified port and sends a test file in response |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 279 | * Non-standard Go libraries - see ``extras/hs-test/go.mod`` |
| 280 | |
| 281 | Generally, these will be updated on a per-need basis, for example when a bug is discovered |
| 282 | or a new version incompatibility issue occurs. |
| 283 | |
| 284 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 285 | .. _ginkgo: https://onsi.github.io/ginkgo/ |
Maros Ondrejicka | 7943c90 | 2022-11-08 08:00:51 +0100 | [diff] [blame] | 286 | .. _volumes: https://docs.docker.com/storage/volumes/ |
| 287 | |
Adrian Villin | cee15aa | 2024-03-14 11:42:55 -0400 | [diff] [blame] | 288 | **List of tests** |
| 289 | |
| 290 | .. _list of tests: |
| 291 | |
| 292 | Please update this list whenever you add a new test by pasting the output below. |
| 293 | |
| 294 | * NsSuite/HttpTpsTest |
| 295 | * NsSuite/VppProxyHttpTcpTest |
| 296 | * NsSuite/VppProxyHttpTlsTest |
| 297 | * NsSuite/EnvoyProxyHttpTcpTest |
| 298 | * NginxSuite/MirroringTest |
| 299 | * VethsSuiteSolo TcpWithLossTest [SOLO] |
| 300 | * NoTopoSuiteSolo HttpStaticPromTest [SOLO] |
| 301 | * TapSuite/LinuxIperfTest |
| 302 | * NoTopoSuite/NginxHttp3Test |
| 303 | * NoTopoSuite/NginxAsServerTest |
| 304 | * NoTopoSuite/NginxPerfCpsTest |
| 305 | * NoTopoSuite/NginxPerfRpsTest |
| 306 | * NoTopoSuite/NginxPerfWrkTest |
| 307 | * VethsSuite/EchoBuiltinTest |
| 308 | * VethsSuite/HttpCliTest |
| 309 | * VethsSuite/LDPreloadIperfVppTest |
| 310 | * VethsSuite/VppEchoQuicTest |
| 311 | * VethsSuite/VppEchoTcpTest |
| 312 | * VethsSuite/VppEchoUdpTest |
| 313 | * VethsSuite/XEchoVclClientUdpTest |
| 314 | * VethsSuite/XEchoVclClientTcpTest |
| 315 | * VethsSuite/XEchoVclServerUdpTest |
| 316 | * VethsSuite/XEchoVclServerTcpTest |
| 317 | * VethsSuite/VclEchoTcpTest |
| 318 | * VethsSuite/VclEchoUdpTest |
| 319 | * VethsSuite/VclRetryAttachTest |