def test_subscribe_same_id(self): """ SubACKs have the same packet IDs as the Subscription that it is replying to. Compliance statements MQTT-3.8.4-2 """ sessions = {} class SubHandler(BasicHandler): def process_subscribe(self, event): return succeed([0]) h = SubHandler() r = Clock() t = StringTransport() p = MQTTServerTwistedProtocol(h, r, sessions) cp = MQTTClientParser() p.makeConnection(t) data = (Connect(client_id=u"test123", flags=ConnectFlags(clean_session=True)).serialise() + Subscribe(packet_identifier=1234, topic_requests=[SubscriptionTopicRequest(u"a", 0) ]).serialise()) for x in iterbytes(data): p.dataReceived(x) events = cp.data_received(t.value()) self.assertEqual(len(events), 2) self.assertEqual(events[1].return_codes, [0]) self.assertEqual(events[1].packet_identifier, 1234)
def test_subscribe_always_gets_packet(self): """ Subscriptions always get a ConnACK, even if none of the subscriptions were successful. Compliance statements MQTT-3.8.4-1 """ sessions = {} class SubHandler(BasicHandler): def process_subscribe(self, event): return succeed([128]) h = SubHandler() r = Clock() t = StringTransport() p = MQTTServerTwistedProtocol(h, r, sessions) cp = MQTTClientParser() p.makeConnection(t) data = (Connect(client_id=u"test123", flags=ConnectFlags(clean_session=True)).serialise() + Subscribe(packet_identifier=1234, topic_requests=[SubscriptionTopicRequest(u"a", 0) ]).serialise()) for x in iterbytes(data): p.dataReceived(x) events = cp.data_received(t.value()) self.assertEqual(len(events), 2) self.assertEqual(events[1].return_codes, [128])
def test_self_subscribe(host, port): record = [ Frame(send=True, data=Connect(client_id=u"test_selfsub", flags=ConnectFlags(clean_session=True))), Frame(send=False, data=ConnACK(session_present=False, return_code=0)), Frame(send=True, data=Subscribe( packet_identifier=1234, topic_requests=[SubscriptionTopicRequest(u"foo", 2)])), Frame(send=False, data=SubACK(packet_identifier=1234, return_codes=[2])), Frame(send=True, data=Publish(duplicate=False, qos_level=0, topic_name=u"foo", payload=b"abc", retain=False)), Frame(send=False, data=Publish(duplicate=False, qos_level=0, topic_name=u"foo", payload=b"abc", retain=False)), Frame(send=True, data=Disconnect()), ConnectionLoss(), ] r = SelectReactor() f = ReplayClientFactory(r, record) e = TCP4ClientEndpoint(r, host, port) e.connect(f) r.run() return Result("self_subscribe", f.success, f.reason, f.client_transcript)
def _test_retained(self): """ The MQTT client can set and receive retained messages. """ reactor, router, server_factory, session_factory = build_mqtt_server() client_transport, client_protocol, mqtt_pump = connect_mqtt_server( server_factory) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", flags=ConnectFlags(clean_session=False, username=True, password=True)).serialise()) client_transport.write( Publish(duplicate=False, qos_level=1, retain=True, topic_name=u"com/test/wamp", packet_identifier=123, payload=b'{}').serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, (ConnACK(session_present=False, return_code=0).serialise() + PubACK(packet_identifier=123).serialise())) client_protocol.data = b"" client_transport.write( Subscribe(packet_identifier=1, topic_requests=[ SubscriptionTopicRequest( topic_filter=u"com/test/wamp", max_qos=0) ]).serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, SubACK(packet_identifier=1, return_codes=[0]).serialise()) client_protocol.data = b"" reactor.advance(0.1) mqtt_pump.flush() # This needs to be replaced with the real deal, see https://github.com/crossbario/crossbar/issues/885 self.assertEqual( client_protocol.data, Publish(duplicate=False, qos_level=0, retain=True, topic_name=u"com/test/wamp", payload=json.dumps( {}, sort_keys=True).encode('utf8')).serialise())
def _test_basic_subscribe(self): """ The MQTT client can subscribe to a WAMP topic and get messages. """ reactor, router, server_factory, session_factory = build_mqtt_server() client_transport, client_protocol, mqtt_pump = connect_mqtt_server( server_factory) session, pump = connect_application_session( server_factory, ApplicationSession, component_config=ComponentConfig(realm=u"mqtt")) client_transport.write( Connect(client_id=u"testclient", username=u"test123", password=u"password", flags=ConnectFlags(clean_session=False, username=True, password=True)).serialise()) client_transport.write( Subscribe(packet_identifier=1, topic_requests=[ SubscriptionTopicRequest( topic_filter=u"com/test/wamp", max_qos=0) ]).serialise()) mqtt_pump.flush() self.assertEqual( client_protocol.data, (ConnACK(session_present=False, return_code=0).serialise() + SubACK(packet_identifier=1, return_codes=[0]).serialise())) client_protocol.data = b"" session.publish(u"com.test.wamp", u"bar") pump.flush() reactor.advance(0.1) mqtt_pump.flush() self.assertEqual( client_protocol.data, Publish(duplicate=False, qos_level=0, retain=False, topic_name=u"com/test/wamp", payload=b'{"args":["bar"]}').serialise())
def test_qos1_send_wrong_confirm(host, port): record = [ Frame(send=True, data=Connect(client_id=u"test_wrong_confirm_qos1", flags=ConnectFlags(clean_session=True))), Frame(send=False, data=ConnACK(session_present=False, return_code=0)), Frame(send=True, data=Subscribe( packet_identifier=1234, topic_requests=[SubscriptionTopicRequest(u"foo", 2)])), Frame(send=False, data=SubACK(packet_identifier=1234, return_codes=[2])), Frame(send=True, data=Publish(duplicate=False, qos_level=1, topic_name=u"foo", payload=b"abc", retain=False, packet_identifier=12)), Frame(send=False, data=[ PubACK(packet_identifier=12), Publish(duplicate=False, qos_level=1, topic_name=u"foo", payload=b"abc", retain=False, packet_identifier=1) ]), # We send a pubrel to the packet_id expecting a puback Frame(send=True, data=PubREL(packet_identifier=1)), # ..aaaaand we get a pubcomp back (even though mosquitto warns). Frame(send=False, data=PubCOMP(packet_identifier=1)), Frame(send=True, data=Disconnect()), ConnectionLoss(), ] r = SelectReactor() f = ReplayClientFactory(r, record) e = TCP4ClientEndpoint(r, host, port) e.connect(f) r.run() return Result("qos1_wrong_confirm", f.success, f.reason, f.client_transcript)
def test_exception_in_subscribe_drops_connection(self): """ Transient failures (like an exception from handler.process_subscribe) will cause the connection it happened on to be dropped. Compliance statement MQTT-4.8.0-2 """ sessions = {} class SubHandler(BasicHandler): @inlineCallbacks def process_subscribe(self, event): raise Exception("boom!") h = SubHandler() r = Clock() t = StringTransport() p = MQTTServerTwistedProtocol(h, r, sessions) cp = MQTTClientParser() p.makeConnection(t) data = (Connect(client_id=u"test123", flags=ConnectFlags(clean_session=True)).serialise() + Subscribe(packet_identifier=1234, topic_requests=[SubscriptionTopicRequest(u"a", 0) ]).serialise()) with LogCapturer("trace") as logs: for x in iterbytes(data): p.dataReceived(x) sent_logs = logs.get_category("MQ500") self.assertEqual(len(sent_logs), 1) self.assertEqual(sent_logs[0]["log_level"], LogLevel.critical) self.assertEqual(sent_logs[0]["log_failure"].value.args[0], "boom!") events = cp.data_received(t.value()) self.assertEqual(len(events), 1) self.assertTrue(t.disconnecting) # We got the error, we need to flush it so it doesn't make the test # error self.flushLoggedErrors()