SlideShare une entreprise Scribd logo
1  sur  69
Télécharger pour lire hors ligne
Josué Melka
Model Based Testing des
applications du protocole MQTT
Mémoire de Master Recherche Informatique
encadré par Fabrice Bouquet, Professeur des Universités
27 Septembre 2016
Table des matières
1 Introduction 4
2 Le protocole MQTT 7
2.1 Fonctionnement . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.1.1 Connexion et Déconnexion . . . . . . . . . . . . . . . 10
2.1.2 Abonnements et Publications . . . . . . . . . . . . . . 10
2.1.3 Qualité de service . . . . . . . . . . . . . . . . . . . . 11
2.1.4 Persistance . . . . . . . . . . . . . . . . . . . . . . . . 13
2.1.5 Messages retenus . . . . . . . . . . . . . . . . . . . . . 13
2.1.6 Testament . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.2 Sécurité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.1 Confidentialité . . . . . . . . . . . . . . . . . . . . . . 14
2.2.2 Authentification . . . . . . . . . . . . . . . . . . . . . 14
2.2.3 Intégrité . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2.4 Gestion des droits . . . . . . . . . . . . . . . . . . . . 15
2.3 Format binaire . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.3.1 CONNECT . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3.2 CONNACK . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3.3 PUBLISH . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3.4 PUBACK, PUBREC, PUBREL, PUBCOMP . . . . . 18
2.3.5 SUBSCRIBE . . . . . . . . . . . . . . . . . . . . . . . 18
2.3.6 SUBACK . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3.7 UNSUBSCRIBE . . . . . . . . . . . . . . . . . . . . . 20
2.3.8 UNSUBACK . . . . . . . . . . . . . . . . . . . . . . . 20
2.3.9 PINGREQ, PINGRESP . . . . . . . . . . . . . . . . . 21
2.3.10 DISCONNECT . . . . . . . . . . . . . . . . . . . . . . 21
2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3 Problématiques de modélisation de MQTT 23
3.1 Model-Based-Testing du protocole . . . . . . . . . . . . . . . 24
3.1.1 Sujet du test et observation . . . . . . . . . . . . . . . 26
3.1.2 Non déterminisme . . . . . . . . . . . . . . . . . . . . 26
3.2 Altération des échanges MQTT . . . . . . . . . . . . . . . . . 27
1
TABLE DES MATIÈRES 2
3.2.1 Suivi et validation des trames . . . . . . . . . . . . . . 27
3.2.2 Critères de transformation . . . . . . . . . . . . . . . . 28
3.2.3 Intégration . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3 Analyse des tests . . . . . . . . . . . . . . . . . . . . . . . . . 28
4 Travail réalisé 30
4.1 Outils utilisés . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.1.1 Smartesting CertifyIt . . . . . . . . . . . . . . . . . . 31
4.1.2 Eclipse Paho project . . . . . . . . . . . . . . . . . . . 33
4.1.3 Wireshark . . . . . . . . . . . . . . . . . . . . . . . . . 34
4.2 Modélisation fonctionnelle du protocole MQTT . . . . . . . . 35
4.2.1 Mise en œuvre . . . . . . . . . . . . . . . . . . . . . . 36
4.2.2 Fonctionnalités modélisées . . . . . . . . . . . . . . . . 38
4.2.3 Génération des tests . . . . . . . . . . . . . . . . . . . 40
4.2.4 Verdict . . . . . . . . . . . . . . . . . . . . . . . . . . 41
4.3 Proxy de test MQTT . . . . . . . . . . . . . . . . . . . . . . . 41
4.3.1 Réalisation . . . . . . . . . . . . . . . . . . . . . . . . 42
4.3.2 Modélisation du protocole . . . . . . . . . . . . . . . . 42
4.3.3 Intégration au script de test . . . . . . . . . . . . . . . 43
4.4 Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.4.1 Tests générés avec CertifyIt . . . . . . . . . . . . . . . 44
4.4.2 Modélisation du format des trames . . . . . . . . . . . 44
4.4.3 Exécution des test . . . . . . . . . . . . . . . . . . . . 45
4.4.4 Validation . . . . . . . . . . . . . . . . . . . . . . . . . 45
5 Conclusion 47
Bibliographie 49
Remerciements 51
A Codes sources (extraits) 52
A.1 Suite de tests . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
A.2 Adaptateur pour le client MQTT . . . . . . . . . . . . . . . . 54
A.3 Modélisation binaire des trames . . . . . . . . . . . . . . . . . 55
B Log des tests exécutés 57
C Extraits de l’annexe B de la norme MQTT 64
Table des figures
1.1 IoT protocol stack . . . . . . . . . . . . . . . . . . . . . . . . 5
2.3 Format d’un paquet CONNECT . . . . . . . . . . . . . . . . 16
2.4 Format d’un paquet CONNACK . . . . . . . . . . . . . . . . 17
2.5 Format d’un paquet PUBLISH . . . . . . . . . . . . . . . . . 18
2.6 Format d’un paquet PUB[ACK/REC/REL/COMP] . . . . . 18
2.7 Format d’un paquet SUBSCRIBE . . . . . . . . . . . . . . . 19
2.8 Format d’un paquet SUBACK . . . . . . . . . . . . . . . . . 20
2.9 Format d’un paquet UNSUBSCRIBE . . . . . . . . . . . . . . 20
2.10 Format d’un paquet UNSUBACK . . . . . . . . . . . . . . . . 21
2.11 Format d’un paquet PING[REQ/RESP] . . . . . . . . . . . . 21
2.12 Format d’un paquet DISCONNECT . . . . . . . . . . . . . . 21
4.4 Processus du test de MQTT basé sur les modèles . . . . . . 35
4.5 Modélisation UML du protocole MQTT . . . . . . . . . . . . 36
4.8 Architecture du proxy de test MQTT . . . . . . . . . . . . . 42
4.9 Notre processus du test pour MQTT . . . . . . . . . . . . . 43
3
Chapitre 1
Introduction
Les objets connectés se démocratisent de plus en plus, le cabinet d’ana-
lyse Gartner estimant leur nombre actuel à plusieurs milliards d’unités, et
prédisant que leur nombre en 2020 pourra atteindre 25 milliards [5].
La fiabilité des produits, les questions d’interopérabilité et les failles de
sécurité sont des problèmes encore très largement rencontrés dans ce do-
maine, ce qui freine l’émergence du marché. De par leur nature, les objets
connectés forment des systèmes complexes qui rendent ces problèmes à la
fois plus cruciaux et plus difficiles à appréhender.
Pouvoir certifier efficacement ces produits apparait donc comme une né-
cessité majeure, alors même que la diversité et la quantité de l’offre ne cesse
de croitre.
Le test est sans doute l’une des techniques de validation la plus à même
de répondre à ce besoin. Malgré le fait qu’il ne puisse apporter de garantie
absolue sur l’absence d’imperfection, c’est un moyen efficace et relativement
peu coûteux pour apporter un certain degré de confiance sur un système.
Toutefois, la mise en place de tests sur une gamme de produits aussi
diversifiée n’est pas sans poser des problèmes d’échelle. En effet, valider
chaque composant peut nécessiter un grand nombre de cas de test pour
fournir une couverture suffisante, et il faut une certaine expertise pour définir
des cas de test pertinents.
La méthodologie du test dirigé par les modèles offre sur ce terrain une
solution intéressante : une fois le système à tester modélisé, la génération des
cas de tests est automatisable et configurable. Ainsi l’on peut se contenter
d’établir un modèle de test, et de le faire évoluer en fonction des besoins.
Toutefois, la complexité inhérente des systèmes connectés impose d’étu-
dier soigneusement la modélisation que l’on va adopter pour générer des
tests. Nous avons voulu approfondir cette question en expérimentant l’ap-
plication du model based testing à une problématique concrète.
4
CHAPITRE 1. INTRODUCTION 5
L’un des aspects essentiels d’une architecture IoT est celui de la commu-
nication entre les divers composants du système global. Il existe bien sûr
de multiples moyens de connecter et de faire communiquer les composants
en question (un aperçu des différentes couches de communication couram-
ment employés est donné Figure 1.1), mais on assiste dans ce domaine à
l’émergence de certains protocoles mieux adaptés que d’autres pour remplir
ce besoin.
Figure 1.1 – IoT protocol stack - Source : [13]
Ainsi, avec son modèle Publish/Subscribe et sa très grande légèreté, le
protocole MQTT est actuellement considéré comme l’un des candidats les
plus sérieux pour assurer le transport des données au sein des architectures
IoT [10]. Déjà largement utilisé – c’est par exemple le protocole fourni par
la plateforme Amazon Webservices IoT 1, on en trouve de nombreuses im-
plémentations dans divers langages de programmation, dont beaucoup sont
open-source.
Nous avons considéré ce protocole comme étant à la fois suffisamment
simple et intéressant pour constituer l’objet de notre expérimentation, qui
1. http://docs.aws.amazon.com/iot/latest/developerguide/what-is-aws-
iot.html
CHAPITRE 1. INTRODUCTION 6
portera donc sur la mise en œuvre de tests basés sur les modèles afin de
valider le support du protocole MQTT par des objets connectés.
Comme objectif de cette étude, nous avons souhaité analyser les probléma-
tiques qui découlent de la mise en œuvre de tels tests, et si possible proposer
les solutions qui nous semblent adaptées et généralisables.
Dans le Chapitre 2, nous présentons en détail à partir de sa spécification
le fonctionnement de MQTT ainsi que les différents aspect susceptibles d’être
modélisés et testés.
Au Chapitre 3, nous discutons des implications de ce fonctionnement sur
la modélisation d’un système MQTT, et tentons de trouver des solutions
réalisables aux problèmes que nous avons rencontrés.
Enfin, le Chapitre 4 exposera notre expérimentation de modélisation du
protocole et ses résultats, ainsi que les outils utilisés et ceux qui ont dû être
créés pour l’occasion.
Chapitre 2
Le protocole MQTT
MQ Telemetry Transport est un protocole de messaging basé sur le pu-
blish/subscribe à la fois extrêmement simple et léger, lui permettant ainsi
d’être utilisable à partir d’un matériel de très faible puissance, ainsi que à
travers des réseaux à forte latence voire peu fiables.
Initialement créé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nip-
per (Eurotech), le protocole est alors pensé pour alimenter les systèmes de
télémesure, et est connu à l’origine sous le nom de MQ Integrator SCADA
Device Protocol [11].
Par la suite, son code source est donné en 2011 au projet Eclipse Paho,
et le protocole est standardisé par l’OASIS en 2014 dans sa version 3.1.1. Il
devient un standard ISO (ISO/IEC 20922) en 2016.
Aujourd’hui, avec l’essor de l’IoT, MQTT suscite un intérêt grandissant,
dont l’on peut se rendre compte en observant l’évolution du nombre de
recherches pour MQTT sur Google Trends (Figure 2.1).
Les principales caractéristiques de MQTT sont les suivantes :
— Emploie le pattern publish/subscribe, permettant une distribution des
messages un-à-plusieurs, ainsi que le découplage des applications.
— Le protocole de transport de messages est totalement indépendant de
leur contenu (content agnostic).
— Trois niveaux de qualité de service pour la distribution des messages :
1. At most once
2. At least once
3. Exactly once
— Volume de données échangées extrêmement réduit, limitant ainsi le
trafic réseau généré.
— Un mécanisme de notification en cas de déconnexion abrupte d’un
client.
7
CHAPITRE 2. LE PROTOCOLE MQTT 8
Figure 2.1 – Google Trends pour MQTT (01/08/2016)
Les qualités intrinsèques de MQTT font de lui un excellent candidat pour
les communications au sein de l’Internet des Objets [10], mais il a également
été utilisé avec succès par Facebook pour être au cœur de leur système de
messagerie, un choix dicté par la performance [16].
Actuellement, un autre protocole nommé MQTT-SN (MQTT for Sensor
Networks) est en cours de développement, afin de pallier aux contraintes de
certains hardwares particulièrement limités tout en garantissant une com-
patibilité avec MQTT, mais ce protocole ne sera pas étudié ici.
La norme MQTT – dont nous fournissons un extrait des principales exi-
gences en Annexe C – décrit le comportement attendu des serveurs (brokers)
et clients MQTT, ainsi que les détails du format binaire employé pour les
échanges. La suite de ce chapitre synthétisera l’essentiel de cette norme afin
de mieux appréhender la question de la modélisation par la suite.
Nous expliquons en détail le fonctionnement du protocole MQTT en
section 2.1.
La partie suivante (section 2.2) sera consacrée à l’exposé des aspects de
sécurité pris en compte par le protocole.
Enfin, le format binaire défini par la norme pour les paquets MQTT sera
étudié dans la dernière partie (section 2.3).
2.1 Fonctionnement
Le fonctionnement de MQTT repose sur le pattern d’échange de mes-
sages désormais bien connu sous le nom de publish/subscribe, ou PUB/SUB.
CHAPITRE 2. LE PROTOCOLE MQTT 9
Ce pattern consiste à organiser les messages par sujets (topics) et à gé-
rer leur distribution selon le principe d’abonnement. Ainsi, toute application
peut publier ses messages sur les topics de son choix, tandis que les applica-
tions intéressées par les messages d’un topic donné peuvent s’abonner pour
recevoir tous les nouveaux messages publiés sur ce topic.
Dans le cas d’un PUB/SUB broker-based comme MQTT, un serveur
(généralement nommé broker) fait office d’intermédiaire entre les clients qui
publient et ceux qui s’abonnent. Ceci afin de découpler les publishers et les
subscribers, qui n’ont besoin que de connaitre le broker pour fonctionner.
Gestion des erreurs
La plupart des erreurs, sauf celles qui ont une valeur informative im-
portante pour le client (typiquement certaines erreurs à la connexion qui
sont signalées par un code de retour) sont soit ignorées, soit provoquent
l’abandon de la connexion par l’autre partie.
Ce comportement rend évidement l’implémentation du protocole plus
simple, mais le diagnostic d’une erreur est dès lors plus difficile à établir
dans bien des cas.
Topologies courantes
Le standard ne définit pas de topologie particulière d’utilisation, la plus
simple étant celle avec un seul broker et un certain nombre de clients, qui
peut finir par poser des problèmes de passage à l’échelle.
D’autres organisation restent évidement possible, avec en particulier les
systèmes à base de bridge dans lesquels plusieurs brokers sont utilisés, chacun
étant client des autres brokers, comme sur la Figure 2.2.
Pour la validation d’objets employant ce protocole, on pourra sans doute
se limiter à la topologie la plus basique.
Figure 2.2 – Exemples de topologies MQTT [7]
CHAPITRE 2. LE PROTOCOLE MQTT 10
2.1.1 Connexion et Déconnexion
MQTT se sert de connexions persistantes entre les clients et le broker,
et exploite pour cela les protocoles de réseau garantissant un bon niveau de
fiabilité comme TCP.
Avant de pouvoir envoyer des commandes de contrôle, un client doit au
préalable s’enregistrer auprès du serveur, ce qui se fait avec la commande
CONNECT 1.
Divers paramètres de connexion peuvent alors être échangés, comme les
identifiants du client ou encore le mode de persistance souhaité. Le serveur
doit confirmer au client que son inscription a bien été prise en compte,
soit indiquer qu’une erreur est survenue (mauvais identifiants par ex.) en
renvoyant un CONNACK accompagné d’un code de retour.
Un autre paramètre intéressant est la précision d’une durée maximale de
session (keepalive), qui indique au serveur de considérer que la connexion est
interrompue s’il ne reçoit aucune commande dans cet intervalle de temps.
Pour cela, il existe une commande PINGREQ permettant de faire savoir
au serveur que le client est toujours actif, le serveur répondra de son coté
avec un PINGRESP pour indiquer au client que la connexion est toujours
active.
Une fois l’enregistrement effectué, un second enregistrement sera consi-
déré comme une erreur, ce qui implique que l’on ne pourra pas modifier les
paramètres de départ en cours de session.
Lorsque le client veut se déconnecter, il envoie au préalable une com-
mande DISCONNECT au serveur pour lui faire part de son intention.
Dans le cas contraire, le serveur considérera la déconnexion comme anor-
male et agira en conséquence (cf. 2.1.6).
2.1.2 Abonnements et Publications
Chaque message publié est nécessairement associé à un sujet, ce qui
permet sa distribution aux abonnés. Les sujets peuvent être organisés en
hiérarchie arborescente, ainsi les abonnements peuvent porter sur des motifs
de filtrage que nous détaillerons plus loin.
La gestion des abonnements est très simple et consiste en trois com-
mandes essentielles :
SUBSCRIBE Permet à un client de s’abonner à un sujet (ou à un filtre),
une fois abonné il recevra par la suite toutes les publications concer-
nant ce sujet. Un abonnement définit également un niveau de qualité
de service, dont il sera question plus bas (section 2.1.3).
1. Ici, le terme de connexion ne doit pas être confondu avec la connexion TCP (ou
équivalent) sous-jacente, c’est pourquoi j’ai préféré le terme d’enregistrement.
CHAPITRE 2. LE PROTOCOLE MQTT 11
La bonne réception de cette commande est confirmée par le serveur
par un SUBACK portant le même identifiant de packet.
UNSUBSCRIBE Donne la possibilité d’annuler un abonnement, et ainsi
ne plus recevoir les publications ultérieures.
La bonne réception de cette commande est confirmée par le serveur
par un UNSUBACK portant le même identifiant de packet.
PUBLISH Initié par un client, permet de publier un message qui sera
transmis par le serveur aux abonnés éventuels. La même commande
sera envoyée par le serveur aux abonnés pour délivrer le message.
Si la qualité de service requise est supérieure à zéro, des messages
seront échangés pour confirmer la prise en charge de la publication (ce
point sera détaillé ci-après).
Motifs de filtrage
Afin de proposer un système de filtrage efficace sur les sujets, il est
possible de définir une arborescence à l’aide du séparateur /. Deux jokers
sont réservés pour représenter un et plusieurs niveaux d’arborescence :
— + représente un niveau d’arborescence, ainsi n1/n2/n3 peut être mis
en correspondance avec divers filtres tels que n1/n2/+, n1/+/n3 ou
n1/+/+.
— # représente autant de niveaux que possible, et ne peut être utilisé
qu’à la fin d’un motif de filtrage ; ainsi n1/# permettra de filtrer tous
les sujets dont le premier niveau est n1, et # permet de recevoir tous
les sujets publiés par le broker 2.
2.1.3 Qualité de service
Comme nous l’avons vu plus haut, trois niveaux de qualité de service
(QoS) sont définis pour la publication des messages, qui sont eux même
régis par deux facteurs : le niveau de QoS de la publication qui définit le
niveau maximal pour la publication, et le niveau de QoS de l’abonnement
qui permet au client de réduire ce niveau le cas échéant.
Ces niveaux sont mis en œuvre par des échanges supplémentaires entre
l’expéditeur et le récepteur, et plus la qualité demandée est élevée, plus il
faudra d’échanges pour valider une publication.
Pour tous les niveaux supérieurs à zéro, un identifiant est associé au
message pour permettre son suivi, MQTT prévoyant la possibilité d’avoir
au plus 65535 messages en attente (l’identifiant de message tenant sur 16
bits).
2. A l’exception des sujets spéciaux commençant par $
CHAPITRE 2. LE PROTOCOLE MQTT 12
Au niveau de qualité le plus bas (at most once), que l’on pourrait qualifier
de fire-and-forget, l’expéditeur se contente d’envoyer le message, sans se
soucier de savoir s’il a bien été reçu et pris en compte. Le diagramme de
séquence est donc le suivant :
Client Broker
PUBLISH
msc QoS 0
Le niveau 1 de qualité de service (at least once) garantit que le message
sera envoyé au moins une fois, car l’expéditeur attend la confirmation que
son message a bien été reçu avant de l’effacer. Néanmoins, un message peut
être dupliqué lors de la distribution dans certaines situations.
Client Broker
PUBLISH
PUBACK
msc QoS 1
Au niveau 2 de qualité de service (exactly once), le récepteur attend la
confirmation que sa réponse est bien arrivée a l’expéditeur, et considère en
attendant toute publication portant le même identifiant comme un duplicata
du message, qui ne sera donc pas publié à nouveau.
CHAPITRE 2. LE PROTOCOLE MQTT 13
Client Broker
PUBLISH
PUBREC
PUBREL
PUBCOMP
msc QoS 2
2.1.4 Persistance
MQTT donne au client la possibilité de choisir au moment de la connexion
s’il souhaite que sa session soit conservée par le serveur même une fois décon-
necté. Dans ce cas, sa session sera restaurée lors d’une éventuelle reconnexion
et le client recevra alors les messages mis en attente.
Les données de session sont tout d’abord les différents sujets auxquels
il s’est abonné, mais aussi les échanges qui n’ont pu se terminer avant la
déconnexion, ainsi que les messages de QoS supérieure à zéro qui parviennent
au broker alors que le client est déconnecté.
Il s’agit ici essentiellement d’une persistance en mémoire, qui sert surtout
pour les cas où la connexion réseau risque d’être interrompue. En revanche,
il n’est pas imposé que le serveur et le client disposent d’un mécanisme de
persistance en cas d’arrêt brutal du logiciel (par exemple sur le disque).
2.1.5 Messages retenus
Afin de pouvoir fournir aux nouveaux abonnés des données rapidement
même lorsque le producteur des données ne publie pas à intervalles réguliers,
il est possible d’indiquer au serveur de retenir une publication reçue comme
dernière publication connue pour un sujet donné, qui sera transmise aux
nouveaux abonnés dès leur inscription.
2.1.6 Testament
Lors de son enregistrement auprès du serveur, un client a la possibilité
d’enregistrer un testament, autrement dit un message à publier par le serveur
en cas de déconnexion anormale de sa part. Ce message sera publié sur un
topic choisi par le client.
CHAPITRE 2. LE PROTOCOLE MQTT 14
2.2 Sécurité
La sécurité d’un protocole de communication est souvent primordiale
pour nombre d’applications.
MQTT offre certaines options basiques pour permettre de sécuriser les
applications utilisant ce protocole, et nous verrons que le protocole est suf-
fisamment souple pour intégrer d’autres mécanismes de sécurité selon les
besoins.
Par ailleurs, la possibilité d’utiliser une connexion TLS/SSL permet d’ap-
porter certaines garanties au niveau de la connexion, comme l’authentifica-
tion du serveur, la confidentialité et l’intégrité des données échangées.
Au final, peu d’aspects de sécurité sont directement gérés par le proto-
cole, sans doute pour garder un protocole le plus simple possible.
2.2.1 Confidentialité
La confidentialité offerte par SSL impose un certain surcoût en termes
de puissance de calcul, qui n’est pas forcément disponible. Par ailleurs, il
existe des cas ou SSL ne peut suffire à garantir le degré de confidentialité
requis, par exemple si le client ne souhaite pas que le serveur ou d’autres
clients non autorisés puissent avoir accès à des données sensibles.
Dans de tels cas, il est possible d’avoir recours au cryptage des mes-
sages, qui seront alors transmis tels quels, et décryptés uniquement par les
destinataires autorisés.
2.2.2 Authentification
Optionnelle, l’authentification des clients est rendue possible au niveau
du protocole par les options username et password lors du CONNECT.
Bien sûr, ceci impose que le broker supporte cette fonctionnalité et dispose
des informations nécessaires sur les clients.
Une autre possibilité est d’utiliser un certificat de client pour réaliser
l’authentification au niveau du hanshake SSL.
Les autres mécanismes d’authentifications courants tels que OAuth ne
sont pas pris en charge.
2.2.3 Intégrité
C’est également une fonctionnalité non intégrée au protocole, mais plutôt
simple à mettre en place au niveau applicatif, et qui peut être suppléée par
l’usage de SSL.
CHAPITRE 2. LE PROTOCOLE MQTT 15
2.2.4 Gestion des droits
Il peut être nécessaire pour un broker d’attribuer des droits différents aux
clients en fonction de leur identité, pour définir par exemple si un client est
autorisé à maintenir une session persistante, le nombre de messages maximal
qu’il peut stocker, sur quels sujets peut-il s’abonner ou publier, avec quelle
qualité de service, etc.
MQTT ne spécifie pas de mécanisme de gestion des droits, mais chaque
implémentation de broker est libre de fournir son propre mécanisme.
Toutefois, les options dont dispose le broker pour refuser l’action d’un
client ne sont pas très nombreuses, par exemple :
— refuser un abonnement est rendu possible en renvoyant un code d’er-
reur pour le filtre en question, mais ce code peut avoir d’autres signi-
fications ;
— il n’est pas possible d’indiquer qu’une publication est interdite, les
seuls choix possibles sont soit de couper la connexion, soit d’ignorer
silencieusement le message.
2.3 Format binaire
Dans cette section, nous définissons le format binaire des paquets spécifié
par la norme MQTT. Lorsqu’un paquet ne respecte pas le format requis, la
seule option possible (sauf indication contraire) est l’abandon pur et simple
de la connexion.
Les chaines de caractères (notamment les sujets de publication et les filtres
d’abonnements) doivent toutes être encodées en utf8, et préfixées par leur
longueur sur deux octets, ces chaines sont donc limitées à une longueur de
216 − 1 = 65535 octets.
Entête fixe
Tous les packets MQTT commencent par un format d’entête fixe, conte-
nant le code de commande MQTT (sur 4 bits), un champs de 4 bits et la
longueur du reste du paquet (remaining length). Cet entête est parfois suivi
d’un entête variable en fonction de la commande.
01234567
Control Packet Type Reserved
Remaining length
...
1 to 4
bytes
CHAPITRE 2. LE PROTOCOLE MQTT 16
Une particularité de ce champs remaining length est qu’il est de longueur
variable, et peut utiliser de 1 à 4 octets en fonction de la taille encodée :
— en dessous de 27 octets, la longueur tient sur un octet ;
— en dessous de 214 octets, la longueur tient sur deux octets ;
— en dessous de 221 octets, la longueur tient sur trois octets ;
— enfin, jusqu’à 228 octets, la longueur tient sur quatre octets.
La taille maximale d’un paquet MQTT est donc de 256 Mo.
2.3.1 CONNECT
L’entête de CONNECT dans la version 3.1.1 se présente sous la forme
suivante :
Figure 2.3 – Format d’un paquet CONNECT
01234567
Connect (1) 0
Remaining length
...



