How to use attach_frame method in Playwright Python

Best Python code snippet using playwright-python

system_tests_link_routes.py

Source:system_tests_link_routes.py Github

copy

Full Screen

1#2# Licensed to the Apache Software Foundation (ASF) under one3# or more contributor license agreements. See the NOTICE file4# distributed with this work for additional information5# regarding copyright ownership. The ASF licenses this file6# to you under the Apache License, Version 2.0 (the7# "License"); you may not use this file except in compliance8# with the License. You may obtain a copy of the License at9#10# http://www.apache.org/licenses/LICENSE-2.011#12# Unless required by applicable law or agreed to in writing,13# software distributed under the License is distributed on an14# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY15# KIND, either express or implied. See the License for the16# specific language governing permissions and limitations17# under the License.18#19from time import sleep, time20from threading import Event21from subprocess import PIPE, STDOUT22import socket23from typing import Optional24from system_test import TestCase, Qdrouterd, main_module, TIMEOUT, Process, TestTimeout, \25 AsyncTestSender, AsyncTestReceiver, MgmtMsgProxy, unittest, QdManager26from test_broker import FakeBroker27from test_broker import FakeService28from proton import Delivery, symbol, Data, Described29from proton import Message, Condition30from proton.handlers import MessagingHandler31from proton.reactor import AtMostOnce, Container, DynamicNodeProperties, LinkOption, AtLeastOnce32from proton.reactor import ApplicationEvent33from proton.reactor import EventInjector34from proton.utils import BlockingConnection35from system_tests_drain_support import DrainMessagesHandler, DrainOneMessageHandler, DrainNoMessagesHandler, DrainNoMoreMessagesHandler36from qpid_dispatch.management.client import Node37from qpid_dispatch.management.error import NotFoundStatus, BadRequestStatus38class LinkRouteTest(TestCase):39 """40 Tests the linkRoute property of the dispatch router.41 Sets up 4 routers (two of which are acting as brokers (QDR.A, QDR.D)). The other two routers have linkRoutes42 configured such that matching traffic will be directed to/from the 'fake' brokers.43 (please see configs in the setUpClass method to get a sense of how the routers and their connections are configured)44 The tests in this class send and receive messages across this network of routers to link routable addresses.45 Uses the Python Blocking API to send/receive messages. The blocking api plays neatly into the synchronous nature46 of system tests.47 QDR.A acting broker #148 +---------+ +---------+ +---------+ +-----------------+49 | | <------ | | <----- | |<----| blocking_sender |50 | QDR.A | | QDR.B | | QDR.C | +-----------------+51 | | ------> | | ------> | | +-------------------+52 +---------+ +---------+ +---------+---->| blocking_receiver |53 ^ | +-------------------+54 | |55 | V56 +---------+57 | |58 | QDR.D |59 | |60 +---------+61 QDR.D acting broker #262 """63 @classmethod64 def get_router(cls, index):65 return cls.routers[index]66 @classmethod67 def setUpClass(cls):68 """Start three routers"""69 super(LinkRouteTest, cls).setUpClass()70 def router(name, connection):71 config = [72 ('router', {'mode': 'interior', 'id': 'QDR.%s' % name}),73 ] + connection74 config = Qdrouterd.Config(config)75 cls.routers.append(cls.tester.qdrouterd(name, config, wait=False))76 cls.routers = []77 a_listener_port = cls.tester.get_port()78 b_listener_port = cls.tester.get_port()79 c_listener_port = cls.tester.get_port()80 d_listener_port = cls.tester.get_port()81 test_tag_listener_port = cls.tester.get_port()82 router('A',83 [84 ('listener', {'role': 'normal', 'host': '0.0.0.0', 'port': a_listener_port, 'saslMechanisms': 'ANONYMOUS'}),85 ])86 router('B',87 [88 # Listener for clients, note that the tests assume this listener is first in this list:89 ('listener', {'role': 'normal', 'host': '0.0.0.0', 'port': b_listener_port, 'saslMechanisms': 'ANONYMOUS'}),90 ('listener', {'name': 'test-tag', 'role': 'route-container', 'host': '0.0.0.0', 'port': test_tag_listener_port, 'saslMechanisms': 'ANONYMOUS'}),91 # This is an route-container connection made from QDR.B's ephemeral port to a_listener_port92 ('connector', {'name': 'broker', 'role': 'route-container', 'host': '0.0.0.0', 'port': a_listener_port, 'saslMechanisms': 'ANONYMOUS'}),93 # Only inter router communication must happen on 'inter-router' connectors. This connector makes94 # a connection from the router B's ephemeral port to c_listener_port95 ('connector', {'name': 'routerC', 'role': 'inter-router', 'host': '0.0.0.0', 'port': c_listener_port}),96 # This is an on-demand connection made from QDR.B's ephemeral port to d_listener_port97 ('connector', {'name': 'routerD', 'role': 'route-container', 'host': '0.0.0.0', 'port': d_listener_port, 'saslMechanisms': 'ANONYMOUS'}),98 #('linkRoute', {'prefix': 'org.apache', 'connection': 'broker', 'direction': 'in'}),99 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'QDR.A', 'direction': 'in'}),100 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'QDR.A', 'direction': 'out'}),101 ('linkRoute', {'prefix': 'pulp.task', 'connection': 'test-tag', 'direction': 'in'}),102 ('linkRoute', {'prefix': 'pulp.task', 'connection': 'test-tag', 'direction': 'out'}),103 # addresses matching pattern 'a.*.toA.#' route to QDR.A104 ('linkRoute', {'pattern': 'a.*.toA.#', 'containerId': 'QDR.A', 'direction': 'in'}),105 ('linkRoute', {'pattern': 'a.*.toA.#', 'containerId': 'QDR.A', 'direction': 'out'}),106 # addresses matching pattern 'a.*.toD.#' route to QDR.D107 # Dont change dir to direction here so we can make sure that the dir attribute is still working.108 ('linkRoute', {'pattern': 'a.*.toD.#', 'containerId': 'QDR.D', 'dir': 'in'}),109 ('linkRoute', {'pattern': 'a.*.toD.#', 'containerId': 'QDR.D', 'dir': 'out'})110 ]111 )112 router('C',113 [114 # The client will exclusively use the following listener to115 # connect to QDR.C, the tests assume this is the first entry116 # in the list117 ('listener', {'host': '0.0.0.0', 'role': 'normal', 'port': cls.tester.get_port(), 'saslMechanisms': 'ANONYMOUS'}),118 ('listener', {'host': '0.0.0.0', 'role': 'inter-router', 'port': c_listener_port, 'saslMechanisms': 'ANONYMOUS'}),119 # The dot(.) at the end is ignored by the address hashing scheme.120 ('linkRoute', {'prefix': 'org.apache.', 'direction': 'in'}),121 ('linkRoute', {'prefix': 'org.apache.', 'direction': 'out'}),122 ('linkRoute', {'prefix': 'pulp.task', 'direction': 'in'}),123 ('linkRoute', {'prefix': 'pulp.task', 'direction': 'out'}),124 ('linkRoute', {'pattern': 'a.*.toA.#', 'direction': 'in'}),125 ('linkRoute', {'pattern': 'a.*.toA.#', 'direction': 'out'}),126 ('linkRoute', {'pattern': 'a.*.toD.#', 'direction': 'in'}),127 ('linkRoute', {'pattern': 'a.*.toD.#', 'direction': 'out'})128 ]129 )130 router('D', # sink for QDR.D routes131 [132 ('listener', {'role': 'normal', 'host': '0.0.0.0', 'port': d_listener_port, 'saslMechanisms': 'ANONYMOUS'}),133 ])134 # Wait for the routers to locate each other, and for route propagation135 # to settle136 cls.routers[1].wait_router_connected('QDR.C')137 cls.routers[2].wait_router_connected('QDR.B')138 cls.routers[2].wait_address("org.apache", remotes=1, delay=0.5, count=2)139 # This is not a classic router network in the sense that QDR.A and D are acting as brokers. We allow a little140 # bit more time for the routers to stabilize.141 sleep(2)142 def run_qdstat_linkRoute(self, address, args=None):143 cmd = ['qdstat', '--bus', str(address), '--timeout', str(TIMEOUT)] + ['--linkroute']144 if args:145 cmd = cmd + args146 p = self.popen(147 cmd,148 name='qdstat-' + self.id(), stdout=PIPE, expect=None,149 universal_newlines=True)150 out = p.communicate()[0]151 assert p.returncode == 0, "qdstat exit status %s, output:\n%s" % (p.returncode, out)152 return out153 def run_qdmanage(self, cmd, input=None, expect=Process.EXIT_OK, address=None):154 p = self.popen(155 ['qdmanage'] + cmd.split(' ') + ['--bus', address or self.address(), '--indent=-1', '--timeout', str(TIMEOUT)],156 stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=expect,157 universal_newlines=True)158 out = p.communicate(input)[0]159 try:160 p.teardown()161 except Exception as e:162 raise Exception("%s\n%s" % (e, out))163 return out164 def test_aaa_qdmanage_query_link_route(self):165 """166 qdmanage converts short type to long type and this test specifically tests if qdmanage is actually doing167 the type conversion correctly by querying with short type and long type.168 """169 cmd = 'QUERY --type=linkRoute'170 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])171 # Make sure there is a dir of in and out.172 self.assertIn('"direction": "in"', out)173 self.assertIn('"direction": "out"', out)174 self.assertIn('"containerId": "QDR.A"', out)175 # Use the long type and make sure that qdmanage does not mess up the long type176 cmd = 'QUERY --type=org.apache.qpid.dispatch.router.config.linkRoute'177 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])178 # Make sure there is a dir of in and out.179 self.assertIn('"direction": "in"', out)180 self.assertIn('"direction": "out"', out)181 self.assertIn('"containerId": "QDR.A"', out)182 identity = out[out.find("identity") + 12: out.find("identity") + 13]183 cmd = 'READ --type=linkRoute --identity=' + identity184 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])185 self.assertIn(identity, out)186 exception_occurred = False187 try:188 # This identity should not be found189 cmd = 'READ --type=linkRoute --identity=9999'190 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])191 except Exception as e:192 exception_occurred = True193 self.assertIn("NotFoundStatus: Not Found", str(e))194 self.assertTrue(exception_occurred)195 exception_occurred = False196 try:197 # There is no identity specified, this is a bad request198 cmd = 'READ --type=linkRoute'199 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])200 except Exception as e:201 exception_occurred = True202 self.assertIn("BadRequestStatus: No name or identity provided", str(e))203 self.assertTrue(exception_occurred)204 cmd = 'CREATE --type=autoLink address=127.0.0.1 direction=in connection=routerC'205 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])206 identity = out[out.find("identity") + 12: out.find("identity") + 14]207 cmd = 'READ --type=autoLink --identity=' + identity208 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])209 self.assertIn(identity, out)210 def test_bbb_qdstat_link_routes_routerB(self):211 """212 Runs qdstat on router B to make sure that router B has 4 link routes,213 each having one 'in' and one 'out' entry214 """215 out = self.run_qdstat_linkRoute(self.routers[1].addresses[0])216 for route in ['a.*.toA.#', 'a.*.toD.#', 'org.apache', 'pulp.task']:217 self.assertIn(route, out)218 out_list = out.split()219 self.assertEqual(out_list.count('in'), 4)220 self.assertEqual(out_list.count('out'), 4)221 parts = out.split("\n")222 self.assertEqual(len(parts), 15)223 out = self.run_qdstat_linkRoute(self.routers[1].addresses[0], args=['--limit=1'])224 parts = out.split("\n")225 self.assertEqual(len(parts), 8)226 def test_ccc_qdstat_link_routes_routerC(self):227 """228 Runs qdstat on router C to make sure that router C has 4 link routes,229 each having one 'in' and one 'out' entry230 """231 out = self.run_qdstat_linkRoute(self.routers[2].addresses[0])232 out_list = out.split()233 self.assertEqual(out_list.count('in'), 4)234 self.assertEqual(out_list.count('out'), 4)235 def test_ddd_partial_link_route_match(self):236 """237 The linkRoute on Routers C and B is set to org.apache.238 Creates a receiver listening on the address 'org.apache.dev' and a sender that sends to address 'org.apache.dev'.239 Sends a message to org.apache.dev via router QDR.C and makes sure that the message was successfully240 routed (using partial address matching) and received using pre-created links that were created as a241 result of specifying addresses in the linkRoute attribute('org.apache.').242 """243 hello_world_1 = "Hello World_1!"244 # Connects to listener #2 on QDR.C245 addr = self.routers[2].addresses[0]246 blocking_connection = BlockingConnection(addr)247 # Receive on org.apache.dev248 blocking_receiver = blocking_connection.create_receiver(address="org.apache.dev")249 apply_options = AtMostOnce()250 # Sender to org.apache.dev251 blocking_sender = blocking_connection.create_sender(address="org.apache.dev", options=apply_options)252 msg = Message(body=hello_world_1)253 # Send a message254 blocking_sender.send(msg)255 received_message = blocking_receiver.receive()256 self.assertEqual(hello_world_1, received_message.body)257 # Connect to the router acting like the broker (QDR.A) and check the deliveriesIngress and deliveriesEgress258 local_node = Node.connect(self.routers[0].addresses[0], timeout=TIMEOUT)259 self.assertEqual('QDR.A', local_node.query(type='org.apache.qpid.dispatch.router',260 attribute_names=['id']).results[0][0])261 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',262 name='M0org.apache.dev').deliveriesEgress)263 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',264 name='M0org.apache.dev').deliveriesIngress)265 # There should be 4 links -266 # 1. outbound receiver link on org.apache.dev267 # 2. inbound sender link on blocking_sender268 # 3. inbound link to the $management269 # 4. outbound link to $management270 # self.assertEqual(4, len()271 self.assertEqual(4, len(local_node.query(type='org.apache.qpid.dispatch.router.link').results))272 blocking_connection.close()273 def test_partial_link_route_match_1(self):274 """275 This test is pretty much the same as the previous test (test_partial_link_route_match) but the connection is276 made to router QDR.B instead of QDR.C and we expect to see the same behavior.277 """278 hello_world_2 = "Hello World_2!"279 addr = self.routers[1].addresses[0]280 blocking_connection = BlockingConnection(addr)281 # Receive on org.apache.dev282 blocking_receiver = blocking_connection.create_receiver(address="org.apache.dev.1")283 apply_options = AtMostOnce()284 # Sender to to org.apache.dev285 blocking_sender = blocking_connection.create_sender(address="org.apache.dev.1", options=apply_options)286 msg = Message(body=hello_world_2)287 # Send a message288 blocking_sender.send(msg)289 received_message = blocking_receiver.receive()290 self.assertEqual(hello_world_2, received_message.body)291 local_node = Node.connect(self.routers[0].addresses[0], timeout=TIMEOUT)292 # Make sure that the router node acting as the broker (QDR.A) had one message routed through it. This confirms293 # that the message was link routed294 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',295 name='M0org.apache.dev.1').deliveriesEgress)296 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',297 name='M0org.apache.dev.1').deliveriesIngress)298 blocking_connection.close()299 def test_full_link_route_match(self):300 """301 The linkRoute on Routers C and B is set to org.apache.302 Creates a receiver listening on the address 'org.apache' and a sender that sends to address 'org.apache'.303 Sends a message to org.apache via router QDR.C and makes sure that the message was successfully304 routed (using full address matching) and received using pre-created links that were created as a305 result of specifying addresses in the linkRoute attribute('org.apache.').306 """307 hello_world_3 = "Hello World_3!"308 # Connects to listener #2 on QDR.C309 addr = self.routers[2].addresses[0]310 blocking_connection = BlockingConnection(addr)311 # Receive on org.apache312 blocking_receiver = blocking_connection.create_receiver(address="org.apache")313 apply_options = AtMostOnce()314 # Sender to to org.apache315 blocking_sender = blocking_connection.create_sender(address="org.apache", options=apply_options)316 msg = Message(body=hello_world_3)317 # Send a message318 blocking_sender.send(msg)319 received_message = blocking_receiver.receive()320 self.assertEqual(hello_world_3, received_message.body)321 local_node = Node.connect(self.routers[0].addresses[0], timeout=TIMEOUT)322 # Make sure that the router node acting as the broker (QDR.A) had one message routed through it. This confirms323 # that the message was link routed324 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',325 name='M0org.apache').deliveriesEgress)326 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',327 name='M0org.apache').deliveriesIngress)328 blocking_connection.close()329 def _link_route_pattern_match(self, connect_node, include_host,330 exclude_host, test_address,331 expected_pattern):332 """333 This helper function ensures that messages sent to 'test_address' pass334 through 'include_host', and are *not* routed to 'exclude_host'335 """336 hello_pattern = "Hello Pattern!"337 route = 'M0' + test_address338 # Connect to the two 'waypoints', ensure the route is not present on339 # either340 node_A = Node.connect(include_host, timeout=TIMEOUT)341 node_B = Node.connect(exclude_host, timeout=TIMEOUT)342 for node in [node_A, node_B]:343 self.assertRaises(NotFoundStatus,344 node.read,345 type='org.apache.qpid.dispatch.router.address',346 name=route)347 # wait until the host we're connecting to gets its next hop for the348 # pattern we're connecting to349 connect_node.wait_address(expected_pattern, remotes=1, delay=0.1, count=2)350 # Connect to 'connect_node' and send message to 'address'351 blocking_connection = BlockingConnection(connect_node.addresses[0])352 blocking_receiver = blocking_connection.create_receiver(address=test_address)353 blocking_sender = blocking_connection.create_sender(address=test_address,354 options=AtMostOnce())355 msg = Message(body=hello_pattern)356 blocking_sender.send(msg)357 received_message = blocking_receiver.receive()358 self.assertEqual(hello_pattern, received_message.body)359 # verify test_address is only present on include_host and not on exclude_host360 self.assertRaises(NotFoundStatus,361 node_B.read,362 type='org.apache.qpid.dispatch.router.address',363 name=route)364 self.assertEqual(1, node_A.read(type='org.apache.qpid.dispatch.router.address',365 name=route).deliveriesIngress)366 self.assertEqual(1, node_A.read(type='org.apache.qpid.dispatch.router.address',367 name=route).deliveriesIngress)368 # drop the connection and verify that test_address is no longer on include_host369 blocking_connection.close()370 timeout = time() + TIMEOUT371 while True:372 try:373 node_A.read(type='org.apache.qpid.dispatch.router.address',374 name=route)375 if time() > timeout:376 raise Exception("Expected route '%s' to expire!" % route)377 sleep(0.1)378 except NotFoundStatus:379 break380 node_A.close()381 node_B.close()382 def test_link_route_pattern_match(self):383 """384 Verify the addresses match the proper patterns and are routed to the385 proper 'waypoint' only386 """387 qdr_A = self.routers[0].addresses[0]388 qdr_D = self.routers[3].addresses[0]389 qdr_C = self.routers[2] # note: the node, not the address!390 self._link_route_pattern_match(connect_node=qdr_C,391 include_host=qdr_A,392 exclude_host=qdr_D,393 test_address='a.notD.toA',394 expected_pattern='a.*.toA.#')395 self._link_route_pattern_match(connect_node=qdr_C,396 include_host=qdr_D,397 exclude_host=qdr_A,398 test_address='a.notA.toD',399 expected_pattern='a.*.toD.#')400 self._link_route_pattern_match(connect_node=qdr_C,401 include_host=qdr_A,402 exclude_host=qdr_D,403 test_address='a.toD.toA.xyz',404 expected_pattern='a.*.toA.#')405 self._link_route_pattern_match(connect_node=qdr_C,406 include_host=qdr_D,407 exclude_host=qdr_A,408 test_address='a.toA.toD.abc',409 expected_pattern='a.*.toD.#')410 def test_custom_annotations_match(self):411 """412 The linkRoute on Routers C and B is set to org.apache.413 Creates a receiver listening on the address 'org.apache' and a sender that sends to address 'org.apache'.414 Sends a message with custom annotations to org.apache via router QDR.C and makes sure that the message was successfully415 routed (using full address matching) and received using pre-created links that were created as a416 result of specifying addresses in the linkRoute attribute('org.apache.'). Make sure custom annotations arrived as well.417 """418 hello_world_3 = "Hello World_3!"419 # Connects to listener #2 on QDR.C420 addr = self.routers[2].addresses[0]421 blocking_connection = BlockingConnection(addr)422 # Receive on org.apache423 blocking_receiver = blocking_connection.create_receiver(address="org.apache.2")424 apply_options = AtMostOnce()425 # Sender to to org.apache426 blocking_sender = blocking_connection.create_sender(address="org.apache.2", options=apply_options)427 msg = Message(body=hello_world_3)428 annotations = {'custom-annotation': '1/Custom_Annotation'}429 msg.annotations = annotations430 # Send a message431 blocking_sender.send(msg)432 received_message = blocking_receiver.receive()433 self.assertEqual(hello_world_3, received_message.body)434 self.assertEqual(received_message.annotations, annotations)435 blocking_connection.close()436 def test_full_link_route_match_1(self):437 """438 This test is pretty much the same as the previous test (test_full_link_route_match) but the connection is439 made to router QDR.B instead of QDR.C and we expect the message to be link routed successfully.440 """441 hello_world_4 = "Hello World_4!"442 addr = self.routers[1].addresses[0]443 blocking_connection = BlockingConnection(addr)444 # Receive on org.apache445 blocking_receiver = blocking_connection.create_receiver(address="org.apache.1")446 apply_options = AtMostOnce()447 # Sender to to org.apache448 blocking_sender = blocking_connection.create_sender(address="org.apache.1", options=apply_options)449 msg = Message(body=hello_world_4)450 # Send a message451 blocking_sender.send(msg)452 received_message = blocking_receiver.receive()453 self.assertEqual(hello_world_4, received_message.body)454 local_node = Node.connect(self.routers[0].addresses[0], timeout=TIMEOUT)455 # Make sure that the router node acting as the broker (QDR.A) had one message routed through it. This confirms456 # that the message was link routed457 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',458 name='M0org.apache.1').deliveriesEgress)459 self.assertEqual(1, local_node.read(type='org.apache.qpid.dispatch.router.address',460 name='M0org.apache.1').deliveriesIngress)461 blocking_connection.close()462 def test_zzz_qdmanage_delete_link_route(self):463 """464 We are deleting the link route using qdmanage short name. This should be the last test to run465 """466 local_node = Node.connect(self.routers[1].addresses[0], timeout=TIMEOUT)467 res = local_node.query(type='org.apache.qpid.dispatch.router')468 results = res.results[0]469 attribute_list = res.attribute_names470 result_list = local_node.query(type='org.apache.qpid.dispatch.router.config.linkRoute').results471 self.assertEqual(results[attribute_list.index('linkRouteCount')], len(result_list))472 # First delete linkRoutes on QDR.B473 for rid in range(8):474 cmd = 'DELETE --type=linkRoute --identity=' + result_list[rid][1]475 self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])476 cmd = 'QUERY --type=linkRoute'477 out = self.run_qdmanage(cmd=cmd, address=self.routers[1].addresses[0])478 self.assertEqual(out.rstrip(), '[]')479 # linkRoutes now gone on QDR.B but remember that it still exist on QDR.C480 # We will now try to create a receiver on address org.apache.dev on QDR.C.481 # Since the linkRoute on QDR.B is gone, QDR.C482 # will not allow a receiver to be created since there is no route to destination.483 # Connects to listener #2 on QDR.C484 addr = self.routers[2].addresses[0]485 # Now delete linkRoutes on QDR.C to eradicate linkRoutes completely486 local_node = Node.connect(addr, timeout=TIMEOUT)487 result_list = local_node.query(type='org.apache.qpid.dispatch.router.config.linkRoute').results488 # QDR.C has 8 link routes configured, nuke 'em:489 self.assertEqual(8, len(result_list))490 for rid in range(8):491 cmd = 'DELETE --type=linkRoute --identity=' + result_list[rid][1]492 self.run_qdmanage(cmd=cmd, address=addr)493 cmd = 'QUERY --type=linkRoute'494 out = self.run_qdmanage(cmd=cmd, address=addr)495 self.assertEqual(out.rstrip(), '[]')496 res = local_node.query(type='org.apache.qpid.dispatch.router')497 results = res.results[0]498 attribute_list = res.attribute_names499 self.assertEqual(results[attribute_list.index('linkRouteCount')], 0)500 blocking_connection = BlockingConnection(addr, timeout=3)501 # Receive on org.apache.dev (this address used to be linkRouted but not anymore since we deleted linkRoutes502 # on both QDR.C and QDR.B)503 blocking_receiver = blocking_connection.create_receiver(address="org.apache.dev")504 apply_options = AtMostOnce()505 hello_world_1 = "Hello World_1!"506 # Sender to org.apache.dev507 blocking_sender = blocking_connection.create_sender(address="org.apache.dev", options=apply_options)508 msg = Message(body=hello_world_1)509 # Send a message510 blocking_sender.send(msg)511 received_message = blocking_receiver.receive(timeout=5)512 self.assertEqual(hello_world_1, received_message.body)513 def test_yyy_delivery_tag(self):514 """515 Tests that the router carries over the delivery tag on a link routed delivery516 """517 listening_address = self.routers[1].addresses[1]518 sender_address = self.routers[2].addresses[0]519 qdstat_address = self.routers[2].addresses[0]520 test = DeliveryTagsTest(sender_address, listening_address, qdstat_address)521 test.run()522 self.assertIsNone(test.error)523 def test_yyy_invalid_delivery_tag(self):524 test = InvalidTagTest(self.routers[2].addresses[0])525 test.run()526 self.assertIsNone(test.error)527 def test_close_with_unsettled(self):528 test = CloseWithUnsettledTest(self.routers[1].addresses[0], self.routers[1].addresses[1])529 test.run()530 self.assertIsNone(test.error)531 def test_www_drain_support_all_messages(self):532 drain_support = DrainMessagesHandler(self.routers[2].addresses[0])533 drain_support.run()534 self.assertIsNone(drain_support.error)535 def test_www_drain_support_one_message(self):536 drain_support = DrainOneMessageHandler(self.routers[2].addresses[0])537 drain_support.run()538 self.assertIsNone(drain_support.error)539 def test_www_drain_support_no_messages(self):540 drain_support = DrainNoMessagesHandler(self.routers[2].addresses[0])541 drain_support.run()542 self.assertIsNone(drain_support.error)543 def test_www_drain_support_no_more_messages(self):544 drain_support = DrainNoMoreMessagesHandler(self.routers[2].addresses[0])545 drain_support.run()546 self.assertIsNone(drain_support.error)547 def test_link_route_terminus_address(self):548 # The receiver is attaching to router B to a listener that has link route for address 'pulp.task' setup.549 listening_address = self.routers[1].addresses[1]550 # Run the query on a normal port551 query_address_listening = self.routers[1].addresses[0]552 # Sender is attaching to router C553 sender_address = self.routers[2].addresses[0]554 query_address_sending = self.routers[2].addresses[0]555 test = TerminusAddrTest(sender_address, listening_address, query_address_sending, query_address_listening)556 test.run()557 self.assertTrue(test.in_receiver_found)558 self.assertTrue(test.out_receiver_found)559 self.assertTrue(test.in_sender_found)560 self.assertTrue(test.out_sender_found)561 def test_dynamic_source(self):562 test = DynamicSourceTest(self.routers[1].addresses[0], self.routers[1].addresses[1])563 test.run()564 self.assertIsNone(test.error)565 def test_dynamic_target(self):566 test = DynamicTargetTest(self.routers[1].addresses[0], self.routers[1].addresses[1])567 test.run()568 self.assertIsNone(test.error)569 def test_detach_without_close(self):570 test = DetachNoCloseTest(self.routers[1].addresses[0], self.routers[1].addresses[1])571 test.run()572 self.assertIsNone(test.error)573 def test_detach_mixed_close(self):574 test = DetachMixedCloseTest(self.routers[1].addresses[0], self.routers[1].addresses[1])575 test.run()576 self.assertIsNone(test.error)577 def _multi_link_send_receive(self, send_host, receive_host, name):578 senders = ["%s/%s" % (send_host, address) for address in ["org.apache.foo", "org.apache.bar"]]579 receivers = ["%s/%s" % (receive_host, address) for address in ["org.apache.foo", "org.apache.bar"]]580 test = MultiLinkSendReceive(senders, receivers, name)581 test.run()582 self.assertIsNone(test.error)583 def test_same_name_route_receivers_through_B(self):584 self._multi_link_send_receive(self.routers[0].addresses[0], self.routers[1].addresses[0], "recv_through_B")585 def test_same_name_route_senders_through_B(self):586 self._multi_link_send_receive(self.routers[1].addresses[0], self.routers[0].addresses[0], "send_through_B")587 def test_same_name_route_receivers_through_C(self):588 self._multi_link_send_receive(self.routers[0].addresses[0], self.routers[2].addresses[0], "recv_through_C")589 def test_same_name_route_senders_through_C(self):590 self._multi_link_send_receive(self.routers[2].addresses[0], self.routers[0].addresses[0], "send_through_C")591 def test_echo_detach_received(self):592 """593 Create two receivers to link routed address org.apache.dev594 Create a sender to the same address that the receiver is listening on and send 100 messages.595 After the receivers receive 10 messages each, the receivers will detach and expect to receive ten596 detaches in response.597 """598 test = EchoDetachReceived(self.routers[2].addresses[0], self.routers[2].addresses[0])599 test.run()600 self.assertIsNone(test.error)601 def test_bad_link_route_config(self):602 """603 What happens when the link route create request is malformed?604 """605 mgmt = self.routers[1].management606 # zero length prefix607 self.assertRaises(BadRequestStatus,608 mgmt.create,609 type="org.apache.qpid.dispatch.router.config.linkRoute",610 name="bad-1",611 attributes={'prefix': '',612 'containerId': 'FakeBroker',613 'direction': 'in'})614 # pattern wrong type615 self.assertRaises(BadRequestStatus,616 mgmt.create,617 type="org.apache.qpid.dispatch.router.config.linkRoute",618 name="bad-2",619 attributes={'pattern': 666,620 'containerId': 'FakeBroker',621 'direction': 'in'})622 # invalid pattern (no tokens)623 self.assertRaises(BadRequestStatus,624 mgmt.create,625 type="org.apache.qpid.dispatch.router.config.linkRoute",626 name="bad-3",627 attributes={'pattern': '///',628 'containerId': 'FakeBroker',629 'direction': 'in'})630 # empty attributes631 self.assertRaises(BadRequestStatus,632 mgmt.create,633 type="org.apache.qpid.dispatch.router.config.linkRoute",634 name="bad-4",635 attributes={})636 # both pattern and prefix637 self.assertRaises(BadRequestStatus,638 mgmt.create,639 type="org.apache.qpid.dispatch.router.config.linkRoute",640 name="bad-5",641 attributes={'prefix': 'a1',642 'pattern': 'b2',643 'containerId': 'FakeBroker',644 'direction': 'in'})645 # bad direction646 self.assertRaises(BadRequestStatus,647 mgmt.create,648 type="org.apache.qpid.dispatch.router.config.linkRoute",649 name="bad-6",650 attributes={'pattern': 'b2',651 'containerId': 'FakeBroker',652 'direction': 'nowhere'})653 # bad distribution654 self.assertRaises(BadRequestStatus,655 mgmt.create,656 type="org.apache.qpid.dispatch.router.config.linkRoute",657 name="bad-7",658 attributes={'pattern': 'b2',659 'containerId': 'FakeBroker',660 'direction': 'in',661 "distribution": "dilly dilly"})662 # no direction663 self.assertRaises(BadRequestStatus,664 mgmt.create,665 type="org.apache.qpid.dispatch.router.config.linkRoute",666 name="bad-8",667 attributes={'prefix': 'b2',668 'containerId': 'FakeBroker'})669 # neither pattern nor prefix670 self.assertRaises(BadRequestStatus,671 mgmt.create,672 type="org.apache.qpid.dispatch.router.config.linkRoute",673 name="bad-9",674 attributes={'direction': 'out',675 'containerId': 'FakeBroker'})676class DeliveryTagsTest(MessagingHandler):677 def __init__(self, sender_address, listening_address, qdstat_address):678 super(DeliveryTagsTest, self).__init__()679 self.sender_address = sender_address680 self.listening_address = listening_address681 self.sender = None682 self.receiver_connection = None683 self.sender_connection = None684 self.qdstat_address = qdstat_address685 self.id = '1235'686 self.times = 1687 self.sent = 0688 self.rcvd = 0689 self.delivery_tag_verified = False690 # The delivery tag we are going to send in the transfer frame691 # We will later make sure that the same delivery tag shows up on the receiving end in the link routed case.692 # KAG: force the literal to type 'str' due to SWIG weirdness: on 2.X a693 # delivery tag cannot be unicode (must be binary), but on 3.X it must694 # be unicode! See https://issues.apache.org/jira/browse/PROTON-1843695 self.delivery_tag = str('92319')696 self.error = None697 def timeout(self):698 self.error = "Timeout expired: sent=%d rcvd=%d" % (self.sent, self.rcvd)699 if self.receiver_connection:700 self.receiver_connection.close()701 if self.sender_connection:702 self.sender_connection.close()703 def on_start(self, event):704 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))705 self.receiver_connection = event.container.connect(self.listening_address)706 def on_connection_remote_open(self, event):707 if event.connection == self.receiver_connection:708 continue_loop = True709 # Don't open the sender connection unless we can make sure that there is a remote receiver ready to710 # accept the message.711 # If there is no remote receiver, the router will throw a 'No route to destination' error when712 # creating sender connection.713 # The following loops introduces a wait before creating the sender connection. It gives time to the714 # router so that the address Dpulp.task can show up on the remoteCount715 i = 0716 while continue_loop:717 if i > 100: # If we have run the read command for more than hundred times and we still do not have718 # the remoteCount set to 1, there is a problem, just exit out of the function instead719 # of looping to infinity.720 self.receiver_connection.close()721 return722 local_node = Node.connect(self.qdstat_address, timeout=TIMEOUT)723 out = local_node.read(type='org.apache.qpid.dispatch.router.address', name='Dpulp.task').remoteCount724 if out == 1:725 continue_loop = False726 else:727 i += 1728 sleep(0.25)729 self.sender_connection = event.container.connect(self.sender_address)730 self.sender = event.container.create_sender(self.sender_connection, "pulp.task", options=AtMostOnce())731 def on_sendable(self, event):732 if self.times == 1:733 msg = Message(body="Hello World")734 self.sender.send(msg, tag=self.delivery_tag)735 self.times += 1736 self.sent += 1737 def on_message(self, event):738 if "Hello World" == event.message.body:739 self.rcvd += 1740 # If the tag on the delivery is the same as the tag we sent with the initial transfer, it means741 # that the router has propagated the delivery tag successfully because of link routing.742 if self.delivery_tag != event.delivery.tag:743 self.error = "Delivery-tag: expected:%r got:%r" % (self.delivery_tag, event.delivery.tag)744 self.receiver_connection.close()745 self.sender_connection.close()746 self.timer.cancel()747 def run(self):748 Container(self).run()749class CloseWithUnsettledTest(MessagingHandler):750 ##751 # This test sends a message across an attach-routed link. While the message752 # is unsettled, the client link is closed. The test is ensuring that the753 # router does not crash during the closing of the links.754 ##755 def __init__(self, normal_addr, route_addr):756 super(CloseWithUnsettledTest, self).__init__(prefetch=0, auto_accept=False)757 self.normal_addr = normal_addr758 self.route_addr = route_addr759 self.dest = "pulp.task.CWUtest"760 self.error = None761 def timeout(self):762 self.error = "Timeout Expired - Check for cores"763 self.conn_normal.close()764 self.conn_route.close()765 def on_start(self, event):766 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))767 self.conn_route = event.container.connect(self.route_addr)768 def on_connection_opened(self, event):769 if event.connection == self.conn_route:770 self.conn_normal = event.container.connect(self.normal_addr)771 elif event.connection == self.conn_normal:772 self.sender = event.container.create_sender(self.conn_normal, self.dest)773 def on_connection_closed(self, event):774 self.conn_route.close()775 self.timer.cancel()776 def on_link_opened(self, event):777 if event.receiver:778 self.receiver = event.receiver779 self.receiver.flow(1)780 def on_sendable(self, event):781 msg = Message(body="CloseWithUnsettled")782 event.sender.send(msg)783 def on_message(self, event):784 self.conn_normal.close()785 def run(self):786 Container(self).run()787class DynamicSourceTest(MessagingHandler):788 ##789 # This test verifies that a dynamic source can be propagated via link-route to790 # a route-container.791 ##792 def __init__(self, normal_addr, route_addr):793 super(DynamicSourceTest, self).__init__(prefetch=0, auto_accept=False)794 self.normal_addr = normal_addr795 self.route_addr = route_addr796 self.dest = "pulp.task.DynamicSource"797 self.address = "DynamicSourceAddress"798 self.error = None799 def timeout(self):800 self.error = "Timeout Expired - Check for cores"801 self.conn_normal.close()802 self.conn_route.close()803 def on_start(self, event):804 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))805 self.conn_route = event.container.connect(self.route_addr)806 def on_connection_opened(self, event):807 if event.connection == self.conn_route:808 self.conn_normal = event.container.connect(self.normal_addr)809 elif event.connection == self.conn_normal:810 self.receiver = event.container.create_receiver(self.conn_normal, None, dynamic=True, options=DynamicNodeProperties({"x-opt-qd.address": "pulp.task.abc"}))811 def on_link_opened(self, event):812 if event.receiver == self.receiver:813 if self.receiver.remote_source.address != self.address:814 self.error = "Expected %s, got %s" % (self.address, self.receiver.remote_source.address)815 self.conn_normal.close()816 self.conn_route.close()817 self.timer.cancel()818 def on_link_opening(self, event):819 if event.sender:820 self.sender = event.sender821 if not self.sender.remote_source.dynamic:822 self.error = "Expected sender with dynamic source"823 self.conn_normal.close()824 self.conn_route.close()825 self.timer.cancel()826 self.sender.source.address = self.address827 self.sender.open()828 def run(self):829 Container(self).run()830class DynamicTarget(LinkOption):831 def apply(self, link):832 link.target.dynamic = True833 link.target.address = None834class DynamicTargetTest(MessagingHandler):835 ##836 # This test verifies that a dynamic source can be propagated via link-route to837 # a route-container.838 ##839 def __init__(self, normal_addr, route_addr):840 super(DynamicTargetTest, self).__init__(prefetch=0, auto_accept=False)841 self.normal_addr = normal_addr842 self.route_addr = route_addr843 self.dest = "pulp.task.DynamicTarget"844 self.address = "DynamicTargetAddress"845 self.error = None846 def timeout(self):847 self.error = "Timeout Expired - Check for cores"848 self.conn_normal.close()849 self.conn_route.close()850 def on_start(self, event):851 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))852 self.conn_route = event.container.connect(self.route_addr)853 def on_connection_opened(self, event):854 if event.connection == self.conn_route:855 self.conn_normal = event.container.connect(self.normal_addr)856 elif event.connection == self.conn_normal:857 self.sender = event.container.create_sender(self.conn_normal, None, options=[DynamicTarget(), DynamicNodeProperties({"x-opt-qd.address": "pulp.task.abc"})])858 def on_link_opened(self, event):859 if event.sender == self.sender:860 if self.sender.remote_target.address != self.address:861 self.error = "Expected %s, got %s" % (self.address, self.receiver.remote_source.address)862 self.conn_normal.close()863 self.conn_route.close()864 self.timer.cancel()865 def on_link_opening(self, event):866 if event.receiver:867 self.receiver = event.receiver868 if not self.receiver.remote_target.dynamic:869 self.error = "Expected receiver with dynamic source"870 self.conn_normal.close()871 self.conn_route.close()872 self.timer.cancel()873 self.receiver.target.address = self.address874 self.receiver.open()875 def run(self):876 Container(self).run()877class DetachNoCloseTest(MessagingHandler):878 ##879 # This test verifies that link-detach (not close) is propagated properly880 ##881 def __init__(self, normal_addr, route_addr):882 super(DetachNoCloseTest, self).__init__(prefetch=0, auto_accept=False)883 self.normal_addr = normal_addr884 self.route_addr = route_addr885 self.dest = "pulp.task.DetachNoClose"886 self.error = None887 def timeout(self):888 self.error = "Timeout Expired - Check for cores"889 self.conn_normal.close()890 self.conn_route.close()891 def stop(self):892 self.conn_normal.close()893 self.conn_route.close()894 self.timer.cancel()895 def on_start(self, event):896 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))897 self.conn_route = event.container.connect(self.route_addr)898 def on_connection_opened(self, event):899 if event.connection == self.conn_route:900 self.conn_normal = event.container.connect(self.normal_addr)901 elif event.connection == self.conn_normal:902 self.receiver = event.container.create_receiver(self.conn_normal, self.dest)903 def on_link_opened(self, event):904 if event.receiver == self.receiver:905 self.receiver.detach()906 def on_link_remote_detach(self, event):907 if event.sender == self.sender:908 self.sender.detach()909 if event.receiver == self.receiver:910 ##911 # Test passed, we expected a detach on the propagated sender and back912 ##913 self.stop()914 def on_link_closing(self, event):915 if event.sender == self.sender:916 self.error = 'Propagated link was closed. Expected it to be detached'917 self.stop()918 if event.receiver == self.receiver:919 self.error = 'Client link was closed. Expected it to be detached'920 self.stop()921 def on_link_opening(self, event):922 if event.sender:923 self.sender = event.sender924 self.sender.source.address = self.sender.remote_source.address925 self.sender.open()926 def run(self):927 Container(self).run()928class DetachMixedCloseTest(MessagingHandler):929 ##930 # This test verifies that link-detach (not close) is propagated properly931 ##932 def __init__(self, normal_addr, route_addr):933 super(DetachMixedCloseTest, self).__init__(prefetch=0, auto_accept=False)934 self.normal_addr = normal_addr935 self.route_addr = route_addr936 self.dest = "pulp.task.DetachMixedClose"937 self.error = None938 def timeout(self):939 self.error = "Timeout Expired - Check for cores"940 self.conn_normal.close()941 self.conn_route.close()942 def stop(self):943 self.conn_normal.close()944 self.conn_route.close()945 self.timer.cancel()946 def on_start(self, event):947 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))948 self.conn_route = event.container.connect(self.route_addr)949 def on_connection_opened(self, event):950 if event.connection == self.conn_route:951 self.conn_normal = event.container.connect(self.normal_addr)952 elif event.connection == self.conn_normal:953 self.receiver = event.container.create_receiver(self.conn_normal, self.dest)954 def on_link_opened(self, event):955 if event.receiver == self.receiver:956 self.receiver.detach()957 def on_link_remote_detach(self, event):958 if event.sender == self.sender:959 self.sender.close()960 if event.receiver == self.receiver:961 self.error = 'Client link was detached. Expected it to be closed'962 self.stop()963 def on_link_closing(self, event):964 if event.sender == self.sender:965 self.error = 'Propagated link was closed. Expected it to be detached'966 self.stop()967 if event.receiver == self.receiver:968 ##969 # Test Passed970 ##971 self.stop()972 def on_link_opening(self, event):973 if event.sender:974 self.sender = event.sender975 self.sender.source.address = self.sender.remote_source.address976 self.sender.open()977 def run(self):978 Container(self).run()979# Test to validate fix for DISPATCH-927980class EchoDetachReceived(MessagingHandler):981 def __init__(self, sender_address, recv_address):982 super(EchoDetachReceived, self).__init__()983 self.sender_address = sender_address984 self.recv_address = recv_address985 self.dest = "org.apache.dev"986 self.num_msgs = 100987 self.num_receivers = 10988 self.msgs_sent = 0989 self.receiver_conn = None990 self.sender_conn = None991 self.sender = None992 self.receiver_dict = {}993 self.error = None994 self.receiver_attaches = 0995 self.timer = None996 self.sender_attached = False997 self.received_msgs_dict = {}998 self.receiver_detach_dict = {}999 self.num_detaches_echoed = 01000 @property1001 def msgs_received(self):1002 return sum(self.received_msgs_dict.values())1003 def timeout(self):1004 self.bail("Timeout Expired: msgs_sent=%d msgs_received=%d, number of detaches received=%d"1005 % (self.msgs_sent, self.msgs_received, self.num_detaches_echoed))1006 def on_start(self, event):1007 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))1008 # Create two separate connections for sender and receivers1009 self.receiver_conn = event.container.connect(self.recv_address)1010 self.sender_conn = event.container.connect(self.sender_address)1011 for i in range(self.num_receivers):1012 name = "R%d" % i1013 self.receiver_dict[name] = event.container.create_receiver(self.receiver_conn, self.dest, name=name)1014 self.received_msgs_dict[name] = 01015 def bail(self, text=None):1016 self.error = text1017 self.sender_conn.close()1018 self.receiver_conn.close()1019 self.timer.cancel()1020 def on_link_opened(self, event):1021 if event.receiver:1022 if event.receiver.name in list(self.receiver_dict):1023 self.receiver_attaches += 11024 # The response receiver attaches have been received. The receiver sent attaches which was link routed1025 # all the way to the 'broker' router and the response attaches have come back.1026 # It is now time to create the sender.1027 if self.receiver_attaches == self.num_receivers:1028 self.sender = event.container.create_sender(self.sender_conn, self.dest)1029 elif event.sender:1030 if not self.sender_attached:1031 if event.sender == self.sender:1032 # The sender attaches were link routed as well and the response attach has been received.1033 self.sender_attached = True1034 def on_sendable(self, event):1035 # The sender will send 100 messages1036 if self.receiver_attaches == self.num_receivers and self.sender_attached:1037 if self.msgs_sent < self.num_msgs:1038 msg = Message(body="Hello World")1039 self.sender.send(msg)1040 self.msgs_sent += 11041 def on_message(self, event):1042 if event.receiver and event.receiver.name in list(self.receiver_dict):1043 self.received_msgs_dict[event.receiver.name] += 11044 if sum(self.received_msgs_dict.values()) == self.num_msgs:1045 # The receivers have received a total of 100 messages. Close the receivers. The detach sent by these1046 # receivers will travel all the way over the link route and the 'broker' router will respond with a1047 # detach1048 for receiver in list(self.receiver_dict):1049 self.receiver_dict[receiver].close()1050 def on_link_closed(self, event):1051 if event.receiver.name in list(self.receiver_dict) and event.receiver.name not in list(self.receiver_detach_dict):1052 self.receiver_detach_dict[event.receiver.name] = event.receiver1053 self.num_detaches_echoed += 11054 # Terminate the test only if both detach frames have been received.1055 if all(receiver in list(self.receiver_detach_dict) for receiver in list(self.receiver_dict)):1056 self.bail()1057 def run(self):1058 Container(self).run()1059class TerminusAddrTest(MessagingHandler):1060 """1061 This tests makes sure that the link route address is visible in the output of qdstat -l command.1062 Sets up a sender on address pulp.task.terminusTestSender and a receiver on pulp.task.terminusTestReceiver.1063 Connects to the router to which the sender is attached and makes sure that the pulp.task.terminusTestSender address1064 shows up with an 'in' and 'out'1065 Similarly connects to the router to which the receiver is attached and makes sure that the1066 pulp.task.terminusTestReceiver address shows up with an 'in' and 'out'1067 """1068 def __init__(self, sender_address, listening_address, query_address_sending, query_address_listening):1069 super(TerminusAddrTest, self).__init__()1070 self.sender_address = sender_address1071 self.listening_address = listening_address1072 self.sender = None1073 self.receiver = None1074 self.message_received = False1075 self.receiver_connection = None1076 self.sender_connection = None1077 # We will run a query on the same router where the sender is attached1078 self.query_address_sending = query_address_sending1079 # We will run a query on the same router where the receiver is attached1080 self.query_address_listening = query_address_listening1081 self.count = 01082 self.in_receiver_found = False1083 self.out_receiver_found = False1084 self.in_sender_found = False1085 self.out_sender_found = False1086 self.receiver_link_opened = False1087 self.sender_link_opened = False1088 def on_start(self, event):1089 self.receiver_connection = event.container.connect(self.listening_address)1090 def on_connection_remote_open(self, event):1091 if event.connection == self.receiver_connection:1092 continue_loop = True1093 # The following loops introduces a wait. It gives time to the1094 # router so that the address Dpulp.task can show up on the remoteCount1095 i = 01096 while continue_loop:1097 if i > 100: # If we have run the read command for more than hundred times and we still do not have1098 # the remoteCount set to 1, there is a problem, just exit out of the function instead1099 # of looping to infinity.1100 self.receiver_connection.close()1101 return1102 local_node = Node.connect(self.query_address_sending, timeout=TIMEOUT)1103 out = local_node.read(type='org.apache.qpid.dispatch.router.address', name='Dpulp.task').remoteCount1104 if out == 1:1105 continue_loop = False1106 i += 11107 sleep(0.25)1108 self.sender_connection = event.container.connect(self.sender_address)1109 # Notice here that the receiver and sender are listening on different addresses. Receiver on1110 # pulp.task.terminusTestReceiver and the sender on pulp.task.terminusTestSender1111 self.receiver = event.container.create_receiver(self.receiver_connection, "pulp.task.terminusTestReceiver")1112 self.sender = event.container.create_sender(self.sender_connection, "pulp.task.terminusTestSender", options=AtMostOnce())1113 def on_link_opened(self, event):1114 if event.receiver == self.receiver:1115 self.receiver_link_opened = True1116 local_node = Node.connect(self.query_address_listening, timeout=TIMEOUT)1117 out = local_node.query(type='org.apache.qpid.dispatch.router.link')1118 link_dir_index = out.attribute_names.index("linkDir")1119 owning_addr_index = out.attribute_names.index("owningAddr")1120 # Make sure that the owningAddr M0pulp.task.terminusTestReceiver shows up on both in and out.1121 # The 'out' link is on address M0pulp.task.terminusTestReceiver outgoing from the router B to the receiver1122 # The 'in' link is on address M0pulp.task.terminusTestReceiver incoming from router C to router B1123 for result in out.results:1124 if result[link_dir_index] == 'in' and result[owning_addr_index] == 'M0pulp.task.terminusTestReceiver':1125 self.in_receiver_found = True1126 if result[link_dir_index] == 'out' and result[owning_addr_index] == 'M0pulp.task.terminusTestReceiver':1127 self.out_receiver_found = True1128 if event.sender == self.sender:1129 self.sender_link_opened = True1130 local_node = Node.connect(self.query_address_sending, timeout=TIMEOUT)1131 out = local_node.query(type='org.apache.qpid.dispatch.router.link')1132 link_dir_index = out.attribute_names.index("linkDir")1133 owning_addr_index = out.attribute_names.index("owningAddr")1134 # Make sure that the owningAddr M0pulp.task.terminusTestSender shows up on both in and out.1135 # The 'in' link is on address M0pulp.task.terminusTestSender incoming from sender to router1136 # The 'out' link is on address M0pulp.task.terminusTestSender outgoing from router C to router B1137 for result in out.results:1138 if result[link_dir_index] == 'in' and result[owning_addr_index] == 'M0pulp.task.terminusTestSender':1139 self.in_sender_found = True1140 if result[link_dir_index] == 'out' and result[owning_addr_index] == 'M0pulp.task.terminusTestSender':1141 self.out_sender_found = True1142 # Shutdown the connections only if the on_link_opened has been called for sender and receiver links.1143 if self.sender_link_opened and self.receiver_link_opened:1144 self.sender.close()1145 self.receiver.close()1146 self.sender_connection.close()1147 self.receiver_connection.close()1148 def run(self):1149 Container(self).run()1150class MultiLinkSendReceive(MessagingHandler):1151 class SendState:1152 def __init__(self, link):1153 self.link = link1154 self.sent = False1155 self.accepted = False1156 self.done = False1157 self.closed = False1158 def send(self, subject, body):1159 if not self.sent:1160 self.link.send(Message(subject=subject, body=body, address=self.link.target.address))1161 self.sent = True1162 def on_accepted(self):1163 self.accepted = True1164 self.done = True1165 def close(self):1166 if not self.closed:1167 self.closed = True1168 self.link.close()1169 self.link.connection.close()1170 class RecvState:1171 def __init__(self, link):1172 self.link = link1173 self.received = False1174 self.done = False1175 self.closed = False1176 def on_message(self):1177 self.received = True1178 self.done = True1179 def close(self):1180 if not self.closed:1181 self.closed = True1182 self.link.close()1183 self.link.connection.close()1184 def __init__(self, send_urls, recv_urls, name, message=None):1185 super(MultiLinkSendReceive, self).__init__()1186 self.send_urls = send_urls1187 self.recv_urls = recv_urls1188 self.senders = {}1189 self.receivers = {}1190 self.message = message or "SendReceiveTest"1191 self.sent = False1192 self.error = None1193 self.name = name1194 def close(self):1195 for sender in self.senders.values():1196 sender.close()1197 for receiver in self.receivers.values():1198 receiver.close()1199 def all_done(self):1200 for sender in self.senders.values():1201 if not sender.done:1202 return False1203 for receiver in self.receivers.values():1204 if not receiver.done:1205 return False1206 return True1207 def timeout(self):1208 self.error = "Timeout Expired"1209 self.close()1210 def stop_if_all_done(self):1211 if self.all_done():1212 self.stop()1213 def stop(self):1214 self.close()1215 self.timer.cancel()1216 def on_start(self, event):1217 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))1218 event.container.container_id = None1219 for u in self.send_urls:1220 s = self.SendState(event.container.create_sender(u, name=self.name))1221 self.senders[s.link.connection.container] = s1222 for u in self.recv_urls:1223 r = self.RecvState(event.container.create_receiver(u, name=self.name))1224 self.receivers[r.link.connection.container] = r1225 def on_sendable(self, event):1226 self.senders[event.connection.container].send(self.name, self.message)1227 def on_message(self, event):1228 if self.message != event.message.body:1229 error = "Incorrect message. Got %s, expected %s" % (event.message.body, self.message.body)1230 self.receivers[event.connection.container].on_message()1231 self.stop_if_all_done()1232 def on_accepted(self, event):1233 self.senders[event.connection.container].on_accepted()1234 self.stop_if_all_done()1235 def run(self):1236 Container(self).run()1237class LinkRouteProtocolTest(TestCase):1238 """1239 Test link route implementation against "misbehaving" containers1240 Uses a custom fake broker (not a router) that can do weird things at the1241 protocol level.1242 +-------------+ +---------+ +-----------------+1243 | | <------ | | <----- | blocking_sender |1244 | fake broker | | QDR.A | +-----------------+1245 | | ------> | | ------> +-------------------+1246 +-------------+ +---------+ | blocking_receiver |1247 +-------------------+1248 """1249 @classmethod1250 def setUpClass(cls):1251 """Configure and start QDR.A"""1252 super(LinkRouteProtocolTest, cls).setUpClass()1253 config = [1254 ('router', {'mode': 'standalone', 'id': 'QDR.A'}),1255 # for client connections:1256 ('listener', {'role': 'normal',1257 'host': '0.0.0.0',1258 'port': cls.tester.get_port(),1259 'saslMechanisms': 'ANONYMOUS'}),1260 # to connect to the fake broker1261 ('connector', {'name': 'broker',1262 'role': 'route-container',1263 'host': '127.0.0.1',1264 'port': cls.tester.get_port(),1265 'saslMechanisms': 'ANONYMOUS'}),1266 # forward 'org.apache' messages to + from fake broker:1267 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'FakeBroker', 'direction': 'in'}),1268 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'FakeBroker', 'direction': 'out'})1269 ]1270 config = Qdrouterd.Config(config)1271 cls.router = cls.tester.qdrouterd('A', config, wait=False)1272 def _fake_broker(self, cls):1273 """Spawn a fake broker listening on the broker's connector1274 """1275 fake_broker = cls(self.router.connector_addresses[0])1276 # wait until the connection to the fake broker activates1277 self.router.wait_connectors()1278 return fake_broker1279 def test_DISPATCH_1092(self):1280 # This fake broker will force the session closed after the link1281 # detaches. Verify that the session comes back up correctly when the1282 # next client attaches1283 killer = self._fake_broker(SessionKiller)1284 for i in range(2):1285 bconn = BlockingConnection(self.router.addresses[0])1286 bsender = bconn.create_sender(address="org.apache",1287 options=AtLeastOnce())1288 msg = Message(body="Hey!")1289 bsender.send(msg)1290 bsender.close()1291 bconn.close()1292 killer.join()1293class SessionKiller(FakeBroker):1294 """DISPATCH-1092: force a session close when the link closes. This should1295 cause the router to re-create the session when the next client attaches.1296 """1297 def __init__(self, url):1298 super(SessionKiller, self).__init__(url)1299 def on_link_closing(self, event):1300 event.link.close()1301 event.session.close()1302class FakeBrokerDrain(FakeBroker):1303 """1304 DISPATCH-1496 - Make sure that the router does not grant additional credit1305 when drain is issued by a receiver connected to the router on a1306 link routed address1307 """1308 def __init__(self, url):1309 super(FakeBrokerDrain, self).__init__(url)1310 self.first_flow_received = False1311 self.first_drain_mode = False1312 self.second_drain_mode = False1313 self.error = None1314 self.num_flows = 01315 self.success = False1316 def on_link_flow(self, event):1317 if event.link.is_sender:1318 if event.sender.drain_mode:1319 if not self.first_drain_mode:1320 self.first_drain_mode = True1321 event.sender.drained()1322 elif not self.second_drain_mode:1323 self.second_drain_mode = True1324 if event.link.credit == 1000:1325 # Without the patch for DISPATCH-1496,1326 # the event.link.credit value would be 20001327 self.success = True1328 else:1329 self.success = False1330 event.sender.drained()1331 else:1332 if not self.first_flow_received:1333 self.first_flow_received = True1334 msg = Message(body="First Drain Transfer")1335 event.link.send(msg)1336class DrainReceiver(MessagingHandler):1337 def __init__(self, url, fake_broker):1338 super(DrainReceiver, self).__init__(prefetch=0, auto_accept=False)1339 self.url = url1340 self.received = 01341 self.receiver = None1342 self.first_drain_sent = False1343 self.second_drain_sent = False1344 self.first_flow_sent = False1345 self.receiver_conn = None1346 self.error = None1347 self.num_flows = 01348 self.fake_broker = fake_broker1349 def on_start(self, event):1350 self.receiver_conn = event.container.connect(self.url)1351 self.receiver = event.container.create_receiver(self.receiver_conn, "org.apache")1352 # Step 1: Send a flow of 1000 to the router. The router will forward this1353 # flow to the FakeBroker1354 self.receiver.flow(1000)1355 self.first_flow_sent = True1356 def on_link_flow(self, event):1357 if event.receiver == self.receiver:1358 self.num_flows += 11359 if self.num_flows == 1:1360 # Step 4: The response drain received from the FakeBroker1361 # Step 5: Send second flow of 1000 credits. This is forwarded to the FakeBroker1362 self.receiver.flow(1000)1363 self.timer = event.reactor.schedule(3, TestTimeout(self))1364 elif self.num_flows == 2:1365 if not self.fake_broker.success:1366 self.error = "The FakeBroker did not receive correct credit of 1000"1367 self.receiver_conn.close()1368 def timeout(self):1369 # Step 6: The second drain is sent to the router. The router was forwarding the wrong credit (2000) to the FakeBroker1370 # but with the fix for DISPATCH-1496, the correct credit is forwarded (1000)1371 self.receiver.drain(0)1372 self.second_drain_sent = True1373 def on_message(self, event):1374 if event.receiver == self.receiver:1375 self.received += 11376 # Step 2: In response to Step 1, the broker has sent the only message in its queue1377 if self.received == 1:1378 self.first_drain_sent = True1379 #print ("First message received. Doing first drain")1380 # Step 3: The receiver drains after receiving the first message.1381 # This drain is forwarded to the FakeBroker1382 self.receiver.drain(0)1383 def run(self):1384 Container(self).run()1385class LinkRouteDrainTest(TestCase):1386 """1387 Test link route drain implementation.1388 DISPATCH-1496 alleges that the router is granting extra credit when1389 forwarding the drain.1390 Uses a router which connects to a FakeBroker (FB)1391 +-------------+ +---------+1392 | | <------ | |1393 | fake broker | | QDR.A |1394 | | ------> | | ------> +-------------------+1395 +-------------+ +---------+ | receiver |1396 +-------------------+1397 The router will grant extra credit when the following sequence is used1398 1. The receiver attaches to the router on a a link routed address called "org.apache"1399 2. Receiver issues a flow of 1000. The FakeBroker has only one message in its1400 "examples" queue and it sends it over to the router which forwards it to the receiver1401 3. After receiving the message the receiver issues a drain(0). This drain is1402 forwarded to the FakeBroker by the router and the FB responds. There1403 is not problem with this drain1404 4. The receiver again gives a flow of 1000 and it is forwarded to the FB. There1405 are no messages in the broker queue, so the FB sends no messages1406 5. The receiver again issues a drain(0). At this time, without the fix for1407 DISPATCH-1496, the router issues double the credit to the FB. Instead1408 of issuing a credit of 1000, it issues a credit of 2000.1409 """1410 @classmethod1411 def setUpClass(cls):1412 """Configure and start QDR.A"""1413 super(LinkRouteDrainTest, cls).setUpClass()1414 config = [1415 ('router', {'mode': 'standalone', 'id': 'QDR.A'}),1416 # for client connections:1417 ('listener', {'role': 'normal',1418 'host': '0.0.0.0',1419 'port': cls.tester.get_port(),1420 'saslMechanisms': 'ANONYMOUS'}),1421 # to connect to the fake broker1422 ('connector', {'name': 'broker',1423 'role': 'route-container',1424 'host': '127.0.0.1',1425 'port': cls.tester.get_port(),1426 'saslMechanisms': 'ANONYMOUS'}),1427 # forward 'org.apache' messages to + from fake broker:1428 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'FakeBroker', 'direction': 'in'}),1429 ('linkRoute', {'prefix': 'org.apache', 'containerId': 'FakeBroker', 'direction': 'out'})1430 ]1431 config = Qdrouterd.Config(config)1432 cls.router = cls.tester.qdrouterd('A', config, wait=False)1433 def _fake_broker(self, cls):1434 """Spawn a fake broker listening on the broker's connector1435 """1436 fake_broker = cls(self.router.connector_addresses[0])1437 # wait until the connection to the fake broker activates1438 self.router.wait_connectors()1439 return fake_broker1440 def test_DISPATCH_1496(self):1441 fake_broker = self._fake_broker(FakeBrokerDrain)1442 drain_receiver = DrainReceiver(self.router.addresses[0], fake_broker)1443 drain_receiver.run()1444 self.assertEqual(drain_receiver.error, None)1445class EmptyTransferTest(TestCase):1446 """Verify empty tranfer frames (no body) do not crash the router. See1447 DISPATCH-1988.1448 """1449 # various identifiers defined by AMQP 1.01450 OPEN_DESCRIPTOR = 0x101451 BEGIN_DESCRIPTOR = 0x111452 ATTACH_DESCRIPTOR = 0x121453 FLOW_DESCRIPTOR = 0x131454 TRANSFER_DESCRIPTOR = 0x141455 DISPO_DESCRIPTOR = 0x151456 ACCEPTED_OUTCOME = 0x241457 REJECTED_OUTCOME = 0x251458 TARGET_DESCRIPTOR = 0x291459 MA_SECTION_DESCRIPTOR = 0x731460 BODY_SECTION_DESCRIPTOR = 0x771461 @classmethod1462 def setUpClass(cls):1463 super(EmptyTransferTest, cls).setUpClass()1464 cls.ROUTER_LISTEN_PORT = cls.tester.get_port()1465 config = [1466 ('router', {'mode': 'standalone', 'id': 'QDR.A'}),1467 # the client will connect to this listener1468 ('listener', {'role': 'normal',1469 'port': cls.ROUTER_LISTEN_PORT,1470 'saslMechanisms': 'ANONYMOUS'}),1471 # to connect to the fake broker1472 ('connector', {'name': 'broker',1473 'role': 'route-container',1474 'host': '127.0.0.1',1475 'port': cls.tester.get_port(),1476 'saslMechanisms': 'ANONYMOUS'}),1477 ('linkRoute',1478 {'prefix': 'examples', 'containerId': 'FakeBroker',1479 'direction': 'in'}),1480 ('linkRoute',1481 {'prefix': 'examples', 'containerId': 'FakeBroker',1482 'direction': 'out'})1483 ]1484 config = Qdrouterd.Config(config)1485 cls.router = cls.tester.qdrouterd('A', config, wait=False)1486 def _fake_broker(self, cls):1487 """1488 Spawn a fake broker listening on the broker's connector1489 """1490 fake_broker = cls(self.router.connector_addresses[0])1491 # wait until the connection to the fake broker activates1492 self.router.wait_connectors()1493 return fake_broker1494 def _find_frame(self, data: bytes, code: int) -> Optional[list]:1495 """Scan a byte sequence for performatives that match code.1496 Return the frame body (list) if match else None1497 """1498 while data:1499 # starts at frame header (8 bytes)1500 frame_len = int.from_bytes(data[:4], "big")1501 if frame_len == 0 or frame_len > len(data):1502 return None1503 desc = Data()1504 desc.decode(data[8:frame_len]) # skip frame header1505 data = data[frame_len:] # advance to next frame1506 desc.rewind()1507 if desc.next() is None:1508 return None1509 if not desc.is_described():1510 return None1511 py_desc = desc.get_py_described()1512 if py_desc.descriptor == code:1513 return py_desc.value1514 return None1515 def _send_frame(self, frame: Data, sock: socket.socket):1516 """Encode and send frame over sock1517 """1518 frame.rewind()1519 fbytes = frame.encode()1520 flen = len(fbytes) + 81521 # AMQP FRAME HEADER: 4 byte length, DOFF, TYPE, CHANNEL1522 sock.sendall(flen.to_bytes(4, "big"))1523 sock.sendall(bytes([2, 0, 0, 0]))1524 sock.sendall(fbytes)1525 def _construct_transfer(self, delivery_id, tag, more=False, add_ma=False,1526 add_body=False) -> Data:1527 """Construct a Transfer frame in a proton Data object1528 """1529 t1_frame = Data()1530 t1_frame.put_described()1531 t1_frame.enter()1532 t1_frame.put_ulong(self.TRANSFER_DESCRIPTOR)1533 t1_frame.put_list()1534 t1_frame.enter()1535 t1_frame.put_uint(0) # handle1536 t1_frame.put_uint(delivery_id)1537 t1_frame.put_binary(tag)1538 t1_frame.put_uint(0) # msg format1539 t1_frame.put_bool(False) # settled1540 t1_frame.put_bool(more)1541 t1_frame.exit() # transfer list1542 t1_frame.exit() # transfer described type1543 if add_ma:1544 t1_frame.put_described()1545 t1_frame.enter()1546 t1_frame.put_ulong(self.MA_SECTION_DESCRIPTOR)1547 t1_frame.put_list()1548 t1_frame.enter()1549 t1_frame.put_ulong(9)1550 t1_frame.exit() # list1551 t1_frame.exit() # described1552 if add_body:1553 t1_frame.put_described()1554 t1_frame.enter()1555 t1_frame.put_ulong(self.BODY_SECTION_DESCRIPTOR)1556 t1_frame.put_string("I'm a small body!")1557 t1_frame.exit()1558 t1_frame.exit()1559 return t1_frame1560 def _get_outcome(self, dispo_frame: list) -> Optional[int]:1561 """Extract the outcome from a raw disposition frame"""1562 outcome = None1563 if len(dispo_frame) >= 5: # list[5] == state1564 if isinstance(dispo_frame[4], Described):1565 outcome = dispo_frame[4].descriptor1566 return outcome1567 def _read_socket(self, sock: socket.socket,1568 timeout: float = 1.0) -> bytes:1569 """Read all available data from the socket, waiting up to 1 second for1570 data to arrive1571 """1572 old_timeout = sock.gettimeout()1573 sock.settimeout(timeout)1574 data = b''1575 while True:1576 try:1577 incoming = sock.recv(4096)1578 if not incoming:1579 break1580 data += incoming1581 except OSError: # timeout1582 break1583 sock.settimeout(old_timeout)1584 return data1585 def test_DISPATCH_1988(self):1586 fake_broker = self._fake_broker(FakeBroker)1587 self.router.wait_ready()1588 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)1589 s.settimeout(TIMEOUT)1590 # Connect to the router listening port and send an amqp, open,1591 # begin, attach. The attach is sent on the link1592 # routed address, "examples"1593 s.connect(("127.0.0.1", EmptyTransferTest.ROUTER_LISTEN_PORT))1594 # send 'AMQP 1 0' preamble1595 s.sendall(b'\x41\x4d\x51\x50\x00\x01\x00\x00')1596 # send Open/Begin/Attach1597 open_frame = Data()1598 open_frame.put_described()1599 open_frame.enter()1600 open_frame.put_ulong(self.OPEN_DESCRIPTOR)1601 open_frame.put_list()1602 open_frame.enter()1603 open_frame.put_string("TestContainer")1604 open_frame.exit()1605 open_frame.exit()1606 open_frame.rewind()1607 begin_frame = Data()1608 begin_frame.put_described()1609 begin_frame.enter()1610 begin_frame.put_ulong(self.BEGIN_DESCRIPTOR)1611 begin_frame.put_list()1612 begin_frame.enter()1613 begin_frame.put_null()1614 begin_frame.put_uint(0) # next out id1615 begin_frame.put_uint(0xfffff) # in/out window1616 begin_frame.put_uint(0xfffff)1617 begin_frame.exit()1618 begin_frame.exit()1619 begin_frame.rewind()1620 attach_frame = Data()1621 attach_frame.put_described()1622 attach_frame.enter()1623 attach_frame.put_ulong(self.ATTACH_DESCRIPTOR)1624 attach_frame.put_list()1625 attach_frame.enter()1626 attach_frame.put_string("test-link-name")1627 attach_frame.put_uint(0) # handle1628 attach_frame.put_bool(False) # sender1629 attach_frame.put_null()1630 attach_frame.put_null()1631 attach_frame.put_null()1632 # target:1633 attach_frame.put_described()1634 attach_frame.enter()1635 attach_frame.put_ulong(self.TARGET_DESCRIPTOR)1636 attach_frame.put_list()1637 attach_frame.enter()1638 attach_frame.put_string("examples/foo")1639 attach_frame.exit() # target list1640 attach_frame.exit() # target descriptor1641 attach_frame.exit() # attach list1642 attach_frame.exit() # attach descriptor1643 attach_frame.rewind()1644 for frame in [open_frame, begin_frame, attach_frame]:1645 self._send_frame(frame, s)1646 # Give time for the attach to propagate to the broker and1647 # for the broker to send a response attach and flow:1648 data = self._read_socket(s, timeout=2.0)1649 self.assertTrue(len(data) > 8)1650 self.assertEqual(data[:8], b'AMQP\x00\x01\x00\x00')1651 # expect that the connection was accepted: check for a flow frame:1652 flow_frame = self._find_frame(data[8:], self.FLOW_DESCRIPTOR)1653 self.assertIsNotNone(flow_frame, "no flow frame received: %s" % data)1654 # First send a message on link routed address "examples" with a small1655 # message body. Verify the the sent message has been accepted.1656 t1_frame = self._construct_transfer(0, b'\x01', add_ma=True, add_body=True)1657 self._send_frame(t1_frame, s)1658 # We expect to get a disposition frame that accepted the message1659 data = self._read_socket(s)1660 self.assertTrue(len(data) > 0)1661 dispo_frame = self._find_frame(data, self.DISPO_DESCRIPTOR)1662 self.assertIsNotNone(dispo_frame,1663 "expected a disposition (none arrived!): %s"1664 % data)1665 outcome = self._get_outcome(dispo_frame)1666 self.assertEqual(self.ACCEPTED_OUTCOME, outcome,1667 "Transfer not accepted (unexpected!) actual=%s"1668 % outcome)1669 # Test case 11670 #1671 # Send an empty transfer frame to the router and you should receive a1672 # rejected disposition from the router. Without the fix for1673 # DISPATCH_1988, upon sending this EMPTY_TRANSFER the router crashes1674 # with the following assert1675 #1676 # qpid-dispatch/src/message.c:1260: qd_message_add_fanout: Assertion `content->pending && qd_buffer_size(content->pending) > 0' failed.1677 t2_frame = self._construct_transfer(1, b'\x02')1678 self._send_frame(t2_frame, s)1679 data = self._read_socket(s)1680 self.assertTrue(len(data) > 0)1681 dispo_frame = self._find_frame(data, self.DISPO_DESCRIPTOR)1682 self.assertIsNotNone(dispo_frame,1683 "expected a disposition (none arrived!): %s"1684 % data)1685 outcome = self._get_outcome(dispo_frame)1686 self.assertEqual(self.REJECTED_OUTCOME, outcome,1687 "Transfer not rejected (unexpected!) actual=%s"1688 % outcome)1689 # Test case 21690 # Now, send two empty transfer frames, first transfer has more=true and1691 # the next transfer has more=false. This will again be rejected by the1692 # router.1693 t3_frame = self._construct_transfer(2, b'\x03', more=True)1694 self._send_frame(t3_frame, s)1695 t4_frame = self._construct_transfer(2, b'\x03')1696 self._send_frame(t4_frame, s)1697 data = self._read_socket(s)1698 self.assertTrue(len(data) > 0)1699 dispo_frame = self._find_frame(data, self.DISPO_DESCRIPTOR)1700 self.assertIsNotNone(dispo_frame,1701 "expected a disposition (none arrived!): %s"1702 % data)1703 outcome = self._get_outcome(dispo_frame)1704 self.assertEqual(self.REJECTED_OUTCOME, outcome,1705 "Transfer not rejected (unexpected!) actual: %s"1706 % outcome)1707 # Now send a good transfer and ensure the router accepts it1708 t5_frame = self._construct_transfer(3, b'\x04', add_ma=True, add_body=True)1709 self._send_frame(t5_frame, s)1710 data = self._read_socket(s)1711 self.assertTrue(len(data) > 0)1712 dispo_frame = self._find_frame(data, self.DISPO_DESCRIPTOR)1713 self.assertIsNotNone(dispo_frame,1714 "expected a disposition (none arrived!): %s"1715 % data)1716 outcome = self._get_outcome(dispo_frame)1717 self.assertEqual(self.ACCEPTED_OUTCOME, outcome,1718 "Transfer not accepted (unexpected!) actual: %s"1719 % outcome)1720 s.close()1721 fake_broker.join()1722class ConnectionLinkRouteTest(TestCase):1723 """1724 Test connection scoped link route implementation1725 Base configuration:1726 +-----------------+1727 +---------+ +---------+<--| blocking_sender |1728 +-----------------+ | | | | +-----------------+1729 | Fake LR Service |<==>| QDR.A |<==>| QDR.B |1730 +-----------------+ | | | | +-------------------+1731 +---------+ +---------+-->| blocking_receiver |1732 +-------------------+1733 The Fake Link Route Service will create connection-scoped link routes to1734 QDR.A, while blocking sender/receivers on QDR.B will send/receive messages1735 via the link route.1736 """1737 _AS_TYPE = "org.apache.qpid.dispatch.router.connection.linkRoute"1738 @classmethod1739 def setUpClass(cls):1740 super(ConnectionLinkRouteTest, cls).setUpClass()1741 b_port = cls.tester.get_port()1742 configs = [1743 # QDR.A:1744 [('router', {'mode': 'interior', 'id': 'QDR.A'}),1745 # for fake connection-scoped LRs:1746 ('listener', {'role': 'normal',1747 'host': '0.0.0.0',1748 'port': cls.tester.get_port(),1749 'saslMechanisms': 'ANONYMOUS'}),1750 # for fake route-container LR connections:1751 ('listener', {'role': 'route-container',1752 'host': '0.0.0.0',1753 'port': cls.tester.get_port(),1754 'saslMechanisms': 'ANONYMOUS'}),1755 # to connect to the QDR.B1756 ('connector', {'role': 'inter-router',1757 'host': '127.0.0.1',1758 'port': b_port,1759 'saslMechanisms': 'ANONYMOUS'})],1760 # QDR.B:1761 [('router', {'mode': 'interior', 'id': 'QDR.B'}),1762 # for client connections1763 ('listener', {'role': 'normal',1764 'host': '0.0.0.0',1765 'port': cls.tester.get_port(),1766 'saslMechanisms': 'ANONYMOUS'}),1767 # for connection to QDR.A1768 ('listener', {'role': 'inter-router',1769 'host': '0.0.0.0',1770 'port': b_port,1771 'saslMechanisms': 'ANONYMOUS'})]1772 ]1773 cls.routers = []1774 for c in configs:1775 config = Qdrouterd.Config(c)1776 cls.routers.append(cls.tester.qdrouterd(config=config, wait=False))1777 cls.QDR_A = cls.routers[0]1778 cls.QDR_B = cls.routers[1]1779 cls.QDR_A.wait_router_connected('QDR.B')1780 cls.QDR_B.wait_router_connected('QDR.A')1781 def _get_address(self, mgmt, addr):1782 a_type = 'org.apache.qpid.dispatch.router.address'1783 return [a for a in mgmt.query(a_type) if a['name'].endswith(addr)]1784 def test_config_file_bad(self):1785 # verify that specifying a connection link route in the configuration1786 # file fails1787 config = [('router', {'mode': 'interior', 'id': 'QDR.X'}),1788 ('listener', {'role': 'normal',1789 'host': '0.0.0.0',1790 'port': self.tester.get_port(),1791 'saslMechanisms': 'ANONYMOUS'}),1792 ('connection.linkRoute',1793 {'pattern': "i/am/bad",1794 'direction': "out"})1795 ]1796 cfg = Qdrouterd.Config(config)1797 # we expect the router to fail1798 router = self.tester.qdrouterd("X", cfg, wait=False, expect=Process.EXIT_FAIL) # type: Qdrouterd1799 self.assertEqual(router.wait(TIMEOUT), Process.EXIT_FAIL)1800 def test_mgmt(self):1801 # test create, delete, and query1802 mgmt_conn = BlockingConnection(self.QDR_A.addresses[0])1803 mgmt_proxy = ConnLinkRouteMgmtProxy(mgmt_conn)1804 for i in range(10):1805 rsp = mgmt_proxy.create_conn_link_route("lr1-%d" % i,1806 {'pattern': "*/hi/there/%d" % i,1807 'direction':1808 'out' if i % 2 else 'in'})1809 self.assertEqual(201, rsp.status_code)1810 # test query1811 rsp = mgmt_proxy.query_conn_link_routes()1812 self.assertEqual(200, rsp.status_code)1813 self.assertEqual(10, len(rsp.results))1814 entities = rsp.results1815 # test read1816 rsp = mgmt_proxy.read_conn_link_route('lr1-5')1817 self.assertEqual(200, rsp.status_code)1818 self.assertEqual("lr1-5", rsp.attrs['name'])1819 self.assertEqual("*/hi/there/5", rsp.attrs['pattern'])1820 self.assertEqual(mgmt_conn.container.container_id,1821 rsp.attrs['containerId'])1822 # bad creates1823 attrs = [{'pattern': "bad", 'direction': "bad"},1824 {'direction': 'in'},1825 {},1826 {'pattern': ''},1827 {'pattern': 7}]1828 for a in attrs:1829 rsp = mgmt_proxy.create_conn_link_route("iamnoone", a)1830 self.assertEqual(400, rsp.status_code)1831 # bad read1832 rsp = mgmt_proxy.read_conn_link_route('iamnoone')1833 self.assertEqual(404, rsp.status_code)1834 # bad delete1835 rsp = mgmt_proxy.delete_conn_link_route('iamnoone')1836 self.assertEqual(404, rsp.status_code)1837 # delete all1838 for r in entities:1839 self.assertEqual(200, r.status_code)1840 rsp = mgmt_proxy.delete_conn_link_route(r.attrs['name'])1841 self.assertEqual(204, rsp.status_code)1842 # query - should be none left1843 rsp = mgmt_proxy.query_conn_link_routes()1844 self.assertEqual(200, rsp.status_code)1845 self.assertEqual(0, len(rsp.results))1846 def test_address_propagation(self):1847 # test service that creates and deletes connection link routes1848 fs = ConnLinkRouteService(self.QDR_A.addresses[1], container_id="FakeService",1849 config=[("clr1",1850 {"pattern": "flea.*",1851 "direction": "out"}),1852 ("clr2",1853 {"pattern": "flea.*",1854 "direction": "in"})])1855 self.assertEqual(2, len(fs.values))1856 # the address should propagate to A and B1857 self.QDR_A.wait_address(address="flea.*", count=2)1858 self.QDR_B.wait_address(address="flea.*", count=2)1859 # now have the service delete the config1860 fs.delete_config()1861 # eventually the addresses will be un-published1862 mgmt_A = QdManager(self, address=self.QDR_A.addresses[0])1863 mgmt_B = QdManager(self, address=self.QDR_B.addresses[0])1864 deadline = time() + TIMEOUT1865 while (self._get_address(mgmt_A, "flea.*")1866 or self._get_address(mgmt_B, "flea.*")):1867 self.assertTrue(time() < deadline)1868 sleep(0.1)1869 fs.join()1870 # simple forwarding tests with auto delete1871 def test_send_receive(self):1872 COUNT = 51873 mgmt_A = QdManager(self, address=self.QDR_A.addresses[0])1874 mgmt_B = QdManager(self, address=self.QDR_B.addresses[0])1875 # connect broker to A route-container1876 fs = ConnLinkRouteService(self.QDR_A.addresses[1], container_id="FakeService",1877 config=[("clr1",1878 {"pattern": "flea.*",1879 "direction": "out"}),1880 ("clr2",1881 {"pattern": "flea.*",1882 "direction": "in"})])1883 self.assertEqual(2, len(fs.values))1884 # wait for the address to propagate to B1885 self.QDR_B.wait_address(address="flea.*", count=2)1886 # ensure the link routes are not visible via other connections1887 clrs = mgmt_A.query(self._AS_TYPE)1888 self.assertEqual(0, len(clrs))1889 # send from A to B1890 r = AsyncTestReceiver(self.QDR_B.addresses[0],1891 "flea.B",1892 container_id="flea.BReceiver")1893 s = AsyncTestSender(self.QDR_A.addresses[0],1894 "flea.B",1895 container_id="flea.BSender",1896 message=Message(body="SENDING TO flea.B"),1897 count=COUNT)1898 s.wait() # for sender to complete1899 for i in range(COUNT):1900 self.assertEqual("SENDING TO flea.B",1901 r.queue.get(timeout=TIMEOUT).body)1902 r.stop()1903 self.assertEqual(COUNT, fs.in_count)1904 # send from B to A1905 r = AsyncTestReceiver(self.QDR_A.addresses[0],1906 "flea.A",1907 container_id="flea.AReceiver")1908 s = AsyncTestSender(self.QDR_B.addresses[0],1909 "flea.A",1910 container_id="flea.ASender",1911 message=Message(body="SENDING TO flea.A"),1912 count=COUNT)1913 s.wait()1914 for i in range(COUNT):1915 self.assertEqual("SENDING TO flea.A",1916 r.queue.get(timeout=TIMEOUT).body)1917 r.stop()1918 self.assertEqual(2 * COUNT, fs.in_count)1919 # once the fake service closes its conn the link routes1920 # are removed so the link route addresses must be gone1921 fs.join()1922 mgmt_A = QdManager(self, address=self.QDR_A.addresses[0])1923 mgmt_B = QdManager(self, address=self.QDR_B.addresses[0])1924 deadline = time() + TIMEOUT1925 while (self._get_address(mgmt_A, "flea.*")1926 or self._get_address(mgmt_B, "flea.*")):1927 self.assertTrue(time() < deadline)1928 sleep(0.1)1929class ConnLinkRouteService(FakeBroker):1930 def __init__(self, url, container_id, config, timeout=TIMEOUT):1931 self.conn = None1932 self.mgmt_proxy = None1933 self.mgmt_sender = None1934 self.mgmt_receiver = None1935 self._config = config1936 self._config_index = 01937 self._config_done = Event()1938 self._config_error = None1939 self._config_values = []1940 self._cleaning_up = False1941 self._delete_done = Event()1942 self._delete_count = 01943 self._event_injector = EventInjector()1944 self._delete_event = ApplicationEvent("delete_config")1945 super(ConnLinkRouteService, self).__init__(url, container_id)1946 if self._config_done.wait(timeout) is False:1947 raise Exception("Timed out waiting for configuration setup")1948 if self._config_error is not None:1949 raise Exception("Error: %s" % self._config_error)1950 @property1951 def values(self):1952 return self._config_values1953 def delete_config(self):1954 self._event_injector.trigger(self._delete_event)1955 if self._delete_done.wait(TIMEOUT) is False:1956 raise Exception("Timed out waiting for configuration delete")1957 def on_start(self, event):1958 """1959 Do not create an acceptor, actively connect instead1960 """1961 event.container.selectable(self._event_injector)1962 self.conn = event.container.connect(self.url)1963 def on_connection_opened(self, event):1964 if event.connection == self.conn:1965 if self.mgmt_receiver is None:1966 self.mgmt_receiver = event.container.create_receiver(self.conn,1967 dynamic=True)1968 super(ConnLinkRouteService, self).on_connection_opened(event)1969 def on_connection_closed(self, event):1970 if self._event_injector:1971 self._event_injector.close()1972 self._event_injector = None1973 super(ConnLinkRouteService, self).on_connection_closed(event)1974 def on_link_opened(self, event):1975 if event.link == self.mgmt_receiver:1976 self.mgmt_proxy = MgmtMsgProxy(self.mgmt_receiver.remote_source.address)1977 self.mgmt_sender = event.container.create_sender(self.conn,1978 target="$management")1979 def on_link_error(self, event):1980 # when a remote client disconnects the service will get a link error1981 # that is expected - simply clean up the link1982 self.on_link_closing(event)1983 def on_sendable(self, event):1984 if event.sender == self.mgmt_sender:1985 if not self._cleaning_up:1986 if self._config_index < len(self._config):1987 cfg = self._config[self._config_index]1988 msg = self.mgmt_proxy.create_conn_link_route(cfg[0], cfg[1])1989 self.mgmt_sender.send(msg)1990 self._config_index += 11991 elif self._config_values:1992 cv = self._config_values.pop()1993 msg = self.mgmt_proxy.delete_conn_link_route(cv['name'])1994 self._delete_count += 11995 else:1996 super(ConnLinkRouteService, self).on_sendable(event)1997 def on_message(self, event):1998 if event.receiver == self.mgmt_receiver:1999 response = self.mgmt_proxy.response(event.message)2000 if response.status_code == 201:2001 # created:2002 self._config_values.append(response.attrs)2003 if len(self._config_values) == len(self._config):2004 self._config_done.set()2005 elif response.status_code == 204:2006 # deleted2007 self._delete_count -= 12008 if (not self._config_values) and self._delete_count == 0:2009 self._delete_done.set()2010 else:2011 # error2012 self._config_error = ("mgmt failed: %s" %2013 response.status_description)2014 self._config_done.set()2015 self._delete_done.set()2016 else:2017 super(ConnLinkRouteService, self).on_message(event)2018 def on_delete_config(self, event):2019 if not self._cleaning_up:2020 self._cleaning_up = True2021 if not self._config_values:2022 self._delete_done.set()2023 else:2024 try:2025 while self.mgmt_sender.credit > 0:2026 cv = self._config_values.pop()2027 msg = self.mgmt_proxy.delete_conn_link_route(cv["name"])2028 self.mgmt_sender.send(msg)2029 self._delete_count += 12030 except IndexError:2031 pass2032class ConnLinkRouteMgmtProxy:2033 """2034 Manage connection scoped link routes over a given connection.2035 While the connection remains open the connection scoped links will remain2036 configured and active2037 """2038 def __init__(self, bconn, credit=250):2039 self._receiver = bconn.create_receiver(address=None, dynamic=True, credit=credit)2040 self._sender = bconn.create_sender(address="$management")2041 self._proxy = MgmtMsgProxy(self._receiver.link.remote_source.address)2042 def __getattr__(self, key):2043 # wrap accesses to the management message functions so we can send and2044 # receive the messages using the blocking links2045 f = getattr(self._proxy, key)2046 if not callable(f):2047 return f2048 def _func(*args, **kwargs):2049 self._sender.send(f(*args, **kwargs))2050 return self._proxy.response(self._receiver.receive())2051 return _func2052class InvalidTagTest(MessagingHandler):2053 """Verify that a message with an invalid tag length is rejected2054 """2055 def __init__(self, router_addr):2056 super(InvalidTagTest, self).__init__(auto_accept=False, auto_settle=False)2057 self.test_conn = None2058 self.test_address = router_addr2059 self.tx_ct = 02060 self.accept_ct = 02061 self.reject_ct = 02062 self.error = None2063 def timeout(self):2064 self.error = "Timeout expired: sent=%d rcvd=%d" % (self.tx_ct,2065 self.accept_ct2066 + self.reject_ct)2067 if self.test_conn:2068 self.test_conn.close()2069 def on_start(self, event):2070 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))2071 self.test_conn = event.container.connect(self.test_address)2072 rx = event.container.create_receiver(self.test_conn, "org.apache.foo")2073 def on_link_opened(self, event):2074 if event.receiver:2075 event.receiver.flow(100)2076 event.container.create_sender(event.connection, "org.apache.foo")2077 def on_sendable(self, event):2078 if self.tx_ct < 10:2079 self.tx_ct += 12080 if self.tx_ct == 5:2081 event.sender.send(Message(body="YO"), tag=str("X" * 64))2082 else:2083 event.sender.send(Message(body="YO"), tag=str("BLAH%d" %2084 self.tx_ct))2085 def on_accepted(self, event):2086 self.accept_ct += 12087 event.delivery.settle()2088 if self.accept_ct == 9 and self.reject_ct == 1:2089 event.connection.close()2090 self.timer.cancel()2091 def on_rejected(self, event):2092 self.reject_ct += 12093 event.delivery.settle()2094 def on_message(self, event):2095 event.delivery.update(Delivery.ACCEPTED)2096 event.delivery.settle()2097 def run(self):2098 Container(self).run()2099class Dispatch1428(TestCase):2100 """2101 Sets up 2 routers (one of which are acting as brokers (QDR.A)).2102 QDR.A acting broker #12103 +---------+ +---------+2104 | | <------ | |2105 | QDR.A | | QDR.B |2106 | | ------> | |2107 +---------+ +---------+2108 """2109 @classmethod2110 def get_router(cls, index):2111 return cls.routers[index]2112 @classmethod2113 def setUpClass(cls):2114 """Start two routers"""2115 super(Dispatch1428, cls).setUpClass()2116 def router(name, connection):2117 config = [2118 ('router', {'mode': 'interior', 'id': 'QDR.%s' % name}),2119 ] + connection2120 config = Qdrouterd.Config(config)2121 cls.routers.append(cls.tester.qdrouterd(name, config, wait=False))2122 cls.routers = []2123 a_listener_port = cls.tester.get_port()2124 b_listener_port = cls.tester.get_port()2125 router('A',2126 [2127 ('listener', {'role': 'normal', 'host': '0.0.0.0', 'port': a_listener_port, 'saslMechanisms': 'ANONYMOUS'}),2128 ])2129 router('B',2130 [2131 ('listener', {'role': 'normal', 'host': '0.0.0.0', 'port': b_listener_port, 'saslMechanisms': 'ANONYMOUS'}),2132 ('connector', {'name': 'one', 'role': 'route-container', 'host': '0.0.0.0', 'port': a_listener_port, 'saslMechanisms': 'ANONYMOUS'}),2133 ('connector', {'name': 'two', 'role': 'route-container', 'host': '0.0.0.0', 'port': a_listener_port, 'saslMechanisms': 'ANONYMOUS'})2134 ]2135 )2136 sleep(2)2137 def run_qdmanage(self, cmd, input=None, expect=Process.EXIT_OK, address=None):2138 p = self.popen(2139 ['qdmanage'] + cmd.split(' ') + ['--bus', address or self.address(), '--indent=-1', '--timeout', str(TIMEOUT)],2140 stdin=PIPE, stdout=PIPE, stderr=STDOUT, expect=expect,2141 universal_newlines=True)2142 out = p.communicate(input)[0]2143 try:2144 p.teardown()2145 except Exception as e:2146 raise Exception("%s\n%s" % (e, out))2147 return out2148 def test_both_link_routes_active(self):2149 cmds = [2150 'CREATE --type=linkRoute name=foo prefix=foo direction=in connection=one',2151 'CREATE --type=linkRoute name=bar prefix=bar direction=in connection=two',2152 'CREATE --type=linkRoute name=baz prefix=baz direction=in containerId=QDR.A'2153 ]2154 for c in cmds:2155 self.run_qdmanage(cmd=c, address=self.routers[1].addresses[0])2156 # Now that the qdmanage has run, query the link routes and make sure that their "operStatus" is "active" before2157 # running any of the tests.2158 long_type = 'org.apache.qpid.dispatch.router.config.linkRoute'2159 qd_manager = QdManager(self, address=self.routers[1].addresses[0])2160 for i in range(5):2161 all_link_routes_activated = True2162 link_routes = qd_manager.query(long_type)2163 for link_route in link_routes:2164 oper_status = link_route['operStatus']2165 if oper_status != "active":2166 all_link_routes_activated = False2167 break2168 if not all_link_routes_activated:2169 # One or more of the link routes have not been activated.2170 # Check after one second.2171 sleep(1)2172 else:2173 break2174 # All link routes created in this test MUST be activated before2175 # we can continue further testing.2176 self.assertTrue(all_link_routes_activated)2177 first = SendReceive("%s/foo" % self.routers[1].addresses[0], "%s/foo" % self.routers[0].addresses[0])2178 first.run()2179 self.assertIsNone(first.error)2180 second = SendReceive("%s/bar" % self.routers[1].addresses[0], "%s/bar" % self.routers[0].addresses[0])2181 second.run()2182 self.assertIsNone(second.error)2183 third = SendReceive("%s/baz" % self.routers[1].addresses[0], "%s/baz" % self.routers[0].addresses[0])2184 third.run()2185 self.assertIsNone(third.error)2186class SendReceive(MessagingHandler):2187 def __init__(self, send_url, recv_url, message=None):2188 super(SendReceive, self).__init__()2189 self.send_url = send_url2190 self.recv_url = recv_url2191 self.message = message or Message(body="SendReceiveTest")2192 self.sent = False2193 self.error = None2194 def close(self):2195 self.sender.close()2196 self.receiver.close()2197 self.sender.connection.close()2198 self.receiver.connection.close()2199 def timeout(self):2200 self.error = "Timeout Expired - Check for cores"2201 self.close()2202 def stop(self):2203 self.close()2204 self.timer.cancel()2205 def on_start(self, event):2206 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))2207 event.container.container_id = "SendReceiveTestClient"2208 self.sender = event.container.create_sender(self.send_url)2209 self.receiver = event.container.create_receiver(self.recv_url)2210 def on_sendable(self, event):2211 if not self.sent:2212 event.sender.send(self.message)2213 self.sent = True2214 def on_message(self, event):2215 if self.message.body != event.message.body:2216 self.error = "Incorrect message. Got %s, expected %s" % (event.message.body, self.message.body)2217 def on_accepted(self, event):2218 self.stop()2219 def run(self):2220 Container(self).run()2221class DispositionSniffer(MessagingHandler):2222 """2223 Capture the outgoing delivery after the remote has set its terminal2224 outcome. Used by tests that need to examine the delivery state2225 """2226 def __init__(self, send_url):2227 super(DispositionSniffer, self).__init__(auto_accept=False,2228 auto_settle=False)2229 self.send_url = send_url2230 self.sender = None2231 self.timer = None2232 self.error = None2233 self.sent = False2234 self.delivery = None2235 def close(self):2236 if self.timer:2237 self.timer.cancel()2238 if self.sender:2239 self.sender.close()2240 self.sender.connection.close()2241 def timeout(self):2242 self.error = "Timeout Expired - Check for cores"2243 self.close()2244 def stop(self):2245 self.close()2246 def on_start(self, event):2247 self.timer = event.reactor.schedule(TIMEOUT, TestTimeout(self))2248 self.sender = event.container.create_sender(self.send_url)2249 def on_sendable(self, event):2250 if not self.sent:2251 event.sender.send(Message(body="HI"))2252 self.sent = True2253 def on_accepted(self, event):2254 self.stop()2255 def on_released(self, event):2256 self.delivery = event.delivery2257 self.close()2258 def on_modified(self, event):2259 self.delivery = event.delivery2260 self.close()2261 def on_rejected(self, event):2262 self.delivery = event.delivery2263 self.close()2264 def run(self):2265 Container(self).run()2266class LinkRoute3Hop(TestCase):2267 """2268 Sets up a linear 3 hop router network for testing multi-hop link routes.2269 +---------+ +---------+ +---------+ +------------------+2270 | | <------ | | <----- | |<----| blocking_senders |2271 | QDR.A | | QDR.B | | QDR.C | +------------------+2272 | | ------> | | ------> | | +--------------------+2273 +---------+ +---------+ +---------+---->| blocking_receivers |2274 ^ +--------------------+2275 |2276 V2277 +-------------+2278 | FakeService |2279 +-------------+2280 """2281 @classmethod2282 def setUpClass(cls):2283 super(LinkRoute3Hop, cls).setUpClass()2284 b_port = cls.tester.get_port()2285 configs = [2286 # QDR.A:2287 [('router', {'mode': 'interior', 'id': 'QDR.A'}),2288 # for client access2289 ('listener', {'role': 'normal',2290 'host': '0.0.0.0',2291 'port': cls.tester.get_port(),2292 'saslMechanisms': 'ANONYMOUS'}),2293 # for fake service:2294 ('listener', {'role': 'route-container',2295 'host': '0.0.0.0',2296 'port': cls.tester.get_port(),2297 'saslMechanisms': 'ANONYMOUS'}),2298 # to connect to the QDR.B2299 ('connector', {'role': 'inter-router',2300 'host': '127.0.0.1',2301 'port': b_port,2302 'saslMechanisms': 'ANONYMOUS'}),2303 # the routes2304 ('linkRoute', {'prefix': 'closest/test-client', 'containerId': 'FakeService', 'direction': 'in'}),2305 ('linkRoute', {'prefix': 'closest/test-client', 'containerId': 'FakeService', 'direction': 'out'})2306 ],2307 # QDR.B:2308 [('router', {'mode': 'interior', 'id': 'QDR.B'}),2309 # for client connections2310 ('listener', {'role': 'normal',2311 'host': '0.0.0.0',2312 'port': cls.tester.get_port(),2313 'saslMechanisms': 'ANONYMOUS'}),2314 # for inter-router connections from QDR.A and QDR.C2315 ('listener', {'role': 'inter-router',2316 'host': '0.0.0.0',2317 'port': b_port,2318 'saslMechanisms': 'ANONYMOUS'}),2319 ('linkRoute', {'prefix': 'closest/test-client', 'direction': 'in'}),2320 ('linkRoute', {'prefix': 'closest/test-client', 'direction': 'out'})2321 ],2322 # QDR.C2323 [('router', {'mode': 'interior', 'id': 'QDR.C'}),2324 # for client connections2325 ('listener', {'role': 'normal',2326 'host': '0.0.0.0',2327 'port': cls.tester.get_port(),2328 'saslMechanisms': 'ANONYMOUS'}),2329 # to connect to the QDR.B2330 ('connector', {'role': 'inter-router',2331 'host': '127.0.0.1',2332 'port': b_port,2333 'saslMechanisms': 'ANONYMOUS'}),2334 ('linkRoute', {'prefix': 'closest/test-client', 'direction': 'in'}),2335 ('linkRoute', {'prefix': 'closest/test-client', 'direction': 'out'})2336 ]2337 ]2338 cls.routers = []2339 for c in configs:2340 config = Qdrouterd.Config(c)2341 cls.routers.append(cls.tester.qdrouterd(config=config, wait=False))2342 cls.QDR_A = cls.routers[0]2343 cls.QDR_B = cls.routers[1]2344 cls.QDR_C = cls.routers[2]2345 cls.QDR_A.wait_router_connected('QDR.B')2346 cls.QDR_B.wait_router_connected('QDR.A')2347 cls.QDR_B.wait_router_connected('QDR.C')2348 cls.QDR_C.wait_router_connected('QDR.B')2349 cls.QDR_C.wait_router_connected('QDR.A')2350 cls.QDR_A.wait_router_connected('QDR.C')2351 def test_01_parallel_link_routes(self):2352 """2353 Verify Q2/Q3 recovery in the case of multiple link-routes sharing the2354 same session.2355 """2356 send_clients = 102357 send_batch = 52358 total = send_clients * send_batch2359 fake_service = FakeService(self.QDR_A.addresses[1],2360 container_id="FakeService")2361 self.QDR_C.wait_address("closest/test-client",2362 remotes=1)2363 env = None2364 rx = self.popen(["test-receiver",2365 "-a", self.QDR_C.addresses[0],2366 "-c", str(total),2367 "-s", "closest/test-client",2368 "-d"],2369 env=env,2370 expect=Process.EXIT_OK)2371 def _spawn_sender(x):2372 return self.popen(["test-sender",2373 "-a", self.QDR_C.addresses[0],2374 "-c", str(send_batch),2375 "-i", "TestSender-%s" % x,2376 "-sx", # huge message size to trigger Q2/Q32377 "-t", "closest/test-client",2378 "-d"],2379 env=env,2380 expect=Process.EXIT_OK)2381 senders = [_spawn_sender(s) for s in range(send_clients)]2382 for tx in senders:2383 out_text, out_err = tx.communicate(timeout=TIMEOUT)2384 if tx.returncode:2385 raise Exception(f"Sender failed: {out_text} {out_err}")2386 if rx.wait(timeout=TIMEOUT):2387 raise Exception(2388 f"Receiver failed to consume all messages in={fake_service.in_count} out={fake_service.out_count}")2389 fake_service.join()2390 self.assertEqual(total, fake_service.in_count)2391 self.assertEqual(total, fake_service.out_count)2392 self.QDR_C.wait_address_unsubscribed("closest/test-client")2393 def test_02_modified_outcome(self):2394 """2395 Ensure all elements of a Modified disposition are passed thru the link2396 route2397 """2398 class FakeServiceModified(FakeService):2399 def on_message(self, event):2400 # set non-default values for delivery state for delivery to2401 # remote endpoint2402 dlv = event.delivery2403 dlv.local.failed = True2404 dlv.local.undeliverable = True2405 dlv.local.annotations = {symbol("Key"): "Value"}2406 dlv.update(Delivery.MODIFIED)2407 dlv.settle()2408 fake_service = FakeServiceModified(self.QDR_A.addresses[1],2409 container_id="FakeService",2410 auto_accept=False,2411 auto_settle=False)2412 self.QDR_C.wait_address("closest/test-client",2413 remotes=1)2414 sniffer = DispositionSniffer("%s/closest/test-client" %2415 self.QDR_C.addresses[0])2416 sniffer.run()2417 self.assertIsNone(sniffer.error)2418 state = sniffer.delivery.remote2419 self.assertTrue(state.failed)2420 self.assertTrue(state.undeliverable)2421 self.assertTrue(state.annotations is not None)2422 self.assertTrue(symbol('Key') in state.annotations)2423 self.assertEqual('Value', state.annotations[symbol('Key')])2424 fake_service.join()2425 self.QDR_C.wait_address_unsubscribed("closest/test-client")2426 def test_03_rejected_outcome(self):2427 """2428 Ensure all elements of a Rejected disposition are passed thru the link2429 route2430 """2431 class FakeServiceReject(FakeService):2432 def on_message(self, event):2433 # set non-default values for delivery state for delivery to2434 # remote endpoint2435 dlv = event.delivery2436 dlv.local.condition = Condition("condition-name",2437 str("condition-description"),2438 {symbol("condition"): "info"})2439 dlv.update(Delivery.REJECTED)2440 dlv.settle()2441 fake_service = FakeServiceReject(self.QDR_A.addresses[1],2442 container_id="FakeService",2443 auto_accept=False,2444 auto_settle=False)2445 self.QDR_C.wait_address("closest/test-client",2446 remotes=1)2447 sniffer = DispositionSniffer("%s/closest/test-client" %2448 self.QDR_C.addresses[0])2449 sniffer.run()2450 self.assertIsNone(sniffer.error)2451 state = sniffer.delivery.remote2452 self.assertTrue(state.condition is not None)2453 self.assertEqual("condition-name", state.condition.name)2454 self.assertEqual("condition-description", state.condition.description)2455 self.assertTrue(state.condition.info is not None)2456 self.assertTrue(symbol("condition") in state.condition.info)2457 self.assertEqual('info', state.condition.info[symbol("condition")])2458 fake_service.join()2459 self.QDR_C.wait_address_unsubscribed("closest/test-client")2460 def test_04_extension_state(self):2461 """2462 system_tests_two_routers.TwoRouterExtensionsStateTest() already tests2463 sending extended state via a link route.2464 """2465 pass2466if __name__ == '__main__':...

