feat(tests): IPsecHW rxq ratio
[csit.git] / resources / libraries / python / autogen / Regenerator.py
1 # Copyright (c) 2024 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Module defining utilities for test directory regeneration.
15
16 TODO: How can we check each suite id is unique,
17       when currently the suite generation is run on each directory separately?
18 """
19
20 import copy
21 import sys
22
23 from glob import glob
24 from io import open
25 from os import getcwd
26
27
28 from resources.libraries.python.Constants import Constants
29 from resources.libraries.python.autogen.Testcase import Testcase
30
31
32 PROTOCOL_TO_MIN_FRAME_SIZE = {
33     u"ip4": 64,
34     u"ip6": 78,
35     u"ethip4vxlan": 114,  # What is the real minimum for latency stream?
36     u"dot1qip4vxlan": 118
37 }
38 MIN_FRAME_SIZE_VALUES = list(PROTOCOL_TO_MIN_FRAME_SIZE.values())
39
40
41 def replace_defensively(
42         whole, to_replace, replace_with, how_many, msg, in_filename):
43     """Replace substrings while checking the number of occurrences.
44
45     Return edited copy of the text. Assuming "whole" is really a string,
46     or something else with .replace not affecting it.
47
48     :param whole: The text to perform replacements on.
49     :param to_replace: Substring occurrences of which to replace.
50     :param replace_with: Substring to replace occurrences with.
51     :param how_many: Number of occurrences to expect.
52     :param msg: Error message to raise.
53     :param in_filename: File name in which the error occurred.
54     :type whole: str
55     :type to_replace: str
56     :type replace_with: str
57     :type how_many: int
58     :type msg: str
59     :type in_filename: str
60     :returns: The whole text after replacements are done.
61     :rtype: str
62     :raises ValueError: If number of occurrences does not match.
63     """
64     found = whole.count(to_replace)
65     if found != how_many:
66         raise ValueError(f"{in_filename}: {msg}")
67     return whole.replace(to_replace, replace_with)
68
69
70 def get_iface_and_suite_ids(filename):
71     """Get NIC code, suite ID and suite tag.
72
73     NIC code is the part of suite name
74     which should be replaced for other NIC.
75     Suite ID is the part os suite name
76     which is appended to test case names.
77     Suite tag is suite ID without both test type and NIC driver parts.
78
79     :param filename: Suite file.
80     :type filename: str
81     :returns: NIC code, suite ID, suite tag.
82     :rtype: 3-tuple of str
83     """
84     dash_split = filename.split(u"-", 1)
85     if len(dash_split[0]) <= 4:
86         # It was something like "2n1l", we need one more split.
87         dash_split = dash_split[1].split(u"-", 1)
88     nic_code = dash_split[0]
89     suite_id = dash_split[1].split(u".robot", 1)[0]
90     suite_tag = suite_id.rsplit(u"-", 1)[0]
91     for prefix in Constants.FORBIDDEN_SUITE_PREFIX_LIST:
92         if suite_tag.startswith(prefix):
93             suite_tag = suite_tag[len(prefix):]
94     return nic_code, suite_id, suite_tag
95
96
97 def check_suite_tag(suite_tag, prolog):
98     """Verify suite tag occurres once in prolog.
99
100     Call this after all edits are done,
101     to confirm the (edited) suite tag still matches the (edited) suite name.
102
103     Currently, the edited suite tag is expect to be identical
104     to the primary suite tag, but having a function is more flexible.
105
106     The occurences are counted including "| " prefix,
107     to lower the chance to match a comment.
108
109     :param suite_tag: Part of suite name, between NIC driver and suite type.
110     :param prolog: The part of .robot file content without test cases.
111     :type suite_tag: str
112     :type prolog: str
113     :raises ValueError: If suite_tag not found exactly once.
114     """
115     found = prolog.count(u"| " + suite_tag)
116     if found != 1:
117         raise ValueError(f"Suite tag found {found} times for {suite_tag}")
118
119
120 def filter_and_edit_kwargs_for_astf(suite_id, kwargs):
121     """Return possibly edited kwargs, or None if to be skipped.
122
123     This is a code block used in few places.
124     Kwargs is (a copy of) one item from tc_kwargs_list.
125     Currently, the editable field is frame_size,
126     to be increased to for tests with data (not just CPS).
127
128     :param suite_id: Suite ID.
129     :param kwargs: Key-value pairs used to construct one testcase.
130     :type suite_id: str
131     :type tc_kwargs_list: dict
132     :returns: Edited kwargs.
133     :rtype Optional[dict]
134     """
135     if u"-cps-" in suite_id:
136         # Contrary to UDP, there is no place to affect frame size
137         # in TCP CPS tests. Actual frames are close to min size.
138         # UDP uses the min value too, for fairer comparison to TCP.
139         if kwargs[u"frame_size"] not in MIN_FRAME_SIZE_VALUES:
140             return None
141     elif (u"-pps-" in suite_id or u"-tput-" in suite_id):
142         if u"imix" in str(kwargs[u"frame_size"]).lower():
143             # ASTF does not support IMIX (yet).
144             return None
145         if kwargs[u"frame_size"] in MIN_FRAME_SIZE_VALUES:
146             # Minimal (TRex) TCP data frame is 80B for IPv4.
147             # In future, we may want to have also IPv6 TCP.
148             # UDP uses the same value, for fairer comparison to TCP.
149             kwargs[u"frame_size"] = 100
150     return kwargs
151
152
153 def add_default_testcases(
154         testcase, nic_code, suite_id, file_out, tc_kwargs_list):
155     """Add default testcases to file.
156
157     :param testcase: Testcase class.
158     :param nic_code: NIC code.
159     :param suite_id: Suite ID.
160     :param file_out: File to write testcases to.
161     :param tc_kwargs_list: Key-value pairs used to construct testcases.
162     :type testcase: Testcase
163     :type nic_code: str
164     :type suite_id: str
165     :type file_out: file
166     :type tc_kwargs_list: dict
167     """
168     for kwas in tc_kwargs_list:
169         # We may edit framesize for ASTF, the copy should be local.
170         kwargs = copy.deepcopy(kwas)
171         # TODO: Is there a better way to disable some combinations?
172         emit = True
173         core_scale = Constants.NIC_CODE_TO_CORESCALE[nic_code]
174         if u"soak" in suite_id:
175             # Soak test take too long, do not risk other than tc01.
176             if kwargs[u"phy_cores"] != 1:
177                 emit = False
178             if u"reassembly" in suite_id:
179                 if kwargs[u"frame_size"] != 1518:
180                     emit = False
181             else:
182                 if kwargs[u"frame_size"] not in MIN_FRAME_SIZE_VALUES:
183                     emit = False
184
185         kwargs.update({'phy_cores': kwas['phy_cores']*core_scale})
186
187         kwargs = filter_and_edit_kwargs_for_astf(suite_id, kwargs)
188         if emit and kwargs is not None:
189             file_out.write(testcase.generate(**kwargs))
190
191
192 def add_tcp_testcases(testcase, file_out, tc_kwargs_list):
193     """Add TCP testcases to file.
194
195     :param testcase: Testcase class.
196     :param file_out: File to write testcases to.
197     :param tc_kwargs_list: Key-value pairs used to construct testcases.
198     :type testcase: Testcase
199     :type file_out: file
200     :type tc_kwargs_list: dict
201     """
202     for kwargs in tc_kwargs_list:
203         file_out.write(testcase.generate(**kwargs))
204
205
206 def add_iperf3_testcases(testcase, file_out, tc_kwargs_list):
207     """Add iperf3 testcases to file.
208
209     :param testcase: Testcase class.
210     :param file_out: File to write testcases to.
211     :param tc_kwargs_list: Key-value pairs used to construct testcases.
212     :type testcase: Testcase
213     :type file_out: file
214     :type tc_kwargs_list: dict
215     """
216     for kwargs in tc_kwargs_list:
217         file_out.write(testcase.generate(**kwargs))
218
219
220 def add_trex_testcases(testcase, suite_id, file_out, tc_kwargs_list):
221     """Add trex testcases to file.
222
223     :param testcase: Testcase class.
224     :param suite_id: Suite ID.
225     :param file_out: File to write testcases to.
226     :param tc_kwargs_list: Key-value pairs used to construct testcases.
227     :type testcase: Testcase
228     :type suite_id: str
229     :type file_out: file
230     :type tc_kwargs_list: dict
231     """
232     for kwas in tc_kwargs_list:
233         # We may edit framesize for ASTF, the copy should be local.
234         kwargs = copy.deepcopy(kwas)
235         kwargs = filter_and_edit_kwargs_for_astf(suite_id, kwargs)
236         if kwargs is not None:
237             file_out.write(testcase.generate(**kwargs))
238
239
240 def write_default_files(in_filename, in_prolog, kwargs_list):
241     """Using given filename and prolog, write all generated suites.
242
243     :param in_filename: Template filename to derive real filenames from.
244     :param in_prolog: Template content to derive real content from.
245     :param kwargs_list: List of kwargs for add_default_testcase.
246     :type in_filename: str
247     :type in_prolog: str
248     :type kwargs_list: list of dict
249     """
250     for suite_type in Constants.PERF_TYPE_TO_KEYWORD:
251         tmp_filename = replace_defensively(
252             in_filename, "ndrpdr", suite_type, 1,
253             "File name should contain suite type once.", in_filename
254         )
255         tmp_prolog = replace_defensively(
256             in_prolog, "ndrpdr".upper(), suite_type.upper(), 1,
257             "Suite type should appear once in uppercase (as tag).",
258             in_filename
259         )
260         tmp_prolog = replace_defensively(
261             tmp_prolog,
262             "Find NDR and PDR intervals using optimized search",
263             Constants.PERF_TYPE_TO_KEYWORD[suite_type], 1,
264             "Main search keyword should appear once in suite.",
265             in_filename
266         )
267         tmp_prolog = replace_defensively(
268             tmp_prolog,
269             Constants.PERF_TYPE_TO_SUITE_DOC_VER["ndrpdr"],
270             Constants.PERF_TYPE_TO_SUITE_DOC_VER[suite_type],
271             1, "Exact suite type doc not found.", in_filename
272         )
273         tmp_prolog = replace_defensively(
274             tmp_prolog,
275             Constants.PERF_TYPE_TO_TEMPLATE_DOC_VER["ndrpdr"],
276             Constants.PERF_TYPE_TO_TEMPLATE_DOC_VER[suite_type],
277             1, "Exact template type doc not found.", in_filename
278         )
279         _, suite_id, _ = get_iface_and_suite_ids(tmp_filename)
280         testcase = Testcase.default(suite_id)
281         for nic_code in Constants.NIC_CODE_TO_NAME:
282             nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
283             tmp2_filename = replace_defensively(
284                 tmp_filename, "10ge2p1x710", nic_code, 1,
285                 "File name should contain NIC code once.", in_filename
286             )
287             tmp2_prolog = replace_defensively(
288                 tmp_prolog, "Intel-X710", nic_name, 2,
289                 "NIC name should appear twice (tag and variable).",
290                 in_filename
291             )
292             if tmp2_prolog.count("HW_") == 2:
293                 # TODO CSIT-1481: Crypto HW should be read
294                 #      from topology file instead.
295                 if nic_name in Constants.NIC_NAME_TO_CRYPTO_HW:
296                     tmp2_prolog = replace_defensively(
297                         tmp2_prolog, "HW_DH895xcc",
298                         Constants.NIC_NAME_TO_CRYPTO_HW[nic_name], 1,
299                         "HW crypto name should appear.", in_filename
300                     )
301             iface, old_suite_id, old_suite_tag = get_iface_and_suite_ids(
302                 tmp2_filename
303             )
304             if "DPDK" in in_prolog:
305                 for driver in Constants.DPDK_NIC_NAME_TO_DRIVER[nic_name]:
306                     out_filename = replace_defensively(
307                         tmp2_filename, old_suite_id,
308                         Constants.DPDK_NIC_DRIVER_TO_SUITE_PREFIX[driver] \
309                             + old_suite_id,
310                         1, "Error adding driver prefix.", in_filename
311                     )
312                     out_prolog = replace_defensively(
313                         tmp2_prolog, "vfio-pci", driver, 1,
314                         "Driver name should appear once.", in_filename
315                     )
316                     out_prolog = replace_defensively(
317                         out_prolog,
318                         Constants.DPDK_NIC_DRIVER_TO_TAG["vfio-pci"],
319                         Constants.DPDK_NIC_DRIVER_TO_TAG[driver], 1,
320                         "Driver tag should appear once.", in_filename
321                     )
322                     iface, suite_id, suite_tag = get_iface_and_suite_ids(
323                         out_filename
324                     )
325                     # The next replace is probably a noop, but it is safer to
326                     # maintain the same structure as for other edits.
327                     out_prolog = replace_defensively(
328                         out_prolog, old_suite_tag, suite_tag, 1,
329                         f"Perf suite tag {old_suite_tag} should appear once.",
330                         in_filename
331                     )
332                     check_suite_tag(suite_tag, out_prolog)
333                     # TODO: Reorder loops so suite_id is finalized sooner.
334                     testcase = Testcase.default(suite_id)
335                     with open(out_filename, "wt") as file_out:
336                         file_out.write(out_prolog)
337                         add_default_testcases(
338                             testcase, nic_code, suite_id, file_out, kwargs_list
339                         )
340                 continue
341             for driver in Constants.NIC_NAME_TO_DRIVER[nic_name]:
342                 out_filename = replace_defensively(
343                     tmp2_filename, old_suite_id,
344                     Constants.NIC_DRIVER_TO_SUITE_PREFIX[driver] + old_suite_id,
345                     1, "Error adding driver prefix.", in_filename
346                 )
347                 out_prolog = replace_defensively(
348                     tmp2_prolog, "vfio-pci", driver, 1,
349                     "Driver name should appear once.", in_filename
350                 )
351                 out_prolog = replace_defensively(
352                     out_prolog, Constants.NIC_DRIVER_TO_TAG["vfio-pci"],
353                     Constants.NIC_DRIVER_TO_TAG[driver], 1,
354                     "Driver tag should appear once.", in_filename
355                 )
356                 out_prolog = replace_defensively(
357                     out_prolog, Constants.NIC_DRIVER_TO_PLUGINS["vfio-pci"],
358                     Constants.NIC_DRIVER_TO_PLUGINS[driver], 1,
359                     "Driver plugin should appear once.", in_filename
360                 )
361                 out_prolog = replace_defensively(
362                     out_prolog, Constants.NIC_DRIVER_TO_VFS["vfio-pci"],
363                     Constants.NIC_DRIVER_TO_VFS[driver], 1,
364                     "NIC VFs argument should appear once.", in_filename
365                 )
366                 out_prolog = replace_defensively(
367                     out_prolog, Constants.NIC_CODE_TO_PFS["10ge2p1x710"],
368                     Constants.NIC_CODE_TO_PFS[nic_code], 1,
369                     "NIC PFs argument should appear once.", in_filename
370                 )
371                 iface, suite_id, suite_tag = get_iface_and_suite_ids(
372                     out_filename
373                 )
374                 # The next replace is probably a noop, but it is safer to
375                 # maintain the same structure as for other edits.
376                 out_prolog = replace_defensively(
377                     out_prolog, old_suite_tag, suite_tag, 1,
378                     f"Perf suite tag {old_suite_tag} should appear once.",
379                     in_filename
380                 )
381                 check_suite_tag(suite_tag, out_prolog)
382                 # TODO: Reorder loops so suite_id is finalized sooner.
383                 testcase = Testcase.default(suite_id)
384                 with open(out_filename, "wt") as file_out:
385                     file_out.write(out_prolog)
386                     add_default_testcases(
387                         testcase, nic_code, suite_id, file_out, kwargs_list
388                     )
389
390
391 def write_reconf_files(in_filename, in_prolog, kwargs_list):
392     """Using given filename and prolog, write all generated reconf suites.
393
394     Use this for suite type reconf, as its local template
395     is incompatible with mrr/ndrpdr/soak local template,
396     while test cases are compatible.
397
398     :param in_filename: Template filename to derive real filenames from.
399     :param in_prolog: Template content to derive real content from.
400     :param kwargs_list: List of kwargs for add_testcase.
401     :type in_filename: str
402     :type in_prolog: str
403     :type kwargs_list: list of dict
404     """
405     _, suite_id, _ = get_iface_and_suite_ids(in_filename)
406     testcase = Testcase.default(suite_id)
407     for nic_code in Constants.NIC_CODE_TO_NAME:
408         nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
409         tmp_filename = replace_defensively(
410             in_filename, u"10ge2p1x710", nic_code, 1,
411             u"File name should contain NIC code once.", in_filename
412         )
413         tmp_prolog = replace_defensively(
414             in_prolog, u"Intel-X710", nic_name, 2,
415             u"NIC name should appear twice (tag and variable).",
416             in_filename
417         )
418         if tmp_prolog.count(u"HW_") == 2:
419             # TODO CSIT-1481: Crypto HW should be read
420             #      from topology file instead.
421             if nic_name in Constants.NIC_NAME_TO_CRYPTO_HW.keys():
422                 tmp_prolog = replace_defensively(
423                     tmp_prolog, u"HW_DH895xcc",
424                     Constants.NIC_NAME_TO_CRYPTO_HW[nic_name], 1,
425                     u"HW crypto name should appear.", in_filename
426                 )
427         iface, old_suite_id, old_suite_tag = get_iface_and_suite_ids(
428             tmp_filename
429         )
430         for driver in Constants.NIC_NAME_TO_DRIVER[nic_name]:
431             out_filename = replace_defensively(
432                 tmp_filename, old_suite_id,
433                 Constants.NIC_DRIVER_TO_SUITE_PREFIX[driver] + old_suite_id,
434                 1, u"Error adding driver prefix.", in_filename
435             )
436             out_prolog = replace_defensively(
437                 tmp_prolog, u"vfio-pci", driver, 1,
438                 u"Driver name should appear once.", in_filename
439             )
440             out_prolog = replace_defensively(
441                 out_prolog, Constants.NIC_DRIVER_TO_TAG[u"vfio-pci"],
442                 Constants.NIC_DRIVER_TO_TAG[driver], 1,
443                 u"Driver tag should appear once.", in_filename
444             )
445             out_prolog = replace_defensively(
446                 out_prolog, Constants.NIC_DRIVER_TO_PLUGINS[u"vfio-pci"],
447                 Constants.NIC_DRIVER_TO_PLUGINS[driver], 1,
448                 u"Driver plugin should appear once.", in_filename
449             )
450             out_prolog = replace_defensively(
451                 out_prolog, Constants.NIC_DRIVER_TO_VFS[u"vfio-pci"],
452                 Constants.NIC_DRIVER_TO_VFS[driver], 1,
453                 u"NIC VFs argument should appear once.", in_filename
454             )
455             out_prolog = replace_defensively(
456                 out_prolog, Constants.NIC_CODE_TO_PFS["10ge2p1x710"],
457                 Constants.NIC_CODE_TO_PFS[nic_code], 1,
458                 "NIC PFs argument should appear once.", in_filename
459             )
460             iface, suite_id, suite_tag = get_iface_and_suite_ids(out_filename)
461             out_prolog = replace_defensively(
462                 out_prolog, old_suite_tag, suite_tag, 1,
463                 u"Perf suite tag should appear once.", in_filename
464             )
465             check_suite_tag(suite_tag, out_prolog)
466             # TODO: Reorder loops so suite_id is finalized sooner.
467             testcase = Testcase.default(suite_id)
468             with open(out_filename, u"wt") as file_out:
469                 file_out.write(out_prolog)
470                 add_default_testcases(
471                     testcase, iface, suite_id, file_out, kwargs_list
472                 )
473
474
475 def write_tcp_files(in_filename, in_prolog, kwargs_list):
476     """Using given filename and prolog, write all generated tcp suites.
477
478     :param in_filename: Template filename to derive real filenames from.
479     :param in_prolog: Template content to derive real content from.
480     :param kwargs_list: List of kwargs for add_default_testcase.
481     :type in_filename: str
482     :type in_prolog: str
483     :type kwargs_list: list of dict
484     """
485     # TODO: Generate rps from cps? There are subtle differences.
486     _, suite_id, suite_tag = get_iface_and_suite_ids(in_filename)
487     testcase = Testcase.tcp(suite_id)
488     for nic_code in Constants.NIC_CODE_TO_NAME:
489         nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
490         tmp_filename = replace_defensively(
491             in_filename, u"10ge2p1x710", nic_code, 1,
492             u"File name should contain NIC code once.", in_filename
493         )
494         tmp_prolog = replace_defensively(
495             in_prolog, u"Intel-X710", nic_name, 2,
496             u"NIC name should appear twice (tag and variable).",
497             in_filename
498         )
499         iface, old_suite_id, old_suite_tag = get_iface_and_suite_ids(
500             tmp_filename
501         )
502         for driver in Constants.NIC_NAME_TO_DRIVER[nic_name]:
503             out_filename = replace_defensively(
504                 tmp_filename, old_suite_id,
505                 Constants.NIC_DRIVER_TO_SUITE_PREFIX[driver] + old_suite_id,
506                 1, u"Error adding driver prefix.", in_filename
507             )
508             out_prolog = replace_defensively(
509                 tmp_prolog, u"vfio-pci", driver, 1,
510                 u"Driver name should appear once.", in_filename
511             )
512             out_prolog = replace_defensively(
513                 out_prolog, Constants.NIC_DRIVER_TO_TAG[u"vfio-pci"],
514                 Constants.NIC_DRIVER_TO_TAG[driver], 1,
515                 u"Driver tag should appear once.", in_filename
516             )
517             out_prolog = replace_defensively(
518                 out_prolog, Constants.NIC_DRIVER_TO_PLUGINS[u"vfio-pci"],
519                 Constants.NIC_DRIVER_TO_PLUGINS[driver], 1,
520                 u"Driver plugin should appear once.", in_filename
521             )
522             out_prolog = replace_defensively(
523                 out_prolog, Constants.NIC_DRIVER_TO_VFS[u"vfio-pci"],
524                 Constants.NIC_DRIVER_TO_VFS[driver], 1,
525                 u"NIC VFs argument should appear once.", in_filename
526             )
527             out_prolog = replace_defensively(
528                 out_prolog, Constants.NIC_CODE_TO_PFS["10ge2p1x710"],
529                 Constants.NIC_CODE_TO_PFS[nic_code], 1,
530                 "NIC PFs argument should appear once.", in_filename
531             )
532             iface, suite_id, suite_tag = get_iface_and_suite_ids(out_filename)
533             out_prolog = replace_defensively(
534                 out_prolog, old_suite_tag, suite_tag, 1,
535                 u"Perf suite tag should appear once.", in_filename
536             )
537             check_suite_tag(suite_tag, out_prolog)
538             testcase = Testcase.tcp(suite_id)
539             with open(out_filename, u"wt") as file_out:
540                 file_out.write(out_prolog)
541                 add_tcp_testcases(testcase, file_out, kwargs_list)
542
543
544 def write_iperf3_files(in_filename, in_prolog, kwargs_list):
545     """Using given filename and prolog, write all generated iperf3 suites.
546
547     :param in_filename: Template filename to derive real filenames from.
548     :param in_prolog: Template content to derive real content from.
549     :param kwargs_list: List of kwargs for add_default_testcase.
550     :type in_filename: str
551     :type in_prolog: str
552     :type kwargs_list: list of dict
553     """
554     _, suite_id, suite_tag = get_iface_and_suite_ids(in_filename)
555     testcase = Testcase.iperf3(suite_id)
556     for nic_code in Constants.NIC_CODE_TO_NAME:
557         nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
558         out_filename = replace_defensively(
559             in_filename, u"10ge2p1x710", nic_code, 1,
560             u"File name should contain NIC code once.", in_filename
561         )
562         out_prolog = replace_defensively(
563             in_prolog, u"Intel-X710", nic_name, 2,
564             u"NIC name should appear twice (tag and variable).",
565             in_filename
566         )
567         check_suite_tag(suite_tag, out_prolog)
568         with open(out_filename, u"wt") as file_out:
569             file_out.write(out_prolog)
570             add_iperf3_testcases(testcase, file_out, kwargs_list)
571
572
573 def write_trex_files(in_filename, in_prolog, kwargs_list):
574     """Using given filename and prolog, write all generated trex suites.
575
576     :param in_filename: Template filename to derive real filenames from.
577     :param in_prolog: Template content to derive real content from.
578     :param kwargs_list: List of kwargs for add_trex_testcase.
579     :type in_filename: str
580     :type in_prolog: str
581     :type kwargs_list: list of dict
582     """
583     for suite_type in Constants.PERF_TYPE_TO_KEYWORD:
584         tmp_filename = replace_defensively(
585             in_filename, u"ndrpdr", suite_type, 1,
586             u"File name should contain suite type once.", in_filename
587         )
588         tmp_prolog = replace_defensively(
589             in_prolog, u"ndrpdr".upper(), suite_type.upper(), 1,
590             u"Suite type should appear once in uppercase (as tag).",
591             in_filename
592         )
593         tmp_prolog = replace_defensively(
594             tmp_prolog,
595             u"Find NDR and PDR intervals using optimized search",
596             Constants.PERF_TYPE_TO_KEYWORD[suite_type], 1,
597             u"Main search keyword should appear once in suite.",
598             in_filename
599         )
600         tmp_prolog = replace_defensively(
601             tmp_prolog,
602             Constants.PERF_TYPE_TO_SUITE_DOC_VER[u"ndrpdr"],
603             Constants.PERF_TYPE_TO_SUITE_DOC_VER[suite_type],
604             1, u"Exact suite type doc not found.", in_filename
605         )
606         tmp_prolog = replace_defensively(
607             tmp_prolog,
608             Constants.PERF_TYPE_TO_TEMPLATE_DOC_VER[u"ndrpdr"],
609             Constants.PERF_TYPE_TO_TEMPLATE_DOC_VER[suite_type],
610             1, u"Exact template type doc not found.", in_filename
611         )
612         _, suite_id, suite_tag = get_iface_and_suite_ids(tmp_filename)
613         testcase = Testcase.trex(suite_id)
614         for nic_code in Constants.NIC_CODE_TO_NAME:
615             nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
616             out_filename = replace_defensively(
617                 tmp_filename, u"10ge2p1x710", nic_code, 1,
618                 u"File name should contain NIC code once.", in_filename
619             )
620             out_prolog = replace_defensively(
621                 tmp_prolog, u"Intel-X710", nic_name, 2,
622                 u"NIC name should appear twice (tag and variable).",
623                 in_filename
624             )
625             check_suite_tag(suite_tag, out_prolog)
626             with open(out_filename, u"wt") as file_out:
627                 file_out.write(out_prolog)
628                 add_trex_testcases(testcase, suite_id, file_out, kwargs_list)
629
630
631 def write_device_files(in_filename, in_prolog, kwargs_list):
632     """Using given filename and prolog, write all generated suites.
633
634     :param in_filename: Template filename to derive real filenames from.
635     :param in_prolog: Template content to derive real content from.
636     :param kwargs_list: List of kwargs for add_default_testcase.
637     :type in_filename: str
638     :type in_prolog: str
639     :type kwargs_list: list of dict
640     """
641     for suite_type in Constants.DEVICE_TYPE_TO_KEYWORD:
642         tmp_filename = replace_defensively(
643             in_filename, u"scapy", suite_type, 1,
644             u"File name should contain suite type once.", in_filename
645         )
646         _, suite_id, _ = get_iface_and_suite_ids(tmp_filename)
647         testcase = Testcase.default(suite_id)
648         for nic_code in Constants.NIC_CODE_TO_NAME:
649             nic_name = Constants.NIC_CODE_TO_NAME[nic_code]
650             tmp2_filename = replace_defensively(
651                 tmp_filename, u"10ge2p1x710", nic_code, 1,
652                 u"File name should contain NIC code once.", in_filename
653             )
654             tmp2_prolog = replace_defensively(
655                 in_prolog, u"Intel-X710", nic_name, 2,
656                 u"NIC name should appear twice (tag and variable).",
657                 in_filename
658             )
659             iface, old_suite_id, _ = get_iface_and_suite_ids(
660                 tmp2_filename
661             )
662             for driver in Constants.NIC_NAME_TO_DRIVER[nic_name]:
663                 out_filename = replace_defensively(
664                     tmp2_filename, old_suite_id,
665                     Constants.NIC_DRIVER_TO_SUITE_PREFIX[driver] + old_suite_id,
666                     1, u"Error adding driver prefix.", in_filename
667                 )
668                 out_prolog = replace_defensively(
669                     tmp2_prolog, u"vfio-pci", driver, 1,
670                     u"Driver name should appear once.", in_filename
671                 )
672                 out_prolog = replace_defensively(
673                     out_prolog, Constants.NIC_DRIVER_TO_TAG[u"vfio-pci"],
674                     Constants.NIC_DRIVER_TO_TAG[driver], 1,
675                     u"Driver tag should appear once.", in_filename
676                 )
677                 out_prolog = replace_defensively(
678                     out_prolog, Constants.NIC_DRIVER_TO_PLUGINS[u"vfio-pci"],
679                     Constants.NIC_DRIVER_TO_PLUGINS[driver], 1,
680                     u"Driver plugin should appear once.", in_filename
681                 )
682                 out_prolog = replace_defensively(
683                     out_prolog, Constants.NIC_DRIVER_TO_VFS[u"vfio-pci"],
684                     Constants.NIC_DRIVER_TO_VFS[driver], 1,
685                     u"NIC VFs argument should appear once.", in_filename
686                 )
687                 out_prolog = replace_defensively(
688                     out_prolog, Constants.NIC_CODE_TO_PFS["10ge2p1x710"],
689                     Constants.NIC_CODE_TO_PFS[nic_code], 1,
690                     "NIC PFs argument should appear once.", in_filename
691                 )
692                 iface, suite_id, suite_tag = get_iface_and_suite_ids(
693                     out_filename
694                 )
695                 check_suite_tag(suite_tag, out_prolog)
696                 # TODO: Reorder loops so suite_id is finalized sooner.
697                 testcase = Testcase.default(suite_id)
698                 with open(out_filename, u"wt") as file_out:
699                     file_out.write(out_prolog)
700                     add_default_testcases(
701                         testcase, iface, suite_id, file_out, kwargs_list
702                     )
703
704
705 class Regenerator:
706     """Class containing file generating methods."""
707
708     def __init__(self, quiet=True):
709         """Initialize the instance.
710
711         :param quiet: Reduce log prints (to stderr) when True (default).
712         :type quiet: boolean
713         """
714         self.quiet = quiet
715
716     def regenerate_glob(self, pattern, protocol=u"ip4"):
717         """Regenerate files matching glob pattern based on arguments.
718
719         In the current working directory, find all files matching
720         the glob pattern. Use testcase template to regenerate test cases
721         according to suffix, governed by protocol, autonumbering them.
722         Also generate suites for other NICs and drivers.
723
724         Log-like prints are emitted to sys.stderr.
725
726         :param pattern: Glob pattern to select files. Example: \*-ndrpdr.robot
727         :param protocol: String determining minimal frame size. Default: "ip4"
728         :type pattern: str
729         :type protocol: str
730         :raises RuntimeError: If invalid source suite is encountered.
731         """
732         if not self.quiet:
733             print(f"Regenerator starts at {getcwd()}", file=sys.stderr)
734
735         min_frame_size = PROTOCOL_TO_MIN_FRAME_SIZE[protocol]
736         default_kwargs_list = [
737             {u"frame_size": min_frame_size, u"phy_cores": 1},
738             {u"frame_size": min_frame_size, u"phy_cores": 2},
739             {u"frame_size": min_frame_size, u"phy_cores": 4},
740             {u"frame_size": 1518, u"phy_cores": 1},
741             {u"frame_size": 1518, u"phy_cores": 2},
742             {u"frame_size": 1518, u"phy_cores": 4},
743             {u"frame_size": 9000, u"phy_cores": 1},
744             {u"frame_size": 9000, u"phy_cores": 2},
745             {u"frame_size": 9000, u"phy_cores": 4},
746             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 1},
747             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 2},
748             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 4}
749         ]
750         hs_bps_kwargs_list = [
751             {u"frame_size": 1460, u"phy_cores": 1},
752         ]
753         hs_quic_kwargs_list = [
754             {u"frame_size": 1280, u"phy_cores": 1},
755         ]
756         iperf3_kwargs_list = [
757             {u"frame_size": 128000, u"phy_cores": 1},
758             {u"frame_size": 128000, u"phy_cores": 2},
759             {u"frame_size": 128000, u"phy_cores": 4}
760         ]
761         # List for tests with one dataplane core
762         # (and variable number of other cores).
763         dp1_kwargs_list = [
764             {u"frame_size": min_frame_size, u"phy_cores": 2},
765             {u"frame_size": min_frame_size, u"phy_cores": 3},
766             {u"frame_size": min_frame_size, u"phy_cores": 4},
767             {u"frame_size": 1518, u"phy_cores": 2},
768             {u"frame_size": 1518, u"phy_cores": 3},
769             {u"frame_size": 1518, u"phy_cores": 4},
770             {u"frame_size": 9000, u"phy_cores": 2},
771             {u"frame_size": 9000, u"phy_cores": 3},
772             {u"frame_size": 9000, u"phy_cores": 4},
773             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 2},
774             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 3},
775             {u"frame_size": u"IMIX_v4_1", u"phy_cores": 4}
776         ]
777
778         http_kwargs_list = [
779             {u"frame_size": 0, u"phy_cores": 1},
780             {u"frame_size": 0, u"phy_cores": 2},
781             {u"frame_size": 64, u"phy_cores": 1},
782             {u"frame_size": 64, u"phy_cores": 2},
783             {u"frame_size": 1024, u"phy_cores": 1},
784             {u"frame_size": 1024, u"phy_cores": 2},
785             {u"frame_size": 2048, u"phy_cores": 1},
786             {u"frame_size": 2048, u"phy_cores": 2}
787         ]
788
789         device_kwargs_list = [
790             {u"frame_size": min_frame_size, u"phy_cores": 0}
791         ]
792
793         trex_kwargs_list = [
794             {u"frame_size": min_frame_size},
795             {u"frame_size": 1518},
796             {u"frame_size": 9000},
797             {u"frame_size": u"IMIX_v4_1"}
798         ]
799
800         for in_filename in glob(pattern):
801             if not self.quiet:
802                 print(
803                     u"Regenerating in_filename:", in_filename, file=sys.stderr
804                 )
805             iface, _, _ = get_iface_and_suite_ids(in_filename)
806             if not iface.endswith(u"10ge2p1x710"):
807                 raise RuntimeError(
808                     f"Error in {in_filename}: non-primary NIC found."
809                 )
810             for prefix in Constants.FORBIDDEN_SUITE_PREFIX_LIST:
811                 if prefix in in_filename:
812                     raise RuntimeError(
813                         f"Error in {in_filename}: non-primary driver found."
814                     )
815             with open(in_filename, u"rt") as file_in:
816                 in_prolog = u"".join(
817                     file_in.read().partition(u"*** Test Cases ***")[:-1]
818                 )
819             if "-tg" in in_filename:
820                 write_trex_files(in_filename, in_prolog, trex_kwargs_list)
821                 continue
822             if in_filename.endswith(u"-ndrpdr.robot"):
823                 if u"scheduler" in in_filename:
824                     write_default_files(
825                         in_filename, in_prolog, dp1_kwargs_list
826                     )
827                 else:
828                     write_default_files(
829                         in_filename, in_prolog, default_kwargs_list
830                     )
831             elif in_filename.endswith(u"-reconf.robot"):
832                 write_reconf_files(in_filename, in_prolog, default_kwargs_list)
833             elif in_filename.endswith(u"-rps.robot") \
834                     or in_filename.endswith(u"-cps.robot"):
835                 write_tcp_files(in_filename, in_prolog, http_kwargs_list)
836             elif in_filename.endswith(u"-bps.robot"):
837                 hoststack_kwargs_list = \
838                     hs_quic_kwargs_list if u"quic" in in_filename \
839                     else hs_bps_kwargs_list
840                 write_tcp_files(in_filename, in_prolog, hoststack_kwargs_list)
841             elif in_filename.endswith(u"-iperf3-mrr.robot"):
842                 write_iperf3_files(in_filename, in_prolog, iperf3_kwargs_list)
843             elif in_filename.endswith(u"-scapy.robot"):
844                 write_device_files(in_filename, in_prolog, device_kwargs_list)
845             else:
846                 raise RuntimeError(
847                     f"Error in {in_filename}: non-primary suite type found."
848                 )
849         if not self.quiet:
850             print(u"Regenerator ends.", file=sys.stderr)
851         print(file=sys.stderr)  # To make autogen check output more readable.