fixed
header
length=4
’M’
’Q’
’T’
’T’



protocol
name
level=4
user pass will
retain
will qos will clean 0 flags
keepalive
length
client id (utf8, optional)
hhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh



client
identifier
...
options
CHAPITRE 2. LE PROTOCOLE MQTT 17
Tout d’abord le nom du protocole (préfixé par sa taille), puis le niveau
du protocole, des flags indiquant la présence ou non de paramètres option-
nels ainsi que la persistance de la session (clean indique que la session est
non persistante, et constitue en même temps une directive pour effacer une
éventuelle session existante), et enfin la valeur du keepalive.
Le corps du message est composé de l’identifiant du client (chaine utf8
préfixée par sa longueur, pouvant être vide depuis MQTT 3.1.1), suivi par les
paramètres optionnels dans un ordre défini : le sujet et le corps du message
de testament, le nom d’utilisateur et son mot de passe.
2.3.2 CONNACK
L’entête du CONNACK est constitué d’un bit pour indiquer si le broker
possède déjà une session pour ce client, dans le cas où le client demande à
restaurer une session existante, et d’un code de retour sur un octet (seuls
les codes de 0 à 5 étant actuellement définis).
Figure 2.4 – Format d’un paquet CONNACK
01234567
Connack (2) 0
Remaining length (2)
fixed
header
SP
Connect return code
2.3.3 PUBLISH
Un paquet PUBLISH contient les valeurs DUP, QoS et Retain dans son
entête fixe, suivi par le sujet (taille puis chaine de caractères obligatoirement
non nulle), le packet identifier si le QoS est supérieur à zero, puis enfin le
corps du message, éventuellement vide.
CHAPITRE 2. LE PROTOCOLE MQTT 18
Figure 2.5 – Format d’un paquet PUBLISH
01234567
Publish (3) DUP QoS retain
Remaining length
...



fixed
header
topic length
topic name (utf8)
hhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh



1 to
216 − 1
bytes
packet identifier (optional)
payload (binary)
hhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh



0 to 228
bytes
2.3.4 PUBACK, PUBREC, PUBREL, PUBCOMP
Tous ces paquets ont la même structure, seules les valeurs du code de
commande et du champs Reserved peuvent varier.
Figure 2.6 – Format d’un paquet PUB[ACK/REC/REL/COMP]
01234567
Control type (4-7) Reserved
Remaining length (2)
fixed
header
packet identifier
2.3.5 SUBSCRIBE
Un paquet SUBSCRIBE comprend un identifiant pour la réponse, puis
une liste de souscriptions d’au moins un élément. La structure d’une sous-
CHAPITRE 2. LE PROTOCOLE MQTT 19
cription est composée d’un filtre (longueur et chaine de caractères) et de la
qualité de service demandée.
Figure 2.7 – Format d’un paquet SUBSCRIBE
01234567
Subscribe (8) 2
Remaining length
...



fixed
header
packet identifier
filter length
topic filter (utf8)
hhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh
QoS
...



1 to n
subscriptions
2.3.6 SUBACK
Dans un paquet SUBACK, le broker répond avec le même identifiant
de paquet, puis retourne les code de retour dans le même ordre que les
souscriptions du paquet SUBSCRIBE correspondant.
Ces codes de retour correspondent à la qualité de service garantie par le
broker (qui peut être inférieure à celle initialement demandée), ou le code
d’erreur 0x80 en cas de problème.
CHAPITRE 2. LE PROTOCOLE MQTT 20
Figure 2.8 – Format d’un paquet SUBACK
01234567
Suback (9) 0
Remaining length
...



fixed
header
packet identifier
return code
...
1 to n
return
codes
2.3.7 UNSUBSCRIBE
UNSUBSCRIBE ressemble beaucoup à SUBSCRIBE, à ceci près
que le client ne spécifie pas de qualité de service.
Figure 2.9 – Format d’un paquet UNSUBSCRIBE
01234567
Unsubscribe (10) 2
Remaining length
...



fixed
header
packet identifier
filter length
topic filter (utf8)
hhhhhhhhhhhhhhhhhhh
hhhhhhhhhhhhhhhhhhh
...