Full Screen

Full Screen

test_element_handle.py

Source:test_element_handle.py Github

copy

Full Screen

...109 }110 assert roundbox(box) == roundbox(web_bounding_box)111def test_content_frame(page, server, utils):112 page.goto(server.EMPTY_PAGE)113 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)114 element_handle = page.query_selector("#frame1")115 frame = element_handle.content_frame()116 assert frame == page.frames[1]117def test_content_frame_for_non_iframes(page, server, utils):118 page.goto(server.EMPTY_PAGE)119 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)120 frame = page.frames[1]121 element_handle = frame.evaluate_handle("document.body")122 assert element_handle.content_frame() is None123def test_content_frame_for_document_element(page, server, utils):124 page.goto(server.EMPTY_PAGE)125 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)126 frame = page.frames[1]127 element_handle = frame.evaluate_handle("document.documentElement")128 assert element_handle.content_frame() is None129def test_owner_frame(page, server, utils):130 page.goto(server.EMPTY_PAGE)131 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)132 frame = page.frames[1]133 element_handle = frame.evaluate_handle("document.body")134 assert element_handle.owner_frame() == frame135def test_owner_frame_for_cross_process_iframes(page, server, utils):136 page.goto(server.EMPTY_PAGE)137 utils.attach_frame(page, "frame1", server.CROSS_PROCESS_PREFIX + "/empty.html")138 frame = page.frames[1]139 element_handle = frame.evaluate_handle("document.body")140 assert element_handle.owner_frame() == frame141def test_owner_frame_for_document(page, server, utils):142 page.goto(server.EMPTY_PAGE)143 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)144 frame = page.frames[1]145 element_handle = frame.evaluate_handle("document")146 assert element_handle.owner_frame() == frame147def test_owner_frame_for_iframe_elements(page, server, utils):148 page.goto(server.EMPTY_PAGE)149 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)150 frame = page.main_frame151 element_handle = frame.evaluate_handle('document.querySelector("#frame1")')152 print(element_handle)153 assert element_handle.owner_frame() == frame154def test_owner_frame_for_cross_frame_evaluations(page, server, utils):155 page.goto(server.EMPTY_PAGE)156 utils.attach_frame(page, "frame1", server.EMPTY_PAGE)157 frame = page.main_frame158 element_handle = frame.evaluate_handle(159 'document.querySelector("#frame1").contentWindow.document.body'160 )161 assert element_handle.owner_frame() == frame.child_frames[0]162def test_owner_frame_for_detached_elements(page, server):163 page.goto(server.EMPTY_PAGE)164 div_handle = page.evaluate_handle(165 """() => {166 div = document.createElement('div');167 document.body.appendChild(div);168 return div;169 }"""170 )...

