def test_login_sub_pub(self): print(topics,len(topics),len(wildtopics)) connack = aclient.connect(host=host,port=port,cleanstart=True) connack = bclient.connect(host=host,port=port,cleanstart=True) succeeded = True print("Basic test starting") succeeded = True number = len(topics) try: for i in range(number): aclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) time.sleep(.1) time.sleep(10) for i in range(number): aclient.publish(topics[i],b"tset aclient %d qos0"%(i),0) aclient.publish(topics[i],b"tset aclient %d qos1"%(i),1) aclient.publish(topics[i],b"tset aclient %d qos2"%(i),2) time.sleep(.1) time.sleep(10) except: succeeded = False print("Basic test", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def test_shared_subscriptions(self): callback.clear() callback2.clear() shared_sub_topic = '$share/sharename/x' shared_pub_topic = 'x' connack = aclient.connect(host=host, port=port, cleanstart=True) self.assertEqual(connack.reasonCode.getName(), "Success") self.assertEqual(connack.sessionPresent, False) aclient.subscribe([shared_sub_topic, topics[0]], [MQTTV5.SubscribeOptions(2)]*2) # subscribe to will message topic self.waitfor(callback.subscribeds, 1, 3) connack = bclient.connect(host=host, port=port, cleanstart=True) self.assertEqual(connack.reasonCode.getName(), "Success") self.assertEqual(connack.sessionPresent, False) bclient.subscribe([shared_sub_topic, topics[0]], [MQTTV5.SubscribeOptions(2)]*2) # subscribe to will message topic self.waitfor(callback2.subscribeds, 1, 3) callback.clear() callback2.clear() count = 10 for i in range(count): bclient.publish(topics[0], "message "+str(i), 0) j = 0 while len(callback.messages) + len(callback2.messages) < 2*count and j < 20: time.sleep(.1) j += 1 time.sleep(1) self.assertEqual(len(callback.messages), count) self.assertEqual(len(callback2.messages), count) callback.clear() callback2.clear() count = 10 for i in range(count): bclient.publish(shared_pub_topic, "message "+str(i), 0) j = 0 while len(callback.messages) + len(callback2.messages) < count and j < 20: time.sleep(.1) j += 1 time.sleep(1) # Each message should only be received once self.assertEqual(len(callback.messages) + len(callback2.messages), count) aclient.disconnect() bclient.disconnect()
def test_publication_expiry(self): callback.clear() callback2.clear() bclient.connect(host=host, port=port, cleanstart=True) bclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) bclient.disconnect() aclient.connect(host=host, port=port, cleanstart=True) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.MessageExpiryInterval = 1 aclient.publish(topics[0], b"qos 1 - expire", 1, retained=False, properties=publish_properties) aclient.publish(topics[0], b"qos 2 - expire", 2, retained=False, properties=publish_properties) publish_properties.MessageExpiryInterval = 6 aclient.publish(topics[0], b"qos 1 - don't expire", 1, retained=False, properties=publish_properties) aclient.publish(topics[0], b"qos 2 - don't expire", 2, retained=False, properties=publish_properties) time.sleep(3) bclient.connect(host=host, port=port, cleanstart=False) self.waitfor(callback2.messages, 1, 3) time.sleep(1) self.assertEqual(len(callback2.messages), 2, callback2.messages) self.assertTrue(callback2.messages[0][5].MessageExpiryInterval < 6, callback2.messages[0][5].MessageExpiryInterval) self.assertTrue(callback2.messages[1][5].MessageExpiryInterval < 6, callback2.messages[1][5].MessageExpiryInterval) aclient.disconnect()
def test_payload_format(self): callback.clear() aclient.connect(host=host, port=port, cleanstart=True) aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.PayloadFormatIndicator = 1 publish_properties.ContentType = "My name" aclient.publish(topics[0], b"", 0, retained=False, properties=publish_properties) aclient.publish(topics[0], b"", 1, retained=False, properties=publish_properties) aclient.publish(topics[0], b"", 2, retained=False, properties=publish_properties) while len(callback.messages) < 3: time.sleep(.1) aclient.disconnect() self.assertEqual(len(callback.messages), 3, callback.messages) props = callback.messages[0][5] self.assertEqual(props.ContentType, "My name", props.ContentType) self.assertEqual(props.PayloadFormatIndicator, 1, props.PayloadFormatIndicator) props = callback.messages[1][5] self.assertEqual(props.ContentType, "My name", props.ContentType) self.assertEqual(props.PayloadFormatIndicator, 1, props.PayloadFormatIndicator) props = callback.messages[2][5] self.assertEqual(props.ContentType, "My name", props.ContentType) self.assertEqual(props.PayloadFormatIndicator, 1, props.PayloadFormatIndicator) qoss = [callback.messages[i][2] for i in range(3)] self.assertTrue(1 in qoss and 2 in qoss and 0 in qoss, qoss)
def connect(self): logger.info("Bridge: connect: connecting to %s:%d" % (self.host, self.port)) connected = False retry = 2 while not connected: try: self.client.connect(host=self.host, port=self.port, cleanstart=True) connected = True except OSError as e: #try again with a small amount of backoff, could ake this configurable logger.debug( "Bridge: failed to connect to remote end due to an OS Error (%s), retrying...", str(e)) time.sleep(retry) retry *= 2 except MQTTV5.MQTTException as e: #I think we'll retry this one too, the other end probably wasn't ready logger.debug( "Bridge: failed to connect to remote end due to an MQTT Error (%s), retrying...", str(e)) time.sleep(retry) retry *= 2 # subscribe if necessary options = MQTTV5.SubscribeOptions() options.noLocal = options.retainAsPublished = True if self.direction == "both" or self.direction == "in": self.client.subscribe([self.topic], [options]) else: logger.info("Bridge: not subscribing to remote")
def test_redelivery_on_reconnect(self): # redelivery on reconnect. When a QoS 1 or 2 exchange has not been completed, the server should retry the # appropriate MQTT packets logging.info("Redelivery on reconnect test starting") succeeded = True try: callback.clear() callback2.clear() bclient.connect(host=host, port=port, cleanstart=False) bclient.subscribe([wildtopics[6]], [MQTTV5.SubscribeOptions(2)]) bclient.pause() # stops responding to incoming publishes bclient.publish(topics[1], b"", 1, retained=False) bclient.publish(topics[3], b"", 2, retained=False) time.sleep(1) bclient.disconnect() assert len(callback2.messages) == 0, "length should be 0: %s" % callback2.messages bclient.resume() bclient.connect(host=host, port=port, cleanstart=False) time.sleep(3) assert len(callback2.messages) == 2, "length should be 2: %s" % callback2.messages bclient.disconnect() except: traceback.print_exc() succeeded = False logging.info("Redelivery on reconnect test %s", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def test_retained_message(self): qos0topic="fromb/qos 0" qos1topic="fromb/qos 1" qos2topic="fromb/qos2" wildcardtopic="fromb/+" publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.UserPropertyList = [("a", "2"), ("c", "3")] # retained messages callback.clear() aclient.connect(host=host, port=port, cleanstart=True) aclient.publish(topics[1], b"qos 0", 0, retained=True, properties=publish_properties) aclient.publish(topics[2], b"qos 1", 1, retained=True, properties=publish_properties) aclient.publish(topics[3], b"qos 2", 2, retained=True, properties=publish_properties) time.sleep(1) aclient.subscribe([wildtopics[5]], [MQTTV5.SubscribeOptions(2)]) time.sleep(1) aclient.disconnect() self.assertEqual(len(callback.messages), 3) userprops = callback.messages[0][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) userprops = callback.messages[1][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) userprops = callback.messages[2][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) qoss = [callback.messages[i][2] for i in range(3)] self.assertTrue(1 in qoss and 2 in qoss and 0 in qoss, qoss) cleanRetained()
def test_server_topic_alias(self): callback.clear() serverTopicAliasMaximum = 1 # server topic alias allowed connect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.CONNECT) connect_properties.TopicAliasMaximum = serverTopicAliasMaximum connack = aclient.connect(host=host, port=port, cleanstart=True, properties=connect_properties) clientTopicAliasMaximum = 0 if hasattr(connack.properties, "TopicAliasMaximum"): clientTopicAliasMaximum = connack.properties.TopicAliasMaximum aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) self.waitfor(callback.subscribeds, 1, 3) for qos in range(3): aclient.publish(topics[0], b"topic alias 1", qos) self.waitfor(callback.messages, 3, 3) self.assertEqual(len(callback.messages), 3, callback.messages) aclient.disconnect() # first message should set the topic alias self.assertTrue(hasattr(callback.messagedicts[0]["properties"], "TopicAlias"), callback.messagedicts[0]["properties"]) topicalias = callback.messagedicts[0]["properties"].TopicAlias self.assertEqual(callback.messagedicts[1]["properties"].TopicAlias, topicalias, topicalias) self.assertEqual(callback.messagedicts[2]["properties"].TopicAlias, topicalias, topicalias)
def test_client_topic_alias(self): callback.clear() # no server side topic aliases allowed connack = aclient.connect(host=host, port=port, cleanstart=True) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.TopicAlias = 0 # topic alias 0 not allowed aclient.publish(topics[0], "topic alias 0", 1, properties=publish_properties) # should get back a disconnect with Topic alias invalid self.waitfor(callback.disconnects, 1, 2) self.assertEqual(len(callback.disconnects), 1, callback.disconnects) #print("disconnect", str(callback.disconnects[0]["reasonCode"])) #self.assertEqual(callback.disconnects, 1, callback.disconnects) connect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.CONNECT) connect_properties.TopicAliasMaximum = 0 # server topic aliases not allowed connack = aclient.connect(host=host, port=port, cleanstart=True, properties=connect_properties) clientTopicAliasMaximum = 0 if hasattr(connack.properties, "TopicAliasMaximum"): clientTopicAliasMaximum = connack.properties.TopicAliasMaximum if clientTopicAliasMaximum == 0: aclient.disconnect() return aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) self.waitfor(callback.subscribeds, 1, 3) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.TopicAlias = 1 aclient.publish(topics[0], b"topic alias 1", 1, properties=publish_properties) self.waitfor(callback.messages, 1, 3) self.assertEqual(len(callback.messages), 1, callback.messages) aclient.publish("", b"topic alias 2", 1, properties=publish_properties) self.waitfor(callback.messages, 2, 3) self.assertEqual(len(callback.messages), 2, callback.messages) aclient.disconnect() # should get rid of the topic aliases but not subscriptions # check aliases have been deleted callback.clear() aclient.connect(host=host, port=port, cleanstart=False) aclient.publish(topics[0], b"topic alias 3", 1) self.waitfor(callback.messages, 1, 3) self.assertEqual(len(callback.messages), 1, callback.messages) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.TopicAlias = 1 aclient.publish("", b"topic alias 4", 1, properties=publish_properties) # should get back a disconnect with Topic alias invalid self.waitfor(callback.disconnects, 1, 2) self.assertEqual(len(callback.disconnects), 1, callback.disconnects)
def test_overlapping_subscriptions(self): # overlapping subscriptions. When there is more than one matching subscription for the same client for a topic, # the server may send back one message with the highest QoS of any matching subscription, or one message for # each subscription with a matching QoS. callback.clear() callback2.clear() aclient.connect(host=host, port=port) aclient.subscribe([wildtopics[6], wildtopics[0]], [MQTTV5.SubscribeOptions(2), MQTTV5.SubscribeOptions(1)]) aclient.publish(topics[3], b"overlapping topic filters", 2) time.sleep(1) self.assertTrue(len(callback.messages) in [1, 2], callback.messages) if len(callback.messages) == 1: logging.info("This server is publishing one message for all matching overlapping subscriptions, not one for each.") self.assertEqual(callback.messages[0][2], 2, callback.messages[0][2]) else: logging.info("This server is publishing one message per each matching overlapping subscription.") self.assertTrue((callback.messages[0][2] == 2 and callback.messages[1][2] == 1) or \ (callback.messages[0][2] == 1 and callback.messages[1][2] == 2), callback.messages) aclient.disconnect()
def local_connect(self): # connect locally with V5, so we get noLocal and retainAsPublished connect = MQTTV5.Connects() connect.ClientIdentifier = "local" broker5.connect(self, connect) subscribe = MQTTV5.Subscribes() options = MQTTV5.SubscribeOptions() options.noLocal = options.retainAsPublished = True subscribe.data = [('+', options)] broker5.subscribe(self, subscribe)
def test_login_sub_unsub_1(self): print(topics,len(topics),len(wildtopics)) connack = aclient.connect(host=host,port=port,cleanstart=True) connack = bclient.connect(host=host,port=port,cleanstart=False) succeeded = True print("Basic test starting") succeeded = True number = len(topics) try: for i in range(number): print("sub is %d"%i) aclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) time.sleep(.1) time.sleep(5) print("重复订阅") for i in range(number): print("sub is %d"%i) aclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) time.sleep(.1) time.sleep(10) for i in range(number): print("unsub is %s"%i) aclient.unsubscribe([topics[i]]) bclient.unsubscribe([topics[i]]) time.sleep(.1) print("重复取消订阅") for i in range(number): print("unsub is %s"%i) aclient.unsubscribe([topics[i]]) bclient.unsubscribe([topics[i]]) time.sleep(.1) time.sleep(10) except: succeeded = False print("Basic test", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def optionsOf(self, clientid, topic): # if there are overlapping subscriptions, choose maximum QoS chosen = None for sub in self.getSubscriptions(topic, clientid): if chosen == None: if hasattr(sub, "getOptions"): chosen = sub.getOptions() else: # MQTT V3 case chosen = (MQTTV5.SubscribeOptions(QoS=sub.getQoS()), MQTTV5.Properties(MQTTV5.PacketTypes.SUBSCRIBE)) else: logger.info("[MQTT-3.3.5-1] Overlapping subscriptions max QoS") if sub.getQoS() > chosen[0].QoS: if hasattr(sub, "getOptions"): chosen = sub.getOptions() else: # MQTT V3 case chosen = (MQTTV5.SubscribeOptions(QoS=sub.getQoS()), MQTTV5.Properties(MQTTV5.PacketTypes.SUBSCRIBE)) # Omit the following optimization because we want to check for condition [MQTT-3.3.5-1] #if chosen == 2: # break return chosen
def local_connect(self): # connect locally with V5, so we get noLocal and retainAsPublished connect = MQTTV5.Connects() connect.ClientIdentifier = self.name logger.debug("Bridge: local_connect:" + connect.ClientIdentifier) broker5.connect(self, connect) subscribe = MQTTV5.Subscribes() options = MQTTV5.SubscribeOptions() options.noLocal = options.retainAsPublished = True subscribe.data = [(self.topic, options)] broker5.subscribe(self, subscribe)
def test_unsubscribe(self): callback2.clear() bclient.connect(host=host, port=port, cleanstart=True) bclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[1]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[2]], [MQTTV5.SubscribeOptions(2)]) time.sleep(1) # wait for any retained messages, hopefully # Unsubscribe from one topic bclient.unsubscribe([topics[0]]) callback2.clear() # if there were any retained messsages aclient.connect(host=host, port=port, cleanstart=True) aclient.publish(topics[0], b"topic 0 - unsubscribed", 1, retained=False) aclient.publish(topics[1], b"topic 1", 1, retained=False) aclient.publish(topics[2], b"topic 2", 1, retained=False) time.sleep(2) bclient.disconnect() aclient.disconnect() self.assertEqual(len(callback2.messages), 2, callback2.messages)
def test_login_sub(self): print(topics,len(topics),len(wildtopics)) connack = aclient.connect(host=host,port=port,cleanstart=True) connack = bclient.connect(host=host,port=port,cleanstart=True) connack = cclient.connect(host=host,port=port,cleanstart=True) succeeded = True print("Basic test starting") succeeded = True try: for i in range(len(topics)): print("sub is %d"%i) aclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) bclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) cclient.subscribe([topics[i]], [MQTTV5.SubscribeOptions(2)]) time.sleep(.1) time.sleep(20) except: succeeded = False self.assertEqual(succeeded, True) return succeeded
def cleanRetained(): callback = Callbacks() curclient = mqtt_client.Client("clean retained".encode("utf-8")) curclient.registerCallback(callback) curclient.connect(host=host, port=port, cleanstart=True) curclient.subscribe(["#"], [MQTTV5.SubscribeOptions(0)]) time.sleep(2) # wait for all retained messages to arrive for message in callback.messages: logging.info("deleting retained message for topic", message[0]) curclient.publish(message[0], b"", 0, retained=True) curclient.disconnect() time.sleep(.1)
def test_request_response(self): callback.clear() callback2.clear() aclient.connect(host=host, port=port, cleanstart=True) bclient.connect(host=host, port=port, cleanstart=True) aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2, noLocal=True)]) self.waitfor(callback.subscribeds, 1, 3) bclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2, noLocal=True)]) self.waitfor(callback.subscribeds, 1, 3) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.ResponseTopic = topics[0] publish_properties.CorrelationData = b"334" # client a is the requester aclient.publish(topics[0], b"request", 1, properties=publish_properties) # client b is the responder self.waitfor(callback2.messages, 1, 3) self.assertEqual(len(callback2.messages), 1, callback2.messages) self.assertEqual(len(callback2.messages), 1, callback2.messages) self.assertEqual(callback2.messages[0][5].ResponseTopic, topics[0], callback2.messages[0][5]) self.assertEqual(callback2.messages[0][5].CorrelationData, b"334", callback2.messages[0][5]) bclient.publish(callback2.messages[0][5].ResponseTopic, b"response", 1, properties=callback2.messages[0][5]) # client a gets the response self.waitfor(callback.messages, 1, 3) self.assertEqual(len(callback.messages), 1, callback.messages) aclient.disconnect() bclient.disconnect() callback.clear() callback2.clear()
def test_subscribe_identifiers(self): callback.clear() aclient.connect(host=host, port=port, cleanstart=True) sub_properties = MQTTV5.Properties(MQTTV5.PacketTypes.SUBSCRIBE) sub_properties.SubscriptionIdentifier = 456789 aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)], properties=sub_properties) self.waitfor(callback.subscribeds, 1, 3) aclient.publish(topics[0], b"sub identifier test", 1, retained=False) self.waitfor(callback.messages, 1, 3) self.assertEqual(len(callback.messages), 1, callback.messages) self.assertEqual(callback.messages[0][5].SubscriptionIdentifier, 456789, callback.messages[0][5].SubscriptionIdentifier) aclient.disconnect() callback.clear()
def test_maximum_packet_size(self): callback.clear() # 1. server max packet size connack = aclient.connect(host=host, port=port, cleanstart=True) serverMaximumPacketSize = 2**28-1 if hasattr(connack.properties, "MaximumPacketSize"): serverMaximumPacketSize = connack.properties.MaximumPacketSize if serverMaximumPacketSize < 65535: # publish bigger packet than server can accept payload = b"."*serverMaximumPacketSize aclient.publish(topics[0], payload, 0) # should get back a disconnect with packet size too big self.waitfor(callback.disconnects, 1, 2) self.assertEqual(len(callback.disconnects), 1, callback.disconnects) self.assertEqual(str(callback.disconnects[0]["reasonCode"]), "Packet too large", str(callback.disconnects[0]["reasonCode"])) else: aclient.disconnect() # 1. client max packet size maximumPacketSize = 64 # max packet size we want to receive connect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.CONNECT) connect_properties.MaximumPacketSize = maximumPacketSize connack = aclient.connect(host=host, port=port, cleanstart=True, properties=connect_properties) serverMaximumPacketSize = 2**28-1 if hasattr(connack.properties, "MaximumPacketSize"): serverMaximumPacketSize = connack.properties.MaximumPacketSize aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) self.waitfor(callback.subscribeds, 1, 3) # send a small enough packet, should get this one back payload = b"."*(int(maximumPacketSize/2)) aclient.publish(topics[0], payload, 0) self.waitfor(callback.messages, 1, 3) self.assertEqual(len(callback.messages), 1, callback.messages) # send a packet too big to receive payload = b"."*maximumPacketSize aclient.publish(topics[0], payload, 1) self.waitfor(callback.messages, 2, 3) self.assertEqual(len(callback.messages), 1, callback.messages) aclient.disconnect()
def test_subscribe_failure(self): # Subscribe failure. A new feature of MQTT 3.1.1 is the ability to send back negative reponses to subscribe # requests. One way of doing this is to subscribe to a topic which is not allowed to be subscribed to. logging.info("Subscribe failure test starting") succeeded = True try: callback.clear() aclient.connect(host=host, port=port) aclient.subscribe([nosubscribe_topics[0]], [MQTTV5.SubscribeOptions(2)]) time.sleep(1) # subscribeds is a list of (msgid, [qos]) logging.info(callback.subscribeds) assert callback.subscribeds[0][1][0].value == 0x80, "return code should be 0x80 %s" % callback.subscribeds except: traceback.print_exc() succeeded = False logging.info("Subscribe failure test %s", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def test_will_message(self): # will messages callback.clear() callback2.clear() self.assertEqual(len(callback2.messages), 0, callback2.messages) will_properties = MQTTV5.Properties(MQTTV5.PacketTypes.WILLMESSAGE) will_properties.WillDelayInterval = 0 # this is the default anyway will_properties.UserPropertyList = [("a", "2"), ("c", "3")] aclient.connect(host=host, port=port, cleanstart=True, willFlag=True, willTopic=topics[2], willMessage=b"will message", keepalive=2, willProperties=will_properties) bclient.connect(host=host, port=port, cleanstart=False) bclient.subscribe([topics[2]], [MQTTV5.SubscribeOptions(2)]) self.waitfor(callback2.subscribeds, 1, 3) # keep alive timeout ought to be triggered so the will message is received self.waitfor(callback2.messages, 1, 10) bclient.disconnect() self.assertEqual(len(callback2.messages), 1, callback2.messages) # should have the will message
def test_keepalive(self): # keepalive processing. We should be kicked off by the server if we don't send or receive any data, and don't send # any pings either. logging.info("Keepalive test starting") succeeded = True try: callback2.clear() aclient.connect(host=host, port=port, cleanstart=True, keepalive=5, willFlag=True, willTopic=topics[4], willMessage=b"keepalive expiry") bclient.connect(host=host, port=port, cleanstart=True, keepalive=0) bclient.subscribe([topics[4]], [MQTTV5.SubscribeOptions(2)]) time.sleep(15) bclient.disconnect() assert len(callback2.messages) == 1, "length should be 1: %s" % callback2.messages # should have the will message except: traceback.print_exc() succeeded = False logging.info("Keepalive test %s", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def test_basic(self): aclient.connect(host=host, port=port) aclient.disconnect() rc = aclient.connect(host=host, port=port) self.assertEqual(rc.reasonCode.getName(), "Success") aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) aclient.publish(topics[0], b"qos 0") aclient.publish(topics[0], b"qos 1", 1) aclient.publish(topics[0], b"qos 2", 2) time.sleep(2) aclient.disconnect() self.assertEqual(len(callback.messages), 3) with self.assertRaises(Exception): aclient.connect(host=host, port=port) aclient.connect(host=host, port=port, newsocket=False) # should fail - second connect on socket with self.assertRaises(Exception): aclient.connect(host=host, port=port, protocolName="hj") # should fail - wrong protocol name
def qostest(self,sub_qos=None,pub_qos=None,message=None): callback.clear() callback2.clear() #用户B连接 print("用户B连接") bclient.connect(host=host, port=port, cleanstart=True) print(wildtopics[6],topics[1]) bclient.subscribe([wildtopics[6]], [MQTTV5.SubscribeOptions(sub_qos)]) time.sleep(1) bclient.publish(topics[1], message, pub_qos, retained=False) time.sleep(2) #用户a连接 print("用户A连接") aclient.connect(host=host, port=port, cleanstart=True) aclient.publish(topics[1], message, pub_qos, retained=False) time.sleep(1) bclient.disconnect() time.sleep(1) aclient.disconnect() print(callback2.messages) return callback2.messages
def test_user_properties(self): callback.clear() aclient.connect(host=host, port=port, cleanstart=True) aclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) publish_properties = MQTTV5.Properties(MQTTV5.PacketTypes.PUBLISH) publish_properties.UserPropertyList = [("a", "2"), ("c", "3")] aclient.publish(topics[0], b"", 0, retained=False, properties=publish_properties) aclient.publish(topics[0], b"", 1, retained=False, properties=publish_properties) aclient.publish(topics[0], b"", 2, retained=False, properties=publish_properties) while len(callback.messages) < 3: time.sleep(.1) aclient.disconnect() self.assertEqual(len(callback.messages), 3, callback.messages) userprops = callback.messages[0][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) userprops = callback.messages[1][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) userprops = callback.messages[2][5].UserPropertyList self.assertTrue(userprops in [[("a", "2"), ("c", "3")],[("c", "3"), ("a", "2")]], userprops) qoss = [callback.messages[i][2] for i in range(3)] self.assertTrue(1 in qoss and 2 in qoss and 0 in qoss, qoss)
def test_dollar_topics(self): # $ topics. The specification says that a topic filter which starts with a wildcard does not match topic names that # begin with a $. Publishing to a topic which starts with a $ may not be allowed on some servers (which is entirely valid), # so this test will not work and should be omitted in that case. logging.info("$ topics test starting") succeeded = True try: callback2.clear() bclient.connect(host=host, port=port, cleanstart=True, keepalive=0) bclient.subscribe([wildtopics[5]], [MQTTV5.SubscribeOptions(2)]) time.sleep(1) # wait for all retained messages, hopefully callback2.clear() bclient.publish("$"+topics[1], b"", 1, retained=False) time.sleep(.2) assert len(callback2.messages) == 0, callback2.messages bclient.disconnect() except: traceback.print_exc() succeeded = False logging.info("$ topics test %s", "succeeded" if succeeded else "failed") self.assertEqual(succeeded, True) return succeeded
def test_offline_message_queueing(self): # message queueing for offline clients callback.clear() callback2.clear() aclient.connect(host=host, port=port, cleanstart=True) aclient.subscribe([wildtopics[5]], [MQTTV5.SubscribeOptions(2)]) aclient.disconnect() bclient.connect(host=host, port=port, cleanstart=True) bclient.publish(topics[1], b"qos 0", 0) bclient.publish(topics[2], b"qos 1", 1) bclient.publish(topics[3], b"qos 2", 2) time.sleep(2) bclient.disconnect() aclient.connect(host=host, port=port, cleanstart=False) time.sleep(2) aclient.disconnect() self.assertTrue(len(callback.messages) in [2, 3], len(callback.messages)) logging.info("This server %s queueing QoS 0 messages for offline clients" % \ ("is" if len(callback.messages) == 3 else "is not"))
def connect(self): self.client.connect(host=self.host, port=self.port, cleanstart=True) # subscribe if necessary options = MQTTV5.SubscribeOptions() options.noLocal = options.retainAsPublished = True self.client.subscribe(["+"], [options])
def test_flow_control1(self): testcallback = Callbacks() # no callback means no background thread, to control receiving testclient = mqtt_client.Client("myclientid".encode("utf-8")) # set receive maximum - the number of concurrent QoS 1 and 2 messages clientReceiveMaximum = 2 # set to low number so we can test connect_properties = MQTTV5.Properties(MQTTV5.PacketTypes.CONNECT) connect_properties.ReceiveMaximum = clientReceiveMaximum connect_properties.SessionExpiryInterval = 0 connack = testclient.connect(host=host, port=port, cleanstart=True, properties=connect_properties) serverReceiveMaximum = 2**16-1 # the default if hasattr(connack.properties, "ReceiveMaximum"): serverReceiveMaximum = connack.properties.ReceiveMaximum receiver = testclient.getReceiver() testclient.subscribe([topics[0]], [MQTTV5.SubscribeOptions(2)]) receiver.receive(testcallback) self.waitfor(testcallback.subscribeds, 1, 3) pubs = 0 for i in range(1, clientReceiveMaximum + 2): testclient.publish(topics[0], "message %d" % i, 1) pubs += 1 # get two publishes acks = 0 while True: response1 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) if response1.fh.PacketType == MQTTV5.PacketTypes.PUBLISH: break self.assertEqual(response1.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[response1.packetIdentifier] self.assertEqual(response1.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response1.fh.QoS, 1, response1.fh.QoS) while True: response2 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) if response2.fh.PacketType == MQTTV5.PacketTypes.PUBLISH: break self.assertEqual(response2.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[response2.packetIdentifier] self.assertEqual(response2.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response2.fh.QoS, 1, response1.fh.QoS) while acks < pubs: ack = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) self.assertEqual(ack.fh.PacketType, MQTTV5.PacketTypes.PUBACK) acks += 1 del receiver.outMsgs[ack.packetIdentifier] with self.assertRaises(socket.timeout): # this should time out because we haven't acknowledged the first one response3 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) # ack the first one puback = MQTTV5.Pubacks() puback.packetIdentifier = response1.packetIdentifier testclient.sock.send(puback.pack()) # now get the next packet response3 = MQTTV5.unpackPacket(MQTTV5.getPacket(testclient.sock)) self.assertEqual(response3.fh.PacketType, MQTTV5.PacketTypes.PUBLISH) self.assertEqual(response3.fh.QoS, 1, response1.fh.QoS) # ack the second one puback.packetIdentifier = response2.packetIdentifier testclient.sock.send(puback.pack()) # ack the third one puback.packetIdentifier = response3.packetIdentifier testclient.sock.send(puback.pack()) testclient.disconnect()