1 to n
subscriptions
2.3.8 UNSUBACK
UNSUBACK sert de confirmation pour UNSUBSCRIBE, et contient
simplement l’identifiant de paquet de la requête correspondante.
CHAPITRE 2. LE PROTOCOLE MQTT 21
Figure 2.10 – Format d’un paquet UNSUBACK
01234567
Unsuback (11) 0
Remaining length (2)
fixed
header
packet identifier
2.3.9 PINGREQ, PINGRESP
Ces deux paquets sont très simples, et sont constitués uniquement de
l’entête fixe du protocole, tenant ainsi sur deux octets.
Figure 2.11 – Format d’un paquet PING[REQ/RESP]
01234567
Control type (12-13) 0
Remaining length (0)
fixed
header
2.3.10 DISCONNECT
Sert à indiquer au broker l’intention du client de se déconnecter, et com-
porte uniquement l’entête fixe.
Figure 2.12 – Format d’un paquet DISCONNECT
01234567
Disconnect (14) 0
Remaining length (0)
fixed
header
2.4 Conclusion
Nous avons vu que MQTT est un protocole tout à la fois minimaliste et
très simple à mettre en œuvre (en particulier du coté client). Malgré tout,
il reste suffisamment souple et extensible pour suffire aux besoins d’un bon
nombre d’applications, et est donc particulièrement adapté au contexte de
l’IoT.
C’est la raison pour laquelle nous avons choisi ce protocole pour expé-
rimenter l’approche du test dirigé par les modèles, avec pour objectif de
CHAPITRE 2. LE PROTOCOLE MQTT 22
réaliser une modélisation du protocole capable de s’assurer des propriétés
que l’on doit être en mesure d’attendre des futurs « objets » d’Internet :
conformité avec la norme, interopérabilité des différentes implémentations,
respect des exigences de sécurité et tolérance aux erreurs.
Chapitre 3
Problématiques de
modélisation de MQTT
Modéliser un protocole afin d’en tester les applications est une opéra-
tion qui présente un intérêt évident dès lors que les tests engendrés vont
permettre d’apporter un certain degré de confiance aux produits testés.
Plus le protocole est couramment employé et les tests généralisables (ie.
applicables au plus grand nombre de produits), plus l’intérêt de ce type d’ap-
proche grandit. En effet, le coût de développement du test peut se trouver
élevé, mais il sera compensé par son potentiel de réutilisation pour tous les
produits ainsi que dans le temps 1.
Idéalement, on aimerait disposer d’un moyen de formaliser simplement
les exigences qui décrivent le protocole, avec un outil permettant de trans-
former ce formalisme en suite de tests garantissant une bonne couverture
de ces exigences. Une bonne modélisation devrait également permettre de
répondre à des objectifs divers, comme s’assurer des propriétés de robus-
tesse des implémentations, d’interopérabilité entre les différents produits,
de sécurité, etc.
Malheureusement, atteindre un tel niveau d’automatisation est loin d’être
trivial. Nous avons voulu d’abord explorer la réalisation d’un banc de test
basé sur les modèles spécifique au protocole MQTT, avec l’objectif d’iden-
tifier et de résoudre les problématiques soulevées, et, dans le cas où cet
exercice se trouverait concluant, d’en généraliser les conclusions à d’autres
protocoles sinon à d’autres approches.
Nous avons déjà montré au Chapitre 2 que les exigences de la norme
MQTT peuvent être divisées en deux parties, avec d’une part l’aspect fonc-
1. On pourra consulter la page du MQTT Interop Testing Day (https://wiki.
eclipse.org/Paho/MQTT_Interop_Testing_Day) pour trouver des détails sur la métho-
dologie adoptée pour les tests d’interopérabilité entre les diverses implémentations du
protocole.
23
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT24
tionnel du protocole, et d’autre part l’aspect de bas niveau concernant la
définition du format binaire des échanges.
En analysant plus en détail la norme MQTT, on s’aperçoit d’ailleurs
que certaines exigences ne sont pas accessible depuis l’interface habituelle
des clients et nécessitent un accès que l’on pourrait qualifier de bas niveau
pour être vérifiées (voir extrait en Table 3.1, les exigences de haut niveau
sont indiquées colonne + et celles de bas niveau colonne −).
Il nous a donc semblé judicieux de définir dans un premier temps un
modèle abstrait du protocole qui ne prenne pas en compte tous les détails
de bas niveau de la norme, et visant à activer les divers comportements
possibles afin de tester la partie fonctionnelle du protocole.
Par la suite, afin de valider le format des commandes échangées, ainsi
que de tester le comportement des différents composants et implémentations
MQTT en cas d’altération des paquets échangés, nous avons imaginé un
système permettant d’analyser et de modifier les trames à la volée.
Dans la première partie de ce chapitre (section 3.1) nous présentons les
problèmes soulevés par la modélisation abstraite envisagée et, le cas échéant,
les solutions proposées.
Puis dans la seconde partie (section 3.2), nous traitons de la mise au
point du test basé sur les fautes de protocole et altérations des échanges,
ainsi que de son intégration au sein de l’environnement de test.
Enfin, dans la dernière partie (section 3.3), nous conclurons par une
discussion sur le suivi des tests qui s’est avéré particulièrement délicat dans
notre contexte.
3.1 Model-Based-Testing du protocole
Pour la modélisation des aspects fonctionnels du protocole, nous avons
utilisé le paradigme de modélisation state-based à l’aide d’une modélisation
UML des différents composants et leurs opérations associées, ainsi que de
contraintes Pre/Post en OCL sur les différentes opérations du modèle per-
mettant de garantir les invariants définis par la norme MQTT.
L’objectif de cette étape étant de formaliser les aspects fonctionnels du
protocole, puis d’employer un moteur de génération de tests afin de trans-
former ce formalisme en suites de test visant à activer les différents compor-
tements possibles pour le protocole.
Nous n’entrerons pas ici dans les détails de la modélisation effectuée (ce
sera fait section 4.2), mais nous exposerons dans un premier temps les prin-
cipales problématiques que nous avons identifiées comme liées au contexte
particulier du test des applications MQTT.
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT25
Table 3.1 – Analyse du « niveau » de quelques exigences de la norme MQTT
Number Normative statement + -
1.5.3-2 A UTF-8 encoded string MUST NOT include an encoding of
the null character U+0000.
2.2.2-1 Where a flag bit is marked as “Reserved” in Table 2.2, it
MUST be set to the value listed in that table.
3.1.2-1 If the protocol name is incorrect the Server MAY disconnect
the Client, or it MAY continue processing the CONNECT
packet in accordance with some other specification.
3.1.2-4 If CleanSession is set to 0, the Server MUST resume commu-
nications with the Client based on state from the current Ses-
sion. If there is no Session associated with the Client identifier
the Server MUST create a new Session.
3.1.2-22 If the User Name Flag is set to 0, the Password Flag MUST
be set to 0.
3.1.3-7 If the Client supplies a zero-byte ClientId, the Client MUST
also set CleanSession to 1.
3.3.1-4 A PUBLISH Packet MUST NOT have both QoS bits set to 1.
3.3.2-2 The Topic Name in the PUBLISH Packet MUST NOT contain
wildcard characters.
3.8.4-1 When the Server receives a SUBSCRIBE Packet from a Client,
the Server MUST respond with a SUBACK Packet.
3.9.3-2 SUBACK return codes other than 0x00, 0x01, 0x02 and 0x80
are reserved and MUST NOT be used.
4.3.1-1 In the QoS 0 delivery protocol, the Sender MUST send a PU-
BLISH packet with QoS=0, DUP=0.
4.3.2-1 In the QoS 1 delivery protocol, the Sender MUST send a PU-
BLISH Packet containing this Packet Identifier with QoS=1,
DUP=0. MUST treat the PUBLISH Packet as "unacknowled-
ged" until it has received the corresponding PUBACK packet
from the receiver.
4.3.2-2 In the QoS 1 delivery protocol, the Receiver MUST respond
with a PUBACK Packet containing the Packet Identifier from
the incoming PUBLISH Packet.
4.3.3-1 In the QoS 2 delivery protocol, the Sender MUST send a PU-
BLISH packet containing this Packet Identifier with QoS=2,
DUP=0. MUST treat the PUBLISH packet as "unacknowled-
ged" until it has received the corresponding PUBREC packet
from the receiver. MUST send a PUBREL packet when it re-
ceives a PUBREC packet from the receiver. MUST treat the
PUBREL packet as "unacknowledged" until it has received the
corresponding PUBCOMP packet from the receiver.
4.3.3-2 In the QoS 2 delivery protocol, the Receiver MUST respond
with a PUBREC containing the Packet Identifier from the
incoming PUBLISH Packet. MUST respond to a PUBREL
packet by sending a PUBCOMP packet containing the same
Packet Identifier as the PUBREL.
4.4.0-1 When a Client reconnects with CleanSession set to 0, both
the Client and Server MUST re-send any unacknowledged PU-
BLISH Packets (where QoS > 0) and PUBREL Packets using
their original Packet Identifiers.
4.7.1-1 The wildcard characters MUST NOT be used within a Topic
Name.
4.7.3-1 All Topic Names and Topic Filters MUST be at least one
character long.
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT26
3.1.1 Sujet du test et observation
Rappelons ici que la définition du protocole englobe le comportement
de différents acteurs tels que le broker et les clients, qui forment un en-
semble d’interactions possibles très riche. Ainsi le système sous test (SUT)
comprendra généralement tous les acteurs dont on cherche à valider le com-
portement, tandis que nous définissons ici comme « sujet » du test le ou les
produits qui sont visés par un test en particulier.
Pour notre part, nous avons opté pour une modélisation globale du sys-
tème sans adopter de point de vue particulier (et notamment sans faire de
distinction selon les différents types de composants testés), ce qui pose la
question lors de l’exécution d’une suite de tests de savoir quel est le compo-
sant testé et comment l’observer en particulier.
En effet, pour des raisons d’interface, les composants directement ma-
nipulés lors d’un test ne seront pas nécessairement ceux dont on cherche
à valider le comportement. Ceci se traduit par une plus grande complexité
dans la mise en place de points d’observation, qui doivent se situer au niveau
macroscopique du système (par ex. en analysant les échanges réseau dans
leur ensemble, et pas seulement coté broker ou client).
Pour résoudre la question de l’identification des composants fautifs, on
utilisera autant que possible une implémentation de référence pour les parties
qui ne sont pas directement concernées par le test, mais il nous a également
paru souhaitable que le suivi des tests soit capable de distinguer quel est le
composant responsable de l’échec d’un test en particulier.
3.1.2 Non déterminisme
Il nous est vite apparu que les séquences d’actions qui font ici l’objet du
test (l’échange de messages entre différentes parties au sein du réseau) sont
essentiellement non déterministes.
En effet, l’aspect asynchrone des échanges fait que l’on ne peut pas tou-
jours contrôler l’ordre d’envoi et/ou de distribution des messages, et plus il
y a d’acteurs impliqués et donc de messages échangés entre les différentes
sources, plus l’incertitude quant à l’ordre des actions augmente.
Par ailleurs, les sujets du test (i.e. les différentes implémentations de
clients et brokers MQTT) ne proposent pas toujours une interface permet-
tant de contrôler finement ce qui se passe au niveau du protocole, ce qui
peut avoir pour effet d’aggraver l’incertitude en question.
En dernier lieu, certaines exigences de la norme MQTT concernant le
broker sont optionnelles (par ex. le support ou non de tous les niveaux de
QoS), et donnent lieu à différents comportements possibles dans certains
cas.
Cet aspect des choses rend le suivi du test beaucoup plus complexe,
les solutions permettant de contrôler l’exécution d’une suite de test non-
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT27
déterministe et donner un verdict étant plus délicates à mettre en œuvre
que pour un test déterministe. Également, certaines configurations seront
plus difficiles sinon impossibles à atteindre, du moment que l’on ne maitrise
pas totalement le déroulement du test.
3.2 Altération des échanges MQTT
Tester uniquement des composants concrets ne permet pas nécessaire-
ment d’activer toutes les erreurs possibles, ainsi il est nécessaire de pouvoir
transmettre des trames spécialement forgées avec des erreurs afin de s’assu-
rer une bonne couverture de test.
Afin de répondre à ce besoin, nous avons choisi d’ajouter un module
capable de modifier à la volée les trames MQTT échangées entre les compo-
sants sous test. Module qui peut être intercalé entre un broker MQTT et ses
clients tout en restant transparent pour les différentes parties, tel un proxy.
En mode analyse, ce proxy se contenterait d’analyser les paquets qui
transitent entre les différents composants, tandis qu’en mode d’injection
il permettrait de modifier les trames MQTT en prenant en compte leur
structure, ciblant ainsi avec précision les champs que l’on veut perturber et
les modifications que l’on souhaite apporter.
Pour mettre au point cet outil, il faut donc modéliser la structure binaire
des trames MQTT et le type des divers champs qui les constituent (cf.
section 2.3), afin de pouvoir leur appliquer des modifications pertinentes
pour le test en fonction du type des champs altérés, de leur valeur, etc.
L’intégration de ce modèle au sein du modèle général pose toutefois un
problème qui sera discuté plus bas. Il serait également possible d’envisager
une approche plus complète, en donnant à un composant intermédiaire la
possibilité de jouer alternativement le rôle du client ou du broker MQTT, et
ainsi de mieux maitriser l’ensemble du test. Mais cette approche reviendrait
à implémenter l’ensemble du protocole uniquement à des fins de test, ce qui
nous a paru trop couteux et impraticable dans le cas général.
3.2.1 Suivi et validation des trames
Un des avantages apportés par l’introduction de ce type de proxy est
qu’il autorise un suivi précis des trames échangées au niveau du réseau sans
avoir à utiliser un outil spécialisé comme un sniffeur de réseau. Ainsi il est
très facile d’enregistrer l’ensemble des trames échangées dans un fichier de
log pour une analyse ultérieure.
On peut également outiller le suivi des trames MQTT en y ajoutant
une validation des trames à la volée, ce qui permet de détecter facilement
les composants fautifs dans l’implémentation de la partie bas niveau du
protocole.
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT28
Ainsi, il est possible de suivre les trames entrant dans le proxy et d’en
contrôler la validité, tout en conservant la faculté d’appliquer des mutations
aux trames sortantes.
3.2.2 Critères de transformation
Dans une optique d’injection de données faussées, il convient d’établir
des critères de transformation pertinents pour les différents champs pré-
sents dans les trames, et de disposer d’un moyen efficace pour choisir et
appliquer ces transformations. Critères qui doivent être pris en compte pour
la modélisation des trames du protocole si l’on veut pouvoir effectuer des
modifications intéressantes dessus.
Pour cela, le type des champs et leur valeur peuvent être exploités afin de
sélectionner diverses catégories de mutations. Par exemple, on peut choisir
les valeurs aux limites en fonction du domaine de chaque champs, ou encore
de réaliser des mutations pour altérer certaines valeurs au plus proche. Il est
également très simple d’injecter des valeurs explicitement interdites par le
protocole pour faire du test de robustesse.
On pourra aussi décider de ne pas retransmettre une commande pour
perturber l’échange entre les clients et le broker, ou encore de couper la
connexion de façon intempestive pour simuler des problèmes de réseau.
3.2.3 Intégration
L’une des difficultés liées à cette approche réside dans le fait que l’outil
en question n’a pas une vision globale sur l’ensemble des échanges, et il lui
est donc difficile de choisir quelles transformations appliquer sur les données
à un moment donné.
Il est bien sûr possible d’appliquer des transformations aléatoires (fuz-
zing), mais l’on perdrait alors l’essentiel du bénéfice de la modélisation. Par
ailleurs, l’analyse des tests deviendrait dès lors beaucoup plus laborieuse,
puisque l’on ne va pas disposer d’un oracle permettant de connaitre auto-
matiquement le résultat attendu pour chaque test.
On peut également envisager des approches plus évoluées dans lesquelles
le proxy serait intégré dans un système de modélisation plus général et piloté
par ce dernier. Il faut pour cela que la modélisation prenne en compte le
format binaire du protocole en question, le proxy devenant alors un simple
exécutant des séquences prévues.
3.3 Analyse des tests
La nature des problématiques évoquées plus haut complexifie largement
le processus de suivi automatisé des suites de test.
CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT29
D’une part, l’aspect non déterministe pose des difficultés pour établir et
vérifier le verdict de chaque cas de test, puisqu’il n’existe pas qu’une seule
trace d’exécution valide possible mais bien plusieurs. Pour pallier à cela, il
faut donc vérifier que la trace obtenue correspond bien à l’une des traces
possibles.
Même sans cette difficulté, le résultat d’une séquence de test n’est pas
toujours exprimable par un résultat précis (par ex. vérifier si tel message est
bien reçu ou non), car il faut vérifier que le protocole a été respecté de bout
en bout.
Pour ces raisons, il nous parait souhaitable de doter le modèle de la ca-
pacité d’analyser le passage d’un test en vérifiant tout au long de l’exécution
que les invariants définis sont bien respectés, autrement dit que la trace cor-
respond bien à un chemin d’exécution possible du modèle. Il ne s’agit pas
seulement ici de générer le test en mode online, mais bien de suivre son
exécution pas à pas à l’aide du modèle.
Le détail des commandes échangées par le protocole devrait dans la plu-
part des cas constituer une trace suffisante pour effectuer ce type d’analyse.
En ce qui concerne l’idée de test à base de mutations des trames, si l’on se
contente de modéliser uniquement la partie bas-niveau du protocole, il sera
impossible de prédire quelle est la réaction attendue pour une grande partie
des modifications possibles.
Pour autant, certaines transformations devraient systématiquement don-
ner lieu à une coupure de la connexion, et sont donc facilement vérifiables.
Pour les autres, elles peuvent être pilotées depuis un système extérieur pro-
posant des modifications ciblées, soit faire l’objet d’une analyse manuelle ou
se limiter à vérifier que le SUT ne tombe pas en panne (crash) à cause d’une
trame mal formée.
Chapitre 4
Travail réalisé
Une partie de notre travail de recherche a consisté en l’expérimenta-
tion de l’approche de modélisation envisagée au chapitre précédent. Nous
présentons ces contributions dans ce chapitre.
Nous avons commencé par modéliser l’aspect fonctionnel de MQTT avec
l’outil CertifyIt de Smartesting, qui nous a permis de construire un modèle
abstrait du protocole. Notre modèle inclut la plupart des fonctionnalités
et exigences définies par la norme sous forme de contraintes, et permet de
générer des suites de test en conséquence.
Faute de temps, nous n’avons pu compléter cette modélisation, mais
l’exercice devrait être pleinement réalisable.
L’outil évoqué en section 3.2 a été partiellement réalisé, à travers la mo-
délisation binaire des trames du protocole et le développement du proxy
MQTT envisagé.
Pour le reste, nous avons dû réviser une partie de nos ambitions à la
baisse. La validation des trames à la volée a été implémentée, ainsi que le
mode de fuzzing autonome, mais nous n’avons pas exploité la possibilité de
piloter le proxy à partir du modèle.
Les suites de tests ont été rendues exécutables grâce à l’export des tests
en python et l’écriture d’un adaptateur approprié pour un client MQTT de
notre choix.
La plus grande difficulté a sans doute été l’établissement du verdict pour
les cas de test. Nous nous sommes finalement contentés de générer les sé-
quences de messages attendues pour chaque cas de test, qui ont fait l’objet
d’un contrôle manuel.
Dans la section 4.1, nous présentons les principaux outils utilisés pour les
expérimentations, depuis la phase de modélisation jusqu’à celle de l’analyse
30
CHAPITRE 4. TRAVAIL RÉALISÉ 31
des tests.
Ensuite, à la section 4.2, nous détaillerons la modélisation de la partie
fonctionnelle du protocole avec CertifyIt, ainsi que de l’export des suites de
tests dans un environnement exécutable.
Dans la section 4.3 nous décrirons la mise en œuvre d’un proxy MQTT
doté de fonctionnalités adaptées à notre banc de test.
Enfin, nous dresserons le bilan de nos expérimentations en section 4.4.
4.1 Outils utilisés
4.1.1 Smartesting CertifyIt
CertifyIt est une chaine d’outils dédiée au Model-Based Testing, basée sur
le langage UML pour la modélisation et le langage OCL (Object Constraint
Language) pour l’expression des contraintes sur les modèles.
Fruit d’une collaboration entre l’institut Femto-ST et la compagnie Smar-
testing, CertifyIt permet de modéliser un système sous test (SUT) et de
générer automatiquement des suites de test selon différents critères, à partir
des contraintes indiquées dans le modèle.
Figure 4.1 – CertifyIt - vue de l’éditeur UML
Le logiciel est divisé en deux parties :
— un éditeur de modèles (Figure 4.1) sous la forme d’un plugin pour
Rational Software Architect Designer d’IBM (lui même reposant sur
Eclipse), qui permet de modéliser le SUT, de définir les critères de
CHAPITRE 4. TRAVAIL RÉALISÉ 32
sélections de tests, et d’exporter le tout dans un format supporté par
le générateur de tests ;
— un générateur de tests (Figure 4.2) avec différentes fonctionnalités
telles que le suivi des exigences, des contraintes activées pour chaque
test, l’export des tests en divers formats d’exploitation (comme XML,
ou encore JUnit).
Figure 4.2 – CertifyIt - vue du générateur de tests
Modélisation
La notation UML employée est un sous ensemble d’UML2, restreint
aux besoins du test dirigé pas les modèles, appelé UML4MBT. La nota-
tion OCL pour les contraintes est également restreinte à un sous ensemble
appelé OCL4MBT.
Seuls trois types de diagrammes UML sont supportés :
— les diagrammes de classes, utilisés pour modéliser les variables du sys-
tème, ainsi que les points de contrôle et d’observation ;
— les diagrammes d’états-transitions, qui permettent de modéliser la dy-
namique du système ;
— les diagrammes d’objets, qui permettent de définir les instances d’ob-
jets qui serviront pour le test.
Les expressions OCL servent deux objectifs bien distincts :
CHAPITRE 4. TRAVAIL RÉALISÉ 33
— d’une part, à exprimer les conditions associées aux objets du modèle,
en définissant les pré-conditions de certaines opérations du diagramme
de classes, et les gardes sur les transitions du diagramme d’états.
— d’autre part, à formaliser le comportement du modèle en termes d’ac-
tions qui vont modifier l’état du système, grâce aux post-conditions
des opérations et aux effets des transitions.
Pour remplir ces deux rôles, la sémantique de OCL4MBT dépend du
contexte, le sens des expressions pouvant être soit déclaratif comme dans le
cas d’OCL, soit exprimeront le comportement des opérations à la façon d’un
langage de programmation.
Sélection des tests
L’approche du test dirigé par les modèles emploie des critères de sélection
divers pour dériver les cas de test à partir du modèle.
Avec CertifyIt, le critère de sélection principal consiste à activer les com-
portements qui ont été modélisés (behavioral test objectives). Il est possible
de sélectionner l’ensemble des méthodes qui seront utilisés pour une suite
de tests donnée (test fixtures) parmi les méthodes publiques du modèle.
D’autres critères peuvent aussi être utilisés, comme avec les test purposes
qui permettent de formaliser différents scénarios que le générateur de tests
cherchera à satisfaire.
4.1.2 Eclipse Paho project
Le projet Paho 1 de la fondation Eclipse a pour vocation de fournir des
implémentations open-source de qualité pour les protocoles de messaging
ouverts et standardisés, dans le but de favoriser l’émergence de nouveaux
produits et applications liés à l’Internet des Objets.
Le projet a été initialement lancé dans le but de fournir des implémen-
tations MQTT pour les plateformes embarquées, et propose aujourd’hui des
clients MQTT pour différents langages de programmation.
Nous nous somme intéressés en particulier à l’implémentation python
du projet, afin d’en étudier son code source et avec l’intention de s’en servir
comme candidat au test.
paho.mqtt.python
paho.mqtt.python provient à l’origine du client python Mosquitto de
Roger Light, qui l’a mis à la disposition du projet Paho et continue son
développement. Le projet est actuellement disponible sur github à l’adresse
https://github.com/eclipse/paho.mqtt.python, et constitue sans doute
l’implémentation open-source de référence en python.
1. https://wiki.eclipse.org/Paho
CHAPITRE 4. TRAVAIL RÉALISÉ 34
Dans un premier temps, nous avons étudié son fonctionnement à l’aide
du code source. Ainsi nous avons pu relever un certain nombre de bugs et
d’anomalies vis-a-vis du protocole qui ont été rapportées sur le bugtracker
du projet 2.
Ceci nous a fait prendre pleinement conscience de l’importance de pou-
voir tester extensivement ces produits, qui malgré le fait d’être open-source
et de disposer d’un bon nombre d’utilisateurs, peuvent tout de même com-
porter divers bugs.
Par la suite, c’est l’implémentation que nous avons choisi d’utiliser coté
client pour nos expérimentations, qui ont été réalisées avec le langage python
et que nous présentons aux sections suivantes.
4.1.3 Wireshark
Wireshark est un analyseur de paquets réseau disposant d’une foule de
fonctionnalités avancées (en particulier un sniffer très pratique à utiliser et
des filtres), et le support de très nombreux protocoles dont MQTT 3 .
Figure 4.3 – Wireshark 2.0.5 - vue du logiciel
Ce logiciel est couramment utilisé dans le monde de l’éducation afin de
permettre aux étudiants de mieux comprendre les protocoles réseau. Nous
2. https://github.com/eclipse/paho.mqtt.python/issues/created_by/yoch
3. Depuis la version 1.12 du 31 Juillet 2014. A noter que MQTT-SN est également
supporté depuis la version 2.0.
CHAPITRE 4. TRAVAIL RÉALISÉ 35
l’avons exploité de deux manières, d’une part afin de mieux comprendre
certains aspects du protocole MQTT, et d’autre part pour l’analyse manuelle
de certains tests.
Dans la capture d’écran visible Figure 4.3, on peut voir que le filtrage
du protocole MQTT est activé, la liste des paquets interceptés est visible
dans le cadre du haut, et dans celui du milieu et celui du bas sont représentés
le contenu du paquet sélectionné (structure détaillée et données binaires).
4.2 Modélisation fonctionnelle du protocole MQTT
Le Model Based Testing suit généralement le processus suivant [15] :
1. Construction du modèle de test d’après les spécifications produit, qui
doit proposer le bon niveau d’abstraction pour permettre de générer
des cas de tests en rapport avec les exigences.
2. Choix de critères de sélection de test, en fonctions des objectifs et de
la politique de test. Ces critères seront transformés en spécifications
sur les cas de test à générer.
3. Génération de la suite de test, éventuellement en optimisant le nombre
de tests produits.
4. Exécution des tests, qui peut être manuelle ou automatisée. Il s’agit
tout d’abord de concrétiser les cas de test, puis d’envoyer les données
au SUT, et d’observer les résultats.
Usuellement, on utilise un adaptateur pour cette tâche, qui sert à
adapter les cas de test au SUT et les sorties du SUT à l’outil de test
qui va les comparer avec le résultat attendu.
Pour notre expérimentation, le processus adopté se représente comme
suit (Figure 4.4) :
Figure 4.4 – Processus du test de MQTT basé sur les modèles
— La modélisation du protocole a été effectuée en UML/OCL ;
— Génération des suites de tests aux critères dits behavioral test objectives
avec l’outil CertifyIt, qui sont ensuite exportés en XML ;
— Ce fichier XML nous permet de générer un script pour piloter les
tests, ainsi que le squelette du code python pour l’adaptateur, qui sera
complété manuellement pour permettre l’exécution des tests sur une
cible donnée ;
CHAPITRE 4. TRAVAIL RÉALISÉ 36
— Les tests sont exécutés à l’aide script python et produisent une trace
d’exécution pour chaque test ;
— Les logs servent pour l’analyse des résultats du test, en les comparant
avec la trace attendue par le modèle.
4.2.1 Mise en œuvre
Nous avons réalisé une modélisation de la partie fonctionnelle du proto-
cole MQTT en UML/OCL à l’aide de CertifyIt (Figure 4.5). Dans ce qui
suit nous retraçons les grandes lignes de cette contribution.
Figure 4.5 – Modélisation UML du protocole MQTT
Détail du modèle
Les composants UML principaux sont les classes Broker et Client, le
broker pouvant prendre en charge simultanément la connexion de plusieurs
clients. Chaque client connecté maintient une Session lui permettant de
contrôler le transit des messages, tandis que le broker maintient une Session
pour chaque client.
CHAPITRE 4. TRAVAIL RÉALISÉ 37
Un client peut être soit déconnecté, soit connecté au broker sans avoir
initié un échange MQTT, soit connecté avec une session en cours. Le premier
aspect est géré par une relation one-to-many entre le broker et les clients
modélisant la connexion TCP, tandis que le second aspect est géré à l’aide
d’un booléen indiquant que la session est commencée.
Coté broker, la gestion des identités des clients se fait à l’aide de la
classe Identifier qui représente simplement un couple login / mot de passe.
Une méthode register permet de modéliser l’ajout de nouveaux couples
d’identifiants (login et mot de passe).
Quant à la gestions des abonnements, elle est gérée par le broker avec
la classe Subscription, et est limitée ici au filtrage des motifs par corres-
pondance exacte pour des raisons de simplicité. Lorsqu’un client envoie une
demande d’abonnement avec la méthode subscribe, le broker crée un nouvel
abonnement avec l’identifiant du client, le filtre de sujet et la qualité de ser-
vice requise, et l’ajoute à sa liste d’abonnements. La méthode unsubscribe
provoque à l’inverse la suppression d’un abonnement existant.
La classe Message modélise les messages véhiculés par le protocole et
contient les informations permettant de suivre l’évolution de l’état de trans-
mission d’un message. Cet état est régi par un système d’états / transitions
implicite codé dans les post-conditions OCL.
Gestion des types chaines de caractères
Le type chaines de caractères n’étant pas supporté par CertifyIt, nous
l’avons substitué par des énumérations destinées à représenter des types de
données particuliers, comme par exemple un mot de passe.
Gestion des échanges asynchrones
Dans une première version de notre travail, l’enchainement des actions
était réalisée par des appels de méthodes imbriqués, ce qui rendait le modèle
totalement synchrone et peu satisfaisant. Il était en effet impossible de pro-
voquer une seconde action avec effet de bord tout au long de l’enchainement
des actions déclenché par telle ou telle méthode (par exemple de couper la
connexion au cours d’un échange de trames servant à valider la réception
d’un message).
C’est pourquoi, nous avons modifié le modèle initial en limitant l’en-
semble des méthodes à un seul échange réseau, la suite de l’enchainement
étant assurée par la méthode process_messages. Ainsi le générateur de
tests peut ou non employer cette méthode pour influer sur le déroulement
du test.
CHAPITRE 4. TRAVAIL RÉALISÉ 38
Annotations pour le suivi des exigences
Les post-conditions ont été documentées à l’aide du mécanisme d’anno-
tation de CertifyIt afin de permettre le suivi des exigences.
Diagramme d’objets
CertifyIt requiert de créer les instances et relations nécessaires au test
dans un diagramme d’objet.
Pour plus de souplesse, le modèle a été conçu pour être aussi dynamique
que possible. Aussi, les relations n’ont pas été établies au sein du diagramme
d’objets, mais sont manipulables à l’aide des méthodes définies par le modèle,
ce qui permet au générateur de créer ou supprimer des relations en fonction
des besoins.
4.2.2 Fonctionnalités modélisées
La plupart des fonctionnalités de MQTT mentionnées section 2.1 ont été
modélisées, certaines n’ayant toutefois pas pu l’être faute de temps.
Comme vu en section 2.2, peu d’aspects de sécurité sont directement
pris en charge par le protocole, mais reposent plutôt sur des mécanismes
connus comme SSL ou sont relégués à des extensions non normalisées voire
au domaine applicatif. Le seul point de sécurité qui a donc été introduit
dans notre modèle est celui de l’authentification des clients.
Nous présentons dans ce qui suit l’essentiel des fonctionnalités modéli-
sées, accompagnées de quelques illustrations concrètes.
Connexion
Les principaux aspects de l’enregistrement auprès du serveur (envoi du
paquet CONNECT et réponse) ont pu être modélisés :
— toute connexion doit débuter par un CONNECT ;
— pas de double CONNECT ;
— gestion du renouvellement de session ;
— authentification des clients ;
La dimension temporelle impliquée par le keepalive n’a pas été introduite
dans le modèle car trop complexe pour un gain relativement faible (seule les
commandes PINGREQ et PINGRESP sont concernées, et leur validation ne
pose pas de problème particulier).
Un exemple de postcondition OCL pour la gestion du CONNECT par
le broker est proposé Figure 4.6. On y trouve l’interdiction d’un double
CONNECT ainsi que celle de restaurer une session pour un client anonyme,
les autres exigences étant traitées par des méthodes auxiliaires.
CHAPITRE 4. TRAVAIL RÉALISÉ 39
Figure 4.6 – Postcondition OCL pour handle_connect()
Abonnements et Publications
Le mécanisme d’abonnement et ses différentes commandes est lui aussi
modélisé :
— vérification (partielle) de la validité des sujets ;
— vérification de la validité de la qualité de service requise ;
— gestion des abonnements et réponse du broker ;
— gestion des publications ;
Cependant, certains détails du protocole ont été simplifiés par commo-
dité, notre modèle ne prenant pas en charge les abonnements multiples.
Qualité de service et Persistance
La gestion des échanges impliqués par les différentes qualités de service
a également pu être modélisée :
— support des différentes réponses : PUBACK, PUBREC, etc.
— mise des messages en file d’attente de la session pour gérer les décon-
nexions ;
— gestion des identifiants de paquets ;
L’aspect asynchrone des échanges a été modélisé avec l’approche détaillée
en section 4.2.1. On peut voir l’essentiel du traitement asynchrone du coté
client Figure 4.7, l’état des messages en file d’attente pouvant changer dès
lors que le générateur fait appel à process_messages() 4 .
4. Il serait également possible de modifier l’état d’un seul message dans la file d’attente,
mais ceci surchargerait à coup sûr le générateur.
CHAPITRE 4. TRAVAIL RÉALISÉ 40
Figure 4.7 – Postcondition de process_messages() coté client
Messages retenus et Testament
Ces deux aspects du protocole n’ont pas été modélisés par manque de
temps, mais ne devraient pas poser de problème particulier.
4.2.3 Génération des tests
Afin de distinguer les différents objectifs de test, nous avons créé plusieurs
suites de test avec différentes cibles : test de l’identification des clients, test
des publications de messages, etc. Pour ce faire, nous avons sélectionné pour
chaque suite des sous-ensembles de fixtures utilisables parmi les méthodes
publiques du modèle, ce qui laisse au générateur un choix restreint d’actions
disponibles pour dériver les cas de tests.
Nous avons été confrontés à quelques problèmes à ce stade, le plus no-
table étant le temps de génération qui pour certaines séquences de test peut
devenir prohibitif. C’est l’une des raisons pour laquelle nous avons décidé
de ne pas modéliser les aspects de bas niveau du protocole dans le même
CHAPITRE 4. TRAVAIL RÉALISÉ 41
modèle, ce qui l’aurait sans doute rendu inutilisable pour générer des tests.
Pour concrétiser et exécuter nos tests, nous avons choisi de transformer les
suites de tests générés avec CertifyIt en scripts python. Pour ce faire, nous
avons utilisé l’export depuis CertifyIt vers XML, puis employé un petit script
pour transformer ce fichier XML en modules et scripts python nécessaires à
l’exécution des tests. On trouvera un extrait d’une des suites de tests ainsi
générées en Annexe A.1.
Une fois cette étape terminée, il faut encore compléter l’écriture de
l’adaptateur qui permettra au code généré de piloter un client ou un broker
existant. Réaliser l’adaptateur se résume à établir un pont entre les diffé-
rentes méthodes publiques du modèle et l’implémentation sous test.
Nous avons utilisé le client python du projet Paho, qui a demandé très
peu d’efforts pour écrire l’adaptateur (voir Annexe A.2). En revanche, notre
suite de tests qui emploie l’interface du broker n’est pas exécutable en l’état.
4.2.4 Verdict
Au vu de la difficulté de poser un verdict sur l’exécution d’un test (évo-
quée ci-dessus section 3.3), la stratégie que nous avons retenue consiste à
comparer les trames virtuellement échangées au niveau du modèle avec celles
réellement échangées par le SUT.
Nous avons pour cela instrumenté le modèle afin de pouvoir extraire les
séquences de trames échangées à partir des cas de test, et stocké ces dernières
dans un fichier généré en même temps que le script de test.
D’autres problématiques sont alors apparues, comme le fait que les iden-
tifiants de paquet ne peuvent être maitrisées depuis le modèle et requièrent
un traitement particulier lors de la comparaison, ou la question de faire cor-
respondre les entités du modèle avec celles des trames réellement échangées,
etc.
Par ailleurs, nous avons relevé que l’implémentation du client a parfois un
comportement préventif et empêchera une action interdite que l’on cherche
à tester, ce qui introduit des faux positifs dans les résultats de test.
Enfin, il s’est avéré que l’aspect asynchrone du système empêche de pré-
dire le résultat attendu dans certains cas de tests qui deviennent non déter-
ministes, puisque l’on ne peut contrôler l’enchainement exact des actions.
Pour toutes ces raisons, cette étape n’a encore pu être complètement
automatisée.
4.3 Proxy de test MQTT
L’architecture logicielle du proxy MQTT évoqué au chapitre précédent
(section 3.2) est celle d’un serveur capable de maintenir des couples de
connexions entre les clients et le broker.
CHAPITRE 4. TRAVAIL RÉALISÉ 42
Figure 4.8 – Architecture du proxy de test MQTT
Comme on peut le voir Figure 4.8, le proxy est donc capable de rester
transparent et se contenter d’analyser le trafic (client 1), mais peut aussi
modifier à la volée voire supprimer les trames échangées dans les deux sens
(client 2).
4.3.1 Réalisation
Nous avons écrit un petit proxy pour MQTT en python sur la base de
l’architecture proposée et mis son code à disposition sur GitHub 5.
Ce proxy consiste en un serveur TCP multi-threads. Il est configuré
en lui donnant l’adresse du broker que l’on veut substituer, et va attendre
les connexions des clients sur son adresse propre. Pour chaque client qui se
connecte, il ouvre une connexion client vers le broker, et transmettra ensuite
les trames MQTT de part et d’autre.
4.3.2 Modélisation du protocole
Si un simple proxy MQTT n’a nullement besoin de reconnaitre le proto-
cole sous-jacent pour fonctionner, les fonctionnalités de validation et d’alté-
ration des trames imposent de modéliser la structure des trames du protocole
pour pouvoir les manipuler.
Nous avons donc réalisé une bibliothèque capable de décoder des trames
MQTT, éventuellement les modifier, et les restituer sous forme binaire (voir
extraits du fichier mqtt_protocol.py en Annexe A.3).
La conception est orientée objet, toute trame MQTT étant représen-
tée par un objet de type MQTTPacket qui comporte l’entête fixe et un ob-
jet MQTTBody pour le reste du paquet. Différentes sous-classes héritent de
MQTTBody et seront utilisées en fonction du type de paquet reçu.
5. https://github.com/yoch/MQTT-Proxy
CHAPITRE 4. TRAVAIL RÉALISÉ 43
Toutes ces classes comportent des méthodes _decode et _encode per-
mettant respectivement de décoder une trame binaire reçue pour initialiser
l’objet ou de créer une trame binaire depuis un objet. Ainsi chaque trame
entrante est transformée en objet, et peut être reconvertie en trame binaire
avant de la transmettre de l’autre coté.
D’autres méthodes ont ensuite été ajoutées aux objets afin de les enrichir
en fonctionnalités, comme check qui permet de vérifier la validité d’une
trame à l’aide d’assertions et remonte en cas d’erreur un code permettant
de connaitre exactement quelle portion de la norme est en cause.
4.3.3 Intégration au script de test
Notre proxy s’est avéré très utile pour s’intégrer au processus de test.
En effet, il permet de :
— valider la structure binaire des trames échangées, ce qui n’est pas pris
en charge par la modélisation fonctionnelle évoquée plus haut ;
— récupérer simplement l’ensemble des trames échangées pour chaque
cas de test, dans le but de valider ou non ledit cas.
L’architecture finale du processus de test est schématisée Figure 4.9.
On peut voir que même si le système est composé d’un broker et d’un client,
il suffit d’initier des actions sur le client (qui sert d’interface) pour que
l’ensemble des échanges soit récupéré par le proxy et analysé.
Figure 4.9 – Notre processus du test pour MQTT
CHAPITRE 4. TRAVAIL RÉALISÉ 44
4.4 Bilan
Nous présentons ici les résultats de nos expérimentations avec le modèle
décrit ci-dessus.
4.4.1 Tests générés avec CertifyIt
Nous avons généré deux suites de tests avec CertifyIt, soit en tout une
quarantaine de tests :
TestAuth visant à tester les fonctionnalités d’authentification, avec 11 tests
générés ;
TestPublish pour tester le fonctionnement du Publish/Subscribe tel que
défini par MQTT, avec 27 tests générés.
On peut voir en Table 4.1 le nombre de scénarios du modèle atteints et
le nombre de scénarios que le générateur n’a pas pu atteindre pour chaque
suite de test 6.
Sont également indiqués le nombre d’exigences couvertes pour chaque
suite de test. Il convient ici de préciser que ce décompte n’est pas lié aux
exigences définies par la norme MQTT, chaque exigence dont il est ques-
tion ici décrit un comportement complet qui peut inclure un grand nombre
d’exigences normatives.
Table 4.1 – Statut de la génération des scénarios et couverture des tests
reached undetermined covered uncovered
TestAuth 36 3 5 16
TestPublish 97 13 21 1
En sachant que tous les aspects fonctionnels du protocole n’ont pas en-
core été modélisés, ces résultats nous semblent encourageants. Le principal
souci à ce stade reste le temps de génération et la difficulté d’atteindre cer-
tains scénarios, sans doute de par la complexité du modèle.
4.4.2 Modélisation du format des trames
La modélisation du format binaire des trames MQTT a été réalisée ad-
hoc en langage python, d’une part pour éviter de surcharger le modèle initial,
et d’autre part afin d’en faire bénéficier notre proxy.
L’ensemble des commandes MQTT a été ainsi formalisé, ainsi que toutes
les exigences définies par la norme à ce sujet. En revanche, nous n’avons
6. Nous ne relevons pas ici les scénarios marqués comme unreachable car ils sont la
conséquence du choix des fixtures pour chaque suite de test. A noter également que nous
avons limité la profondeur de recherche à 10 à cause de problèmes de mémoire et de
lenteur.
CHAPITRE 4. TRAVAIL RÉALISÉ 45
pas exploité ce modèle pour générer des cas de test, mais surtout pour la
validation des trames transitant par notre proxy.
Un module permettant de faire du fuzzing en altérant les échanges MQTT
a également été développé par dessus ce modèle, avec la possibilité de mo-
difier les champs selon des critères établis (par ex. test aux limites), mais
nous n’avons pas approfondi cette voie.
4.4.3 Exécution des test
Nous avons pu réaliser la couche d’adaptation pour le client en python
sans difficulté notable, ce qui nous permet d’exécuter la seconde suite de
tests. Pour pouvoir exécuter la première suite de tests, il reste à écrire l’adap-
tateur vers un broker de notre choix. De la même façon, tester une autre
implémentation de client nécessite l’écriture d’une couche d’adaptation spé-
cifique.
Le proxy a également été intégré dans le processus de test avec succès,
ce qui nous permet de valider le format des trames échangées entre le broker
et les clients, ainsi que d’obtenir la trace des échanges entre le broker et les
clients.
L’extraction des séquences de trames attendues à partir du modèle a
nécessité d’introduire certaines conventions dans le modèle et d’écrire un
outil spécifique permettant d’obtenir ces séquences depuis les cas de test.
Toutefois, la validation des tests exécutés pose quant à elle un défi bien
plus important, et nous n’avons pas été en mesure d’automatiser le processus
pour les raisons invoquées en section 4.2.4. C’est pourquoi, nos tests sont
pour l’instant analysés et validés manuellement.
4.4.4 Validation
On trouvera en Annexe B la trace produite par les 27 cas de la suite de
tests TestPublish. Nous avons étudié attentivement l’ensemble des résul-
tats :
— 9 cas de tests provoquent une exception du coté client. Parmi ces cas, 5
d’entre eux correspondent à une protection ajoutée par l’implémenta-
tion, et 4 d’entre eux proviennent d’un bug du client. Tous ces derniers
cas sont liés à une mauvaise gestion de la taille maximale des sujets ;
— 2 cas de tests impliquant des sujets invalides (contenant un caractère
null) provoquent une exception du proxy. Deux brokers différents ont
été testés sur ce cas par la suite, tous deux présentant des défauts
(dans les deux cas pour Mosquitto, dans un seul pour HiveMQ) ;
— Le problème de non déterminisme évoqué plus haut est bien visible,
la plupart des séquences différant de celle attendues, que ce soit pour
une raison d’ordre ou de trames supplémentaires ;
CHAPITRE 4. TRAVAIL RÉALISÉ 46
— Le client python Paho a comme particularité de se reconnecter au-
tomatiquement en cas de déconnexion du broker, ce qui ajoute des
échanges de messages inattendus ;
— Les comportements testés sont variés, mais l’on ne peut prétendre
qu’ils soient exhaustifs, et certains cas de tests ne sont pas bien diffé-
renciés (semblent redondants ou peu pertinents).
— Le modèle semble cohérent, toutes les traces produites étant parfai-
tement valides, même si notre introduction de l’asynchronisme peut
donner des traces plus courtes que dans la réalité.
Chapitre 5
Conclusion
Notre travail nous a permis d’étudier l’application du test dirigé par les
modèles au domaine de la communication au sein de l’Internet des objets,
et plus globalement aux problématiques liées au réseau.
Même si le protocole MQTT n’est pas nécessairement représentatif de
toute la complexité de cette question, et malgré le fait que notre travail
puisse être encore complété et approfondi, nous avons pu tirer quelques
enseignements importants de notre expérimentation et des difficultés que
nous avons rencontrées.
Tout d’abord, il faut remarquer que la nature même des applications
distribuées sur le réseau complexifie fortement la modélisation : il faut en
effet prendre en compte la multiplicité des composants qui font partie du
système ou de son environnement, ainsi que de l’asynchronisme fréquent des
communications qui tend à rendre le modèle non-déterministe.
Mais cette complexité impacte aussi l’observation du système sous test,
comme nous l’avons développé dans ce document. Le modèle doit permettre
d’analyser l’ensemble du système, y compris les composants qui ne sont pas
sous le contrôle du testeur, de valider l’ensemble des échanges, et d’identifier
les éventuels responsables d’un échec.
L’usage de CertifyIt pour cette expérience nous a fait prendre conscience
de certaines limites de l’outil. Il est notamment incapable de produire ou
d’exploiter des diagrammes de séquence, et ne supporte pas bien les mo-
dèles non-déterministes. La comparaison avec les solutions de modélisation
existant dans le monde des télécommunications nous parait particulièrement
intéressante à cet égard [2].
Même en envisageant l’usage d’autres outils voire d’autres paradigmes
de modélisation pour le test des systèmes connectés, nous pensons que la
réflexion devra passer par l’anticipation des problèmes que nous avons ren-
contré dans notre exploration de la question.
47
CHAPITRE 5. CONCLUSION 48
Notre contribution pourrait servir de base pour la validation des implé-
mentations MQTT existantes. Peu d’outils existent encore à ce sujet, le seul
dont nous ayons connaissance étant celui de Ian Craggs 1, également basé sur
le concept model-based testing [3] mais qui se distingue de notre approche
par son orientation ad-hoc.
Il est toutefois intéressant de noter que l’auteur s’est trouvé confronté à
des questions similaires, et que les réponses apportées vont souvent dans le
même sens que notre travail.
Pour notre recherche, nous nous sommes focalisés essentiellement sur les
questions de conformité et d’interopérabilité des implémentations. La di-
mension évolutive de notre modèle n’a pas été étudiée, mais n’en reste pas
moins intéressante à évaluer, les normes pouvant évoluer.
Les aspects de sécurité du protocole pourraient quant à eux faire l’objet
d’une étude séparée, même si comme nous l’avons montré une grande part
de cette problématique est déléguée aux applications et ne dépend pas du
protocole.
1. https://github.com/eclipse/paho.mqtt.testing
Bibliographie
[1] Andrew Banks et Rahul Gupta. MQTT Version 3.1.1. Rapp. tech.
OASIS standard, 2014.
[2] Conformiq. Testing Bluetooth Protocol Stacks with Computer-Generated
Tests. Rapp. tech. url : https://www.conformiq.com/wp-content/
uploads/2015/02/Bluetooth-Technology-Brief.pdf.
[3] Ian Craggs. More Rigorous Testing for MQTT Servers. Model-Based
Testing. 18 oct. 2014. url : http://modelbasedtesting.co.uk/?p=
144 (visité le 29/06/2016).
[4] ETSI. « Methods for Testing and Specification (MTS) ; Model-Based
Testing (MBT) ; Requirements for Modeling Notations ». In : ETSI
ES (2011).
[5] Gartner Says 6.4 Billion Connected. url : http://www.gartner.
com/newsroom/id/3165317 (visité le 07/01/2016).
[6] JoramMQ, a distributed MQTT broker for the Internet of Things.
Sept. 2014. url : http://www.scalagent.com/IMG/pdf/JoramMQ_
MQTT_white_paper-v1-2.pdf.
[7] Valerie Lampkin et al. Building Smarter Planet Solutions with MQTT
and IBM WebSphere MQ Telemetry. en. IBM Redbooks, sept. 2012.
isbn : 978-0-738-43708-8.
[8] Object Constraint Language, v2.4. Rapp. tech. www.omg.org, fév. 2014.
url : http://www.omg.org/spec/OCL/2.4.
[9] Andy Piper. Eclipse Paho Progress Report. EclipseCon 2012, avr.
2012. url : http://www.slideshare.net/andypiper/eclipse-
paho-progress-report-eclipsecon-2012 (visité le 13/09/2016).
[10] Protocol Analysis. Juin 2014. url : http://www.onem2m.org/images/
files/deliverables/TR-0009-Protocol_Analysis-V0_7_0_1.
pdf.
[11] Andy Stanford-Clark. « Integrating monitoring and telemetry de-
vices as part of enterprise information resources ». In : WebSphere MQ
Integrator (2002).
49
BIBLIOGRAPHIE 50
[12] Sasu Tarkoma. Publish / Subscribe Systems : Design and Principles.
Wiley, 18 juin 2012. isbn : 978-1-118-35429-2.
[13] The Internet of Things Protocol stack - from sensors to business value.
url : https://entrepreneurshiptalk.wordpress.com/2014/01/
29/the-internet-of-thing-protocol-stack-from-sensors-to-
business-value/ (visité le 10/01/2016).
[14] Unified Modeling Language 2.5. Rapp. tech. www.omg.org, 2015. url :
http://www.omg.org/spec/UML/2.5.
[15] Mark Utting, Alexander Pretschner et Bruno Legeard. « A taxo-
nomy of model-based testing approaches ». In : Software Testing, Ve-
rification and Reliability 22.5 (2012), p. 297–312.
[16] Lucy Zhang. Building Facebook Messenger. Août 2011. url : https:
//www.facebook.com/notes/facebook-engineering/building-
facebook-messenger/10150259350998920/ (visité le 05/07/2016).
Remerciements
Je tiens à remercier toutes les personnes qui m’ont aidé tout au long de
ce travail de recherche.
Tout d’abord, j’adresse mes plus vifs remerciements à M. Fabrice Bou-
quet qui a encadré mon travail pour ses conseils précieux lors de toutes les
discussions que nous avons eues, pour la qualité de ses explications, et pour
avoir su me guider tout au long de ma recherche. Ce mémoire a bénéficié de
sa relecture et remarques avisées sur le fond comme sur la forme.
Je remercie M. Fabien Peureux qui m’a encouragé à suivre le cursus de
recherche, et qui me fait l’honneur de faire partie de mon jury.
Je tiens également à exprimer ma gratitude envers l’entreprise Smartes-
ting pour m’avoir accordé une licence d’utilisation de leur logiciel CertifyIt
dans le cadre de cette recherche.
Merci enfin à toute ma famille pour leur soutien, en particulier mon
épouse Ochrite qui m’a encouragé tout au long de mon Master, et sans qui
ce mémoire n’aurait pas été possible.
51
Annexe A
Codes sources (extraits)
A.1 Suite de tests
from mqtt import *
from mqtt_enums import *
# publish (68-e3-eb)
def test_16():
Client2.connection(BrokerInstance)
Client2.connect(ClientIdentifier.CLIENTID_NORMAL_1, False, 36)
Client2.subscribe(Utf8Type.UTF8_DATA_NORMAL_2, 0)
Client2.publish(Utf8Type.UTF8_DATA_NORMAL_2,
PayloadType.BINARY_DATA_EMPTY, 0, False)→
# connect (68-fc-66)
def test_17():
Client2.connection(BrokerInstance)
Client1.connection(BrokerInstance)
Client1.connect(ClientIdentifier.CLIENTID_EMPTY, True, 37)
Client2.connect(ClientIdentifier.CLIENTID_EMPTY, True, 37)
# process_messages (68-2e-6d)
def test_26():
Client1.connection(BrokerInstance)
Client1.connect(ClientIdentifier.CLIENTID_NORMAL_1, True, 36)
Client1.publish(Utf8Type.UTF8_DATA_NORMAL_2,
PayloadType.BINARY_DATA_TOO_LONG, 2, False)→
BrokerInstance.process_messages()
Client1.process_messages()
BrokerInstance.process_messages()
excepted = [
[Client1.send_disconnect()],
[Client2.send_connect(ClientIdentifier.CLIENTID_EMPTY, False, 5,
ClientName.NONE, ClientPassword.NONE),
BrokerInstance.send_connack(Client2,
ConnectReturnCode.IDENTIFIER_REJECTED)],
→
→
→
52
ANNEXE A. CODES SOURCES (EXTRAITS) 53
[Client2.send_connect(ClientIdentifier.CLIENTID_EMPTY, True, 36,
ClientName.NONE, ClientPassword.NONE),
BrokerInstance.send_connack(Client2, ConnectReturnCode.OK),
Client2.send_disconnect()],
→
→
→
# ...
[Client1.send_connect(ClientIdentifier.CLIENTID_EMPTY, True, 36,
ClientName.NONE, ClientPassword.NONE),
BrokerInstance.send_connack(Client1, ConnectReturnCode.OK),
Client1.send_subscribe(1, Utf8Type.UTF8_DATA_NORMAL_2, 2),
BrokerInstance.send_suback(Client1, 1), Client1.send_publish(2,
Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_TOO_LONG,
1, False, False), BrokerInstance.send_publish(Client1,
Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_TOO_LONG,
2, False), Client1.send_pubrec(1),
BrokerInstance.send_pubrel(Client1, 1),
BrokerInstance.send_puback(Client1, 2),
Client1.send_pubcomp(1)]
→
→
→
→
→
→
→
→
→
→
→
]
ANNEXE A. CODES SOURCES (EXTRAITS) 54
A.2 Adaptateur pour le client MQTT
import paho.mqtt.client as mqtt
class Client:
def __init__(self):
self.client = mqtt.Client()
def __del__(self):
self.disconnect()
del self.client
def connect(self, server):
#Hack: se contente de définir son adresse
self.address = server.host, server.port
def disconnect(self):
self.client.loop_stop()
self.client.reinitialise()
def publish(self, topic, payload, qos, retain):
self.client.publish(topic, payload, qos, retain)
def send_connect(self, client_id, clean, keepalive):
host, port = self.address
#Hack: force these values
self.client._client_id = client_id
self.client._clean_session = clean
self.client.connect(host, port, keepalive)
self.client.loop_start()
def send_disconnect(self):
self.client.disconnect()
def setup_id(self, nom, passw):
#self.client.username_pw_set(nom, passw)
if nom is not None:
nom = nom.encode('utf8')
if passw is not None:
passw = passw.encode('utf8')
self._username = nom
self._password = passw
def subscribe(self, topic, qos):
self.client.subscribe(topic, qos)
def unsubscribe(self, topic):
self.client.unsubscribe(topic)
ANNEXE A. CODES SOURCES (EXTRAITS) 55
A.3 Modélisation binaire des trames
class MQTTPacket:
def __init__(self, buf):
self._data = buf
self._decode(buf)
def _decode(self, buf):
self.command = buf[0] >> 4
self.flags = buf[0] & 0xf
self.length = remaining_length_decode(buf)
self._pos = next(i for i in range(1,5) if buf[i] & 128 == 0) + 1
cls = MQTTCommandRegistry.get_cls(self.command)
self.packet = cls(buf, self._pos)
def check(self):
assert len(self._data) == self._pos + self.length, 'invalid length'
self.packet.check()
def _encode(self):
tmp = bytearray()
self.packet._encode(tmp)
buf = bytearray()
buf.append(self.command << 4 | self.flags)
remaining_length_encode(len(tmp), buf)
buf.extend(tmp)
return buf
# ...
class MQTTBody:
def __init__(self, buf, pos):
self.flags = buf[0] & 0xf
self._decode(buf, pos)
class MQTTConnect(MQTTBody):
def _decode(self, buf, pos):
self.protocol, pos = get_utf8_string(buf, pos)
self.protolevel, pos = get_uint8(buf, pos)
cflags, pos = get_uint8(buf, pos)
assert (cflags & 0x1) == 0, 'reserved flag'
self.clean = (cflags & 0x2) >> 1
self.wflag = (cflags & 0x4) >> 2
self.wqos = (cflags & 0x18) >> 3
self.wrflag = (cflags & 0x20) >> 5
self.pflag = (cflags & 0x40) >> 6
self.uflag = (cflags & 0x80) >> 7
self.keepalive, pos = get_uint16(buf, pos)
self.clientid, pos = get_utf8_string(buf, pos)
if self.wflag:
self.will_topic, pos = get_utf8_string(buf, pos)
self.will_msg, pos = get_binary_string(buf, pos)
ANNEXE A. CODES SOURCES (EXTRAITS) 56
else:
self.will_topic = None
self.will_msg = None
if self.uflag:
self.username, pos = get_utf8_string(buf, pos)
else:
self.username = None
if self.pflag:
self.userpassword, pos = get_binary_string(buf, pos)
else:
self.userpassword = None
def check(self):
assert self.flags == 0, '[MQTT-3.1.2-3]'
assert (self.protocol == 'MQTT' and self.protolevel == 4) or
(self.protocol == 'MQIsdp' and self.protolevel == 3), 'invalid
or unkown protocol'
→
→
assert (self.wflag != 0 or self.wqos == 0), '[MQTT-3.1.2-13]'
assert self.wqos != 3, '[MQTT-3.1.2-14]'
assert (self.wflag != 0 or self.wrflag == 0), '[MQTT-3.1.2-15]'
assert (self.uflag != 0 or self.pflag == 0), '[MQTT-3.1.2-22]'
def _encode(self, buf):
set_utf8_string(self.protocol, buf)
set_uint8(self.protolevel, buf)
cflags = self.clean << 1 | self.wflag << 2 | self.wqos << 3 |
self.wrflag << 5 | self.pflag << 6 | self.uflag << 7→
set_uint8(cflags, buf)
set_uint16(self.keepalive, buf)
set_utf8_string(self.clientid, buf)
if self.wflag:
set_utf8_string(self.will_topic or '', buf)
set_binary_string(self.will_msg or '', buf)
if self.uflag:
set_utf8_string(self.username or '', buf)
if self.pflag:
set_binary_string(self.userpassword or '', buf)
def read_paquet(sock):
buf = bytearray()
read_fixed_header(sock, buf)
length = remaining_length_decode(buf)
# read the whole packet
while len(buf) < length + 2:
data = sock.recv(length + 2 - len(buf))
buf.extend(data)
packet = MQTTPacket(buf)
# check the received packet
packet.check()
# encode and return new packet
return packet._encode()
Annexe B
Log des tests exécutés
TEST: connect (68-15-95)
Exception occured in client side: Payload too large.
------------------------------------------------------------
TEST: connect (68-79-ca)
excepted:
["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>",
'<CONNACK: code=0>',
"<CONNECT: client_id='aaa', username=None, password=None, clean=0, "
'keepalive=5>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=1, keepalive=36>',
'<CONNACK: session_present=0, code=0>',
"<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, "
'password=None, clean=0, keepalive=5>',
"<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=1, code=0>']
------------------------------------------------------------
TEST: connect (68-9f-0a)
excepted:
["<CONNECT: client_id='bbb', username=None, password=None, clean=1, "
'keepalive=5>',
'<CONNACK: code=0>',
"<CONNECT: client_id='bbb', username=None, password=None, clean=0, "
'keepalive=5>',
'<CONNACK: code=0>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, "
'password=None, clean=1, keepalive=5>',
'<CONNACK: session_present=0, code=0>',
"<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=1, code=0>',
'<PINGREQ: >']
------------------------------------------------------------
TEST: connect (68-ca-0e)
excepted:
57
ANNEXE B. LOG DES TESTS EXÉCUTÉS 58
["<CONNECT: client_id='', username=None, password=None, clean=0, keepalive=5>",
'<CONNACK: code=2>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=0, code=2>',
"<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=0, code=2>',
"<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=0, code=2>']
------------------------------------------------------------
TEST: connect (68-d1-a6)
excepted:
["<CONNECT: client_id='aaa', username=None, password=None, clean=0, "
'keepalive=36>',
'<CONNACK: code=0>',
"<SUBSCRIBE: packet_id=1, topic='bca', qos=2>",
'<SUBACK: packet_id=1>',
"<PUBLISH: packet_id=None, topic='bca', qos=0, retain=0, dup=0>",
"<PUBLISH: topic='bca', qos=2, retain=0>",
"<CONNECT: client_id='aaa', username=None, password=None, clean=0, "
'keepalive=5>',
'<CONNACK: code=0>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, "
'password=None, clean=0, keepalive=36>',
"<SUBSCRIBE: packet_id=1 subscriptions=['bca':2]>",
"<PUBLISH: qos=0, retain=0, dup=0, topic='bca'>",
'<CONNACK: session_present=1, code=0>',
'<SUBACK: packet_id=1, return_codes=[2]>',
"<PUBLISH: qos=0, retain=0, dup=0, topic='bca'>",
"<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, "
'password=None, clean=0, keepalive=5>',
'<CONNACK: session_present=1, code=0>']
------------------------------------------------------------
TEST: connect (68-d2-3f)
excepted:
["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>",
'<CONNACK: code=0>',
"<CONNECT: client_id='bbb', username=None, password=None, clean=1, "
'keepalive=5>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=1, keepalive=36>',
'<CONNACK: session_present=0, code=0>',
"<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, "
'password=None, clean=1, keepalive=5>',
"<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, "
'password=None, clean=1, keepalive=5>',
'<CONNACK: session_present=0, code=0>']
------------------------------------------------------------
TEST: connect (68-fc-66)
ANNEXE B. LOG DES TESTS EXÉCUTÉS 59
excepted:
["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=37>",
'<CONNACK: code=0>',
"<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=37>",
'<CONNACK: code=0>']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=1, keepalive=37>',
'<CONNACK: session_present=0, code=0>',
"<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=1, keepalive=37>',
'<CONNACK: session_present=0, code=0>']
------------------------------------------------------------
TEST: disconnect (68-83-fd)
excepted:
["<CONNECT: client_id='aaa', username=None, password=None, clean=0, "
'keepalive=36>',
'<CONNACK: code=0>',
'<DISCONNECT: >']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, "
'password=None, clean=0, keepalive=36>',
'<DISCONNECT: >',
'<CONNACK: session_present=0, code=0>']
------------------------------------------------------------
TEST: disconnect (68-8e-49)
excepted:
['<DISCONNECT: >']
retrieved:
[]
------------------------------------------------------------
TEST: disconnect (68-8e-49)
excepted:
['<DISCONNECT: >']
retrieved:
[]
------------------------------------------------------------
TEST: disconnect (68-e8-24)
excepted:
["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>",
'<CONNACK: code=0>',
'<DISCONNECT: >']
retrieved:
["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, "
'password=None, clean=1, keepalive=36>',
'<DISCONNECT: >',
'<CONNACK: session_present=0, code=0>']
------------------------------------------------------------
TEST: publish (68-2c-98)
Exception occured in client side: Invalid topic.
------------------------------------------------------------
TEST: publish (68-9a-6c)
excepted:
["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>",
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT
Model Based Testing des applications du protocole MQTT

Contenu connexe

Tendances

Rapport stage pfe
Rapport stage  pfe Rapport stage  pfe
Rapport stage pfe rimeh moussi
 
Rapport pfe talan_2018_donia_hammami
Rapport pfe talan_2018_donia_hammamiRapport pfe talan_2018_donia_hammami
Rapport pfe talan_2018_donia_hammamiDonia Hammami
 
Rapport PFE "Conception et développement d'un Portail web pour le Smart Met...
Rapport  PFE  "Conception et développement d'un Portail web pour le Smart Met...Rapport  PFE  "Conception et développement d'un Portail web pour le Smart Met...
Rapport PFE "Conception et développement d'un Portail web pour le Smart Met...Hajer Dahech
 
Automatisation d'une maison intelligente via une application android
Automatisation d'une maison intelligente via une application androidAutomatisation d'une maison intelligente via une application android
Automatisation d'une maison intelligente via une application androidAbderrahim Bouharaoua
 
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...Ayoub Rouzi
 
Supervision d'un réseau informatique avec Nagios
Supervision d'un réseau informatique avec NagiosSupervision d'un réseau informatique avec Nagios
Supervision d'un réseau informatique avec Nagioschristedy keihouad
 
Implémentation d’une solution de supervision de température et d’humidité pou...
Implémentation d’une solution de supervision de température et d’humidité pou...Implémentation d’une solution de supervision de température et d’humidité pou...
Implémentation d’une solution de supervision de température et d’humidité pou...Mohammed Lymame
 
rapport de projet de fin d'étude_PFE
rapport de projet de fin d'étude_PFErapport de projet de fin d'étude_PFE
rapport de projet de fin d'étude_PFEDonia Hammami
 
RapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITRapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITLina Meddeb
 
rapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATrapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATSiwar GUEMRI
 
La spécification des besoins
La spécification des besoinsLa spécification des besoins
La spécification des besoinsIsmahen Traya
 
Rapport de stage de fin d'études ISI 2015
Rapport de stage de fin d'études ISI 2015Rapport de stage de fin d'études ISI 2015
Rapport de stage de fin d'études ISI 2015Anouar Kacem
 
Installation et configuration d'un système de Détection d'intrusion (IDS)
Installation et configuration d'un système de Détection d'intrusion (IDS)Installation et configuration d'un système de Détection d'intrusion (IDS)
Installation et configuration d'un système de Détection d'intrusion (IDS)Charif Khrichfa
 
Pfe master fst_final_decembre2015
Pfe master fst_final_decembre2015Pfe master fst_final_decembre2015
Pfe master fst_final_decembre2015Ghali Rahma
 
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2Sofien Benrhouma
 
Projet de fin étude ( LFIG : Conception et Développement d'une application W...
Projet de fin étude  ( LFIG : Conception et Développement d'une application W...Projet de fin étude  ( LFIG : Conception et Développement d'une application W...
Projet de fin étude ( LFIG : Conception et Développement d'une application W...Ramzi Noumairi
 

Tendances (20)

Rapport stage pfe
Rapport stage  pfe Rapport stage  pfe
Rapport stage pfe
 
Rapport pfe talan_2018_donia_hammami
Rapport pfe talan_2018_donia_hammamiRapport pfe talan_2018_donia_hammami
Rapport pfe talan_2018_donia_hammami
 
Rapport PFE "Conception et développement d'un Portail web pour le Smart Met...
Rapport  PFE  "Conception et développement d'un Portail web pour le Smart Met...Rapport  PFE  "Conception et développement d'un Portail web pour le Smart Met...
Rapport PFE "Conception et développement d'un Portail web pour le Smart Met...
 
Automatisation d'une maison intelligente via une application android
Automatisation d'une maison intelligente via une application androidAutomatisation d'une maison intelligente via une application android
Automatisation d'une maison intelligente via une application android
 
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...
Smart Parking: Stationnement intelligent État de l’art, Étude d’un exemple De...
 
Supervision d'un réseau informatique avec Nagios
Supervision d'un réseau informatique avec NagiosSupervision d'un réseau informatique avec Nagios
Supervision d'un réseau informatique avec Nagios
 
Implémentation d’une solution de supervision de température et d’humidité pou...
Implémentation d’une solution de supervision de température et d’humidité pou...Implémentation d’une solution de supervision de température et d’humidité pou...
Implémentation d’une solution de supervision de température et d’humidité pou...
 
rapport de projet de fin d'étude_PFE
rapport de projet de fin d'étude_PFErapport de projet de fin d'étude_PFE
rapport de projet de fin d'étude_PFE
 
Rapport finiale
Rapport finialeRapport finiale
Rapport finiale
 
RapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRITRapportPFE_IngenieurInformatique_ESPRIT
RapportPFE_IngenieurInformatique_ESPRIT
 
rapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSATrapport PFE ingénieur génie logiciel INSAT
rapport PFE ingénieur génie logiciel INSAT
 
La spécification des besoins
La spécification des besoinsLa spécification des besoins
La spécification des besoins
 
Rapport de stage de fin d'études ISI 2015
Rapport de stage de fin d'études ISI 2015Rapport de stage de fin d'études ISI 2015
Rapport de stage de fin d'études ISI 2015
 
Mémoire de Master 2
Mémoire de Master 2Mémoire de Master 2
Mémoire de Master 2
 
Présentation PFE
Présentation PFEPrésentation PFE
Présentation PFE
 
Installation et configuration d'un système de Détection d'intrusion (IDS)
Installation et configuration d'un système de Détection d'intrusion (IDS)Installation et configuration d'un système de Détection d'intrusion (IDS)
Installation et configuration d'un système de Détection d'intrusion (IDS)
 
Pfe master fst_final_decembre2015
Pfe master fst_final_decembre2015Pfe master fst_final_decembre2015
Pfe master fst_final_decembre2015
 
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2
Rapport Projet De Fin D'étude Développent d'une application web avec Symfony2
 
Projet de fin étude ( LFIG : Conception et Développement d'une application W...
Projet de fin étude  ( LFIG : Conception et Développement d'une application W...Projet de fin étude  ( LFIG : Conception et Développement d'une application W...
Projet de fin étude ( LFIG : Conception et Développement d'une application W...
 
SMART Home Rapport
SMART Home RapportSMART Home Rapport
SMART Home Rapport
 

Similaire à Model Based Testing des applications du protocole MQTT

Projet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsProjet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsUniversité de Rennes 1
 
Rapport de projet de fin d"études
Rapport de projet de fin d"étudesRapport de projet de fin d"études
Rapport de projet de fin d"étudesMohamed Boubaya
 
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Nawres Farhat
 
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...Alaaeddine Tlich
 
réaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testréaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testahmed oumezzine
 
OpenERP - Gestion de prix de revient
OpenERP - Gestion de prix de revientOpenERP - Gestion de prix de revient
OpenERP - Gestion de prix de revientTaieb Kristou
 
Conception et Développement d'un Network Management System ATM Nortel
Conception et Développement d'un Network Management System ATM NortelConception et Développement d'un Network Management System ATM Nortel
Conception et Développement d'un Network Management System ATM NortelTidiane Sylla
 
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...mouafekmazia
 
Gestion des actifs applicatifs
Gestion des actifs applicatifsGestion des actifs applicatifs
Gestion des actifs applicatifsSafaAballagh
 
Evaluation de la quantité de travail (in)utile dans l’exécution des programmes
Evaluation de la quantité de travail (in)utile dans l’exécution des programmesEvaluation de la quantité de travail (in)utile dans l’exécution des programmes
Evaluation de la quantité de travail (in)utile dans l’exécution des programmesBenjamin Vidal
 
Projet réalisé par ameny Khedhira & Arij Mekki
Projet réalisé par  ameny Khedhira & Arij MekkiProjet réalisé par  ameny Khedhira & Arij Mekki
Projet réalisé par ameny Khedhira & Arij MekkiAmeny Khedhira
 

Similaire à Model Based Testing des applications du protocole MQTT (20)

ns.pdf
ns.pdfns.pdf
ns.pdf
 
siem.pdf
siem.pdfsiem.pdf
siem.pdf
 
vanderpypendaniel_msc
vanderpypendaniel_mscvanderpypendaniel_msc
vanderpypendaniel_msc
 
Projet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objetsProjet Passerelle sécurisée intelligente pour l'internet des objets
Projet Passerelle sécurisée intelligente pour l'internet des objets
 
Rapport de projet de fin d"études
Rapport de projet de fin d"étudesRapport de projet de fin d"études
Rapport de projet de fin d"études
 
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
Rapport pfe- Refonte et déploiement d’une solution de messagerie en utilisant...
 
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...
Mise en place d'une Plateforme de Supervision et de Détection d'Intrusion Sys...
 
réaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de testréaliser une plateforme d’automatisation et de génération des rapports de test
réaliser une plateforme d’automatisation et de génération des rapports de test
 
Report Master
Report MasterReport Master
Report Master
 
OpenERP - Gestion de prix de revient
OpenERP - Gestion de prix de revientOpenERP - Gestion de prix de revient
OpenERP - Gestion de prix de revient
 
Deploy automatic in the cloud
Deploy automatic in the cloudDeploy automatic in the cloud
Deploy automatic in the cloud
 
These
TheseThese
These
 
Conception et Développement d'un Network Management System ATM Nortel
Conception et Développement d'un Network Management System ATM NortelConception et Développement d'un Network Management System ATM Nortel
Conception et Développement d'un Network Management System ATM Nortel
 
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
Rapport Projet De Fin D'étude de Conception et développement d’une applicatio...
 
Gestion des actifs applicatifs
Gestion des actifs applicatifsGestion des actifs applicatifs
Gestion des actifs applicatifs
 
Belwafi bilel
Belwafi bilelBelwafi bilel
Belwafi bilel
 
Belwafi bilel
Belwafi bilelBelwafi bilel
Belwafi bilel
 
iRecruite
iRecruiteiRecruite
iRecruite
 
Evaluation de la quantité de travail (in)utile dans l’exécution des programmes
Evaluation de la quantité de travail (in)utile dans l’exécution des programmesEvaluation de la quantité de travail (in)utile dans l’exécution des programmes
Evaluation de la quantité de travail (in)utile dans l’exécution des programmes
 
Projet réalisé par ameny Khedhira & Arij Mekki
Projet réalisé par  ameny Khedhira & Arij MekkiProjet réalisé par  ameny Khedhira & Arij Mekki
Projet réalisé par ameny Khedhira & Arij Mekki
 

Model Based Testing des applications du protocole MQTT

  • 1. Josué Melka Model Based Testing des applications du protocole MQTT Mémoire de Master Recherche Informatique encadré par Fabrice Bouquet, Professeur des Universités 27 Septembre 2016
  • 2. Table des matières 1 Introduction 4 2 Le protocole MQTT 7 2.1 Fonctionnement . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.1.1 Connexion et Déconnexion . . . . . . . . . . . . . . . 10 2.1.2 Abonnements et Publications . . . . . . . . . . . . . . 10 2.1.3 Qualité de service . . . . . . . . . . . . . . . . . . . . 11 2.1.4 Persistance . . . . . . . . . . . . . . . . . . . . . . . . 13 2.1.5 Messages retenus . . . . . . . . . . . . . . . . . . . . . 13 2.1.6 Testament . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.2 Sécurité . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.2.1 Confidentialité . . . . . . . . . . . . . . . . . . . . . . 14 2.2.2 Authentification . . . . . . . . . . . . . . . . . . . . . 14 2.2.3 Intégrité . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.2.4 Gestion des droits . . . . . . . . . . . . . . . . . . . . 15 2.3 Format binaire . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.3.1 CONNECT . . . . . . . . . . . . . . . . . . . . . . . . 16 2.3.2 CONNACK . . . . . . . . . . . . . . . . . . . . . . . . 17 2.3.3 PUBLISH . . . . . . . . . . . . . . . . . . . . . . . . . 17 2.3.4 PUBACK, PUBREC, PUBREL, PUBCOMP . . . . . 18 2.3.5 SUBSCRIBE . . . . . . . . . . . . . . . . . . . . . . . 18 2.3.6 SUBACK . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.3.7 UNSUBSCRIBE . . . . . . . . . . . . . . . . . . . . . 20 2.3.8 UNSUBACK . . . . . . . . . . . . . . . . . . . . . . . 20 2.3.9 PINGREQ, PINGRESP . . . . . . . . . . . . . . . . . 21 2.3.10 DISCONNECT . . . . . . . . . . . . . . . . . . . . . . 21 2.4 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3 Problématiques de modélisation de MQTT 23 3.1 Model-Based-Testing du protocole . . . . . . . . . . . . . . . 24 3.1.1 Sujet du test et observation . . . . . . . . . . . . . . . 26 3.1.2 Non déterminisme . . . . . . . . . . . . . . . . . . . . 26 3.2 Altération des échanges MQTT . . . . . . . . . . . . . . . . . 27 1
  • 3. TABLE DES MATIÈRES 2 3.2.1 Suivi et validation des trames . . . . . . . . . . . . . . 27 3.2.2 Critères de transformation . . . . . . . . . . . . . . . . 28 3.2.3 Intégration . . . . . . . . . . . . . . . . . . . . . . . . 28 3.3 Analyse des tests . . . . . . . . . . . . . . . . . . . . . . . . . 28 4 Travail réalisé 30 4.1 Outils utilisés . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.1.1 Smartesting CertifyIt . . . . . . . . . . . . . . . . . . 31 4.1.2 Eclipse Paho project . . . . . . . . . . . . . . . . . . . 33 4.1.3 Wireshark . . . . . . . . . . . . . . . . . . . . . . . . . 34 4.2 Modélisation fonctionnelle du protocole MQTT . . . . . . . . 35 4.2.1 Mise en œuvre . . . . . . . . . . . . . . . . . . . . . . 36 4.2.2 Fonctionnalités modélisées . . . . . . . . . . . . . . . . 38 4.2.3 Génération des tests . . . . . . . . . . . . . . . . . . . 40 4.2.4 Verdict . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.3 Proxy de test MQTT . . . . . . . . . . . . . . . . . . . . . . . 41 4.3.1 Réalisation . . . . . . . . . . . . . . . . . . . . . . . . 42 4.3.2 Modélisation du protocole . . . . . . . . . . . . . . . . 42 4.3.3 Intégration au script de test . . . . . . . . . . . . . . . 43 4.4 Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.4.1 Tests générés avec CertifyIt . . . . . . . . . . . . . . . 44 4.4.2 Modélisation du format des trames . . . . . . . . . . . 44 4.4.3 Exécution des test . . . . . . . . . . . . . . . . . . . . 45 4.4.4 Validation . . . . . . . . . . . . . . . . . . . . . . . . . 45 5 Conclusion 47 Bibliographie 49 Remerciements 51 A Codes sources (extraits) 52 A.1 Suite de tests . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 A.2 Adaptateur pour le client MQTT . . . . . . . . . . . . . . . . 54 A.3 Modélisation binaire des trames . . . . . . . . . . . . . . . . . 55 B Log des tests exécutés 57 C Extraits de l’annexe B de la norme MQTT 64
  • 4. Table des figures 1.1 IoT protocol stack . . . . . . . . . . . . . . . . . . . . . . . . 5 2.3 Format d’un paquet CONNECT . . . . . . . . . . . . . . . . 16 2.4 Format d’un paquet CONNACK . . . . . . . . . . . . . . . . 17 2.5 Format d’un paquet PUBLISH . . . . . . . . . . . . . . . . . 18 2.6 Format d’un paquet PUB[ACK/REC/REL/COMP] . . . . . 18 2.7 Format d’un paquet SUBSCRIBE . . . . . . . . . . . . . . . 19 2.8 Format d’un paquet SUBACK . . . . . . . . . . . . . . . . . 20 2.9 Format d’un paquet UNSUBSCRIBE . . . . . . . . . . . . . . 20 2.10 Format d’un paquet UNSUBACK . . . . . . . . . . . . . . . . 21 2.11 Format d’un paquet PING[REQ/RESP] . . . . . . . . . . . . 21 2.12 Format d’un paquet DISCONNECT . . . . . . . . . . . . . . 21 4.4 Processus du test de MQTT basé sur les modèles . . . . . . 35 4.5 Modélisation UML du protocole MQTT . . . . . . . . . . . . 36 4.8 Architecture du proxy de test MQTT . . . . . . . . . . . . . 42 4.9 Notre processus du test pour MQTT . . . . . . . . . . . . . 43 3
  • 5. Chapitre 1 Introduction Les objets connectés se démocratisent de plus en plus, le cabinet d’ana- lyse Gartner estimant leur nombre actuel à plusieurs milliards d’unités, et prédisant que leur nombre en 2020 pourra atteindre 25 milliards [5]. La fiabilité des produits, les questions d’interopérabilité et les failles de sécurité sont des problèmes encore très largement rencontrés dans ce do- maine, ce qui freine l’émergence du marché. De par leur nature, les objets connectés forment des systèmes complexes qui rendent ces problèmes à la fois plus cruciaux et plus difficiles à appréhender. Pouvoir certifier efficacement ces produits apparait donc comme une né- cessité majeure, alors même que la diversité et la quantité de l’offre ne cesse de croitre. Le test est sans doute l’une des techniques de validation la plus à même de répondre à ce besoin. Malgré le fait qu’il ne puisse apporter de garantie absolue sur l’absence d’imperfection, c’est un moyen efficace et relativement peu coûteux pour apporter un certain degré de confiance sur un système. Toutefois, la mise en place de tests sur une gamme de produits aussi diversifiée n’est pas sans poser des problèmes d’échelle. En effet, valider chaque composant peut nécessiter un grand nombre de cas de test pour fournir une couverture suffisante, et il faut une certaine expertise pour définir des cas de test pertinents. La méthodologie du test dirigé par les modèles offre sur ce terrain une solution intéressante : une fois le système à tester modélisé, la génération des cas de tests est automatisable et configurable. Ainsi l’on peut se contenter d’établir un modèle de test, et de le faire évoluer en fonction des besoins. Toutefois, la complexité inhérente des systèmes connectés impose d’étu- dier soigneusement la modélisation que l’on va adopter pour générer des tests. Nous avons voulu approfondir cette question en expérimentant l’ap- plication du model based testing à une problématique concrète. 4
  • 6. CHAPITRE 1. INTRODUCTION 5 L’un des aspects essentiels d’une architecture IoT est celui de la commu- nication entre les divers composants du système global. Il existe bien sûr de multiples moyens de connecter et de faire communiquer les composants en question (un aperçu des différentes couches de communication couram- ment employés est donné Figure 1.1), mais on assiste dans ce domaine à l’émergence de certains protocoles mieux adaptés que d’autres pour remplir ce besoin. Figure 1.1 – IoT protocol stack - Source : [13] Ainsi, avec son modèle Publish/Subscribe et sa très grande légèreté, le protocole MQTT est actuellement considéré comme l’un des candidats les plus sérieux pour assurer le transport des données au sein des architectures IoT [10]. Déjà largement utilisé – c’est par exemple le protocole fourni par la plateforme Amazon Webservices IoT 1, on en trouve de nombreuses im- plémentations dans divers langages de programmation, dont beaucoup sont open-source. Nous avons considéré ce protocole comme étant à la fois suffisamment simple et intéressant pour constituer l’objet de notre expérimentation, qui 1. http://docs.aws.amazon.com/iot/latest/developerguide/what-is-aws- iot.html
  • 7. CHAPITRE 1. INTRODUCTION 6 portera donc sur la mise en œuvre de tests basés sur les modèles afin de valider le support du protocole MQTT par des objets connectés. Comme objectif de cette étude, nous avons souhaité analyser les probléma- tiques qui découlent de la mise en œuvre de tels tests, et si possible proposer les solutions qui nous semblent adaptées et généralisables. Dans le Chapitre 2, nous présentons en détail à partir de sa spécification le fonctionnement de MQTT ainsi que les différents aspect susceptibles d’être modélisés et testés. Au Chapitre 3, nous discutons des implications de ce fonctionnement sur la modélisation d’un système MQTT, et tentons de trouver des solutions réalisables aux problèmes que nous avons rencontrés. Enfin, le Chapitre 4 exposera notre expérimentation de modélisation du protocole et ses résultats, ainsi que les outils utilisés et ceux qui ont dû être créés pour l’occasion.
  • 8. Chapitre 2 Le protocole MQTT MQ Telemetry Transport est un protocole de messaging basé sur le pu- blish/subscribe à la fois extrêmement simple et léger, lui permettant ainsi d’être utilisable à partir d’un matériel de très faible puissance, ainsi que à travers des réseaux à forte latence voire peu fiables. Initialement créé en 1999 par Andy Stanford-Clark (IBM) et Arlen Nip- per (Eurotech), le protocole est alors pensé pour alimenter les systèmes de télémesure, et est connu à l’origine sous le nom de MQ Integrator SCADA Device Protocol [11]. Par la suite, son code source est donné en 2011 au projet Eclipse Paho, et le protocole est standardisé par l’OASIS en 2014 dans sa version 3.1.1. Il devient un standard ISO (ISO/IEC 20922) en 2016. Aujourd’hui, avec l’essor de l’IoT, MQTT suscite un intérêt grandissant, dont l’on peut se rendre compte en observant l’évolution du nombre de recherches pour MQTT sur Google Trends (Figure 2.1). Les principales caractéristiques de MQTT sont les suivantes : — Emploie le pattern publish/subscribe, permettant une distribution des messages un-à-plusieurs, ainsi que le découplage des applications. — Le protocole de transport de messages est totalement indépendant de leur contenu (content agnostic). — Trois niveaux de qualité de service pour la distribution des messages : 1. At most once 2. At least once 3. Exactly once — Volume de données échangées extrêmement réduit, limitant ainsi le trafic réseau généré. — Un mécanisme de notification en cas de déconnexion abrupte d’un client. 7
  • 9. CHAPITRE 2. LE PROTOCOLE MQTT 8 Figure 2.1 – Google Trends pour MQTT (01/08/2016) Les qualités intrinsèques de MQTT font de lui un excellent candidat pour les communications au sein de l’Internet des Objets [10], mais il a également été utilisé avec succès par Facebook pour être au cœur de leur système de messagerie, un choix dicté par la performance [16]. Actuellement, un autre protocole nommé MQTT-SN (MQTT for Sensor Networks) est en cours de développement, afin de pallier aux contraintes de certains hardwares particulièrement limités tout en garantissant une com- patibilité avec MQTT, mais ce protocole ne sera pas étudié ici. La norme MQTT – dont nous fournissons un extrait des principales exi- gences en Annexe C – décrit le comportement attendu des serveurs (brokers) et clients MQTT, ainsi que les détails du format binaire employé pour les échanges. La suite de ce chapitre synthétisera l’essentiel de cette norme afin de mieux appréhender la question de la modélisation par la suite. Nous expliquons en détail le fonctionnement du protocole MQTT en section 2.1. La partie suivante (section 2.2) sera consacrée à l’exposé des aspects de sécurité pris en compte par le protocole. Enfin, le format binaire défini par la norme pour les paquets MQTT sera étudié dans la dernière partie (section 2.3). 2.1 Fonctionnement Le fonctionnement de MQTT repose sur le pattern d’échange de mes- sages désormais bien connu sous le nom de publish/subscribe, ou PUB/SUB.
  • 10. CHAPITRE 2. LE PROTOCOLE MQTT 9 Ce pattern consiste à organiser les messages par sujets (topics) et à gé- rer leur distribution selon le principe d’abonnement. Ainsi, toute application peut publier ses messages sur les topics de son choix, tandis que les applica- tions intéressées par les messages d’un topic donné peuvent s’abonner pour recevoir tous les nouveaux messages publiés sur ce topic. Dans le cas d’un PUB/SUB broker-based comme MQTT, un serveur (généralement nommé broker) fait office d’intermédiaire entre les clients qui publient et ceux qui s’abonnent. Ceci afin de découpler les publishers et les subscribers, qui n’ont besoin que de connaitre le broker pour fonctionner. Gestion des erreurs La plupart des erreurs, sauf celles qui ont une valeur informative im- portante pour le client (typiquement certaines erreurs à la connexion qui sont signalées par un code de retour) sont soit ignorées, soit provoquent l’abandon de la connexion par l’autre partie. Ce comportement rend évidement l’implémentation du protocole plus simple, mais le diagnostic d’une erreur est dès lors plus difficile à établir dans bien des cas. Topologies courantes Le standard ne définit pas de topologie particulière d’utilisation, la plus simple étant celle avec un seul broker et un certain nombre de clients, qui peut finir par poser des problèmes de passage à l’échelle. D’autres organisation restent évidement possible, avec en particulier les systèmes à base de bridge dans lesquels plusieurs brokers sont utilisés, chacun étant client des autres brokers, comme sur la Figure 2.2. Pour la validation d’objets employant ce protocole, on pourra sans doute se limiter à la topologie la plus basique. Figure 2.2 – Exemples de topologies MQTT [7]
  • 11. CHAPITRE 2. LE PROTOCOLE MQTT 10 2.1.1 Connexion et Déconnexion MQTT se sert de connexions persistantes entre les clients et le broker, et exploite pour cela les protocoles de réseau garantissant un bon niveau de fiabilité comme TCP. Avant de pouvoir envoyer des commandes de contrôle, un client doit au préalable s’enregistrer auprès du serveur, ce qui se fait avec la commande CONNECT 1. Divers paramètres de connexion peuvent alors être échangés, comme les identifiants du client ou encore le mode de persistance souhaité. Le serveur doit confirmer au client que son inscription a bien été prise en compte, soit indiquer qu’une erreur est survenue (mauvais identifiants par ex.) en renvoyant un CONNACK accompagné d’un code de retour. Un autre paramètre intéressant est la précision d’une durée maximale de session (keepalive), qui indique au serveur de considérer que la connexion est interrompue s’il ne reçoit aucune commande dans cet intervalle de temps. Pour cela, il existe une commande PINGREQ permettant de faire savoir au serveur que le client est toujours actif, le serveur répondra de son coté avec un PINGRESP pour indiquer au client que la connexion est toujours active. Une fois l’enregistrement effectué, un second enregistrement sera consi- déré comme une erreur, ce qui implique que l’on ne pourra pas modifier les paramètres de départ en cours de session. Lorsque le client veut se déconnecter, il envoie au préalable une com- mande DISCONNECT au serveur pour lui faire part de son intention. Dans le cas contraire, le serveur considérera la déconnexion comme anor- male et agira en conséquence (cf. 2.1.6). 2.1.2 Abonnements et Publications Chaque message publié est nécessairement associé à un sujet, ce qui permet sa distribution aux abonnés. Les sujets peuvent être organisés en hiérarchie arborescente, ainsi les abonnements peuvent porter sur des motifs de filtrage que nous détaillerons plus loin. La gestion des abonnements est très simple et consiste en trois com- mandes essentielles : SUBSCRIBE Permet à un client de s’abonner à un sujet (ou à un filtre), une fois abonné il recevra par la suite toutes les publications concer- nant ce sujet. Un abonnement définit également un niveau de qualité de service, dont il sera question plus bas (section 2.1.3). 1. Ici, le terme de connexion ne doit pas être confondu avec la connexion TCP (ou équivalent) sous-jacente, c’est pourquoi j’ai préféré le terme d’enregistrement.
  • 12. CHAPITRE 2. LE PROTOCOLE MQTT 11 La bonne réception de cette commande est confirmée par le serveur par un SUBACK portant le même identifiant de packet. UNSUBSCRIBE Donne la possibilité d’annuler un abonnement, et ainsi ne plus recevoir les publications ultérieures. La bonne réception de cette commande est confirmée par le serveur par un UNSUBACK portant le même identifiant de packet. PUBLISH Initié par un client, permet de publier un message qui sera transmis par le serveur aux abonnés éventuels. La même commande sera envoyée par le serveur aux abonnés pour délivrer le message. Si la qualité de service requise est supérieure à zéro, des messages seront échangés pour confirmer la prise en charge de la publication (ce point sera détaillé ci-après). Motifs de filtrage Afin de proposer un système de filtrage efficace sur les sujets, il est possible de définir une arborescence à l’aide du séparateur /. Deux jokers sont réservés pour représenter un et plusieurs niveaux d’arborescence : — + représente un niveau d’arborescence, ainsi n1/n2/n3 peut être mis en correspondance avec divers filtres tels que n1/n2/+, n1/+/n3 ou n1/+/+. — # représente autant de niveaux que possible, et ne peut être utilisé qu’à la fin d’un motif de filtrage ; ainsi n1/# permettra de filtrer tous les sujets dont le premier niveau est n1, et # permet de recevoir tous les sujets publiés par le broker 2. 2.1.3 Qualité de service Comme nous l’avons vu plus haut, trois niveaux de qualité de service (QoS) sont définis pour la publication des messages, qui sont eux même régis par deux facteurs : le niveau de QoS de la publication qui définit le niveau maximal pour la publication, et le niveau de QoS de l’abonnement qui permet au client de réduire ce niveau le cas échéant. Ces niveaux sont mis en œuvre par des échanges supplémentaires entre l’expéditeur et le récepteur, et plus la qualité demandée est élevée, plus il faudra d’échanges pour valider une publication. Pour tous les niveaux supérieurs à zéro, un identifiant est associé au message pour permettre son suivi, MQTT prévoyant la possibilité d’avoir au plus 65535 messages en attente (l’identifiant de message tenant sur 16 bits). 2. A l’exception des sujets spéciaux commençant par $
  • 13. CHAPITRE 2. LE PROTOCOLE MQTT 12 Au niveau de qualité le plus bas (at most once), que l’on pourrait qualifier de fire-and-forget, l’expéditeur se contente d’envoyer le message, sans se soucier de savoir s’il a bien été reçu et pris en compte. Le diagramme de séquence est donc le suivant : Client Broker PUBLISH msc QoS 0 Le niveau 1 de qualité de service (at least once) garantit que le message sera envoyé au moins une fois, car l’expéditeur attend la confirmation que son message a bien été reçu avant de l’effacer. Néanmoins, un message peut être dupliqué lors de la distribution dans certaines situations. Client Broker PUBLISH PUBACK msc QoS 1 Au niveau 2 de qualité de service (exactly once), le récepteur attend la confirmation que sa réponse est bien arrivée a l’expéditeur, et considère en attendant toute publication portant le même identifiant comme un duplicata du message, qui ne sera donc pas publié à nouveau.
  • 14. CHAPITRE 2. LE PROTOCOLE MQTT 13 Client Broker PUBLISH PUBREC PUBREL PUBCOMP msc QoS 2 2.1.4 Persistance MQTT donne au client la possibilité de choisir au moment de la connexion s’il souhaite que sa session soit conservée par le serveur même une fois décon- necté. Dans ce cas, sa session sera restaurée lors d’une éventuelle reconnexion et le client recevra alors les messages mis en attente. Les données de session sont tout d’abord les différents sujets auxquels il s’est abonné, mais aussi les échanges qui n’ont pu se terminer avant la déconnexion, ainsi que les messages de QoS supérieure à zéro qui parviennent au broker alors que le client est déconnecté. Il s’agit ici essentiellement d’une persistance en mémoire, qui sert surtout pour les cas où la connexion réseau risque d’être interrompue. En revanche, il n’est pas imposé que le serveur et le client disposent d’un mécanisme de persistance en cas d’arrêt brutal du logiciel (par exemple sur le disque). 2.1.5 Messages retenus Afin de pouvoir fournir aux nouveaux abonnés des données rapidement même lorsque le producteur des données ne publie pas à intervalles réguliers, il est possible d’indiquer au serveur de retenir une publication reçue comme dernière publication connue pour un sujet donné, qui sera transmise aux nouveaux abonnés dès leur inscription. 2.1.6 Testament Lors de son enregistrement auprès du serveur, un client a la possibilité d’enregistrer un testament, autrement dit un message à publier par le serveur en cas de déconnexion anormale de sa part. Ce message sera publié sur un topic choisi par le client.
  • 15. CHAPITRE 2. LE PROTOCOLE MQTT 14 2.2 Sécurité La sécurité d’un protocole de communication est souvent primordiale pour nombre d’applications. MQTT offre certaines options basiques pour permettre de sécuriser les applications utilisant ce protocole, et nous verrons que le protocole est suf- fisamment souple pour intégrer d’autres mécanismes de sécurité selon les besoins. Par ailleurs, la possibilité d’utiliser une connexion TLS/SSL permet d’ap- porter certaines garanties au niveau de la connexion, comme l’authentifica- tion du serveur, la confidentialité et l’intégrité des données échangées. Au final, peu d’aspects de sécurité sont directement gérés par le proto- cole, sans doute pour garder un protocole le plus simple possible. 2.2.1 Confidentialité La confidentialité offerte par SSL impose un certain surcoût en termes de puissance de calcul, qui n’est pas forcément disponible. Par ailleurs, il existe des cas ou SSL ne peut suffire à garantir le degré de confidentialité requis, par exemple si le client ne souhaite pas que le serveur ou d’autres clients non autorisés puissent avoir accès à des données sensibles. Dans de tels cas, il est possible d’avoir recours au cryptage des mes- sages, qui seront alors transmis tels quels, et décryptés uniquement par les destinataires autorisés. 2.2.2 Authentification Optionnelle, l’authentification des clients est rendue possible au niveau du protocole par les options username et password lors du CONNECT. Bien sûr, ceci impose que le broker supporte cette fonctionnalité et dispose des informations nécessaires sur les clients. Une autre possibilité est d’utiliser un certificat de client pour réaliser l’authentification au niveau du hanshake SSL. Les autres mécanismes d’authentifications courants tels que OAuth ne sont pas pris en charge. 2.2.3 Intégrité C’est également une fonctionnalité non intégrée au protocole, mais plutôt simple à mettre en place au niveau applicatif, et qui peut être suppléée par l’usage de SSL.
  • 16. CHAPITRE 2. LE PROTOCOLE MQTT 15 2.2.4 Gestion des droits Il peut être nécessaire pour un broker d’attribuer des droits différents aux clients en fonction de leur identité, pour définir par exemple si un client est autorisé à maintenir une session persistante, le nombre de messages maximal qu’il peut stocker, sur quels sujets peut-il s’abonner ou publier, avec quelle qualité de service, etc. MQTT ne spécifie pas de mécanisme de gestion des droits, mais chaque implémentation de broker est libre de fournir son propre mécanisme. Toutefois, les options dont dispose le broker pour refuser l’action d’un client ne sont pas très nombreuses, par exemple : — refuser un abonnement est rendu possible en renvoyant un code d’er- reur pour le filtre en question, mais ce code peut avoir d’autres signi- fications ; — il n’est pas possible d’indiquer qu’une publication est interdite, les seuls choix possibles sont soit de couper la connexion, soit d’ignorer silencieusement le message. 2.3 Format binaire Dans cette section, nous définissons le format binaire des paquets spécifié par la norme MQTT. Lorsqu’un paquet ne respecte pas le format requis, la seule option possible (sauf indication contraire) est l’abandon pur et simple de la connexion. Les chaines de caractères (notamment les sujets de publication et les filtres d’abonnements) doivent toutes être encodées en utf8, et préfixées par leur longueur sur deux octets, ces chaines sont donc limitées à une longueur de 216 − 1 = 65535 octets. Entête fixe Tous les packets MQTT commencent par un format d’entête fixe, conte- nant le code de commande MQTT (sur 4 bits), un champs de 4 bits et la longueur du reste du paquet (remaining length). Cet entête est parfois suivi d’un entête variable en fonction de la commande. 01234567 Control Packet Type Reserved Remaining length ... 1 to 4 bytes
  • 17. CHAPITRE 2. LE PROTOCOLE MQTT 16 Une particularité de ce champs remaining length est qu’il est de longueur variable, et peut utiliser de 1 à 4 octets en fonction de la taille encodée : — en dessous de 27 octets, la longueur tient sur un octet ; — en dessous de 214 octets, la longueur tient sur deux octets ; — en dessous de 221 octets, la longueur tient sur trois octets ; — enfin, jusqu’à 228 octets, la longueur tient sur quatre octets. La taille maximale d’un paquet MQTT est donc de 256 Mo. 2.3.1 CONNECT L’entête de CONNECT dans la version 3.1.1 se présente sous la forme suivante : Figure 2.3 – Format d’un paquet CONNECT 01234567 Connect (1) 0 Remaining length ...    fixed header length=4 ’M’ ’Q’ ’T’ ’T’    protocol name level=4 user pass will retain will qos will clean 0 flags keepalive length client id (utf8, optional) hhhhhhhhhhhhhhhhhhh hhhhhhhhhhhhhhhhhhh    client identifier ... options
  • 18. CHAPITRE 2. LE PROTOCOLE MQTT 17 Tout d’abord le nom du protocole (préfixé par sa taille), puis le niveau du protocole, des flags indiquant la présence ou non de paramètres option- nels ainsi que la persistance de la session (clean indique que la session est non persistante, et constitue en même temps une directive pour effacer une éventuelle session existante), et enfin la valeur du keepalive. Le corps du message est composé de l’identifiant du client (chaine utf8 préfixée par sa longueur, pouvant être vide depuis MQTT 3.1.1), suivi par les paramètres optionnels dans un ordre défini : le sujet et le corps du message de testament, le nom d’utilisateur et son mot de passe. 2.3.2 CONNACK L’entête du CONNACK est constitué d’un bit pour indiquer si le broker possède déjà une session pour ce client, dans le cas où le client demande à restaurer une session existante, et d’un code de retour sur un octet (seuls les codes de 0 à 5 étant actuellement définis). Figure 2.4 – Format d’un paquet CONNACK 01234567 Connack (2) 0 Remaining length (2) fixed header SP Connect return code 2.3.3 PUBLISH Un paquet PUBLISH contient les valeurs DUP, QoS et Retain dans son entête fixe, suivi par le sujet (taille puis chaine de caractères obligatoirement non nulle), le packet identifier si le QoS est supérieur à zero, puis enfin le corps du message, éventuellement vide.
  • 19. CHAPITRE 2. LE PROTOCOLE MQTT 18 Figure 2.5 – Format d’un paquet PUBLISH 01234567 Publish (3) DUP QoS retain Remaining length ...    fixed header topic length topic name (utf8) hhhhhhhhhhhhhhhhhhh hhhhhhhhhhhhhhhhhhh    1 to 216 − 1 bytes packet identifier (optional) payload (binary) hhhhhhhhhhhhhhhhhhh hhhhhhhhhhhhhhhhhhh    0 to 228 bytes 2.3.4 PUBACK, PUBREC, PUBREL, PUBCOMP Tous ces paquets ont la même structure, seules les valeurs du code de commande et du champs Reserved peuvent varier. Figure 2.6 – Format d’un paquet PUB[ACK/REC/REL/COMP] 01234567 Control type (4-7) Reserved Remaining length (2) fixed header packet identifier 2.3.5 SUBSCRIBE Un paquet SUBSCRIBE comprend un identifiant pour la réponse, puis une liste de souscriptions d’au moins un élément. La structure d’une sous-
  • 20. CHAPITRE 2. LE PROTOCOLE MQTT 19 cription est composée d’un filtre (longueur et chaine de caractères) et de la qualité de service demandée. Figure 2.7 – Format d’un paquet SUBSCRIBE 01234567 Subscribe (8) 2 Remaining length ...    fixed header packet identifier filter length topic filter (utf8) hhhhhhhhhhhhhhhhhhh hhhhhhhhhhhhhhhhhhh QoS ...    1 to n subscriptions 2.3.6 SUBACK Dans un paquet SUBACK, le broker répond avec le même identifiant de paquet, puis retourne les code de retour dans le même ordre que les souscriptions du paquet SUBSCRIBE correspondant. Ces codes de retour correspondent à la qualité de service garantie par le broker (qui peut être inférieure à celle initialement demandée), ou le code d’erreur 0x80 en cas de problème.
  • 21. CHAPITRE 2. LE PROTOCOLE MQTT 20 Figure 2.8 – Format d’un paquet SUBACK 01234567 Suback (9) 0 Remaining length ...    fixed header packet identifier return code ... 1 to n return codes 2.3.7 UNSUBSCRIBE UNSUBSCRIBE ressemble beaucoup à SUBSCRIBE, à ceci près que le client ne spécifie pas de qualité de service. Figure 2.9 – Format d’un paquet UNSUBSCRIBE 01234567 Unsubscribe (10) 2 Remaining length ...    fixed header packet identifier filter length topic filter (utf8) hhhhhhhhhhhhhhhhhhh hhhhhhhhhhhhhhhhhhh ...    1 to n subscriptions 2.3.8 UNSUBACK UNSUBACK sert de confirmation pour UNSUBSCRIBE, et contient simplement l’identifiant de paquet de la requête correspondante.
  • 22. CHAPITRE 2. LE PROTOCOLE MQTT 21 Figure 2.10 – Format d’un paquet UNSUBACK 01234567 Unsuback (11) 0 Remaining length (2) fixed header packet identifier 2.3.9 PINGREQ, PINGRESP Ces deux paquets sont très simples, et sont constitués uniquement de l’entête fixe du protocole, tenant ainsi sur deux octets. Figure 2.11 – Format d’un paquet PING[REQ/RESP] 01234567 Control type (12-13) 0 Remaining length (0) fixed header 2.3.10 DISCONNECT Sert à indiquer au broker l’intention du client de se déconnecter, et com- porte uniquement l’entête fixe. Figure 2.12 – Format d’un paquet DISCONNECT 01234567 Disconnect (14) 0 Remaining length (0) fixed header 2.4 Conclusion Nous avons vu que MQTT est un protocole tout à la fois minimaliste et très simple à mettre en œuvre (en particulier du coté client). Malgré tout, il reste suffisamment souple et extensible pour suffire aux besoins d’un bon nombre d’applications, et est donc particulièrement adapté au contexte de l’IoT. C’est la raison pour laquelle nous avons choisi ce protocole pour expé- rimenter l’approche du test dirigé par les modèles, avec pour objectif de
  • 23. CHAPITRE 2. LE PROTOCOLE MQTT 22 réaliser une modélisation du protocole capable de s’assurer des propriétés que l’on doit être en mesure d’attendre des futurs « objets » d’Internet : conformité avec la norme, interopérabilité des différentes implémentations, respect des exigences de sécurité et tolérance aux erreurs.
  • 24. Chapitre 3 Problématiques de modélisation de MQTT Modéliser un protocole afin d’en tester les applications est une opéra- tion qui présente un intérêt évident dès lors que les tests engendrés vont permettre d’apporter un certain degré de confiance aux produits testés. Plus le protocole est couramment employé et les tests généralisables (ie. applicables au plus grand nombre de produits), plus l’intérêt de ce type d’ap- proche grandit. En effet, le coût de développement du test peut se trouver élevé, mais il sera compensé par son potentiel de réutilisation pour tous les produits ainsi que dans le temps 1. Idéalement, on aimerait disposer d’un moyen de formaliser simplement les exigences qui décrivent le protocole, avec un outil permettant de trans- former ce formalisme en suite de tests garantissant une bonne couverture de ces exigences. Une bonne modélisation devrait également permettre de répondre à des objectifs divers, comme s’assurer des propriétés de robus- tesse des implémentations, d’interopérabilité entre les différents produits, de sécurité, etc. Malheureusement, atteindre un tel niveau d’automatisation est loin d’être trivial. Nous avons voulu d’abord explorer la réalisation d’un banc de test basé sur les modèles spécifique au protocole MQTT, avec l’objectif d’iden- tifier et de résoudre les problématiques soulevées, et, dans le cas où cet exercice se trouverait concluant, d’en généraliser les conclusions à d’autres protocoles sinon à d’autres approches. Nous avons déjà montré au Chapitre 2 que les exigences de la norme MQTT peuvent être divisées en deux parties, avec d’une part l’aspect fonc- 1. On pourra consulter la page du MQTT Interop Testing Day (https://wiki. eclipse.org/Paho/MQTT_Interop_Testing_Day) pour trouver des détails sur la métho- dologie adoptée pour les tests d’interopérabilité entre les diverses implémentations du protocole. 23
  • 25. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT24 tionnel du protocole, et d’autre part l’aspect de bas niveau concernant la définition du format binaire des échanges. En analysant plus en détail la norme MQTT, on s’aperçoit d’ailleurs que certaines exigences ne sont pas accessible depuis l’interface habituelle des clients et nécessitent un accès que l’on pourrait qualifier de bas niveau pour être vérifiées (voir extrait en Table 3.1, les exigences de haut niveau sont indiquées colonne + et celles de bas niveau colonne −). Il nous a donc semblé judicieux de définir dans un premier temps un modèle abstrait du protocole qui ne prenne pas en compte tous les détails de bas niveau de la norme, et visant à activer les divers comportements possibles afin de tester la partie fonctionnelle du protocole. Par la suite, afin de valider le format des commandes échangées, ainsi que de tester le comportement des différents composants et implémentations MQTT en cas d’altération des paquets échangés, nous avons imaginé un système permettant d’analyser et de modifier les trames à la volée. Dans la première partie de ce chapitre (section 3.1) nous présentons les problèmes soulevés par la modélisation abstraite envisagée et, le cas échéant, les solutions proposées. Puis dans la seconde partie (section 3.2), nous traitons de la mise au point du test basé sur les fautes de protocole et altérations des échanges, ainsi que de son intégration au sein de l’environnement de test. Enfin, dans la dernière partie (section 3.3), nous conclurons par une discussion sur le suivi des tests qui s’est avéré particulièrement délicat dans notre contexte. 3.1 Model-Based-Testing du protocole Pour la modélisation des aspects fonctionnels du protocole, nous avons utilisé le paradigme de modélisation state-based à l’aide d’une modélisation UML des différents composants et leurs opérations associées, ainsi que de contraintes Pre/Post en OCL sur les différentes opérations du modèle per- mettant de garantir les invariants définis par la norme MQTT. L’objectif de cette étape étant de formaliser les aspects fonctionnels du protocole, puis d’employer un moteur de génération de tests afin de trans- former ce formalisme en suites de test visant à activer les différents compor- tements possibles pour le protocole. Nous n’entrerons pas ici dans les détails de la modélisation effectuée (ce sera fait section 4.2), mais nous exposerons dans un premier temps les prin- cipales problématiques que nous avons identifiées comme liées au contexte particulier du test des applications MQTT.
  • 26. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT25 Table 3.1 – Analyse du « niveau » de quelques exigences de la norme MQTT Number Normative statement + - 1.5.3-2 A UTF-8 encoded string MUST NOT include an encoding of the null character U+0000. 2.2.2-1 Where a flag bit is marked as “Reserved” in Table 2.2, it MUST be set to the value listed in that table. 3.1.2-1 If the protocol name is incorrect the Server MAY disconnect the Client, or it MAY continue processing the CONNECT packet in accordance with some other specification. 3.1.2-4 If CleanSession is set to 0, the Server MUST resume commu- nications with the Client based on state from the current Ses- sion. If there is no Session associated with the Client identifier the Server MUST create a new Session. 3.1.2-22 If the User Name Flag is set to 0, the Password Flag MUST be set to 0. 3.1.3-7 If the Client supplies a zero-byte ClientId, the Client MUST also set CleanSession to 1. 3.3.1-4 A PUBLISH Packet MUST NOT have both QoS bits set to 1. 3.3.2-2 The Topic Name in the PUBLISH Packet MUST NOT contain wildcard characters. 3.8.4-1 When the Server receives a SUBSCRIBE Packet from a Client, the Server MUST respond with a SUBACK Packet. 3.9.3-2 SUBACK return codes other than 0x00, 0x01, 0x02 and 0x80 are reserved and MUST NOT be used. 4.3.1-1 In the QoS 0 delivery protocol, the Sender MUST send a PU- BLISH packet with QoS=0, DUP=0. 4.3.2-1 In the QoS 1 delivery protocol, the Sender MUST send a PU- BLISH Packet containing this Packet Identifier with QoS=1, DUP=0. MUST treat the PUBLISH Packet as "unacknowled- ged" until it has received the corresponding PUBACK packet from the receiver. 4.3.2-2 In the QoS 1 delivery protocol, the Receiver MUST respond with a PUBACK Packet containing the Packet Identifier from the incoming PUBLISH Packet. 4.3.3-1 In the QoS 2 delivery protocol, the Sender MUST send a PU- BLISH packet containing this Packet Identifier with QoS=2, DUP=0. MUST treat the PUBLISH packet as "unacknowled- ged" until it has received the corresponding PUBREC packet from the receiver. MUST send a PUBREL packet when it re- ceives a PUBREC packet from the receiver. MUST treat the PUBREL packet as "unacknowledged" until it has received the corresponding PUBCOMP packet from the receiver. 4.3.3-2 In the QoS 2 delivery protocol, the Receiver MUST respond with a PUBREC containing the Packet Identifier from the incoming PUBLISH Packet. MUST respond to a PUBREL packet by sending a PUBCOMP packet containing the same Packet Identifier as the PUBREL. 4.4.0-1 When a Client reconnects with CleanSession set to 0, both the Client and Server MUST re-send any unacknowledged PU- BLISH Packets (where QoS > 0) and PUBREL Packets using their original Packet Identifiers. 4.7.1-1 The wildcard characters MUST NOT be used within a Topic Name. 4.7.3-1 All Topic Names and Topic Filters MUST be at least one character long.
  • 27. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT26 3.1.1 Sujet du test et observation Rappelons ici que la définition du protocole englobe le comportement de différents acteurs tels que le broker et les clients, qui forment un en- semble d’interactions possibles très riche. Ainsi le système sous test (SUT) comprendra généralement tous les acteurs dont on cherche à valider le com- portement, tandis que nous définissons ici comme « sujet » du test le ou les produits qui sont visés par un test en particulier. Pour notre part, nous avons opté pour une modélisation globale du sys- tème sans adopter de point de vue particulier (et notamment sans faire de distinction selon les différents types de composants testés), ce qui pose la question lors de l’exécution d’une suite de tests de savoir quel est le compo- sant testé et comment l’observer en particulier. En effet, pour des raisons d’interface, les composants directement ma- nipulés lors d’un test ne seront pas nécessairement ceux dont on cherche à valider le comportement. Ceci se traduit par une plus grande complexité dans la mise en place de points d’observation, qui doivent se situer au niveau macroscopique du système (par ex. en analysant les échanges réseau dans leur ensemble, et pas seulement coté broker ou client). Pour résoudre la question de l’identification des composants fautifs, on utilisera autant que possible une implémentation de référence pour les parties qui ne sont pas directement concernées par le test, mais il nous a également paru souhaitable que le suivi des tests soit capable de distinguer quel est le composant responsable de l’échec d’un test en particulier. 3.1.2 Non déterminisme Il nous est vite apparu que les séquences d’actions qui font ici l’objet du test (l’échange de messages entre différentes parties au sein du réseau) sont essentiellement non déterministes. En effet, l’aspect asynchrone des échanges fait que l’on ne peut pas tou- jours contrôler l’ordre d’envoi et/ou de distribution des messages, et plus il y a d’acteurs impliqués et donc de messages échangés entre les différentes sources, plus l’incertitude quant à l’ordre des actions augmente. Par ailleurs, les sujets du test (i.e. les différentes implémentations de clients et brokers MQTT) ne proposent pas toujours une interface permet- tant de contrôler finement ce qui se passe au niveau du protocole, ce qui peut avoir pour effet d’aggraver l’incertitude en question. En dernier lieu, certaines exigences de la norme MQTT concernant le broker sont optionnelles (par ex. le support ou non de tous les niveaux de QoS), et donnent lieu à différents comportements possibles dans certains cas. Cet aspect des choses rend le suivi du test beaucoup plus complexe, les solutions permettant de contrôler l’exécution d’une suite de test non-
  • 28. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT27 déterministe et donner un verdict étant plus délicates à mettre en œuvre que pour un test déterministe. Également, certaines configurations seront plus difficiles sinon impossibles à atteindre, du moment que l’on ne maitrise pas totalement le déroulement du test. 3.2 Altération des échanges MQTT Tester uniquement des composants concrets ne permet pas nécessaire- ment d’activer toutes les erreurs possibles, ainsi il est nécessaire de pouvoir transmettre des trames spécialement forgées avec des erreurs afin de s’assu- rer une bonne couverture de test. Afin de répondre à ce besoin, nous avons choisi d’ajouter un module capable de modifier à la volée les trames MQTT échangées entre les compo- sants sous test. Module qui peut être intercalé entre un broker MQTT et ses clients tout en restant transparent pour les différentes parties, tel un proxy. En mode analyse, ce proxy se contenterait d’analyser les paquets qui transitent entre les différents composants, tandis qu’en mode d’injection il permettrait de modifier les trames MQTT en prenant en compte leur structure, ciblant ainsi avec précision les champs que l’on veut perturber et les modifications que l’on souhaite apporter. Pour mettre au point cet outil, il faut donc modéliser la structure binaire des trames MQTT et le type des divers champs qui les constituent (cf. section 2.3), afin de pouvoir leur appliquer des modifications pertinentes pour le test en fonction du type des champs altérés, de leur valeur, etc. L’intégration de ce modèle au sein du modèle général pose toutefois un problème qui sera discuté plus bas. Il serait également possible d’envisager une approche plus complète, en donnant à un composant intermédiaire la possibilité de jouer alternativement le rôle du client ou du broker MQTT, et ainsi de mieux maitriser l’ensemble du test. Mais cette approche reviendrait à implémenter l’ensemble du protocole uniquement à des fins de test, ce qui nous a paru trop couteux et impraticable dans le cas général. 3.2.1 Suivi et validation des trames Un des avantages apportés par l’introduction de ce type de proxy est qu’il autorise un suivi précis des trames échangées au niveau du réseau sans avoir à utiliser un outil spécialisé comme un sniffeur de réseau. Ainsi il est très facile d’enregistrer l’ensemble des trames échangées dans un fichier de log pour une analyse ultérieure. On peut également outiller le suivi des trames MQTT en y ajoutant une validation des trames à la volée, ce qui permet de détecter facilement les composants fautifs dans l’implémentation de la partie bas niveau du protocole.
  • 29. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT28 Ainsi, il est possible de suivre les trames entrant dans le proxy et d’en contrôler la validité, tout en conservant la faculté d’appliquer des mutations aux trames sortantes. 3.2.2 Critères de transformation Dans une optique d’injection de données faussées, il convient d’établir des critères de transformation pertinents pour les différents champs pré- sents dans les trames, et de disposer d’un moyen efficace pour choisir et appliquer ces transformations. Critères qui doivent être pris en compte pour la modélisation des trames du protocole si l’on veut pouvoir effectuer des modifications intéressantes dessus. Pour cela, le type des champs et leur valeur peuvent être exploités afin de sélectionner diverses catégories de mutations. Par exemple, on peut choisir les valeurs aux limites en fonction du domaine de chaque champs, ou encore de réaliser des mutations pour altérer certaines valeurs au plus proche. Il est également très simple d’injecter des valeurs explicitement interdites par le protocole pour faire du test de robustesse. On pourra aussi décider de ne pas retransmettre une commande pour perturber l’échange entre les clients et le broker, ou encore de couper la connexion de façon intempestive pour simuler des problèmes de réseau. 3.2.3 Intégration L’une des difficultés liées à cette approche réside dans le fait que l’outil en question n’a pas une vision globale sur l’ensemble des échanges, et il lui est donc difficile de choisir quelles transformations appliquer sur les données à un moment donné. Il est bien sûr possible d’appliquer des transformations aléatoires (fuz- zing), mais l’on perdrait alors l’essentiel du bénéfice de la modélisation. Par ailleurs, l’analyse des tests deviendrait dès lors beaucoup plus laborieuse, puisque l’on ne va pas disposer d’un oracle permettant de connaitre auto- matiquement le résultat attendu pour chaque test. On peut également envisager des approches plus évoluées dans lesquelles le proxy serait intégré dans un système de modélisation plus général et piloté par ce dernier. Il faut pour cela que la modélisation prenne en compte le format binaire du protocole en question, le proxy devenant alors un simple exécutant des séquences prévues. 3.3 Analyse des tests La nature des problématiques évoquées plus haut complexifie largement le processus de suivi automatisé des suites de test.
  • 30. CHAPITRE 3. PROBLÉMATIQUES DE MODÉLISATION DE MQTT29 D’une part, l’aspect non déterministe pose des difficultés pour établir et vérifier le verdict de chaque cas de test, puisqu’il n’existe pas qu’une seule trace d’exécution valide possible mais bien plusieurs. Pour pallier à cela, il faut donc vérifier que la trace obtenue correspond bien à l’une des traces possibles. Même sans cette difficulté, le résultat d’une séquence de test n’est pas toujours exprimable par un résultat précis (par ex. vérifier si tel message est bien reçu ou non), car il faut vérifier que le protocole a été respecté de bout en bout. Pour ces raisons, il nous parait souhaitable de doter le modèle de la ca- pacité d’analyser le passage d’un test en vérifiant tout au long de l’exécution que les invariants définis sont bien respectés, autrement dit que la trace cor- respond bien à un chemin d’exécution possible du modèle. Il ne s’agit pas seulement ici de générer le test en mode online, mais bien de suivre son exécution pas à pas à l’aide du modèle. Le détail des commandes échangées par le protocole devrait dans la plu- part des cas constituer une trace suffisante pour effectuer ce type d’analyse. En ce qui concerne l’idée de test à base de mutations des trames, si l’on se contente de modéliser uniquement la partie bas-niveau du protocole, il sera impossible de prédire quelle est la réaction attendue pour une grande partie des modifications possibles. Pour autant, certaines transformations devraient systématiquement don- ner lieu à une coupure de la connexion, et sont donc facilement vérifiables. Pour les autres, elles peuvent être pilotées depuis un système extérieur pro- posant des modifications ciblées, soit faire l’objet d’une analyse manuelle ou se limiter à vérifier que le SUT ne tombe pas en panne (crash) à cause d’une trame mal formée.
  • 31. Chapitre 4 Travail réalisé Une partie de notre travail de recherche a consisté en l’expérimenta- tion de l’approche de modélisation envisagée au chapitre précédent. Nous présentons ces contributions dans ce chapitre. Nous avons commencé par modéliser l’aspect fonctionnel de MQTT avec l’outil CertifyIt de Smartesting, qui nous a permis de construire un modèle abstrait du protocole. Notre modèle inclut la plupart des fonctionnalités et exigences définies par la norme sous forme de contraintes, et permet de générer des suites de test en conséquence. Faute de temps, nous n’avons pu compléter cette modélisation, mais l’exercice devrait être pleinement réalisable. L’outil évoqué en section 3.2 a été partiellement réalisé, à travers la mo- délisation binaire des trames du protocole et le développement du proxy MQTT envisagé. Pour le reste, nous avons dû réviser une partie de nos ambitions à la baisse. La validation des trames à la volée a été implémentée, ainsi que le mode de fuzzing autonome, mais nous n’avons pas exploité la possibilité de piloter le proxy à partir du modèle. Les suites de tests ont été rendues exécutables grâce à l’export des tests en python et l’écriture d’un adaptateur approprié pour un client MQTT de notre choix. La plus grande difficulté a sans doute été l’établissement du verdict pour les cas de test. Nous nous sommes finalement contentés de générer les sé- quences de messages attendues pour chaque cas de test, qui ont fait l’objet d’un contrôle manuel. Dans la section 4.1, nous présentons les principaux outils utilisés pour les expérimentations, depuis la phase de modélisation jusqu’à celle de l’analyse 30
  • 32. CHAPITRE 4. TRAVAIL RÉALISÉ 31 des tests. Ensuite, à la section 4.2, nous détaillerons la modélisation de la partie fonctionnelle du protocole avec CertifyIt, ainsi que de l’export des suites de tests dans un environnement exécutable. Dans la section 4.3 nous décrirons la mise en œuvre d’un proxy MQTT doté de fonctionnalités adaptées à notre banc de test. Enfin, nous dresserons le bilan de nos expérimentations en section 4.4. 4.1 Outils utilisés 4.1.1 Smartesting CertifyIt CertifyIt est une chaine d’outils dédiée au Model-Based Testing, basée sur le langage UML pour la modélisation et le langage OCL (Object Constraint Language) pour l’expression des contraintes sur les modèles. Fruit d’une collaboration entre l’institut Femto-ST et la compagnie Smar- testing, CertifyIt permet de modéliser un système sous test (SUT) et de générer automatiquement des suites de test selon différents critères, à partir des contraintes indiquées dans le modèle. Figure 4.1 – CertifyIt - vue de l’éditeur UML Le logiciel est divisé en deux parties : — un éditeur de modèles (Figure 4.1) sous la forme d’un plugin pour Rational Software Architect Designer d’IBM (lui même reposant sur Eclipse), qui permet de modéliser le SUT, de définir les critères de
  • 33. CHAPITRE 4. TRAVAIL RÉALISÉ 32 sélections de tests, et d’exporter le tout dans un format supporté par le générateur de tests ; — un générateur de tests (Figure 4.2) avec différentes fonctionnalités telles que le suivi des exigences, des contraintes activées pour chaque test, l’export des tests en divers formats d’exploitation (comme XML, ou encore JUnit). Figure 4.2 – CertifyIt - vue du générateur de tests Modélisation La notation UML employée est un sous ensemble d’UML2, restreint aux besoins du test dirigé pas les modèles, appelé UML4MBT. La nota- tion OCL pour les contraintes est également restreinte à un sous ensemble appelé OCL4MBT. Seuls trois types de diagrammes UML sont supportés : — les diagrammes de classes, utilisés pour modéliser les variables du sys- tème, ainsi que les points de contrôle et d’observation ; — les diagrammes d’états-transitions, qui permettent de modéliser la dy- namique du système ; — les diagrammes d’objets, qui permettent de définir les instances d’ob- jets qui serviront pour le test. Les expressions OCL servent deux objectifs bien distincts :
  • 34. CHAPITRE 4. TRAVAIL RÉALISÉ 33 — d’une part, à exprimer les conditions associées aux objets du modèle, en définissant les pré-conditions de certaines opérations du diagramme de classes, et les gardes sur les transitions du diagramme d’états. — d’autre part, à formaliser le comportement du modèle en termes d’ac- tions qui vont modifier l’état du système, grâce aux post-conditions des opérations et aux effets des transitions. Pour remplir ces deux rôles, la sémantique de OCL4MBT dépend du contexte, le sens des expressions pouvant être soit déclaratif comme dans le cas d’OCL, soit exprimeront le comportement des opérations à la façon d’un langage de programmation. Sélection des tests L’approche du test dirigé par les modèles emploie des critères de sélection divers pour dériver les cas de test à partir du modèle. Avec CertifyIt, le critère de sélection principal consiste à activer les com- portements qui ont été modélisés (behavioral test objectives). Il est possible de sélectionner l’ensemble des méthodes qui seront utilisés pour une suite de tests donnée (test fixtures) parmi les méthodes publiques du modèle. D’autres critères peuvent aussi être utilisés, comme avec les test purposes qui permettent de formaliser différents scénarios que le générateur de tests cherchera à satisfaire. 4.1.2 Eclipse Paho project Le projet Paho 1 de la fondation Eclipse a pour vocation de fournir des implémentations open-source de qualité pour les protocoles de messaging ouverts et standardisés, dans le but de favoriser l’émergence de nouveaux produits et applications liés à l’Internet des Objets. Le projet a été initialement lancé dans le but de fournir des implémen- tations MQTT pour les plateformes embarquées, et propose aujourd’hui des clients MQTT pour différents langages de programmation. Nous nous somme intéressés en particulier à l’implémentation python du projet, afin d’en étudier son code source et avec l’intention de s’en servir comme candidat au test. paho.mqtt.python paho.mqtt.python provient à l’origine du client python Mosquitto de Roger Light, qui l’a mis à la disposition du projet Paho et continue son développement. Le projet est actuellement disponible sur github à l’adresse https://github.com/eclipse/paho.mqtt.python, et constitue sans doute l’implémentation open-source de référence en python. 1. https://wiki.eclipse.org/Paho
  • 35. CHAPITRE 4. TRAVAIL RÉALISÉ 34 Dans un premier temps, nous avons étudié son fonctionnement à l’aide du code source. Ainsi nous avons pu relever un certain nombre de bugs et d’anomalies vis-a-vis du protocole qui ont été rapportées sur le bugtracker du projet 2. Ceci nous a fait prendre pleinement conscience de l’importance de pou- voir tester extensivement ces produits, qui malgré le fait d’être open-source et de disposer d’un bon nombre d’utilisateurs, peuvent tout de même com- porter divers bugs. Par la suite, c’est l’implémentation que nous avons choisi d’utiliser coté client pour nos expérimentations, qui ont été réalisées avec le langage python et que nous présentons aux sections suivantes. 4.1.3 Wireshark Wireshark est un analyseur de paquets réseau disposant d’une foule de fonctionnalités avancées (en particulier un sniffer très pratique à utiliser et des filtres), et le support de très nombreux protocoles dont MQTT 3 . Figure 4.3 – Wireshark 2.0.5 - vue du logiciel Ce logiciel est couramment utilisé dans le monde de l’éducation afin de permettre aux étudiants de mieux comprendre les protocoles réseau. Nous 2. https://github.com/eclipse/paho.mqtt.python/issues/created_by/yoch 3. Depuis la version 1.12 du 31 Juillet 2014. A noter que MQTT-SN est également supporté depuis la version 2.0.
  • 36. CHAPITRE 4. TRAVAIL RÉALISÉ 35 l’avons exploité de deux manières, d’une part afin de mieux comprendre certains aspects du protocole MQTT, et d’autre part pour l’analyse manuelle de certains tests. Dans la capture d’écran visible Figure 4.3, on peut voir que le filtrage du protocole MQTT est activé, la liste des paquets interceptés est visible dans le cadre du haut, et dans celui du milieu et celui du bas sont représentés le contenu du paquet sélectionné (structure détaillée et données binaires). 4.2 Modélisation fonctionnelle du protocole MQTT Le Model Based Testing suit généralement le processus suivant [15] : 1. Construction du modèle de test d’après les spécifications produit, qui doit proposer le bon niveau d’abstraction pour permettre de générer des cas de tests en rapport avec les exigences. 2. Choix de critères de sélection de test, en fonctions des objectifs et de la politique de test. Ces critères seront transformés en spécifications sur les cas de test à générer. 3. Génération de la suite de test, éventuellement en optimisant le nombre de tests produits. 4. Exécution des tests, qui peut être manuelle ou automatisée. Il s’agit tout d’abord de concrétiser les cas de test, puis d’envoyer les données au SUT, et d’observer les résultats. Usuellement, on utilise un adaptateur pour cette tâche, qui sert à adapter les cas de test au SUT et les sorties du SUT à l’outil de test qui va les comparer avec le résultat attendu. Pour notre expérimentation, le processus adopté se représente comme suit (Figure 4.4) : Figure 4.4 – Processus du test de MQTT basé sur les modèles — La modélisation du protocole a été effectuée en UML/OCL ; — Génération des suites de tests aux critères dits behavioral test objectives avec l’outil CertifyIt, qui sont ensuite exportés en XML ; — Ce fichier XML nous permet de générer un script pour piloter les tests, ainsi que le squelette du code python pour l’adaptateur, qui sera complété manuellement pour permettre l’exécution des tests sur une cible donnée ;
  • 37. CHAPITRE 4. TRAVAIL RÉALISÉ 36 — Les tests sont exécutés à l’aide script python et produisent une trace d’exécution pour chaque test ; — Les logs servent pour l’analyse des résultats du test, en les comparant avec la trace attendue par le modèle. 4.2.1 Mise en œuvre Nous avons réalisé une modélisation de la partie fonctionnelle du proto- cole MQTT en UML/OCL à l’aide de CertifyIt (Figure 4.5). Dans ce qui suit nous retraçons les grandes lignes de cette contribution. Figure 4.5 – Modélisation UML du protocole MQTT Détail du modèle Les composants UML principaux sont les classes Broker et Client, le broker pouvant prendre en charge simultanément la connexion de plusieurs clients. Chaque client connecté maintient une Session lui permettant de contrôler le transit des messages, tandis que le broker maintient une Session pour chaque client.
  • 38. CHAPITRE 4. TRAVAIL RÉALISÉ 37 Un client peut être soit déconnecté, soit connecté au broker sans avoir initié un échange MQTT, soit connecté avec une session en cours. Le premier aspect est géré par une relation one-to-many entre le broker et les clients modélisant la connexion TCP, tandis que le second aspect est géré à l’aide d’un booléen indiquant que la session est commencée. Coté broker, la gestion des identités des clients se fait à l’aide de la classe Identifier qui représente simplement un couple login / mot de passe. Une méthode register permet de modéliser l’ajout de nouveaux couples d’identifiants (login et mot de passe). Quant à la gestions des abonnements, elle est gérée par le broker avec la classe Subscription, et est limitée ici au filtrage des motifs par corres- pondance exacte pour des raisons de simplicité. Lorsqu’un client envoie une demande d’abonnement avec la méthode subscribe, le broker crée un nouvel abonnement avec l’identifiant du client, le filtre de sujet et la qualité de ser- vice requise, et l’ajoute à sa liste d’abonnements. La méthode unsubscribe provoque à l’inverse la suppression d’un abonnement existant. La classe Message modélise les messages véhiculés par le protocole et contient les informations permettant de suivre l’évolution de l’état de trans- mission d’un message. Cet état est régi par un système d’états / transitions implicite codé dans les post-conditions OCL. Gestion des types chaines de caractères Le type chaines de caractères n’étant pas supporté par CertifyIt, nous l’avons substitué par des énumérations destinées à représenter des types de données particuliers, comme par exemple un mot de passe. Gestion des échanges asynchrones Dans une première version de notre travail, l’enchainement des actions était réalisée par des appels de méthodes imbriqués, ce qui rendait le modèle totalement synchrone et peu satisfaisant. Il était en effet impossible de pro- voquer une seconde action avec effet de bord tout au long de l’enchainement des actions déclenché par telle ou telle méthode (par exemple de couper la connexion au cours d’un échange de trames servant à valider la réception d’un message). C’est pourquoi, nous avons modifié le modèle initial en limitant l’en- semble des méthodes à un seul échange réseau, la suite de l’enchainement étant assurée par la méthode process_messages. Ainsi le générateur de tests peut ou non employer cette méthode pour influer sur le déroulement du test.
  • 39. CHAPITRE 4. TRAVAIL RÉALISÉ 38 Annotations pour le suivi des exigences Les post-conditions ont été documentées à l’aide du mécanisme d’anno- tation de CertifyIt afin de permettre le suivi des exigences. Diagramme d’objets CertifyIt requiert de créer les instances et relations nécessaires au test dans un diagramme d’objet. Pour plus de souplesse, le modèle a été conçu pour être aussi dynamique que possible. Aussi, les relations n’ont pas été établies au sein du diagramme d’objets, mais sont manipulables à l’aide des méthodes définies par le modèle, ce qui permet au générateur de créer ou supprimer des relations en fonction des besoins. 4.2.2 Fonctionnalités modélisées La plupart des fonctionnalités de MQTT mentionnées section 2.1 ont été modélisées, certaines n’ayant toutefois pas pu l’être faute de temps. Comme vu en section 2.2, peu d’aspects de sécurité sont directement pris en charge par le protocole, mais reposent plutôt sur des mécanismes connus comme SSL ou sont relégués à des extensions non normalisées voire au domaine applicatif. Le seul point de sécurité qui a donc été introduit dans notre modèle est celui de l’authentification des clients. Nous présentons dans ce qui suit l’essentiel des fonctionnalités modéli- sées, accompagnées de quelques illustrations concrètes. Connexion Les principaux aspects de l’enregistrement auprès du serveur (envoi du paquet CONNECT et réponse) ont pu être modélisés : — toute connexion doit débuter par un CONNECT ; — pas de double CONNECT ; — gestion du renouvellement de session ; — authentification des clients ; La dimension temporelle impliquée par le keepalive n’a pas été introduite dans le modèle car trop complexe pour un gain relativement faible (seule les commandes PINGREQ et PINGRESP sont concernées, et leur validation ne pose pas de problème particulier). Un exemple de postcondition OCL pour la gestion du CONNECT par le broker est proposé Figure 4.6. On y trouve l’interdiction d’un double CONNECT ainsi que celle de restaurer une session pour un client anonyme, les autres exigences étant traitées par des méthodes auxiliaires.
  • 40. CHAPITRE 4. TRAVAIL RÉALISÉ 39 Figure 4.6 – Postcondition OCL pour handle_connect() Abonnements et Publications Le mécanisme d’abonnement et ses différentes commandes est lui aussi modélisé : — vérification (partielle) de la validité des sujets ; — vérification de la validité de la qualité de service requise ; — gestion des abonnements et réponse du broker ; — gestion des publications ; Cependant, certains détails du protocole ont été simplifiés par commo- dité, notre modèle ne prenant pas en charge les abonnements multiples. Qualité de service et Persistance La gestion des échanges impliqués par les différentes qualités de service a également pu être modélisée : — support des différentes réponses : PUBACK, PUBREC, etc. — mise des messages en file d’attente de la session pour gérer les décon- nexions ; — gestion des identifiants de paquets ; L’aspect asynchrone des échanges a été modélisé avec l’approche détaillée en section 4.2.1. On peut voir l’essentiel du traitement asynchrone du coté client Figure 4.7, l’état des messages en file d’attente pouvant changer dès lors que le générateur fait appel à process_messages() 4 . 4. Il serait également possible de modifier l’état d’un seul message dans la file d’attente, mais ceci surchargerait à coup sûr le générateur.
  • 41. CHAPITRE 4. TRAVAIL RÉALISÉ 40 Figure 4.7 – Postcondition de process_messages() coté client Messages retenus et Testament Ces deux aspects du protocole n’ont pas été modélisés par manque de temps, mais ne devraient pas poser de problème particulier. 4.2.3 Génération des tests Afin de distinguer les différents objectifs de test, nous avons créé plusieurs suites de test avec différentes cibles : test de l’identification des clients, test des publications de messages, etc. Pour ce faire, nous avons sélectionné pour chaque suite des sous-ensembles de fixtures utilisables parmi les méthodes publiques du modèle, ce qui laisse au générateur un choix restreint d’actions disponibles pour dériver les cas de tests. Nous avons été confrontés à quelques problèmes à ce stade, le plus no- table étant le temps de génération qui pour certaines séquences de test peut devenir prohibitif. C’est l’une des raisons pour laquelle nous avons décidé de ne pas modéliser les aspects de bas niveau du protocole dans le même
  • 42. CHAPITRE 4. TRAVAIL RÉALISÉ 41 modèle, ce qui l’aurait sans doute rendu inutilisable pour générer des tests. Pour concrétiser et exécuter nos tests, nous avons choisi de transformer les suites de tests générés avec CertifyIt en scripts python. Pour ce faire, nous avons utilisé l’export depuis CertifyIt vers XML, puis employé un petit script pour transformer ce fichier XML en modules et scripts python nécessaires à l’exécution des tests. On trouvera un extrait d’une des suites de tests ainsi générées en Annexe A.1. Une fois cette étape terminée, il faut encore compléter l’écriture de l’adaptateur qui permettra au code généré de piloter un client ou un broker existant. Réaliser l’adaptateur se résume à établir un pont entre les diffé- rentes méthodes publiques du modèle et l’implémentation sous test. Nous avons utilisé le client python du projet Paho, qui a demandé très peu d’efforts pour écrire l’adaptateur (voir Annexe A.2). En revanche, notre suite de tests qui emploie l’interface du broker n’est pas exécutable en l’état. 4.2.4 Verdict Au vu de la difficulté de poser un verdict sur l’exécution d’un test (évo- quée ci-dessus section 3.3), la stratégie que nous avons retenue consiste à comparer les trames virtuellement échangées au niveau du modèle avec celles réellement échangées par le SUT. Nous avons pour cela instrumenté le modèle afin de pouvoir extraire les séquences de trames échangées à partir des cas de test, et stocké ces dernières dans un fichier généré en même temps que le script de test. D’autres problématiques sont alors apparues, comme le fait que les iden- tifiants de paquet ne peuvent être maitrisées depuis le modèle et requièrent un traitement particulier lors de la comparaison, ou la question de faire cor- respondre les entités du modèle avec celles des trames réellement échangées, etc. Par ailleurs, nous avons relevé que l’implémentation du client a parfois un comportement préventif et empêchera une action interdite que l’on cherche à tester, ce qui introduit des faux positifs dans les résultats de test. Enfin, il s’est avéré que l’aspect asynchrone du système empêche de pré- dire le résultat attendu dans certains cas de tests qui deviennent non déter- ministes, puisque l’on ne peut contrôler l’enchainement exact des actions. Pour toutes ces raisons, cette étape n’a encore pu être complètement automatisée. 4.3 Proxy de test MQTT L’architecture logicielle du proxy MQTT évoqué au chapitre précédent (section 3.2) est celle d’un serveur capable de maintenir des couples de connexions entre les clients et le broker.
  • 43. CHAPITRE 4. TRAVAIL RÉALISÉ 42 Figure 4.8 – Architecture du proxy de test MQTT Comme on peut le voir Figure 4.8, le proxy est donc capable de rester transparent et se contenter d’analyser le trafic (client 1), mais peut aussi modifier à la volée voire supprimer les trames échangées dans les deux sens (client 2). 4.3.1 Réalisation Nous avons écrit un petit proxy pour MQTT en python sur la base de l’architecture proposée et mis son code à disposition sur GitHub 5. Ce proxy consiste en un serveur TCP multi-threads. Il est configuré en lui donnant l’adresse du broker que l’on veut substituer, et va attendre les connexions des clients sur son adresse propre. Pour chaque client qui se connecte, il ouvre une connexion client vers le broker, et transmettra ensuite les trames MQTT de part et d’autre. 4.3.2 Modélisation du protocole Si un simple proxy MQTT n’a nullement besoin de reconnaitre le proto- cole sous-jacent pour fonctionner, les fonctionnalités de validation et d’alté- ration des trames imposent de modéliser la structure des trames du protocole pour pouvoir les manipuler. Nous avons donc réalisé une bibliothèque capable de décoder des trames MQTT, éventuellement les modifier, et les restituer sous forme binaire (voir extraits du fichier mqtt_protocol.py en Annexe A.3). La conception est orientée objet, toute trame MQTT étant représen- tée par un objet de type MQTTPacket qui comporte l’entête fixe et un ob- jet MQTTBody pour le reste du paquet. Différentes sous-classes héritent de MQTTBody et seront utilisées en fonction du type de paquet reçu. 5. https://github.com/yoch/MQTT-Proxy
  • 44. CHAPITRE 4. TRAVAIL RÉALISÉ 43 Toutes ces classes comportent des méthodes _decode et _encode per- mettant respectivement de décoder une trame binaire reçue pour initialiser l’objet ou de créer une trame binaire depuis un objet. Ainsi chaque trame entrante est transformée en objet, et peut être reconvertie en trame binaire avant de la transmettre de l’autre coté. D’autres méthodes ont ensuite été ajoutées aux objets afin de les enrichir en fonctionnalités, comme check qui permet de vérifier la validité d’une trame à l’aide d’assertions et remonte en cas d’erreur un code permettant de connaitre exactement quelle portion de la norme est en cause. 4.3.3 Intégration au script de test Notre proxy s’est avéré très utile pour s’intégrer au processus de test. En effet, il permet de : — valider la structure binaire des trames échangées, ce qui n’est pas pris en charge par la modélisation fonctionnelle évoquée plus haut ; — récupérer simplement l’ensemble des trames échangées pour chaque cas de test, dans le but de valider ou non ledit cas. L’architecture finale du processus de test est schématisée Figure 4.9. On peut voir que même si le système est composé d’un broker et d’un client, il suffit d’initier des actions sur le client (qui sert d’interface) pour que l’ensemble des échanges soit récupéré par le proxy et analysé. Figure 4.9 – Notre processus du test pour MQTT
  • 45. CHAPITRE 4. TRAVAIL RÉALISÉ 44 4.4 Bilan Nous présentons ici les résultats de nos expérimentations avec le modèle décrit ci-dessus. 4.4.1 Tests générés avec CertifyIt Nous avons généré deux suites de tests avec CertifyIt, soit en tout une quarantaine de tests : TestAuth visant à tester les fonctionnalités d’authentification, avec 11 tests générés ; TestPublish pour tester le fonctionnement du Publish/Subscribe tel que défini par MQTT, avec 27 tests générés. On peut voir en Table 4.1 le nombre de scénarios du modèle atteints et le nombre de scénarios que le générateur n’a pas pu atteindre pour chaque suite de test 6. Sont également indiqués le nombre d’exigences couvertes pour chaque suite de test. Il convient ici de préciser que ce décompte n’est pas lié aux exigences définies par la norme MQTT, chaque exigence dont il est ques- tion ici décrit un comportement complet qui peut inclure un grand nombre d’exigences normatives. Table 4.1 – Statut de la génération des scénarios et couverture des tests reached undetermined covered uncovered TestAuth 36 3 5 16 TestPublish 97 13 21 1 En sachant que tous les aspects fonctionnels du protocole n’ont pas en- core été modélisés, ces résultats nous semblent encourageants. Le principal souci à ce stade reste le temps de génération et la difficulté d’atteindre cer- tains scénarios, sans doute de par la complexité du modèle. 4.4.2 Modélisation du format des trames La modélisation du format binaire des trames MQTT a été réalisée ad- hoc en langage python, d’une part pour éviter de surcharger le modèle initial, et d’autre part afin d’en faire bénéficier notre proxy. L’ensemble des commandes MQTT a été ainsi formalisé, ainsi que toutes les exigences définies par la norme à ce sujet. En revanche, nous n’avons 6. Nous ne relevons pas ici les scénarios marqués comme unreachable car ils sont la conséquence du choix des fixtures pour chaque suite de test. A noter également que nous avons limité la profondeur de recherche à 10 à cause de problèmes de mémoire et de lenteur.
  • 46. CHAPITRE 4. TRAVAIL RÉALISÉ 45 pas exploité ce modèle pour générer des cas de test, mais surtout pour la validation des trames transitant par notre proxy. Un module permettant de faire du fuzzing en altérant les échanges MQTT a également été développé par dessus ce modèle, avec la possibilité de mo- difier les champs selon des critères établis (par ex. test aux limites), mais nous n’avons pas approfondi cette voie. 4.4.3 Exécution des test Nous avons pu réaliser la couche d’adaptation pour le client en python sans difficulté notable, ce qui nous permet d’exécuter la seconde suite de tests. Pour pouvoir exécuter la première suite de tests, il reste à écrire l’adap- tateur vers un broker de notre choix. De la même façon, tester une autre implémentation de client nécessite l’écriture d’une couche d’adaptation spé- cifique. Le proxy a également été intégré dans le processus de test avec succès, ce qui nous permet de valider le format des trames échangées entre le broker et les clients, ainsi que d’obtenir la trace des échanges entre le broker et les clients. L’extraction des séquences de trames attendues à partir du modèle a nécessité d’introduire certaines conventions dans le modèle et d’écrire un outil spécifique permettant d’obtenir ces séquences depuis les cas de test. Toutefois, la validation des tests exécutés pose quant à elle un défi bien plus important, et nous n’avons pas été en mesure d’automatiser le processus pour les raisons invoquées en section 4.2.4. C’est pourquoi, nos tests sont pour l’instant analysés et validés manuellement. 4.4.4 Validation On trouvera en Annexe B la trace produite par les 27 cas de la suite de tests TestPublish. Nous avons étudié attentivement l’ensemble des résul- tats : — 9 cas de tests provoquent une exception du coté client. Parmi ces cas, 5 d’entre eux correspondent à une protection ajoutée par l’implémenta- tion, et 4 d’entre eux proviennent d’un bug du client. Tous ces derniers cas sont liés à une mauvaise gestion de la taille maximale des sujets ; — 2 cas de tests impliquant des sujets invalides (contenant un caractère null) provoquent une exception du proxy. Deux brokers différents ont été testés sur ce cas par la suite, tous deux présentant des défauts (dans les deux cas pour Mosquitto, dans un seul pour HiveMQ) ; — Le problème de non déterminisme évoqué plus haut est bien visible, la plupart des séquences différant de celle attendues, que ce soit pour une raison d’ordre ou de trames supplémentaires ;
  • 47. CHAPITRE 4. TRAVAIL RÉALISÉ 46 — Le client python Paho a comme particularité de se reconnecter au- tomatiquement en cas de déconnexion du broker, ce qui ajoute des échanges de messages inattendus ; — Les comportements testés sont variés, mais l’on ne peut prétendre qu’ils soient exhaustifs, et certains cas de tests ne sont pas bien diffé- renciés (semblent redondants ou peu pertinents). — Le modèle semble cohérent, toutes les traces produites étant parfai- tement valides, même si notre introduction de l’asynchronisme peut donner des traces plus courtes que dans la réalité.
  • 48. Chapitre 5 Conclusion Notre travail nous a permis d’étudier l’application du test dirigé par les modèles au domaine de la communication au sein de l’Internet des objets, et plus globalement aux problématiques liées au réseau. Même si le protocole MQTT n’est pas nécessairement représentatif de toute la complexité de cette question, et malgré le fait que notre travail puisse être encore complété et approfondi, nous avons pu tirer quelques enseignements importants de notre expérimentation et des difficultés que nous avons rencontrées. Tout d’abord, il faut remarquer que la nature même des applications distribuées sur le réseau complexifie fortement la modélisation : il faut en effet prendre en compte la multiplicité des composants qui font partie du système ou de son environnement, ainsi que de l’asynchronisme fréquent des communications qui tend à rendre le modèle non-déterministe. Mais cette complexité impacte aussi l’observation du système sous test, comme nous l’avons développé dans ce document. Le modèle doit permettre d’analyser l’ensemble du système, y compris les composants qui ne sont pas sous le contrôle du testeur, de valider l’ensemble des échanges, et d’identifier les éventuels responsables d’un échec. L’usage de CertifyIt pour cette expérience nous a fait prendre conscience de certaines limites de l’outil. Il est notamment incapable de produire ou d’exploiter des diagrammes de séquence, et ne supporte pas bien les mo- dèles non-déterministes. La comparaison avec les solutions de modélisation existant dans le monde des télécommunications nous parait particulièrement intéressante à cet égard [2]. Même en envisageant l’usage d’autres outils voire d’autres paradigmes de modélisation pour le test des systèmes connectés, nous pensons que la réflexion devra passer par l’anticipation des problèmes que nous avons ren- contré dans notre exploration de la question. 47
  • 49. CHAPITRE 5. CONCLUSION 48 Notre contribution pourrait servir de base pour la validation des implé- mentations MQTT existantes. Peu d’outils existent encore à ce sujet, le seul dont nous ayons connaissance étant celui de Ian Craggs 1, également basé sur le concept model-based testing [3] mais qui se distingue de notre approche par son orientation ad-hoc. Il est toutefois intéressant de noter que l’auteur s’est trouvé confronté à des questions similaires, et que les réponses apportées vont souvent dans le même sens que notre travail. Pour notre recherche, nous nous sommes focalisés essentiellement sur les questions de conformité et d’interopérabilité des implémentations. La di- mension évolutive de notre modèle n’a pas été étudiée, mais n’en reste pas moins intéressante à évaluer, les normes pouvant évoluer. Les aspects de sécurité du protocole pourraient quant à eux faire l’objet d’une étude séparée, même si comme nous l’avons montré une grande part de cette problématique est déléguée aux applications et ne dépend pas du protocole. 1. https://github.com/eclipse/paho.mqtt.testing
  • 50. Bibliographie [1] Andrew Banks et Rahul Gupta. MQTT Version 3.1.1. Rapp. tech. OASIS standard, 2014. [2] Conformiq. Testing Bluetooth Protocol Stacks with Computer-Generated Tests. Rapp. tech. url : https://www.conformiq.com/wp-content/ uploads/2015/02/Bluetooth-Technology-Brief.pdf. [3] Ian Craggs. More Rigorous Testing for MQTT Servers. Model-Based Testing. 18 oct. 2014. url : http://modelbasedtesting.co.uk/?p= 144 (visité le 29/06/2016). [4] ETSI. « Methods for Testing and Specification (MTS) ; Model-Based Testing (MBT) ; Requirements for Modeling Notations ». In : ETSI ES (2011). [5] Gartner Says 6.4 Billion Connected. url : http://www.gartner. com/newsroom/id/3165317 (visité le 07/01/2016). [6] JoramMQ, a distributed MQTT broker for the Internet of Things. Sept. 2014. url : http://www.scalagent.com/IMG/pdf/JoramMQ_ MQTT_white_paper-v1-2.pdf. [7] Valerie Lampkin et al. Building Smarter Planet Solutions with MQTT and IBM WebSphere MQ Telemetry. en. IBM Redbooks, sept. 2012. isbn : 978-0-738-43708-8. [8] Object Constraint Language, v2.4. Rapp. tech. www.omg.org, fév. 2014. url : http://www.omg.org/spec/OCL/2.4. [9] Andy Piper. Eclipse Paho Progress Report. EclipseCon 2012, avr. 2012. url : http://www.slideshare.net/andypiper/eclipse- paho-progress-report-eclipsecon-2012 (visité le 13/09/2016). [10] Protocol Analysis. Juin 2014. url : http://www.onem2m.org/images/ files/deliverables/TR-0009-Protocol_Analysis-V0_7_0_1. pdf. [11] Andy Stanford-Clark. « Integrating monitoring and telemetry de- vices as part of enterprise information resources ». In : WebSphere MQ Integrator (2002). 49
  • 51. BIBLIOGRAPHIE 50 [12] Sasu Tarkoma. Publish / Subscribe Systems : Design and Principles. Wiley, 18 juin 2012. isbn : 978-1-118-35429-2. [13] The Internet of Things Protocol stack - from sensors to business value. url : https://entrepreneurshiptalk.wordpress.com/2014/01/ 29/the-internet-of-thing-protocol-stack-from-sensors-to- business-value/ (visité le 10/01/2016). [14] Unified Modeling Language 2.5. Rapp. tech. www.omg.org, 2015. url : http://www.omg.org/spec/UML/2.5. [15] Mark Utting, Alexander Pretschner et Bruno Legeard. « A taxo- nomy of model-based testing approaches ». In : Software Testing, Ve- rification and Reliability 22.5 (2012), p. 297–312. [16] Lucy Zhang. Building Facebook Messenger. Août 2011. url : https: //www.facebook.com/notes/facebook-engineering/building- facebook-messenger/10150259350998920/ (visité le 05/07/2016).
  • 52. Remerciements Je tiens à remercier toutes les personnes qui m’ont aidé tout au long de ce travail de recherche. Tout d’abord, j’adresse mes plus vifs remerciements à M. Fabrice Bou- quet qui a encadré mon travail pour ses conseils précieux lors de toutes les discussions que nous avons eues, pour la qualité de ses explications, et pour avoir su me guider tout au long de ma recherche. Ce mémoire a bénéficié de sa relecture et remarques avisées sur le fond comme sur la forme. Je remercie M. Fabien Peureux qui m’a encouragé à suivre le cursus de recherche, et qui me fait l’honneur de faire partie de mon jury. Je tiens également à exprimer ma gratitude envers l’entreprise Smartes- ting pour m’avoir accordé une licence d’utilisation de leur logiciel CertifyIt dans le cadre de cette recherche. Merci enfin à toute ma famille pour leur soutien, en particulier mon épouse Ochrite qui m’a encouragé tout au long de mon Master, et sans qui ce mémoire n’aurait pas été possible. 51
  • 53. Annexe A Codes sources (extraits) A.1 Suite de tests from mqtt import * from mqtt_enums import * # publish (68-e3-eb) def test_16(): Client2.connection(BrokerInstance) Client2.connect(ClientIdentifier.CLIENTID_NORMAL_1, False, 36) Client2.subscribe(Utf8Type.UTF8_DATA_NORMAL_2, 0) Client2.publish(Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_EMPTY, 0, False)→ # connect (68-fc-66) def test_17(): Client2.connection(BrokerInstance) Client1.connection(BrokerInstance) Client1.connect(ClientIdentifier.CLIENTID_EMPTY, True, 37) Client2.connect(ClientIdentifier.CLIENTID_EMPTY, True, 37) # process_messages (68-2e-6d) def test_26(): Client1.connection(BrokerInstance) Client1.connect(ClientIdentifier.CLIENTID_NORMAL_1, True, 36) Client1.publish(Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_TOO_LONG, 2, False)→ BrokerInstance.process_messages() Client1.process_messages() BrokerInstance.process_messages() excepted = [ [Client1.send_disconnect()], [Client2.send_connect(ClientIdentifier.CLIENTID_EMPTY, False, 5, ClientName.NONE, ClientPassword.NONE), BrokerInstance.send_connack(Client2, ConnectReturnCode.IDENTIFIER_REJECTED)], → → → 52
  • 54. ANNEXE A. CODES SOURCES (EXTRAITS) 53 [Client2.send_connect(ClientIdentifier.CLIENTID_EMPTY, True, 36, ClientName.NONE, ClientPassword.NONE), BrokerInstance.send_connack(Client2, ConnectReturnCode.OK), Client2.send_disconnect()], → → → # ... [Client1.send_connect(ClientIdentifier.CLIENTID_EMPTY, True, 36, ClientName.NONE, ClientPassword.NONE), BrokerInstance.send_connack(Client1, ConnectReturnCode.OK), Client1.send_subscribe(1, Utf8Type.UTF8_DATA_NORMAL_2, 2), BrokerInstance.send_suback(Client1, 1), Client1.send_publish(2, Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_TOO_LONG, 1, False, False), BrokerInstance.send_publish(Client1, Utf8Type.UTF8_DATA_NORMAL_2, PayloadType.BINARY_DATA_TOO_LONG, 2, False), Client1.send_pubrec(1), BrokerInstance.send_pubrel(Client1, 1), BrokerInstance.send_puback(Client1, 2), Client1.send_pubcomp(1)] → → → → → → → → → → → ]
  • 55. ANNEXE A. CODES SOURCES (EXTRAITS) 54 A.2 Adaptateur pour le client MQTT import paho.mqtt.client as mqtt class Client: def __init__(self): self.client = mqtt.Client() def __del__(self): self.disconnect() del self.client def connect(self, server): #Hack: se contente de définir son adresse self.address = server.host, server.port def disconnect(self): self.client.loop_stop() self.client.reinitialise() def publish(self, topic, payload, qos, retain): self.client.publish(topic, payload, qos, retain) def send_connect(self, client_id, clean, keepalive): host, port = self.address #Hack: force these values self.client._client_id = client_id self.client._clean_session = clean self.client.connect(host, port, keepalive) self.client.loop_start() def send_disconnect(self): self.client.disconnect() def setup_id(self, nom, passw): #self.client.username_pw_set(nom, passw) if nom is not None: nom = nom.encode('utf8') if passw is not None: passw = passw.encode('utf8') self._username = nom self._password = passw def subscribe(self, topic, qos): self.client.subscribe(topic, qos) def unsubscribe(self, topic): self.client.unsubscribe(topic)
  • 56. ANNEXE A. CODES SOURCES (EXTRAITS) 55 A.3 Modélisation binaire des trames class MQTTPacket: def __init__(self, buf): self._data = buf self._decode(buf) def _decode(self, buf): self.command = buf[0] >> 4 self.flags = buf[0] & 0xf self.length = remaining_length_decode(buf) self._pos = next(i for i in range(1,5) if buf[i] & 128 == 0) + 1 cls = MQTTCommandRegistry.get_cls(self.command) self.packet = cls(buf, self._pos) def check(self): assert len(self._data) == self._pos + self.length, 'invalid length' self.packet.check() def _encode(self): tmp = bytearray() self.packet._encode(tmp) buf = bytearray() buf.append(self.command << 4 | self.flags) remaining_length_encode(len(tmp), buf) buf.extend(tmp) return buf # ... class MQTTBody: def __init__(self, buf, pos): self.flags = buf[0] & 0xf self._decode(buf, pos) class MQTTConnect(MQTTBody): def _decode(self, buf, pos): self.protocol, pos = get_utf8_string(buf, pos) self.protolevel, pos = get_uint8(buf, pos) cflags, pos = get_uint8(buf, pos) assert (cflags & 0x1) == 0, 'reserved flag' self.clean = (cflags & 0x2) >> 1 self.wflag = (cflags & 0x4) >> 2 self.wqos = (cflags & 0x18) >> 3 self.wrflag = (cflags & 0x20) >> 5 self.pflag = (cflags & 0x40) >> 6 self.uflag = (cflags & 0x80) >> 7 self.keepalive, pos = get_uint16(buf, pos) self.clientid, pos = get_utf8_string(buf, pos) if self.wflag: self.will_topic, pos = get_utf8_string(buf, pos) self.will_msg, pos = get_binary_string(buf, pos)
  • 57. ANNEXE A. CODES SOURCES (EXTRAITS) 56 else: self.will_topic = None self.will_msg = None if self.uflag: self.username, pos = get_utf8_string(buf, pos) else: self.username = None if self.pflag: self.userpassword, pos = get_binary_string(buf, pos) else: self.userpassword = None def check(self): assert self.flags == 0, '[MQTT-3.1.2-3]' assert (self.protocol == 'MQTT' and self.protolevel == 4) or (self.protocol == 'MQIsdp' and self.protolevel == 3), 'invalid or unkown protocol' → → assert (self.wflag != 0 or self.wqos == 0), '[MQTT-3.1.2-13]' assert self.wqos != 3, '[MQTT-3.1.2-14]' assert (self.wflag != 0 or self.wrflag == 0), '[MQTT-3.1.2-15]' assert (self.uflag != 0 or self.pflag == 0), '[MQTT-3.1.2-22]' def _encode(self, buf): set_utf8_string(self.protocol, buf) set_uint8(self.protolevel, buf) cflags = self.clean << 1 | self.wflag << 2 | self.wqos << 3 | self.wrflag << 5 | self.pflag << 6 | self.uflag << 7→ set_uint8(cflags, buf) set_uint16(self.keepalive, buf) set_utf8_string(self.clientid, buf) if self.wflag: set_utf8_string(self.will_topic or '', buf) set_binary_string(self.will_msg or '', buf) if self.uflag: set_utf8_string(self.username or '', buf) if self.pflag: set_binary_string(self.userpassword or '', buf) def read_paquet(sock): buf = bytearray() read_fixed_header(sock, buf) length = remaining_length_decode(buf) # read the whole packet while len(buf) < length + 2: data = sock.recv(length + 2 - len(buf)) buf.extend(data) packet = MQTTPacket(buf) # check the received packet packet.check() # encode and return new packet return packet._encode()
  • 58. Annexe B Log des tests exécutés TEST: connect (68-15-95) Exception occured in client side: Payload too large. ------------------------------------------------------------ TEST: connect (68-79-ca) excepted: ["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>", '<CONNACK: code=0>', "<CONNECT: client_id='aaa', username=None, password=None, clean=0, " 'keepalive=5>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=1, keepalive=36>', '<CONNACK: session_present=0, code=0>', "<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, " 'password=None, clean=0, keepalive=5>', "<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=1, code=0>'] ------------------------------------------------------------ TEST: connect (68-9f-0a) excepted: ["<CONNECT: client_id='bbb', username=None, password=None, clean=1, " 'keepalive=5>', '<CONNACK: code=0>', "<CONNECT: client_id='bbb', username=None, password=None, clean=0, " 'keepalive=5>', '<CONNACK: code=0>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, " 'password=None, clean=1, keepalive=5>', '<CONNACK: session_present=0, code=0>', "<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=1, code=0>', '<PINGREQ: >'] ------------------------------------------------------------ TEST: connect (68-ca-0e) excepted: 57
  • 59. ANNEXE B. LOG DES TESTS EXÉCUTÉS 58 ["<CONNECT: client_id='', username=None, password=None, clean=0, keepalive=5>", '<CONNACK: code=2>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=0, code=2>', "<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=0, code=2>', "<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=0, code=2>'] ------------------------------------------------------------ TEST: connect (68-d1-a6) excepted: ["<CONNECT: client_id='aaa', username=None, password=None, clean=0, " 'keepalive=36>', '<CONNACK: code=0>', "<SUBSCRIBE: packet_id=1, topic='bca', qos=2>", '<SUBACK: packet_id=1>', "<PUBLISH: packet_id=None, topic='bca', qos=0, retain=0, dup=0>", "<PUBLISH: topic='bca', qos=2, retain=0>", "<CONNECT: client_id='aaa', username=None, password=None, clean=0, " 'keepalive=5>', '<CONNACK: code=0>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, " 'password=None, clean=0, keepalive=36>', "<SUBSCRIBE: packet_id=1 subscriptions=['bca':2]>", "<PUBLISH: qos=0, retain=0, dup=0, topic='bca'>", '<CONNACK: session_present=1, code=0>', '<SUBACK: packet_id=1, return_codes=[2]>', "<PUBLISH: qos=0, retain=0, dup=0, topic='bca'>", "<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, " 'password=None, clean=0, keepalive=5>', '<CONNACK: session_present=1, code=0>'] ------------------------------------------------------------ TEST: connect (68-d2-3f) excepted: ["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>", '<CONNACK: code=0>', "<CONNECT: client_id='bbb', username=None, password=None, clean=1, " 'keepalive=5>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=1, keepalive=36>', '<CONNACK: session_present=0, code=0>', "<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, " 'password=None, clean=1, keepalive=5>', "<CONNECT: protocol='MQTT', level=4, clientid='bbb', username=None, " 'password=None, clean=1, keepalive=5>', '<CONNACK: session_present=0, code=0>'] ------------------------------------------------------------ TEST: connect (68-fc-66)
  • 60. ANNEXE B. LOG DES TESTS EXÉCUTÉS 59 excepted: ["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=37>", '<CONNACK: code=0>', "<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=37>", '<CONNACK: code=0>'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=1, keepalive=37>', '<CONNACK: session_present=0, code=0>', "<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=1, keepalive=37>', '<CONNACK: session_present=0, code=0>'] ------------------------------------------------------------ TEST: disconnect (68-83-fd) excepted: ["<CONNECT: client_id='aaa', username=None, password=None, clean=0, " 'keepalive=36>', '<CONNACK: code=0>', '<DISCONNECT: >'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='aaa', username=None, " 'password=None, clean=0, keepalive=36>', '<DISCONNECT: >', '<CONNACK: session_present=0, code=0>'] ------------------------------------------------------------ TEST: disconnect (68-8e-49) excepted: ['<DISCONNECT: >'] retrieved: [] ------------------------------------------------------------ TEST: disconnect (68-8e-49) excepted: ['<DISCONNECT: >'] retrieved: [] ------------------------------------------------------------ TEST: disconnect (68-e8-24) excepted: ["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>", '<CONNACK: code=0>', '<DISCONNECT: >'] retrieved: ["<CONNECT: protocol='MQTT', level=4, clientid='', username=None, " 'password=None, clean=1, keepalive=36>', '<DISCONNECT: >', '<CONNACK: session_present=0, code=0>'] ------------------------------------------------------------ TEST: publish (68-2c-98) Exception occured in client side: Invalid topic. ------------------------------------------------------------ TEST: publish (68-9a-6c) excepted: ["<CONNECT: client_id='', username=None, password=None, clean=1, keepalive=36>",