Full Screen

Full Screen

emergency_equip_frontend_tk.py

Source:emergency_equip_frontend_tk.py Github

copy

Full Screen

12import tkinter as tk3from tkinter import *4from tkinter import ttk5from tkinter.ttk import *6import tkinter.messagebox78import gui_styles_tk9import components_tk10import data_input_checks_tk11import emergency_equip_backend as ee_bknd12import double_scrollbar13import treeview_functions14import comment_box15import file_menu16import copy171819def check_ee_used(self):20 used = False21 eels = []22 eel_comparisons = []2324 eel_dict = components_tk.get_all_components(self.mainapp, 'EELs')2526 for e in eel_dict['All']:27 28 for loc in self.mainapp.frames[e].backend.layout.keys():29 for p in self.mainapp.frames[e].backend.layout[loc]:3031 if p[1] == self.backend.title:32 used = True33 eels.append(e)34 35 eel_dict = components_tk.get_all_components(self.mainapp, 'EEL Comparisons')3637 for e in eel_dict['All']:38 39 for loc in self.mainapp.frames[e].backend.layout.keys():40 for p in self.mainapp.frames[e].backend.layout[loc]:4142 if p[1] == self.backend.title:43 used = True44 eel_comparisons.append(e)45 break46 if e in eel_comparisons:47 break484950 return used, eels, eel_comparisons515253class Emergency_Equipment_Page_Tk(tk.Frame):5455 def __init__(self, container, mainapp):56 tk.Frame.__init__(self, container)57 58 self.mainapp = mainapp59 60 self.top_label = tk.Label(self, text=('PSU Layout: '),font=self.mainapp.title_font, anchor="w")61 self.top_label.pack(fill=tk.BOTH, expand=True)62 63 self.backend = ee_bknd.Emergency_Equip_Backend(self, mainapp)64 65 self.treeview_iid = None66 self.setup_notebook()67 self.setup_scrollable_frames()68 self.setup_label_frames()69 self.setup_labels()70 self.setup_treeviews()71 self.setup_buttons()72 #self.set_grid_configures()737475 def setup_scrollable_frames(self):76 77 self.main_scroll_frame = double_scrollbar.Double_ScrollableFrame(self.main_tab, self.mainapp)78 self.main_scroll_frame.pack(fill=tk.BOTH, expand=True)7980 def setup_notebook(self):81 82 self.note = ttk.Notebook(self)83 self.main_tab = Frame(self.note)84 self.comments_tab = Frame(self.note)85 86 self.note.add(self.main_tab, text = "Main")87 self.note.add(self.comments_tab, text = "Comments")88 89 #self.note.grid(row=1,column=0,sticky='NSEW')90 self.note.pack(fill=tk.BOTH, expand=True)91 # ####### COMMENTS TEXT ######################################92 self.comment_text = tk.Text(self.comments_tab, width = 110, height = 50, state='disabled')93 self.comment_text.grid(row=1, column=0, columnspan = 8, sticky='NW',padx=5, pady=5, ipadx=2, ipady=5)9495 def setup_label_frames(self):96 97 self.main_frame = LabelFrame(self.main_scroll_frame.inner,text="Emergency Equipment Details:")98 self.main_frame.grid(row=2, column=0, columnspan = 16, rowspan = 2,sticky='NW',padx=5, pady=5, ipadx=2, ipady=5)99100 self.attach_frame = LabelFrame(self.main_scroll_frame.inner,text="Attaching Hardware:")101 self.attach_frame.grid(row=4, column=0, columnspan = 16, rowspan = 2,sticky='NW',padx=5, pady=5, ipadx=2, ipady=5)102103 def setup_labels(self):104 self.part_no_label = gui_styles_tk.create_label(self.main_frame,'')105 self.part_no_label.grid(row = 2, column = 0,pady=2,padx=2, sticky="nsew")106107 self.description_label = gui_styles_tk.create_label(self.main_frame,'')108 self.description_label.grid(row = 2, column = 1, columnspan=5,pady=2,padx=2, sticky="nsew")109 110 self.manu_label = gui_styles_tk.create_label(self.main_frame,'')111 self.manu_label.grid(row = 3, column = 0,pady=2,padx=2, sticky="nsew")112 #113 self.type_label = gui_styles_tk.create_label(self.main_frame,'')114 self.type_label.grid(row = 3, column = 1,pady=2,padx=2, sticky="nsew")115116 self.weight_label = gui_styles_tk.create_label(self.main_frame,'')117 self.weight_label.grid(row = 3, column = 2,pady=2,padx=2, sticky="nsew")118119 self.aircraft_label = gui_styles_tk.create_label(self.main_frame,'')120 self.aircraft_label.grid(row = 3, column = 3,pady=2,padx=2, sticky="nsew")121122 def setup_treeviews(self):123 self.parts_tree = ttk.Treeview(self.attach_frame, selectmode="extended",columns=("A","B",'C'),height = 15)124 #self.monument_tree.grid(row=1,column=0, columnspan= 6,sticky="nsew")125 self.parts_tree.heading("#0", text="#")126 self.parts_tree.column("#0",minwidth=0,width=60, stretch='NO')127 self.parts_tree.heading("A", text="Type") 128 self.parts_tree.column("A",minwidth=0,width=200, stretch='NO') 129 self.parts_tree.heading("B", text="Part Number") 130 self.parts_tree.column("B",minwidth=0,width=250, stretch='NO')131 self.parts_tree.heading("C", text="Qty") 132 self.parts_tree.column("C",minwidth=0,width=150, stretch='NO') 133 134 self.parts_tree.grid(row = 2, column = 0, columnspan = 8, sticky = 'NSEW')135136 self.parts_tree.bind("<Double-1>", lambda event: self.parts_double_click(event))137138 def setup_buttons(self):139140 self.edit_btn = Button(self.main_scroll_frame.inner, text = 'Edit', image = self.mainapp.edit_icon2, compound = LEFT, width = 30, command= lambda: self.edit())141 self.edit_btn.grid(row=1, column=0, columnspan = 1, sticky='W',padx=5, pady=2, ipadx=2, ipady=2)142143 self.add_attach_btn = Button(self.attach_frame, text='Add', image = self.mainapp.add_icon2, compound = LEFT, command= lambda mode='new': self.add_attachment(mode))144 self.add_attach_btn.grid(row = 1, column = 0, columnspan = 1, sticky = 'NSEW', pady=2)145146 self.del_attach_btn = Button(self.attach_frame, text='Delete', image = self.mainapp.del_icon2, compound = LEFT, command= lambda mode='new': self.del_attachment())147 self.del_attach_btn.grid(row = 1, column = 1, columnspan = 1, sticky = 'NSEW', pady=2)148149 self.edit_comment_button=Button(self.comments_tab,text='Edit', image = self.mainapp.edit_icon2, compound = LEFT,150 command= lambda self=self :comment_box.edit_comments(self))151 self.edit_comment_button.grid(row=0,column=0, pady=5,sticky="nsew", ipadx=2, ipady=2)152153154 def update_label_text(self):155 self.top_label.config(text=f' Emergency Equipment: {self.backend.title}')156 self.part_no_label.config(text=f' Part Number: {self.backend.title}')157 self.manu_label.config(text=f' Manufacturer: {self.backend.manufacturer}')158 self.description_label.config(text=f' Description: {self.backend.description}')159 self.type_label.config(text=f' Type: {self.backend.equipment_type}')160 self.weight_label.config(text=f' Weight (lbs): {self.backend.weight}')161 self.aircraft_label.config(text=f' Aircraft: {self.backend.aircraft_type}')162163164 def update_component(self, window, type, redraw = True):165166 if type != 'new':167 orig_title = self.backend.title168 orig_weight = self.backend.weight169 used, eels, eel_comparisons = check_ee_used(self)170 else:171 used = False172173 self.backend.update_component(window, type)174 self.update_label_text()175 self.update_parts_tree()176177 if self.treeview_iid:178 self.mainapp.main_treeview.item(self.treeview_iid, text = self.backend.title)179 components_tk.component_renamed(self)180181182 if used:183184 if orig_title != self.backend.title or orig_weight != self.backend:185 for e in eels:186 e = self.mainapp.frames[e]187 for loc in e.backend.layout.keys():188 for idx, p in enumerate(e.backend.layout[loc]):189 if p[1] == orig_title:190 191 e.backend.layout[loc][idx][1] = self.backend.title192193 e.update_component(e.backend, 'ohsc')194195 #update tables in eel comparisons196 for e in eel_comparisons:197 e = self.mainapp.frames[e]198 for loc in e.backend.layout.keys():199 for idx, p in enumerate(e.backend.layout[loc]):200 if p[1] == orig_title:201 202 e.backend.layout[loc][idx][1] = self.backend.title203204 for idx, p in enumerate(e.backend.instructions):205 #parse part from instruction206 part = p[1].split('(')[0]207208 instruc = f"({p[1].split('(')[1]}"209210 if part[0:9] == 'Install x' or part[0:10] == 'Relocate x':211212 if part[0:9] == 'Install x':213 action = part[:9]214 part = part[9:]215 elif part[0:10] == 'Relocate x':216 action = part[:10]217 part = part[10:] 218219 qty = part.split()[0]220221 part = part[len(qty):].strip()222 print(part)223 if orig_title == part:224 e.backend.instructions[idx][1] = f'{action}{qty} {self.backend.title} {instruc}'225226 else: #remains installed in227228 qty = part.split()[0]229 part = part[len(qty):].strip()230231 if orig_title == part:232 e.backend.instructions[idx][1] = f'{qty} {self.backend.title} {instruc}' 233234235 e.update_component(e.backend, 'ohsc')236 self.mainapp.update_titlebar('edit')237 def update_parts_tree(self):238239 treeview_functions.write_data_to_treeview(self.parts_tree, 'replace', self.backend.attaching_hardware)240241 def edit(self):242243 self.w = Edit_Emergency_Equip_Window_Tk(self.mainapp, self.master, 'edit', self)244 self.master.wait_window(self.w.top) 245 246 if self.w.button == 'ok':247 self.update_component(self.w, 'edit')248249250 def add_attachment(self, mode):251252 if mode == 'edit':253 index, parts_data = treeview_functions.get_current_selection(self.parts_tree)254 else:255 index = None256 parts_data = None257258 self.w=Double_Click_Part_Window_Tk(self, self.mainapp, self.master, parts_data, index, mode)259 self.master.wait_window(self.w.top)260261 if self.w.button == 'ok':262263 self.update_component(self.w, 'edit', False)264265 def del_attachment(self):266267 save_dict = copy.deepcopy(self.backend.gen_save_dict())268 w = file_menu.Load('Emergency Equipment', save_dict)269 #print(w.attaching_hardware)270 index, data = treeview_functions.get_current_selection(self.parts_tree)271 w.attaching_hardware.pop(index)272 #print(w.attaching_hardware)273 #print(self.backend.attaching_hardware)274 275 self.update_component(w, 'edit', False)276277 del(w)278279 def parts_double_click(self, event):280 index, data = treeview_functions.get_current_selection(self.parts_tree)281282 self.w=Double_Click_Part_Window_Tk(self, self.mainapp, self.master, data, index, 'edit') #lazy nones, not used283 self.master.wait_window(self.w.top)284285 if self.w.button == 'ok':286 save_dict = copy.deepcopy(self.backend.gen_save_dict())287 w = file_menu.Load('Emergency Equipment', save_dict) 288 w.attaching_hardware[index] = [index+1, self.w.attach_type, self.w.attach_part_no, self.w.attach_qty]289290 self.update_component(w, 'edit', False)291292 del(w)293class Edit_Emergency_Equip_Window_Tk(object):294 def __init__(self, mainapp, master, mode, parent_ee):295 #self.drawing_dictionary = drawing_dictionary296 top=self.top=Toplevel(master)297 top.grab_set()298 self.mainapp = mainapp299 self.mode = mode300 self.parent_ee = parent_ee301302 ee_bknd.setup_variables(self)303 304 if self.mode == 'edit':305 self.orig_title = parent_ee.backend.title306 ee_bknd.update_variables(self, self.parent_ee.backend)307 else:308 self.orig_title = None309 310 self.data_checks = {}311 312 self.setup_label_frames()313 self.setup_widgets()314 315 def setup_label_frames(self):316 317 self.main_frame = LabelFrame(self.top,text="Aircraft Details:")318 self.main_frame.grid(row=2, column=0, columnspan = 8, rowspan = 2,sticky='NW',padx=5, pady=5, ipadx=2, ipady=5)319 320 def setup_widgets(self):321 322 labels = ['Part Number:', 'Description:', 'Equipment Type:', 'Aircraft Type:', 'Weight (lbs):', 'Manufacturer:']323 row = 1324 gui_styles_tk.create_multiple_labels(self.main_frame, labels, row, 2, 20, 2, 2) 325 326 self.title_entry=Entry(self.main_frame, width=20) 327 self.title_entry.grid(row=1,column=3,padx=2, pady=2,sticky = 'NSEW')328 self.data_checks['Title'] = ['title', self.title_entry, self.orig_title]329 if self.mode == 'edit':330 self.title_entry.insert(0, self.parent_ee.backend.title)331 332 self.description_entry=Entry(self.main_frame, width=50) 333 self.description_entry.grid(row=2,column=3,padx=2, pady=2,sticky = 'NSEW')334 if self.mode == 'edit':335 self.description_entry.insert(0, self.parent_ee.backend.description)336 337 self.equip_type_combo= ttk.Combobox(self.main_frame, values=self.available_equipment)338 self.equip_type_combo.grid(row=3,column=3,padx=2, pady=2,sticky = 'NSEW')339 if self.mode == 'edit':340 self.equip_type_combo.set(self.parent_ee.backend.equipment_type)341 342 self.ac_combo= ttk.Combobox(self.main_frame, values=['A320 Family'], state='disabled')343 self.ac_combo.grid(row=4,column=3,padx=2, pady=2,sticky = 'NSEW')344 self.ac_combo.set('A320 Family')345346 self.weight_entry = Entry(self.main_frame, width=50)347 self.weight_entry.grid(row=5, column=3,padx=2, pady=2,sticky = 'NSEW')348 self.data_checks['Weight'] = ['entry', self.weight_entry, 'float greater equal zero', 'Weight']349 if self.mode == 'edit':350 self.weight_entry.insert(0, self.parent_ee.backend.weight)351352 self.manu_entry = Entry(self.main_frame, width=50)353 self.manu_entry.grid(row=6, column=3,padx=2, pady=2,sticky = 'NSEW')354 if self.mode == 'edit':355 self.manu_entry.insert(0, self.parent_ee.backend.manufacturer)356357 # ok button358 self.ok_button=Button(self.top,text='OK', command= lambda button = 'ok': self.cleanup(button))359 self.ok_button.grid(row=8,column=3, padx=5, pady=5,sticky="ne")360361 # cancel button362 self.b=Button(self.top,text='Cancel', command= lambda button = 'cancel': self.cleanup(button))363 self.b.grid(row=8,column=4, padx=5, pady=5,sticky="nw")364365 self.button = 'cancel'366 367 def cleanup(self,button):368 369 if button == 'ok':370 371 data_good, msg = data_input_checks_tk.check_data_input(self.data_checks, self.mainapp)372373 if data_good:374 self.title = self.title_entry.get()375 self.aircraft_type = self.ac_combo.get()376 self.description = self.description_entry.get()377 self.equipment_type = self.equip_type_combo.get()378 self.manufacturer = self.manu_entry.get()379 self.weight = self.weight_entry.get()380 self.button = 'ok'381 self.top.destroy()382 else:383 tkinter.messagebox.showerror(master=self.top, title='Error', message=msg)384 else:385 self.top.destroy()386 387 388class Double_Click_Part_Window_Tk(object): 389 def __init__(self, parent_ee, mainapp, master, parts_data, index, mode):390 top=self.top=Toplevel(master)391 top.grab_set()392 393 self.mainapp = mainapp394 self.parent_ee = parent_ee395 self.parts_data = copy.deepcopy(parts_data)396 self.index = index397 self.mode = mode398 399 self.data_checks = {}400 ee_bknd.setup_variables(self)401 ee_bknd.update_variables(self, self.parent_ee.backend)402 403 self.setup_label_frames()404 self.setup_widgets()405 406 if self.mode == 'edit':407408 self.type_combo.set(parts_data[1])409 self.pn_entry.insert(0, parts_data[2])410 self.qty_entry.insert(0, parts_data[3])411412 self.button = 'cancel'413 def setup_label_frames(self):414 415 self.options_frame = LabelFrame(self.top,text="Options:")416 self.options_frame.grid(row=2, column=0, columnspan = 4, rowspan = 4,sticky='NW',padx=5, pady=5, ipadx=2, ipady=5)417418 def setup_widgets(self):419 420 labels = ['Type:', 'Part Number:', 'Qty:']421 row = 2422 gui_styles_tk.create_multiple_labels(self.options_frame, labels, row, 2, 20, 2, 2) 423424 self.type_combo= ttk.Combobox(self.options_frame, values=['Bracket', 'Screw', 'Washer'])425 self.type_combo.grid(row=2,column=3,padx=2, pady=2,sticky = 'NSEW')426427 self.pn_entry=Entry(self.options_frame, width=20) 428 self.pn_entry.grid(row=3,column=3,padx=2, pady=2,sticky = 'NSEW')429430 self.qty_entry=Entry(self.options_frame, width=20) 431 self.qty_entry.grid(row=4,column=3,padx=2, pady=2,sticky = 'NSEW')432 self.data_checks['Qty'] = ['entry', self.qty_entry, 'int positive', 'Qty']433434 # ok button435 self.ok_button=Button(self.top,text='OK', command= lambda button = 'ok': self.cleanup(button))436 self.ok_button.grid(row=8,column=1, padx=5, pady=5,sticky="ne")437438 # cancel button439 self.b=Button(self.top,text='Cancel', command= lambda button = 'cancel': self.cleanup(button))440 self.b.grid(row=8,column=2, padx=5, pady=5,sticky="nw")441 442 def cleanup(self,button):443 444 self.button = button445 if button == 'ok':446447 data_good, msg = data_input_checks_tk.check_data_input(self.data_checks, self.mainapp)448449 if data_good:450451 #check part number is entered452 if self.pn_entry.get() == '':453 tkinter.messagebox.showerror(master=self.top, title='Error', message='Part Number Must be Entered')454 else:455 self.attach_type = self.type_combo.get()456 self.attach_part_no = self.pn_entry.get()457 self.attach_qty = self.qty_entry.get()458459 self.attaching_hardware.append([len(self.attaching_hardware)+1, self.attach_type, self.attach_part_no, self.attach_qty])460 self.top.destroy()461462 else:463 tkinter.messagebox.showerror(master=self.top, title='Error', message=msg)464465 else: ...

