def test_no_subscriptions(self): adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) dispatcher = AsyncDispatcher(FakeConnection(adapter), adapter) frame1 = Frame( Command.SUBSCRIBE, { Headers.DESTINATION: 'jms.queue.events', 'ack': 'auto', 'id': 'ad052acb-a934-4e10-8ec3-00c7417ef8d1' }) frame2 = Frame( Command.SUBSCRIBE, { Headers.DESTINATION: 'jms.queue.events', 'ack': 'auto', 'id': 'ad052acb-a934-4e10-8ec3-00c7417ef8d2' }) destinations = defaultdict(list) adapter = StompAdapterImpl(Reactor(), destinations, {}) adapter.handle_frame(dispatcher, frame1) adapter.handle_frame(dispatcher, frame2) adapter.handle_timeout(dispatcher) self.assertEqual(len(adapter._sub_ids), 0) self.assertEqual(len(destinations), 0)
def test_parsing_frame_with_headers(headers): parser = Parser() frame = Frame(Command.CONNECT, headers) parser.parse(frame.encode()) parsed_frame = parser.pop_frame() assert parsed_frame.command == Command.CONNECT assert parsed_frame.headers == headers assert parsed_frame.body == b""
def test_frame_should_have_a_copy_method(): original = Frame(Command.SEND, {"abc": "def"}, "zorro") original_encoded = original.encode() copy = original.copy() copy.command = Command.CONNECT copy.body = "batman" copy.headers["geh"] = "xyz" assert original.encode() == original_encoded
def test_parsing_frame_with_headers_and_body(body): parser = Parser() frame = Frame(Command.CONNECT, {"abc": "def"}, body) parser.parse(frame.encode()) parsed_frame = parser.pop_frame() assert parsed_frame.command == Command.CONNECT assert "abc" in parsed_frame.headers assert parsed_frame.headers["abc"] == "def" assert "content-length" in parsed_frame.headers assert int(parsed_frame.headers["content-length"]) == len(body) assert parsed_frame.body == body
def test_parser_should_accept_frames_with_crlf_eols(): parser = Parser() frame = Frame(Command.CONNECT, {"abc": "def"}, b"zorro") encoded_frame = frame.encode().replace(b"\n", b"\r\n") parser.parse(encoded_frame) parsed_frame = parser.pop_frame() assert parsed_frame.command == Command.CONNECT assert "abc" in parsed_frame.headers assert parsed_frame.headers["abc"] == "def" assert "content-length" in parsed_frame.headers assert int(parsed_frame.headers["content-length"]) == 5 assert parsed_frame.body == b"zorro"
def test_parsing_multiple_frames_with_headers_and_body(): parser = Parser() frame = Frame(Command.CONNECT, {"abc": "def"}, b"zorro") parser.parse(frame.encode() * 2) for _ in range(2): parsed_frame = parser.pop_frame() assert parsed_frame.command == Command.CONNECT assert "abc" in parsed_frame.headers assert parsed_frame.headers["abc"] == "def" assert "content-length" in parsed_frame.headers assert int(parsed_frame.headers["content-length"]) == len(b"zorro") assert parsed_frame.body == b"zorro"
def subscribe(self, destination, ack=None, sub_id=None, message_handler=None): if ack is None: ack = AckMode.AUTO if message_handler is None: message_handler = lambda sub, frame: None if sub_id is None: sub_id = str(uuid4()) self.queue_frame( Frame(Command.SUBSCRIBE, { "destination": destination, "ack": ack, "id": sub_id })) sub = Subscription(self, destination, sub_id, ack, message_handler) self._subscriptions[sub_id] = sub return sub
def test_send_internal_and_broker(self): frame = Frame(command=Command.SEND, headers={Headers.DESTINATION: 'jms.topic.vdsm_requests', Headers.REPLY_TO: 'jms.topic.vdsm_responses', Headers.CONTENT_LENGTH: '103'}, body=('{"jsonrpc":"2.0","method":"Host.getAllVmStats",' '"params":{},"id":"e8a936a6-d886-4cfa-97b9-2d54209' '053ff"}' ) ) ids = {} subscription = FakeSubscription('jms.topic.vdsm_requests', 'e8a936a6-d886-4cfa-97b9-2d54209053ff') client = FakeAsyncClient() subscription.set_client(client) destinations = defaultdict(list) destinations['jms.topic.vdsm_requests'].append(subscription) adapter = StompAdapterImpl(Reactor(), destinations, ids) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) data = adapter.pop_message() self.assertIsNot(data, None) request = JsonRpcRequest.decode(data) self.assertEqual(request.method, 'Host.getAllVmStats') self.assertEqual(len(ids), 1) resp_frame = client.pop_message() self.assertIsNot(resp_frame, None) self.assertEqual(resp_frame.command, Command.MESSAGE) self.assertEqual(resp_frame.body, data)
def test_handle_read(self): frame_handler = FakeFrameHandler() headers = {Headers.CONTENT_LENGTH: '78', Headers.DESTINATION: 'jms.topic.vdsm_responses', Headers.CONTENT_TYPE: 'application/json', Headers.SUBSCRIPTION: 'ad052acb-a934-4e10-8ec3-00c7417ef8d'} body = ('{"jsonrpc": "2.0", "id": "e8a936a6-d886-4cfa-97b9-2d54209053f' 'f", "result": []}') frame = Frame(command=Command.MESSAGE, headers=headers, body=body) dispatcher = AsyncDispatcher(FakeConnection(), frame_handler) dispatcher.handle_read(FakeAsyncDispatcher(None, data=frame.encode())) self.assertTrue(frame_handler.has_outgoing_messages) recv_frame = frame_handler.pop_message() self.assertEqual(Command.MESSAGE, recv_frame.command) self.assertEqual(body, recv_frame.body)
def unsubscribe(self, sub): try: del self._subscriptions[sub.id] except KeyError: self.log.warning('No subscription with %s id', sub.id) else: self.queue_frame(Frame(Command.UNSUBSCRIBE, {"id": sub.id}))
def test_handle_read(self): frame_handler = TestFrameHandler() headers = {Headers.CONTENT_LENGTH: '78', Headers.DESTINATION: 'jms.topic.vdsm_responses', Headers.CONTENT_TYPE: 'application/json', Headers.SUBSCRIPTION: 'ad052acb-a934-4e10-8ec3-00c7417ef8d'} body = ('{"jsonrpc": "2.0", "id": "e8a936a6-d886-4cfa-97b9-2d54209053f' 'f", "result": []}') frame = Frame(command=Command.MESSAGE, headers=headers, body=body) dispatcher = AsyncDispatcher(TestConnection(), frame_handler) dispatcher.handle_read(TestDispatcher(frame.encode())) self.assertTrue(frame_handler.has_outgoing_messages) recv_frame = frame_handler.pop_message() self.assertEquals(Command.MESSAGE, recv_frame.command) self.assertEquals(body, recv_frame.body)
def test_receive_connected(self): client = AsyncClient() frame = Frame(Command.CONNECTED, {'version': '1.2', Headers.HEARTBEAT: '8000,0'}) client.handle_frame(None, frame) self.assertTrue(client.connected)
def test_parsing_simple_frame(command): parser = Parser() parser.parse(Frame(command).encode()) parsed_frame = parser.pop_frame() assert parsed_frame.command == command assert parsed_frame.headers == {} assert parsed_frame.body == b""
def test_send_no_destination(self): frame = Frame(Command.SEND, {Headers.DESTINATION: 'jms.topic.unknown'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, 'Subscription not available')
def test_unsuported_version(self): frame = Frame(Command.CONNECT, {Headers.ACCEPT_VERSION: '1.0'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, 'Version unsupported')
def test_no_id(self): frame = Frame(Command.UNSUBSCRIBE) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, b'Missing id header')
def test_no_headers(self): frame = Frame(Command.CONNECT) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, b'Version unsupported')
def _process_disconnect(self, frame, dispatcher): r_id = frame.headers[Headers.RECEIPT] if not r_id: self.log.debug("No receipt id for disconnect frame") # it is not mandatory to send receipt frame return headers = {Headers.RECEIPT_ID: r_id} self.queue_frame(Frame(Command.RECEIPT, headers))
def test_handle_read(): frame_handler = FakeFrameHandler() headers = {Headers.CONTENT_LENGTH: '78', Headers.DESTINATION: 'jms.topic.vdsm_responses', Headers.CONTENT_TYPE: 'application/json', Headers.SUBSCRIPTION: 'ad052acb-a934-4e10-8ec3-00c7417ef8d'} body = json.dumps({ "jsonrpc": "2.0", "id": "e8a936a6-d886-4cfa-97b9-2d54209053ff", "result": [], }).encode("utf-8") frame = Frame(command=Command.MESSAGE, headers=headers, body=body) dispatcher = AsyncDispatcher(FakeConnection(), frame_handler) dispatcher.handle_read(FakeAsyncDispatcher(None, data=frame.encode())) assert frame_handler.has_outgoing_messages recv_frame = frame_handler.pop_message() assert Command.MESSAGE == recv_frame.command assert body == recv_frame.body
def test_no_heartbeat(self): frame = Frame(Command.CONNECT, {Headers.ACCEPT_VERSION: '1.2'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.CONNECTED) self.assertEqual(resp_frame.headers['version'], '1.2') self.assertEqual(resp_frame.headers[Headers.HEARTBEAT], '0,0')
def test_parser_should_skip_heartbeat_frames(): parser = Parser() heartbeats = b"\n\n\n\n\n" encoded_frame = Frame(Command.CONNECT).encode() parser.parse(heartbeats + encoded_frame) assert parser.pending == 1 decoded_frame = parser.pop_frame() assert decoded_frame is not None assert decoded_frame.command == Command.CONNECT
def test_connect(self): frame = Frame(Command.CONNECT, {Headers.ACCEPT_VERSION: '1.2', Headers.HEARTEBEAT: '0,8000'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(TestDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEquals(resp_frame.command, Command.CONNECTED) self.assertEquals(resp_frame.headers['version'], '1.2') self.assertEquals(resp_frame.headers[Headers.HEARTEBEAT], '8000,0')
def test_no_id(self): frame = Frame(Command.SUBSCRIBE, {'ack': 'auto', Headers.DESTINATION: 'jms.queue.events'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, b'Missing destination or subscription id header')
def test_no_destination(self): frame = Frame(Command.SUBSCRIBE, {'ack': 'auto', 'id': 'ad052acb-a934-4e10-8ec3-00c7417ef8d1'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.ERROR) self.assertEqual(resp_frame.body, b'Missing destination or subscription id header')
def test_incoming_heartbeat(self): frame = Frame(Command.CONNECT, {Headers.ACCEPT_VERSION: '1.2', Headers.HEARTBEAT: '6000,5000'}) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) dispatcher = AsyncDispatcher(FakeConnection(adapter), adapter) adapter.handle_frame(dispatcher, frame) resp_frame = adapter.pop_message() self.assertEqual(resp_frame.command, Command.CONNECTED) self.assertEqual(resp_frame.headers['version'], '1.2') self.assertEqual(resp_frame.headers[Headers.HEARTBEAT], '5000,6000') self.assertEqual(dispatcher._incoming_heartbeat_in_milis, 6000) self.assertEqual(dispatcher._outgoing_heartbeat_in_milis, 5000)
def test_unsubscribe(self): frame = Frame(Command.UNSUBSCRIBE, {'id': 'ad052acb-a934-4e10-8ec3-00c7417ef8d1'}) subscription = FakeSubscription('jms.queue.events', 'ad052acb-a934-4e10-8ec3-00c7417ef8d1') destinations = defaultdict(list) destinations['jms.queue.events'].append(subscription) adapter = StompAdapterImpl(Reactor(), destinations, {}) adapter._sub_ids['ad052acb-a934-4e10-8ec3-00c7417ef8d1'] = subscription adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) self.assertEqual(len(adapter._sub_ids), 0) self.assertEqual(len(destinations), 0)
def test_subscribe(self): frame = Frame(Command.SUBSCRIBE, {Headers.DESTINATION: 'jms.queue.events', 'ack': 'auto', 'id': 'ad052acb-a934-4e10-8ec3-00c7417ef8d1'}) destinations = defaultdict(list) adapter = StompAdapterImpl(Reactor(), destinations, {}) adapter.handle_frame(FakeAsyncDispatcher(adapter), frame) subscription = destinations['jms.queue.events'][0] self.assertEqual(subscription.id, 'ad052acb-a934-4e10-8ec3-00c7417ef8d1') self.assertEqual(subscription.destination, 'jms.queue.events')
def handle_connect(self): self._outbox.clear() outgoing_heartbeat = \ int(self._outgoing_heartbeat * (1 + GRACE_PERIOD_FACTOR)) incoming_heartbeat = \ int(self._incoming_heartbeat * (1 - GRACE_PERIOD_FACTOR)) self._outbox.appendleft( Frame( Command.CONNECT, { Headers.ACCEPT_VERSION: "1.2", Headers.HEARTBEAT: "%d,%d" % (outgoing_heartbeat, incoming_heartbeat), })) self.restore_subscriptions()
def test_handle_write(self): headers = {Headers.CONTENT_LENGTH: '78', Headers.DESTINATION: 'jms.topic.vdsm_responses', Headers.CONTENT_TYPE: 'application/json', Headers.SUBSCRIPTION: 'ad052acb-a934-4e10-8ec3-00c7417ef8d'} body = ('{"jsonrpc": "2.0", "id": "e8a936a6-d886-4cfa-97b9-2d54209053f' 'f", "result": []}') frame = Frame(command=Command.MESSAGE, headers=headers, body=body) frame_handler = FakeFrameHandler() frame_handler.handle_frame(None, frame) dispatcher = AsyncDispatcher(FakeConnection(), frame_handler) self.assertTrue(dispatcher.writable(None)) dispatcher.handle_write(FakeAsyncDispatcher('')) self.assertFalse(frame_handler.has_outgoing_messages)
def test_no_flow_header(self): frame = Frame(command=Command.SEND, headers={Headers.DESTINATION: SUBSCRIPTION_ID_REQUEST, Headers.REPLY_TO: 'jms.topic.vdsm_responses', Headers.CONTENT_LENGTH: '103'}, body=('{"jsonrpc":"2.0","method":"Host.getAllVmStats",' '"params":{},"id":"e8a936a6-d886-4cfa-97b9-2d54209' '053ff"}' ) ) adapter = StompAdapterImpl(Reactor(), defaultdict(list), {}) dispatcher = FakeAsyncDispatcher(adapter) adapter.handle_frame(dispatcher, frame) self.assertIsNone(dispatcher.connection.flow_id)
def test_send_broker_parent_topic(self): frame = Frame(command=Command.SEND, headers={Headers.DESTINATION: 'jms.topic.vdsm_requests.getAllVmStats', Headers.REPLY_TO: 'jms.topic.vdsm_responses.getAllVmStats', Headers.CONTENT_LENGTH: '103'}, body=('{"jsonrpc":"2.0","method":"Host.getAllVmStats",' '"params":{},"id":"e8a936a6-d886-4cfa-97b9-2d54209' '053ff"}' ) ) ids = {} subscription = TestSubscription('jms.topic.vdsm_requests', 'e8a936a6-d886-4cfa-97b9-2d54209053ff') client = TestClient() subscription.set_client(client) destinations = defaultdict(list) destinations['jms'].append(subscription) destinations['jms.topic'].append(subscription) destinations['jms.topic.vdsm_requests'].append(subscription) # Topics that should not match destinations['jms.other'].append(subscription) destinations['jms.top'].append(subscription) adapter = StompAdapterImpl(Reactor(), destinations, ids) adapter.handle_frame(TestDispatcher(adapter), frame) data = adapter.pop_message() self.assertIsNot(data, None) request = JsonRpcRequest.decode(data) self.assertEqual(request.method, 'Host.getAllVmStats') self.assertEqual(len(ids), 1) for i in range(3): resp_frame = client.pop_message() self.assertIsNot(resp_frame, None) self.assertEqual(resp_frame.command, Command.MESSAGE) self.assertEqual(resp_frame.body, data) # The last two subscriptions do not match self.assertTrue(client.empty())