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