Full Screen

Full Screen

test_frames.py

Source:test_frames.py Github

copy

Full Screen

...19 window_handle = await main_frame.evaluate_handle("window")20 assert window_handle21async def test_frame_element(page, server, utils):22 await page.goto(server.EMPTY_PAGE)23 frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)24 await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)25 frame3 = await utils.attach_frame(page, "frame3", server.EMPTY_PAGE)26 frame1handle1 = await page.query_selector("#frame1")27 frame1handle2 = await frame1.frame_element()28 frame3handle1 = await page.query_selector("#frame3")29 frame3handle2 = await frame3.frame_element()30 assert await frame1handle1.evaluate("(a, b) => a === b", frame1handle2)31 assert await frame3handle1.evaluate("(a, b) => a === b", frame3handle2)32 assert await frame1handle1.evaluate("(a, b) => a === b", frame3handle1) is False33async def test_frame_element_with_content_frame(page, server, utils):34 await page.goto(server.EMPTY_PAGE)35 frame = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)36 handle = await frame.frame_element()37 content_frame = await handle.content_frame()38 assert content_frame == frame39async def test_frame_element_throw_when_detached(page, server, utils):40 await page.goto(server.EMPTY_PAGE)41 frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)42 await page.eval_on_selector("#frame1", "e => e.remove()")43 error = None44 try:45 await frame1.frame_element()46 except Error as e:47 error = e48 assert error.message == "Frame has been detached."49async def test_evaluate_throw_for_detached_frames(page, server, utils):50 frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)51 await utils.detach_frame(page, "frame1")52 error = None53 try:54 await frame1.evaluate("7 * 8")55 except Error as e:56 error = e57 assert "Execution Context is not available in detached frame" in error.message58async def test_evaluate_isolated_between_frames(page, server, utils):59 await page.goto(server.EMPTY_PAGE)60 await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)61 assert len(page.frames) == 262 [frame1, frame2] = page.frames63 assert frame1 != frame264 await asyncio.gather(65 frame1.evaluate("window.a = 1"), frame2.evaluate("window.a = 2")66 )67 [a1, a2] = await asyncio.gather(68 frame1.evaluate("window.a"), frame2.evaluate("window.a")69 )70 assert a1 == 171 assert a2 == 272async def test_should_handle_nested_frames(page, server, utils):73 await page.goto(server.PREFIX + "/frames/nested-frames.html")74 assert utils.dump_frames(page.main_frame) == [75 "http://localhost:<PORT>/frames/nested-frames.html",76 " http://localhost:<PORT>/frames/frame.html (aframe)",77 " http://localhost:<PORT>/frames/two-frames.html (2frames)",78 " http://localhost:<PORT>/frames/frame.html (dos)",79 " http://localhost:<PORT>/frames/frame.html (uno)",80 ]81async def test_should_send_events_when_frames_are_manipulated_dynamically(82 page, server, utils83):84 await page.goto(server.EMPTY_PAGE)85 # validate frameattached events86 attached_frames = []87 page.on("frameattached", lambda frame: attached_frames.append(frame))88 await utils.attach_frame(page, "frame1", "./assets/frame.html")89 assert len(attached_frames) == 190 assert "/assets/frame.html" in attached_frames[0].url91 # validate framenavigated events92 navigated_frames = []93 page.on("framenavigated", lambda frame: navigated_frames.append(frame))94 await page.evaluate(95 """() => {96 frame = document.getElementById('frame1')97 frame.src = './empty.html'98 return new Promise(x => frame.onload = x)99 }"""100 )101 assert len(navigated_frames) == 1102 assert navigated_frames[0].url == server.EMPTY_PAGE103 # validate framedetached events104 detached_frames = list()105 page.on("framedetached", lambda frame: detached_frames.append(frame))106 await utils.detach_frame(page, "frame1")107 assert len(detached_frames) == 1108 assert detached_frames[0].is_detached()109async def test_framenavigated_when_navigating_on_anchor_urls(page, server):110 await page.goto(server.EMPTY_PAGE)111 async with page.expect_event("framenavigated"):112 await page.goto(server.EMPTY_PAGE + "#foo")113 assert page.url == server.EMPTY_PAGE + "#foo"114async def test_persist_main_frame_on_cross_process_navigation(page, server):115 await page.goto(server.EMPTY_PAGE)116 main_frame = page.main_frame117 await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")118 assert page.main_frame == main_frame119async def test_should_not_send_attach_detach_events_for_main_frame(page, server):120 has_events = list()121 page.on("frameattached", lambda frame: has_events.append(True))122 page.on("framedetached", lambda frame: has_events.append(True))123 await page.goto(server.EMPTY_PAGE)124 assert has_events == []125async def test_detach_child_frames_on_navigation(page, server):126 attached_frames = []127 detached_frames = []128 navigated_frames = []129 page.on("frameattached", lambda frame: attached_frames.append(frame))130 page.on("framedetached", lambda frame: detached_frames.append(frame))131 page.on("framenavigated", lambda frame: navigated_frames.append(frame))132 await page.goto(server.PREFIX + "/frames/nested-frames.html")133 assert len(attached_frames) == 4134 assert len(detached_frames) == 0135 assert len(navigated_frames) == 5136 attached_frames = []137 detached_frames = []138 navigated_frames = []139 await page.goto(server.EMPTY_PAGE)140 assert len(attached_frames) == 0141 assert len(detached_frames) == 4142 assert len(navigated_frames) == 1143async def test_framesets(page, server):144 attached_frames = []145 detached_frames = []146 navigated_frames = []147 page.on("frameattached", lambda frame: attached_frames.append(frame))148 page.on("framedetached", lambda frame: detached_frames.append(frame))149 page.on("framenavigated", lambda frame: navigated_frames.append(frame))150 await page.goto(server.PREFIX + "/frames/frameset.html")151 assert len(attached_frames) == 4152 assert len(detached_frames) == 0153 assert len(navigated_frames) == 5154 attached_frames = []155 detached_frames = []156 navigated_frames = []157 await page.goto(server.EMPTY_PAGE)158 assert len(attached_frames) == 0159 assert len(detached_frames) == 4160 assert len(navigated_frames) == 1161async def test_frame_from_inside_shadow_dom(page, server):162 await page.goto(server.PREFIX + "/shadow.html")163 await page.evaluate(164 """async url => {165 frame = document.createElement('iframe');166 frame.src = url;167 document.body.shadowRoot.appendChild(frame);168 await new Promise(x => frame.onload = x);169 }""",170 server.EMPTY_PAGE,171 )172 assert len(page.frames) == 2173 assert page.frames[1].url == server.EMPTY_PAGE174async def test_frame_name(page, server, utils):175 await utils.attach_frame(page, "theFrameId", server.EMPTY_PAGE)176 await page.evaluate(177 """url => {178 frame = document.createElement('iframe');179 frame.name = 'theFrameName';180 frame.src = url;181 document.body.appendChild(frame);182 return new Promise(x => frame.onload = x);183 }""",184 server.EMPTY_PAGE,185 )186 assert page.frames[0].name == ""187 assert page.frames[1].name == "theFrameId"188 assert page.frames[2].name == "theFrameName"189async def test_frame_parent(page, server, utils):190 await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)191 await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)192 assert page.frames[0].parent_frame is None193 assert page.frames[1].parent_frame == page.main_frame194 assert page.frames[2].parent_frame == page.main_frame195async def test_should_report_different_frame_instance_when_frame_re_attaches(196 page, server, utils197):198 frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)199 await page.evaluate(200 """() => {201 window.frame = document.querySelector('#frame1')202 window.frame.remove()203 }"""204 )205 assert frame1.is_detached()206 async with page.expect_event("frameattached") as frame2_info:207 await page.evaluate("() => document.body.appendChild(window.frame)")208 frame2 = await frame2_info.value209 assert frame2.is_detached() is False...

Full Screen

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Python automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful