4 # Copyright (c) 2020 by VMware, Inc. ("VMware")
5 # Used Copyright (c) 2018 by Network Device Education Foundation,
6 # Inc. ("NetDEF") in this file.
8 # Permission to use, copy, modify, and/or distribute this software
9 # for any purpose with or without fee is hereby granted, provided
10 # that the above copyright notice and this permission notice appear
13 # THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
14 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
16 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
17 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 Following tests are covered to test multicast pim sm:
27 - Create topology (setup module)
30 Following tests are covered:
31 1. Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
39 from time
import sleep
42 # Save the Current Working Directory to find configuration files.
43 CWD
= os
.path
.dirname(os
.path
.realpath(__file__
))
44 sys
.path
.append(os
.path
.join(CWD
, "../"))
45 sys
.path
.append(os
.path
.join(CWD
, "../lib/"))
47 # Required to instantiate the topology builder class.
49 # pylint: disable=C0413
50 # Import topogen and topotest helpers
51 from lib
.topogen
import Topogen
, get_topogen
53 from lib
.common_config
import (
58 reset_config_on_routers
,
60 add_interfaces_to_vlan
,
65 required_linux_kernel_version
,
72 clear_pim_interface_traffic
,
75 verify_multicast_flag_state
,
78 from lib
.topolog
import logger
79 from lib
.topojson
import build_config_from_json
84 pytestmark
= [pytest
.mark
.pimd
]
88 Descripton: Configuring static routes on r1/r2/r3/r4/r5 for RP reachablility.
89 IPs are assigned automatically to routers, start IP and subnet is defined in respective JSON file
91 "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 24},
94 10.0.3.2/24| 10.0.0.2/24
97 ------------ r4 ----------
98 | 10.0.1.2/24 10.0.2.2/24 |
99 10.0.1.1/24 | | 10.0.2.1/24
100 r1 ----------- s1 ---------- r2
101 10.0.4.2/24 | 10.0.4.3/24
107 i1, i2 - FRR running iperf to send IGMP
109 r1, r2, r3, r4, r5 - FRR ruter
115 GROUP_RANGE
= "225.0.0.0/8"
116 IGMP_JOIN
= "225.1.1.1"
117 VLAN_INTF_ADRESS_1
= "10.0.8.3/24"
118 SAME_VLAN_IP_1
= {"ip": "10.1.1.1", "subnet": "255.255.255.0", "cidr": "24"}
119 SAME_VLAN_IP_2
= {"ip": "10.1.1.2", "subnet": "255.255.255.0", "cidr": "24"}
120 SAME_VLAN_IP_3
= {"ip": "10.1.1.3", "subnet": "255.255.255.0", "cidr": "24"}
121 SAME_VLAN_IP_4
= {"ip": "10.1.1.4", "subnet": "255.255.255.0", "cidr": "24"}
129 IGMP_JOIN_RANGE_1
= ["225.1.1.1", "225.1.1.2", "225.1.1.3", "225.1.1.4", "225.1.1.5"]
137 IGMP_JOIN_RANGE_2
= ["226.1.1.1", "226.1.1.2", "226.1.1.3", "226.1.1.4", "226.1.1.5"]
145 IGMP_JOIN_RANGE_3
= ["227.1.1.1", "227.1.1.2", "227.1.1.3", "227.1.1.4", "227.1.1.5"]
148 intf_r1_s1_addr
= None
150 intf_r2_s1_addr
= None
152 intf_r3_s1_addr
= None
154 intf_i1_s1_addr
= None
157 def setup_module(mod
):
159 Sets up the pytest environment
164 # Required linux kernel version for this suite to run.
165 result
= required_linux_kernel_version("4.19")
166 if result
is not True:
167 pytest
.skip("Kernel requirements are not met")
169 testsuite_run_time
= time
.asctime(time
.localtime(time
.time()))
170 logger
.info("Testsuite start time: {}".format(testsuite_run_time
))
171 logger
.info("=" * 40)
172 logger
.info("Master Topology: \n {}".format(TOPOLOGY
))
174 logger
.info("Running setup_module to create topology")
176 testdir
= os
.path
.dirname(os
.path
.realpath(__file__
))
177 json_file
= "{}/pim_dr_nondr_with_static_routes_topo1.json".format(testdir
)
178 tgen
= Topogen(json_file
, mod
.__name
__)
180 topo
= tgen
.json_topo
181 # ... and here it calls Mininet initialization functions.
183 # get list of daemons needs to be started for this suite.
184 daemons
= topo_daemons(tgen
, tgen
.json_topo
)
186 # Starting topology, create tmp files which are loaded to routers
187 # to start deamons and then start routers
188 start_topology(tgen
, daemons
)
190 # Don"t run this test if we have any failure.
191 if tgen
.routers_have_failure():
192 pytest
.skip(tgen
.errors
)
194 # Creating configuration from JSON
195 build_config_from_json(tgen
, tgen
.json_topo
)
197 # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
199 app_helper
= McastTesterHelper(tgen
)
201 logger
.info("Running setup_module() done")
204 def teardown_module():
205 """Teardown the pytest environment"""
207 logger
.info("Running teardown_module to delete topology")
213 # Stop toplogy and Remove tmp files
217 "Testsuite end time: {}".format(time
.asctime(time
.localtime(time
.time())))
219 logger
.info("=" * 40)
222 #####################################################
226 #####################################################
229 def pre_config_for_receiver_dr_tests(
230 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
233 API to do common pre-configuration for receiver test cases
237 * `tgen`: topogen object
238 * `topo`: input json data
239 * `tc_name`: caller test case name
240 * `highest_priority`: router which will be having highest DR priority
241 * `lowest_priority`: router which will be having lowest DR priority
244 global intf_r1_s1
, intf_r1_s1_addr
, intf_r2_s1
, intf_r2_s1_addr
, intf_r3_s1
, intf_r3_s1_addr
, intf_i1_s1
, intf_i1_s1_addr
246 step("Configure IGMP and PIM on switch connected receiver nodes")
247 step("Configure PIM on all upstream interfaces")
249 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
251 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
252 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
255 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
256 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
258 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
259 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
261 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
262 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
264 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
265 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
267 if lowest_priority
== "r1":
268 lowest_pr_intf
= intf_r1_s1
270 lowest_pr_intf
= intf_r3_s1
272 if highest_priority
== "r1":
273 highest_pr_intf
= intf_r1_s1
275 highest_pr_intf
= intf_r3_s1
283 "ip": SAME_VLAN_IP_1
["ip"],
284 "subnet": SAME_VLAN_IP_1
["subnet"],
295 "ip": SAME_VLAN_IP_2
["ip"],
296 "subnet": SAME_VLAN_IP_2
["subnet"],
307 "ip": SAME_VLAN_IP_3
["ip"],
308 "subnet": SAME_VLAN_IP_3
["subnet"],
319 "ip": SAME_VLAN_IP_4
["ip"],
320 "subnet": SAME_VLAN_IP_4
["subnet"],
328 add_interfaces_to_vlan(tgen
, vlan_input
)
333 "interface {}".format(intf_r1_s1
),
334 "no ip address {}".format(intf_r1_s1_addr
),
340 "interface {}".format(intf_r2_s1
),
341 "no ip address {}".format(intf_r2_s1_addr
),
347 "interface {}".format(intf_r3_s1
),
348 "no ip address {}".format(intf_r3_s1_addr
),
354 "interface {}".format(intf_i1_s1
),
355 "no ip address {}".format(intf_i1_s1_addr
),
360 result
= apply_raw_config(tgen
, raw_config
)
361 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
366 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
367 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
375 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
376 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
384 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
385 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
393 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
394 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
399 result
= apply_raw_config(tgen
, raw_config
)
400 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
402 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
406 "interface {}.{}".format(intf
, VLAN_1
),
407 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
411 result
= apply_raw_config(tgen
, raw_config
)
412 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
414 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
421 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
424 "group_addr_range": GROUP_RANGE_1
,
431 result
= create_pim_config(tgen
, topo
, input_dict
)
432 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
434 step("Send IGMP join for groups 226.1.1.1 to 226.1.1.5")
436 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
437 result
= app_helper
.run_join("i1", IGMP_JOIN_RANGE_1
, join_intf
=vlan_intf_i1_s1
)
438 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
440 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
442 step("Start traffic from R4 connected source")
444 result
= app_helper
.run_traffic("i2", IGMP_JOIN_RANGE_1
, "r5")
445 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
450 def pre_config_for_source_dr_tests(
451 tgen
, topo
, tc_name
, highest_priority
, lowest_priority
454 API to do common pre-configuration for source test cases
458 * `tgen`: topogen object
459 * `topo`: input json data
460 * `tc_name`: caller test case name
461 * `highest_priority`: router which will be having highest DR priority
462 * `lowest_priority`: router which will be having lowest DR priority
465 global intf_r1_s1
, intf_r1_s1_addr
, intf_r2_s1
, intf_r2_s1_addr
, intf_r3_s1
, intf_r3_s1_addr
, intf_i1_s1
, intf_i1_s1_addr
467 step("Configure IGMP and PIM on switch connected receiver nodes")
468 step("Configure PIM on all upstream interfaces")
470 step("Configure link between R1, R2 ,R3 and receiver on" " same vlan")
472 "Make sure {0} is DR initially configuring highest IP on {0} and R2 "
473 "second highest, {1} is lower".format(highest_priority
, lowest_priority
)
476 intf_r1_s1
= topo
["routers"]["r1"]["links"]["s1"]["interface"]
477 intf_r1_s1_addr
= topo
["routers"]["r1"]["links"]["s1"]["ipv4"]
479 intf_r2_s1
= topo
["routers"]["r2"]["links"]["s1"]["interface"]
480 intf_r2_s1_addr
= topo
["routers"]["r2"]["links"]["s1"]["ipv4"]
482 intf_r3_s1
= topo
["routers"]["r3"]["links"]["s1"]["interface"]
483 intf_r3_s1_addr
= topo
["routers"]["r3"]["links"]["s1"]["ipv4"]
485 intf_i1_s1
= topo
["routers"]["i1"]["links"]["s1"]["interface"]
486 intf_i1_s1_addr
= topo
["routers"]["i1"]["links"]["s1"]["ipv4"]
488 if lowest_priority
== "r1":
489 lowest_pr_intf
= intf_r1_s1
491 lowest_pr_intf
= intf_r3_s1
493 if highest_priority
== "r1":
494 highest_pr_intf
= intf_r1_s1
496 highest_pr_intf
= intf_r3_s1
504 "ip": SAME_VLAN_IP_1
["ip"],
505 "subnet": SAME_VLAN_IP_1
["subnet"],
516 "ip": SAME_VLAN_IP_2
["ip"],
517 "subnet": SAME_VLAN_IP_2
["subnet"],
528 "ip": SAME_VLAN_IP_3
["ip"],
529 "subnet": SAME_VLAN_IP_3
["subnet"],
540 "ip": SAME_VLAN_IP_4
["ip"],
541 "subnet": SAME_VLAN_IP_4
["subnet"],
549 add_interfaces_to_vlan(tgen
, vlan_input
)
554 "interface {}".format(intf_r1_s1
),
555 "no ip address {}".format(intf_r1_s1_addr
),
561 "interface {}".format(intf_r2_s1
),
562 "no ip address {}".format(intf_r2_s1_addr
),
568 "interface {}".format(intf_r3_s1
),
569 "no ip address {}".format(intf_r3_s1_addr
),
575 "interface {}".format(intf_i1_s1
),
576 "no ip address {}".format(intf_i1_s1_addr
),
581 result
= apply_raw_config(tgen
, raw_config
)
582 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
585 "Configure IGMP and PIM on switch connected receiver nodes , "
586 "configure PIM nbr with hello timer 1"
592 "interface {}.{}".format(lowest_pr_intf
, VLAN_1
),
593 "ip address {}/{}".format(SAME_VLAN_IP_1
["ip"], SAME_VLAN_IP_1
["cidr"]),
599 "interface {}.{}".format(intf_r2_s1
, VLAN_1
),
600 "ip address {}/{}".format(SAME_VLAN_IP_2
["ip"], SAME_VLAN_IP_2
["cidr"]),
606 "interface {}.{}".format(highest_pr_intf
, VLAN_1
),
607 "ip address {}/{}".format(SAME_VLAN_IP_3
["ip"], SAME_VLAN_IP_3
["cidr"]),
613 "interface {}.{}".format(intf_i1_s1
, VLAN_1
),
614 "ip address {}/{}".format(SAME_VLAN_IP_4
["ip"], SAME_VLAN_IP_4
["cidr"]),
619 result
= apply_raw_config(tgen
, raw_config
)
620 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
622 for dut
, intf
in zip(["r1", "r2", "r3"], [intf_r1_s1
, intf_r2_s1
, intf_r3_s1
]):
626 "interface {}.{}".format(intf
, VLAN_1
),
627 "ip pim hello {} {}".format(HELLO_TIMER
, HOLD_TIMER
),
631 result
= apply_raw_config(tgen
, raw_config
)
632 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
634 step("Configure R4 as RP on all the nodes for group range 224.0.0.0/24")
641 "rp_addr": topo
["routers"]["r4"]["links"]["lo"]["ipv4"].split(
644 "group_addr_range": GROUP_RANGE_1
,
651 result
= create_pim_config(tgen
, topo
, input_dict
)
652 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
654 step("Configure IGMP on R5 port and send IGMP join for groups " "(226.1.1.1-5)")
656 intf_r5_i2
= topo
["routers"]["r5"]["links"]["i2"]["interface"]
658 "r5": {"igmp": {"interfaces": {intf_r5_i2
: {"igmp": {"version": "2"}}}}}
660 result
= create_igmp_config(tgen
, topo
, input_dict
)
661 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
663 input_src
= {"i2": topo
["routers"]["i2"]["links"]["r5"]["interface"]}
665 result
= app_helper
.run_join("i2", IGMP_JOIN_RANGE_1
, "r5")
666 assert result
is True, "Testcase {}: Failed Error: {}".format(tc_name
, result
)
668 step("Using static routes instead OSPF: Enable OSPF between all the nodes")
670 step("Start traffic from Source node")
672 vlan_intf_i1_s1
= "{}.{}".format(intf_i1_s1
, VLAN_1
)
673 result
= app_helper
.run_traffic("i1", IGMP_JOIN_RANGE_1
, bind_intf
=vlan_intf_i1_s1
)
674 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
679 #####################################################
683 #####################################################
686 def test_pim_source_dr_functionality_while_rebooting_dr_non_dr_nodes_p1(request
):
688 Verify mroute while rebooting DR /Non DR nodes( r1, r2 , r3 on all the nodes)
692 tc_name
= request
.node
.name
693 write_test_header(tc_name
)
695 # Creating configuration from JSON
696 app_helper
.stop_all_hosts()
698 check_router_status(tgen
)
699 reset_config_on_routers(tgen
)
700 clear_pim_interface_traffic(tgen
, topo
)
702 # Don"t run this test if we have any failure.
703 if tgen
.routers_have_failure():
704 pytest
.skip(tgen
.errors
)
706 result
= pre_config_for_source_dr_tests(tgen
, topo
, tc_name
, "r1", "r3")
707 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
709 step("R1 is the DR , verify using 'show ip pim interface json'")
711 vlan_intf_r1_s1
= "{}.{}".format(intf_r1_s1
, VLAN_1
)
715 "interfaces": {vlan_intf_r1_s1
: {"drAddress": SAME_VLAN_IP_3
["ip"]}}
719 result
= verify_pim_config(tgen
, input_dict_dr
)
720 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
723 "R2 is transit router for I1 to reach R4, mroute should have (s, g) mroute with "
724 "OIL towards R4, using 'show ip mroute json'"
727 "R2 (s, g) upstream should be in join state verify using "
728 "'show ip pim upstream json'"
731 "R1 has (S, G) mroute with NONE OIL and upstream as not joined, verify using "
732 "'show ip mroute json' 'show ip pim upstream json'"
735 source_i1
= SAME_VLAN_IP_4
["ip"]
739 "src_address": source_i1
,
741 "iif": "{}.{}".format(
742 topo
["routers"]["r1"]["links"]["s1"]["interface"], VLAN_1
747 "src_address": source_i1
,
748 "oil": topo
["routers"]["r2"]["links"]["r4"]["interface"],
749 "iif": "{}.{}".format(
750 topo
["routers"]["r2"]["links"]["s1"]["interface"], VLAN_1
755 for data
in input_dict_r1_r2
:
756 result
= verify_mroutes(
764 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
766 if data
["dut"] == "r2":
767 result
= verify_upstream_iif(
768 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
770 assert result
is True, "Testcase {} : Failed Error: {}".format(
774 result
= verify_upstream_iif(
782 assert result
is not True, (
783 "Testcase {} : Failed \n "
784 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
787 step("Reboot R3 node")
788 stop_router(tgen
, "r3")
791 "After reboot of R3 verify R1 continues to be DR, using 'show ip pim interface json'"
794 result
= verify_pim_config(tgen
, input_dict_dr
)
795 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
797 step("R3 should not have any mroute and upstream")
798 step("R2 has mroute with OIL towards R4 /R1 , verify using 'show ip mroute'")
800 "R2 has upstream with Join RejP state verify using 'show ip pim upstream json'"
802 step("R1 has mroute with none OIL and upstream with Not Join")
804 for data
in input_dict_r1_r2
:
805 result
= verify_mroutes(
813 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
815 if data
["dut"] == "r2":
816 result
= verify_upstream_iif(
817 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
819 assert result
is True, "Testcase {} : Failed Error: {}".format(
823 result
= verify_upstream_iif(
831 assert result
is not True, (
832 "Testcase {} : Failed \n "
833 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
836 step("Reboot R2 node")
837 stop_router(tgen
, "r2")
840 "After reboot of R2, R1 continues to be DR verify using 'show ip pim interface json'"
843 result
= verify_pim_config(tgen
, input_dict_dr
)
844 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
847 "R3 and R2 should not have any mroute and upstream , verify using "
848 "'show ip mroute json' 'show ip pim upstream json'"
850 step("R1 has mroute created with empty OIL, using 'show ip mroute json'")
852 "R1 has upstream with Not Join, Rej Prune , verify using 'show ip pim upstream json'"
855 for data
in input_dict_r1_r2
:
856 if data
["dut"] == "r1":
857 result
= verify_mroutes(
865 assert result
is True, "Testcase {} : Failed Error: {}".format(
869 result
= verify_upstream_iif(
877 assert result
is not True, (
878 "Testcase {} : Failed \n "
879 "Upstream is still joined state \n Error: {}".format(tc_name
, result
)
882 step("Reboot R1 node using FRR stop")
883 stop_router(tgen
, "r1")
886 "After stop of all the routers, verify upstream and mroutes should "
887 "not present in any of them"
890 for data
in input_dict_r1_r2
:
891 result
= verify_mroutes(
902 ), "Testcase {} : Failed \n " "mroutes are still present \n Error: {}".format(
906 step("start FRR for all the nodes")
907 start_router(tgen
, "r1")
908 start_router(tgen
, "r2")
909 start_router(tgen
, "r3")
911 step("After start of all the routers, R1 became DR")
913 result
= verify_pim_config(tgen
, input_dict_dr
)
914 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
916 for data
in input_dict_r1_r2
:
917 result
= verify_mroutes(
925 assert result
is True, "Testcase {} : Failed Error: {}".format(tc_name
, result
)
927 if data
["dut"] == "r2":
928 result
= verify_upstream_iif(
929 tgen
, data
["dut"], data
["iif"], data
["src_address"], IGMP_JOIN_RANGE_1
931 assert result
is True, "Testcase {} : Failed Error: {}".format(
935 write_test_footer(tc_name
)
938 if __name__
== "__main__":
939 args
= ["-s"] + sys
.argv
[1:]
940 sys
.exit(pytest
.main(args
))