test_quic.py revision 1063f2ae
1#!/usr/bin/env python3
2""" Vpp QUIC tests """
3
4import unittest
5import os
6import subprocess
7import signal
8from framework import VppTestCase, VppTestRunner, running_extended_tests, \
9    Worker
10from vpp_ip_route import VppIpTable, VppIpRoute, VppRoutePath
11
12
13class QUICAppWorker(Worker):
14    """ QUIC Test Application Worker """
15    process = None
16
17    def __init__(self, build_dir, appname, args, logger, role, testcase,
18                 env={}):
19        app = "%s/vpp/bin/%s" % (build_dir, appname)
20        self.args = [app] + args
21        self.role = role
22        self.wait_for_gdb = 'wait-for-gdb'
23        self.testcase = testcase
24        super(QUICAppWorker, self).__init__(self.args, logger, env)
25
26    def run(self):
27        super(QUICAppWorker, self).run()
28
29    def teardown(self, logger, timeout):
30        if self.process is None:
31            return False
32        try:
33            logger.debug("Killing worker process (pid %d)" % self.process.pid)
34            os.killpg(os.getpgid(self.process.pid), signal.SIGKILL)
35            self.join(timeout)
36        except OSError as e:
37            logger.debug("Couldn't kill worker process")
38            return True
39        return False
40
41
42class QUICTestCase(VppTestCase):
43    """ QUIC Test Case """
44
45    timeout = 20
46    pre_test_sleep = 0.3
47    post_test_sleep = 0.2
48
49    @classmethod
50    def setUpClass(cls):
51        cls.extra_vpp_plugin_config.append("plugin quic_plugin.so { enable }")
52        super(QUICTestCase, cls).setUpClass()
53
54    def setUp(self):
55        super(QUICTestCase, self).setUp()
56        var = "VPP_BUILD_DIR"
57        self.build_dir = os.getenv(var, None)
58        if self.build_dir is None:
59            raise Exception("Environment variable `%s' not set" % var)
60        self.vppDebug = 'vpp_debug' in self.build_dir
61        self.vapi.session_enable_disable(is_enabled=1)
62
63        self.create_loopback_interfaces(2)
64        self.uri = "quic://%s/1234" % self.loop0.local_ip4
65        table_id = 1
66        for i in self.lo_interfaces:
67            i.admin_up()
68
69            if table_id != 0:
70                tbl = VppIpTable(self, table_id)
71                tbl.add_vpp_config()
72
73            i.set_table_ip4(table_id)
74            i.config_ip4()
75            table_id += 1
76
77        # Configure namespaces
78        self.vapi.app_namespace_add_del(namespace_id=b"server",
79                                        sw_if_index=self.loop0.sw_if_index)
80        self.vapi.app_namespace_add_del(namespace_id=b"client",
81                                        sw_if_index=self.loop1.sw_if_index)
82
83        # Add inter-table routes
84        self.ip_t01 = VppIpRoute(self, self.loop1.local_ip4, 32,
85                                 [VppRoutePath("0.0.0.0",
86                                               0xffffffff,
87                                               nh_table_id=2)], table_id=1)
88        self.ip_t10 = VppIpRoute(self, self.loop0.local_ip4, 32,
89                                 [VppRoutePath("0.0.0.0",
90                                               0xffffffff,
91                                               nh_table_id=1)], table_id=2)
92        self.ip_t01.add_vpp_config()
93        self.ip_t10.add_vpp_config()
94        self.logger.debug(self.vapi.cli("show ip fib"))
95
96    def tearDown(self):
97        self.vapi.session_enable_disable(is_enabled=0)
98        # Delete inter-table routes
99        self.ip_t01.remove_vpp_config()
100        self.ip_t10.remove_vpp_config()
101
102        for i in self.lo_interfaces:
103            i.unconfig_ip4()
104            i.set_table_ip4(0)
105            i.admin_down()
106        super(QUICTestCase, self).tearDown()
107
108
109class QUICEchoIntTestCase(QUICTestCase):
110    """QUIC Echo Internal Test Case"""
111    test_bytes = ' test-bytes'
112
113    def setUp(self):
114        super(QUICEchoIntTestCase, self).setUp()
115        self.client_args = 'uri {uri} fifo-size 64{testbytes} appns client' \
116            .format(uri=self.uri, testbytes=self.test_bytes)
117        self.server_args = "uri %s fifo-size 64 appns server" % self.uri
118
119    def server(self, *args):
120        error = self.vapi.cli(
121            "test echo server %s %s" %
122            (self.server_args, ' '.join(args)))
123        if error:
124            self.logger.critical(error)
125            self.assertNotIn("failed", error)
126
127    def client(self, *args):
128        error = self.vapi.cli(
129            "test echo client %s %s" %
130            (self.client_args, ' '.join(args)))
131        if error:
132            self.logger.critical(error)
133            self.assertNotIn("failed", error)
134
135
136class QUICEchoIntTransferTestCase(QUICEchoIntTestCase):
137    """QUIC Echo Internal Transfer Test Case"""
138    def test_quic_int_transfer(self):
139        self.server()
140        self.client("no-output", "mbytes", "2")
141
142
143class QUICEchoIntTransferBigTestCase(QUICEchoIntTestCase):
144    """QUIC Echo Internal Transfer Big Test Case"""
145    test_bytes = ''
146
147    @unittest.skipUnless(running_extended_tests, "part of extended tests")
148    def test_quic_int_transfer_big(self):
149        self.server()
150        self.client("no-output", "gbytes", "10")
151
152
153class QUICEchoIntSerialTestCase(QUICEchoIntTestCase):
154    """QUIC Echo Internal Serial Transfer Test Case"""
155    def test_quic_serial_int_transfer(self):
156        self.server()
157        self.client("no-output", "mbytes", "2")
158        self.client("no-output", "mbytes", "2")
159        self.client("no-output", "mbytes", "2")
160        self.client("no-output", "mbytes", "2")
161        self.client("no-output", "mbytes", "2")
162
163
164class QUICEchoIntSerialBigTestCase(QUICEchoIntTestCase):
165    """QUIC Echo Internal Serial Transfer Big Test Case"""
166
167    @unittest.skipUnless(running_extended_tests, "part of extended tests")
168    def test_quic_serial_int_transfer_big(self):
169        self.server()
170        self.client("no-output", "gbytes", "5")
171        self.client("no-output", "gbytes", "5")
172        self.client("no-output", "gbytes", "5")
173        self.client("no-output", "gbytes", "5")
174        self.client("no-output", "gbytes", "5")
175
176
177class QUICEchoIntMStreamTestCase(QUICEchoIntTestCase):
178    """QUIC Echo Internal MultiStream Test Case"""
179    def test_quic_int_multistream_transfer(self):
180        self.server()
181        self.client("nclients", "10", "mbytes", "1", "no-output")
182
183
184class QUICEchoIntMStreamBigTestCase(QUICEchoIntTestCase):
185    """QUIC Echo Internal MultiStream Big Test Case"""
186
187    @unittest.skipUnless(running_extended_tests, "part of extended tests")
188    def test_quic_int_multistream_transfer(self):
189        self.server()
190        self.client("nclients", "10", "gbytes", "5", "no-output")
191
192
193class QUICEchoExtTestCase(QUICTestCase):
194    extra_vpp_punt_config = ["session", "{", "evt_qs_memfd_seg", "}"]
195    quic_setup = "default"
196    test_bytes = "test-bytes:assert"
197    app = "vpp_echo"
198
199    def setUp(self):
200        super(QUICEchoExtTestCase, self).setUp()
201        common_args = [
202            "uri",
203            self.uri,
204            "json",
205            self.test_bytes,
206            "socket-name", self.api_sock,
207            "quic-setup", self.quic_setup]
208        self.server_echo_test_args = common_args + \
209            ["server", "appns", "server"]  # use default fifo-size
210        self.client_echo_test_args = common_args + \
211            ["client", "appns", "client", "fifo-size", "4M"]
212        error = self.vapi.cli("quic set fifo-size 2M")
213        if error:
214            self.logger.critical(error)
215            self.assertNotIn("failed", error)
216
217    def server(self, *args):
218        _args = self.server_echo_test_args + list(args)
219        self.worker_server = QUICAppWorker(
220            self.build_dir,
221            self.app,
222            _args,
223            self.logger,
224            'server',
225            self)
226        self.worker_server.start()
227        self.sleep(self.pre_test_sleep)
228
229    def client(self, *args):
230        _args = self.client_echo_test_args + list(args)
231        self.worker_client = QUICAppWorker(
232            self.build_dir,
233            self.app,
234            _args,
235            self.logger,
236            'client',
237            self)
238        self.worker_client.start()
239        timeout = None if self.debug_all else self.timeout
240        self.worker_client.join(timeout)
241        self.worker_server.join(timeout)
242        self.sleep(self.post_test_sleep)
243
244    def validate_ext_test_results(self):
245        server_result = self.worker_server.result
246        client_result = self.worker_client.result
247        self.logger.info("Server worker result is `%s'" %
248                         server_result)
249        self.logger.info("Client worker result is `%s'" %
250                         client_result)
251        server_kill_error = False
252        if self.worker_server.result is None:
253            server_kill_error = self.worker_server.teardown(
254                self.logger, self.timeout)
255        if self.worker_client.result is None:
256            self.worker_client.teardown(self.logger, self.timeout)
257        err_msg = "Wrong server worker return code (%s)" % server_result
258        self.assertEqual(server_result, 0, err_msg)
259        self.assertIsNotNone(
260            client_result,
261            "Timeout! Client worker did not finish in %ss" %
262            self.timeout)
263        err_msg = "Wrong client worker return code (%s)" % client_result
264        self.assertEqual(client_result, 0, err_msg)
265        self.assertFalse(server_kill_error, "Server kill errored")
266
267
268class QUICEchoExtTransferTestCase(QUICEchoExtTestCase):
269    """QUIC Echo External Transfer Test Case"""
270    timeout = 60
271
272    def test_quic_ext_transfer(self):
273        self.server()
274        self.client()
275        self.validate_ext_test_results()
276
277
278class QUICEchoExtTransferBigTestCase(QUICEchoExtTestCase):
279    """QUIC Echo External Transfer Big Test Case"""
280    test_bytes = ''
281    timeout = 60
282
283    @unittest.skipUnless(running_extended_tests, "part of extended tests")
284    def test_quic_ext_transfer_big(self):
285        self.server("TX=0", "RX=10Gb")
286        self.client("TX=10Gb", "RX=0")
287        self.validate_ext_test_results()
288
289
290class QUICEchoExtQcloseRxTestCase(QUICEchoExtTestCase):
291    """QUIC Echo External Transfer Qclose Rx Test Case"""
292
293    @unittest.skipUnless(running_extended_tests, "part of extended tests")
294    def test_quic_ext_qclose_rx(self):
295        self.server("TX=0", "RX=10Mb", "qclose=Y", "sclose=N")
296        self.client("TX=10Mb", "RX=0", "qclose=W", "sclose=W")
297        self.validate_ext_test_results()
298
299
300class QUICEchoExtQcloseTxTestCase(QUICEchoExtTestCase):
301    """QUIC Echo External Transfer Qclose Tx Test Case"""
302
303    @unittest.skipUnless(running_extended_tests, "part of extended tests")
304    def test_quic_ext_qclose_tx(self):
305        self.server("TX=0", "RX=10Mb", "qclose=W", "sclose=W",
306                    "rx-results-diff")
307        self.client("TX=10Mb", "RX=0", "qclose=Y", "sclose=N")
308        self.validate_ext_test_results()
309
310
311class QUICEchoExtEarlyQcloseRxTestCase(QUICEchoExtTestCase):
312    """QUIC Echo External Transfer Early Qclose Rx Test Case"""
313
314    @unittest.skipUnless(running_extended_tests, "part of extended tests")
315    def test_quic_ext_early_qclose_rx(self):
316        self.server("TX=0", "RX=10Mb", "qclose=Y", "sclose=N")
317        self.client("TX=20Mb", "RX=0", "qclose=W", "sclose=W",
318                    "tx-results-diff")
319        self.validate_ext_test_results()
320
321
322class QUICEchoExtEarlyQcloseTxTestCase(QUICEchoExtTestCase):
323    """QUIC Echo External Transfer Early Qclose Tx Test Case"""
324
325    @unittest.skipUnless(running_extended_tests, "part of extended tests")
326    def test_quic_ext_early_qclose_tx(self):
327        self.server("TX=0", "RX=20Mb", "qclose=W", "sclose=W",
328                    "rx-results-diff")
329        self.client("TX=10Mb", "RX=0", "qclose=Y", "sclose=N")
330        self.validate_ext_test_results()
331
332
333class QUICEchoExtScloseRxTestCase(QUICEchoExtTestCase):
334    """QUIC Echo External Transfer Sclose Rx Test Case"""
335
336    @unittest.skipUnless(running_extended_tests, "part of extended tests")
337    def test_quic_ext_sclose_rx(self):
338        self.server("TX=0", "RX=10Mb", "qclose=N", "sclose=Y")
339        self.client("TX=10Mb", "RX=0", "qclose=W", "sclose=W")
340        self.validate_ext_test_results()
341
342
343class QUICEchoExtScloseTxTestCase(QUICEchoExtTestCase):
344    """QUIC Echo External Transfer Sclose Tx Test Case"""
345
346    @unittest.skipUnless(running_extended_tests, "part of extended tests")
347    def test_quic_ext_sclose_tx(self):
348        self.server("TX=0", "RX=10Mb", "qclose=W", "sclose=W")
349        self.client("TX=10Mb", "RX=0", "qclose=Y", "sclose=Y")
350        self.validate_ext_test_results()
351
352
353class QUICEchoExtEarlyScloseRxTestCase(QUICEchoExtTestCase):
354    """QUIC Echo External Transfer Early Sclose Rx Test Case"""
355
356    @unittest.skipUnless(running_extended_tests, "part of extended tests")
357    def test_quic_ext_early_sclose_rx(self):
358        self.server("TX=0", "RX=10Mb", "qclose=N", "sclose=Y")
359        self.client("TX=20Mb", "RX=0", "qclose=W", "sclose=W",
360                    "tx-results-diff")
361        self.validate_ext_test_results()
362
363
364class QUICEchoExtEarlyScloseTxTestCase(QUICEchoExtTestCase):
365    """QUIC Echo External Transfer Early Sclose Tx Test Case"""
366
367    @unittest.skipUnless(running_extended_tests, "part of extended tests")
368    def test_quic_ext_early_sclose_tx(self):
369        self.server("TX=0", "RX=20Mb", "qclose=W", "sclose=W",
370                    "rx-results-diff")
371        self.client("TX=10Mb", "RX=0", "qclose=Y", "sclose=Y")
372        self.validate_ext_test_results()
373
374
375class QUICEchoExtServerStreamTestCase(QUICEchoExtTestCase):
376    """QUIC Echo External Transfer Server Stream Test Case"""
377    quic_setup = "serverstream"
378
379    def test_quic_ext_transfer_server_stream(self):
380        self.server("TX=10Mb", "RX=0")
381        self.client("TX=0", "RX=10Mb")
382        self.validate_ext_test_results()
383
384
385class QUICEchoExtBigServerStreamTestCase(QUICEchoExtTestCase):
386    """QUIC Echo External Transfer Big Server Stream Test Case"""
387    quic_setup = "serverstream"
388    test_bytes = ''
389
390    @unittest.skipUnless(running_extended_tests, "part of extended tests")
391    def test_quic_ext_transfer_big_server_stream(self):
392        self.server("TX=10Gb", "RX=0")
393        self.client("TX=0", "RX=10Gb")
394        self.validate_ext_test_results()
395
396
397class QUICEchoExtServerStreamQcloseRxTestCase(QUICEchoExtTestCase):
398    """QUIC Echo External Transfer Server Stream Qclose Rx Test Case"""
399    quic_setup = "serverstream"
400
401    @unittest.skipUnless(running_extended_tests, "part of extended tests")
402    def test_quic_ext_server_stream_qclose_rx(self):
403        self.server("TX=10Mb", "RX=0", "qclose=W", "sclose=W")
404        self.client("TX=0", "RX=10Mb", "qclose=Y", "sclose=N")
405        self.validate_ext_test_results()
406
407
408class QUICEchoExtServerStreamQcloseTxTestCase(QUICEchoExtTestCase):
409    """QUIC Echo External Transfer Server Stream Qclose Tx Test Case"""
410    quic_setup = "serverstream"
411
412    @unittest.skipUnless(running_extended_tests, "part of extended tests")
413    def test_quic_ext_server_stream_qclose_tx(self):
414        self.server("TX=10Mb", "RX=0", "qclose=Y", "sclose=N")
415        self.client("TX=0", "RX=10Mb", "qclose=W", "sclose=W",
416                    "rx-results-diff")
417        self.validate_ext_test_results()
418
419
420class QUICEchoExtServerStreamEarlyQcloseRxTestCase(QUICEchoExtTestCase):
421    """QUIC Echo External Transfer Server Stream Early Qclose Rx Test Case"""
422    quic_setup = "serverstream"
423
424    @unittest.skipUnless(running_extended_tests, "part of extended tests")
425    def test_quic_ext_server_stream_early_qclose_rx(self):
426        self.server("TX=20Mb", "RX=0", "qclose=W", "sclose=W",
427                    "tx-results-diff")
428        self.client("TX=0", "RX=10Mb", "qclose=Y", "sclose=N")
429        self.validate_ext_test_results()
430
431
432class QUICEchoExtServerStreamEarlyQcloseTxTestCase(QUICEchoExtTestCase):
433    """QUIC Echo External Transfer Server Stream Early Qclose Tx Test Case"""
434    quic_setup = "serverstream"
435
436    @unittest.skipUnless(running_extended_tests, "part of extended tests")
437    def test_quic_ext_server_stream_early_qclose_tx(self):
438        self.server("TX=10Mb", "RX=0", "qclose=Y", "sclose=N")
439        self.client("TX=0", "RX=20Mb", "qclose=W", "sclose=W",
440                    "rx-results-diff")
441        self.validate_ext_test_results()
442
443
444class QUICEchoExtServerStreamScloseRxTestCase(QUICEchoExtTestCase):
445    """QUIC Echo External Transfer Server Stream Sclose Rx Test Case"""
446    quic_setup = "serverstream"
447
448    @unittest.skipUnless(running_extended_tests, "part of extended tests")
449    def test_quic_ext_server_stream_sclose_rx(self):
450        self.server("TX=10Mb", "RX=0", "qclose=W", "sclose=W")
451        self.client("TX=0", "RX=10Mb", "qclose=N", "sclose=Y")
452        self.validate_ext_test_results()
453
454
455class QUICEchoExtServerStreamScloseTxTestCase(QUICEchoExtTestCase):
456    """QUIC Echo External Transfer Server Stream Sclose Tx Test Case"""
457    quic_setup = "serverstream"
458
459    @unittest.skipUnless(running_extended_tests, "part of extended tests")
460    def test_quic_ext_server_stream_sclose_tx(self):
461        self.server("TX=10Mb", "RX=0", "qclose=Y", "sclose=Y")
462        self.client("TX=0", "RX=10Mb", "qclose=W", "sclose=W")
463        self.validate_ext_test_results()
464
465
466class QUICEchoExtServerStreamEarlyScloseRxTestCase(QUICEchoExtTestCase):
467    """QUIC Echo External Transfer Server Stream Early Sclose Rx Test Case"""
468    quic_setup = "serverstream"
469
470    @unittest.skipUnless(running_extended_tests, "part of extended tests")
471    def test_quic_ext_server_stream_early_sclose_rx(self):
472        self.server("TX=20Mb", "RX=0", "qclose=W", "sclose=W",
473                    "tx-results-diff")
474        self.client("TX=0", "RX=10Mb", "qclose=N", "sclose=Y")
475        self.validate_ext_test_results()
476
477
478class QUICEchoExtServerStreamEarlyScloseTxTestCase(QUICEchoExtTestCase):
479    """QUIC Echo Ext Transfer Server Stream Early Sclose Tx Test Case"""
480    quic_setup = "serverstream"
481
482    @unittest.skipUnless(running_extended_tests, "part of extended tests")
483    def test_quic_ext_server_stream_early_sclose_tx(self):
484        self.server("TX=10Mb", "RX=0", "qclose=Y", "sclose=Y")
485        self.client("TX=0", "RX=20Mb", "qclose=W", "sclose=W",
486                    "rx-results-diff")
487        self.validate_ext_test_results()
488
489
490class QUICEchoExtServerStreamWorkersTestCase(QUICEchoExtTestCase):
491    """QUIC Echo External Transfer Server Stream MultiWorker Test Case"""
492    quic_setup = "serverstream"
493
494    @unittest.skipUnless(running_extended_tests, "part of extended tests")
495    def test_quic_ext_transfer_server_stream_multi_workers(self):
496        self.server("nclients", "4", "quic-streams", "4", "TX=10Mb", "RX=0")
497        self.client("nclients", "4", "quic-streams", "4", "TX=0", "RX=10Mb")
498        self.validate_ext_test_results()
499
500
501if __name__ == '__main__':
502    unittest.main(testRunner=VppTestRunner)
503