1bd03f10aSAlexander V. Chernikovimport pytest
2bd03f10aSAlexander V. Chernikovfrom atf_python.sys.net.rtsock import RtConst
3bd03f10aSAlexander V. Chernikovfrom atf_python.sys.net.rtsock import Rtsock
4bd03f10aSAlexander V. Chernikovfrom atf_python.sys.net.rtsock import RtsockRtMessage
5bd03f10aSAlexander V. Chernikovfrom atf_python.sys.net.tools import ToolsHelper
6bd03f10aSAlexander V. Chernikovfrom atf_python.sys.net.vnet import SingleVnetTestTemplate
7bd03f10aSAlexander V. Chernikov
8bd03f10aSAlexander V. Chernikov
9bd03f10aSAlexander V. Chernikovclass TestRtmMultipath(SingleVnetTestTemplate):
10bd03f10aSAlexander V. Chernikov    def setup_method(self, method):
11bd03f10aSAlexander V. Chernikov        method_name = method.__name__
12bd03f10aSAlexander V. Chernikov        if "multipath4" in method_name:
13bd03f10aSAlexander V. Chernikov            self.IPV4_PREFIXES = ["192.0.2.1/24"]
14bd03f10aSAlexander V. Chernikov            self.PREFIX = "128.66.0.0/24"
15bd03f10aSAlexander V. Chernikov        elif "multipath6" in method_name:
16bd03f10aSAlexander V. Chernikov            self.IPV6_PREFIXES = ["2001:db8::1/64"]
17bd03f10aSAlexander V. Chernikov            self.PREFIX = "2001:db8:0:ddbb::/64"
18bd03f10aSAlexander V. Chernikov        super().setup_method(method)
19bd03f10aSAlexander V. Chernikov        self.rtsock = Rtsock()
20bd03f10aSAlexander V. Chernikov
21bd03f10aSAlexander V. Chernikov    def get_prefix_routes(self):
22bd03f10aSAlexander V. Chernikov        family = "inet6" if ":" in self.PREFIX else "inet"
23bd03f10aSAlexander V. Chernikov        routes = ToolsHelper.get_routes(family)
24bd03f10aSAlexander V. Chernikov        return [r for r in routes if r["destination"] == self.PREFIX]
25bd03f10aSAlexander V. Chernikov
26bd03f10aSAlexander V. Chernikov    @pytest.mark.parametrize(
27bd03f10aSAlexander V. Chernikov        "gws",
28bd03f10aSAlexander V. Chernikov        [
29bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3"], id="transition_multi"),
30bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3", "-.10=2"], id="transition_single1"),
31bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3", "-.5=3"], id="transition_single2"),
32bd03f10aSAlexander V. Chernikov            pytest.param(
33bd03f10aSAlexander V. Chernikov                ["+.10", "+.11", "+.50", "+.13", "+.145", "+.72"], id="correctness1"
34bd03f10aSAlexander V. Chernikov            ),
35bd03f10aSAlexander V. Chernikov            pytest.param(
36bd03f10aSAlexander V. Chernikov                ["+.10", "+.11", "+.50", "-.50", "+.145", "+.72"], id="correctness2"
37bd03f10aSAlexander V. Chernikov            ),
38bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=1", "+.5=2"], id="weight1"),
39bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=7"], id="weight2"),
40bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=13", "+.5=21"], id="weight3_max"),
41bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3", "~.5=4"], id="change_new_weight1"),
42bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3", "~.10=3"], id="change_new_weight2"),
43bd03f10aSAlexander V. Chernikov            pytest.param(
44bd03f10aSAlexander V. Chernikov                ["+.10=2", "+.5=3", "+.7=4", "~.10=3"], id="change_new_weight3"
45bd03f10aSAlexander V. Chernikov            ),
46bd03f10aSAlexander V. Chernikov            pytest.param(["+.10=2", "+.5=3", "~.5=3"], id="change_same_weight1"),
47bd03f10aSAlexander V. Chernikov            pytest.param(
48bd03f10aSAlexander V. Chernikov                ["+.10=2", "+.5=3", "+.7=4", "~.5=3"], id="change_same_weight2"
49bd03f10aSAlexander V. Chernikov            ),
50bd03f10aSAlexander V. Chernikov        ],
51bd03f10aSAlexander V. Chernikov    )
52bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
53bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4(self, gws):
54bd03f10aSAlexander V. Chernikov        """Tests RTM_ADD with IPv4 dest transitioning to multipath"""
55bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath(gws, "192.0.2")
56bd03f10aSAlexander V. Chernikov
57bd03f10aSAlexander V. Chernikov    @pytest.mark.parametrize(
58bd03f10aSAlexander V. Chernikov        "gws",
59bd03f10aSAlexander V. Chernikov        [
60bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3"], id="transition_multi"),
61bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3", "-:10=2"], id="transition_single1"),
62bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3", "-:5=3"], id="transition_single2"),
63bd03f10aSAlexander V. Chernikov            pytest.param(
64bd03f10aSAlexander V. Chernikov                ["+:10", "+:11", "+:50", "+:13", "+:145", "+:72"], id="correctness1"
65bd03f10aSAlexander V. Chernikov            ),
66bd03f10aSAlexander V. Chernikov            pytest.param(
67bd03f10aSAlexander V. Chernikov                ["+:10", "+:11", "+:50", "-:50", "+:145", "+:72"], id="correctness2"
68bd03f10aSAlexander V. Chernikov            ),
69bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=1", "+:5=2"], id="weight1"),
70bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=7"], id="weight2"),
71bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=13", "+:5=21"], id="weight3_max"),
72bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=13", "+:5=21"], id="weight3_max"),
73bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3", "~:5=4"], id="change_new_weight1"),
74bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3", "~:10=3"], id="change_new_weight2"),
75bd03f10aSAlexander V. Chernikov            pytest.param(
76bd03f10aSAlexander V. Chernikov                ["+:10=2", "+:5=3", "+:7=4", "~:10=3"], id="change_new_weight3"
77bd03f10aSAlexander V. Chernikov            ),
78bd03f10aSAlexander V. Chernikov            pytest.param(["+:10=2", "+:5=3", "~:5=3"], id="change_same_weight1"),
79bd03f10aSAlexander V. Chernikov            pytest.param(
80bd03f10aSAlexander V. Chernikov                ["+:10=2", "+:5=3", "+:7=4", "~:5=3"], id="change_same_weight2"
81bd03f10aSAlexander V. Chernikov            ),
82bd03f10aSAlexander V. Chernikov        ],
83bd03f10aSAlexander V. Chernikov    )
84bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
85bd03f10aSAlexander V. Chernikov    def test_rtm_multipath6(self, gws):
86bd03f10aSAlexander V. Chernikov        """Tests RTM_ADD with IPv6 dest transitioning to multipath"""
87bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath(gws, "2001:db8:")
88bd03f10aSAlexander V. Chernikov
89bd03f10aSAlexander V. Chernikov    def _test_rtm_multipath(self, gws, gw_prefix: str):
90bd03f10aSAlexander V. Chernikov        desired_map = {}
91bd03f10aSAlexander V. Chernikov        for gw_act in gws:
92bd03f10aSAlexander V. Chernikov            # GW format: <+-~>GW[=weight]
93bd03f10aSAlexander V. Chernikov            if "=" in gw_act:
94bd03f10aSAlexander V. Chernikov                arr = gw_act[1:].split("=")
95bd03f10aSAlexander V. Chernikov                weight = int(arr[1])
96bd03f10aSAlexander V. Chernikov                gw = gw_prefix + arr[0]
97bd03f10aSAlexander V. Chernikov            else:
98bd03f10aSAlexander V. Chernikov                weight = None
99bd03f10aSAlexander V. Chernikov                gw = gw_prefix + gw_act[1:]
100bd03f10aSAlexander V. Chernikov            if gw_act[0] == "+":
101bd03f10aSAlexander V. Chernikov                msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
102bd03f10aSAlexander V. Chernikov                desired_map[gw] = self.rtsock.get_weight(weight)
103bd03f10aSAlexander V. Chernikov            elif gw_act[0] == "-":
104bd03f10aSAlexander V. Chernikov                msg = self.rtsock.new_rtm_del(self.PREFIX, gw)
105bd03f10aSAlexander V. Chernikov                del desired_map[gw]
106bd03f10aSAlexander V. Chernikov            else:
107bd03f10aSAlexander V. Chernikov                msg = self.rtsock.new_rtm_change(self.PREFIX, gw)
108bd03f10aSAlexander V. Chernikov                desired_map[gw] = self.rtsock.get_weight(weight)
109bd03f10aSAlexander V. Chernikov
110bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
111bd03f10aSAlexander V. Chernikov            if weight:
112bd03f10aSAlexander V. Chernikov                msg.rtm_inits |= RtConst.RTV_WEIGHT
113bd03f10aSAlexander V. Chernikov                msg.rtm_rmx.rmx_weight = weight
114bd03f10aSAlexander V. Chernikov            # Prepare SAs to check for
115bd03f10aSAlexander V. Chernikov            desired_sa = {
116bd03f10aSAlexander V. Chernikov                RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST),
117bd03f10aSAlexander V. Chernikov                RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK),
118bd03f10aSAlexander V. Chernikov                RtConst.RTA_GATEWAY: msg.get_sa(RtConst.RTA_GATEWAY),
119bd03f10aSAlexander V. Chernikov            }
120bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
121bd03f10aSAlexander V. Chernikov
122bd03f10aSAlexander V. Chernikov            data = self.rtsock.read_data(msg.rtm_seq)
123bd03f10aSAlexander V. Chernikov            msg_in = RtsockRtMessage.from_bytes(data)
124bd03f10aSAlexander V. Chernikov            msg_in.print_in_message()
125bd03f10aSAlexander V. Chernikov            msg_in.verify(msg.rtm_type, desired_sa)
126bd03f10aSAlexander V. Chernikov            assert msg_in.rtm_rmx.rmx_weight == self.rtsock.get_weight(weight)
127bd03f10aSAlexander V. Chernikov
128bd03f10aSAlexander V. Chernikov            routes = self.get_prefix_routes()
129bd03f10aSAlexander V. Chernikov            derived_map = {r["gateway"]: r["weight"] for r in routes}
130bd03f10aSAlexander V. Chernikov            assert derived_map == desired_map
131bd03f10aSAlexander V. Chernikov
132bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
133bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4_add_same_eexist(self):
134bd03f10aSAlexander V. Chernikov        """Tests adding same IPv4 gw to the multipath group (EEXIST)"""
135bd03f10aSAlexander V. Chernikov        gws = ["192.0.2.10", "192.0.2.11", "192.0.2.11"]
136bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_add_same_eexist(gws)
137bd03f10aSAlexander V. Chernikov
138bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
139bd03f10aSAlexander V. Chernikov    def test_rtm_multipath6_add_same_eexist(self):
140bd03f10aSAlexander V. Chernikov        """Tests adding same IPv4 gw to the multipath group (EEXIST)"""
141bd03f10aSAlexander V. Chernikov        gws = ["2001:db8::10", "2001:db8::11", "2001:db8::11"]
142bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_add_same_eexist(gws)
143bd03f10aSAlexander V. Chernikov
144bd03f10aSAlexander V. Chernikov    def _test_rtm_multipath_add_same_eexist(self, gws):
145bd03f10aSAlexander V. Chernikov        for idx, gw in enumerate(gws):
146bd03f10aSAlexander V. Chernikov            msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
147bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
148bd03f10aSAlexander V. Chernikov            try:
149bd03f10aSAlexander V. Chernikov                self.rtsock.write_message(msg)
150bd03f10aSAlexander V. Chernikov            except FileExistsError as e:
151bd03f10aSAlexander V. Chernikov                if idx != 2:
152bd03f10aSAlexander V. Chernikov                    raise
153bd03f10aSAlexander V. Chernikov                print("Succcessfully raised {}".format(e))
154bd03f10aSAlexander V. Chernikov
155bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
156bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4_del_unknown_esrch(self):
157bd03f10aSAlexander V. Chernikov        """Tests deleting non-existing dest from the multipath group (ESRCH)"""
158bd03f10aSAlexander V. Chernikov        gws = ["192.0.2.10", "192.0.2.11"]
159bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_del_unknown_esrch(gws, "192.0.2.7")
160bd03f10aSAlexander V. Chernikov
161bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
162bd03f10aSAlexander V. Chernikov    def test_rtm_multipath6_del_unknown_esrch(self):
163bd03f10aSAlexander V. Chernikov        """Tests deleting non-existing dest from the multipath group (ESRCH)"""
164bd03f10aSAlexander V. Chernikov        gws = ["2001:db8::10", "2001:db8::11"]
165bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_del_unknown_esrch(gws, "2001:db8::7")
166bd03f10aSAlexander V. Chernikov
167bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
168bd03f10aSAlexander V. Chernikov    def _test_rtm_multipath_del_unknown_esrch(self, gws, target_gw):
169bd03f10aSAlexander V. Chernikov        for gw in gws:
170bd03f10aSAlexander V. Chernikov            msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
171bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
172bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
173bd03f10aSAlexander V. Chernikov        msg = self.rtsock.new_rtm_del(self.PREFIX, target_gw)
174bd03f10aSAlexander V. Chernikov        msg.rtm_flags = RtConst.RTF_GATEWAY
175bd03f10aSAlexander V. Chernikov        try:
176bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
177bd03f10aSAlexander V. Chernikov        except ProcessLookupError as e:
178bd03f10aSAlexander V. Chernikov            print("Succcessfully raised {}".format(e))
179bd03f10aSAlexander V. Chernikov
180bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
181bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4_change_unknown_esrch(self):
182bd03f10aSAlexander V. Chernikov        """Tests changing non-existing dest in the multipath group (ESRCH)"""
183bd03f10aSAlexander V. Chernikov        gws = ["192.0.2.10", "192.0.2.11"]
184bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_change_unknown_esrch(gws, "192.0.2.7")
185bd03f10aSAlexander V. Chernikov
186bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
187bd03f10aSAlexander V. Chernikov    def test_rtm_multipath6_change_unknown_esrch(self):
188bd03f10aSAlexander V. Chernikov        """Tests changing non-existing dest in the multipath group (ESRCH)"""
189bd03f10aSAlexander V. Chernikov        gws = ["2001:db8::10", "2001:db8::11"]
190bd03f10aSAlexander V. Chernikov        self._test_rtm_multipath_change_unknown_esrch(gws, "2001:db8::7")
191bd03f10aSAlexander V. Chernikov
192bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
193bd03f10aSAlexander V. Chernikov    def _test_rtm_multipath_change_unknown_esrch(self, gws, target_gw):
194bd03f10aSAlexander V. Chernikov        for gw in gws:
195bd03f10aSAlexander V. Chernikov            msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
196bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
197bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
198bd03f10aSAlexander V. Chernikov        msg = self.rtsock.new_rtm_change(self.PREFIX, target_gw)
199bd03f10aSAlexander V. Chernikov        msg.rtm_flags = RtConst.RTF_GATEWAY
200bd03f10aSAlexander V. Chernikov        try:
201bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
202bd03f10aSAlexander V. Chernikov        except ProcessLookupError as e:
203bd03f10aSAlexander V. Chernikov            print("Succcessfully raised {}".format(e))
204bd03f10aSAlexander V. Chernikov
205bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
206bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4_add_zero_weight(self):
207bd03f10aSAlexander V. Chernikov        """Tests RTM_ADD with dest transitioning to multipath"""
208bd03f10aSAlexander V. Chernikov
209bd03f10aSAlexander V. Chernikov        desired_map = {}
210bd03f10aSAlexander V. Chernikov        for gw in ["192.0.2.10", "192.0.2.11", "192.0.2.13"]:
211bd03f10aSAlexander V. Chernikov            msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
212bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
213bd03f10aSAlexander V. Chernikov            msg.rtm_rmx.rmx_weight = 0
214bd03f10aSAlexander V. Chernikov            msg.rtm_inits |= RtConst.RTV_WEIGHT
215bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
216bd03f10aSAlexander V. Chernikov            desired_map[gw] = self.rtsock.get_weight(0)
217bd03f10aSAlexander V. Chernikov
218bd03f10aSAlexander V. Chernikov        routes = self.get_prefix_routes()
219bd03f10aSAlexander V. Chernikov        derived_map = {r["gateway"]: r["weight"] for r in routes}
220bd03f10aSAlexander V. Chernikov        assert derived_map == desired_map
221bd03f10aSAlexander V. Chernikov
222bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
223bd03f10aSAlexander V. Chernikov    def test_rtm_multipath4_getroute(self):
224bd03f10aSAlexander V. Chernikov        """Tests RTM_GET with exact prefix lookup on the multipath group"""
225bd03f10aSAlexander V. Chernikov        gws = ["192.0.2.10", "192.0.2.11", "192.0.2.13"]
226bd03f10aSAlexander V. Chernikov        return self._test_rtm_multipath_getroute(gws)
227bd03f10aSAlexander V. Chernikov
228bd03f10aSAlexander V. Chernikov    @pytest.mark.require_user("root")
229bd03f10aSAlexander V. Chernikov    def test_rtm_multipath6_getroute(self):
230bd03f10aSAlexander V. Chernikov        """Tests RTM_GET with exact prefix lookup on the multipath group"""
231bd03f10aSAlexander V. Chernikov        gws = ["2001:db8::10", "2001:db8::11", "2001:db8::13"]
232bd03f10aSAlexander V. Chernikov        return self._test_rtm_multipath_getroute(gws)
233bd03f10aSAlexander V. Chernikov
234bd03f10aSAlexander V. Chernikov    def _test_rtm_multipath_getroute(self, gws):
235bd03f10aSAlexander V. Chernikov        valid_gws = []
236bd03f10aSAlexander V. Chernikov        for gw in gws:
237bd03f10aSAlexander V. Chernikov            msg = self.rtsock.new_rtm_add(self.PREFIX, gw)
238bd03f10aSAlexander V. Chernikov            msg.rtm_flags = RtConst.RTF_GATEWAY
239bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg)
240bd03f10aSAlexander V. Chernikov
241bd03f10aSAlexander V. Chernikov            desired_sa = {
242bd03f10aSAlexander V. Chernikov                RtConst.RTA_DST: msg.get_sa(RtConst.RTA_DST),
243bd03f10aSAlexander V. Chernikov                RtConst.RTA_NETMASK: msg.get_sa(RtConst.RTA_NETMASK),
244bd03f10aSAlexander V. Chernikov            }
245bd03f10aSAlexander V. Chernikov            valid_gws.append(msg.get_sa(RtConst.RTA_GATEWAY))
246bd03f10aSAlexander V. Chernikov
247bd03f10aSAlexander V. Chernikov            msg_get = RtsockRtMessage(
248bd03f10aSAlexander V. Chernikov                RtConst.RTM_GET,
249bd03f10aSAlexander V. Chernikov                self.rtsock.get_seq(),
250bd03f10aSAlexander V. Chernikov                msg.get_sa(RtConst.RTA_DST),
251bd03f10aSAlexander V. Chernikov                msg.get_sa(RtConst.RTA_NETMASK),
252bd03f10aSAlexander V. Chernikov            )
253bd03f10aSAlexander V. Chernikov            self.rtsock.write_message(msg_get)
254bd03f10aSAlexander V. Chernikov
255bd03f10aSAlexander V. Chernikov            data = self.rtsock.read_data(msg_get.rtm_seq)
256bd03f10aSAlexander V. Chernikov            msg_in = RtsockRtMessage.from_bytes(data)
257bd03f10aSAlexander V. Chernikov            msg_in.print_in_message()
258bd03f10aSAlexander V. Chernikov            msg_in.verify(RtConst.RTM_GET, desired_sa)
259bd03f10aSAlexander V. Chernikov
260bd03f10aSAlexander V. Chernikov            # Additionally, check that the gateway is among the valid
261bd03f10aSAlexander V. Chernikov            # gateways
262bd03f10aSAlexander V. Chernikov            gw_found = False
263bd03f10aSAlexander V. Chernikov            gw_in = msg_in.get_sa(RtConst.RTA_GATEWAY)
264bd03f10aSAlexander V. Chernikov            for valid_gw in valid_gws:
265bd03f10aSAlexander V. Chernikov                try:
266bd03f10aSAlexander V. Chernikov                    assert valid_gw == gw_in
267bd03f10aSAlexander V. Chernikov                    gw_found = True
268bd03f10aSAlexander V. Chernikov                    break
269bd03f10aSAlexander V. Chernikov                except AssertionError:
270bd03f10aSAlexander V. Chernikov                    pass
271bd03f10aSAlexander V. Chernikov            assert gw_found is True
272