Gladys 4 - Développement du service Arduino

Ah mais donc tu parlais bien de la détection en elle-même ? Du style “si l’arduino reçoit tel code 433, alors la porte a été ouverte” ?

Parce que ça je n’ai pas encore eu l’occasion de le coder, mais les features sont là, prêtes à être codées :smile:

Bon et bien selon moi tout est bon pour une première version. Le plus gros qu’il reste à faire maintenant, ce sont les tests ! Seul bémol… J’ai du mal à assimiler le fonctionnement des tests :sweat_smile:

Est-ce qu’une âme charitable aurait la bonté de me guider pour rédiger ces tests correctement s’il vous plaît ?

Merci beaucoup :smile:

1 « J'aime »

Oui! c’est pas codé ça? :sweat_smile: Ca serait peut-etre bien que ça marche avant une release quand même, sinon c’est peu utile de déployer :smiley:

L’objectif des tests, c’est de faire tourner le code que tu as écris, et de tester le résultat de ton code.

Les tests sont exécuté par CircleCI à chaque push sur le repo Gladys, et permettent de vérifier que le nouveau code écrit ne « casse » pas de l’ancien code.

Par exemple, si tu écris une fonction

// lib/sum.js
function sum(a, b) {
   return a + b;
}

Tu peux vouloir écrire 1 test qui vérifie que sum(1, 2) = 3.

Ton test peut ressembler à ça:

// test/sum.js
const { expect } = require('chai');
const sum = require('../lib/sum.js');

describe('sum', () => {
  it('should return 3', () => {
      const result = sum(1, 2);
      expect(result).to.equal(3);
  });
});

Lorsque l’on exécute ce bout de code en lançant « mocha » (l’outil de test que nous utilisons), nous allons voir:

:white_check_mark:should return 3

Maintenant imaginons que dans un futur proche du projet, quelqu’un casse notre fonction sum(a, b), et remplace par erreur le + par un *.

Lors de l’exécution des tests, le test « should return 3 » var renvoyer 2, et mocha va crier:

:x: should return 3
Expected « 2 » to equal « 3 »

Ainsi, on saura que cette PR casse quelque chose.

Cet exemple est simpliste, mais dans la réalité, c’est très utile. Car là tu travaille sur l’arduino, mais qu’est ce qui me dit que tu n’as pas cassé l’intégration Z-Wave en développant l’intégration arduino? Les tests :slight_smile:

Le mocking

Sauf que là tu vas me dire: oui mais mon code appelle en USB un arduino, comment je fais ça dans mes tests?

Dans les tests, on ne veut pas communiquer avec l’extérieur: inutile de tester le comportement de la lib serialport qui elle même a déjà des tests!

On va donc « mocker » les appels aux librairies externes, en utilisant une lib qui s’appelle « proxyquire » ( GitHub - thlorenz/proxyquire: 🔮 Proxies nodejs require in order to allow overriding dependencies during testing. )

Ou alors en réecrivant nous même la librairie en simplifiant tous les appels de fonction par des returns

Exemple, dans le test du service Z-Wave, j’ai entièrement re-écris la lib openzwave en 28 lignes:

https://github.com/GladysAssistant/Gladys/blob/master/server/test/services/zwave/ZwaveMock.test.js

Chaque fonction de la lib est remplaçée par une fonction « fake » qui retourne null.

Je t’invite à lire les tests de toutes les autres intégrations (server/test/services), et de te familiariser avec :slight_smile:

Un tutoriel pourrait aussi t’aider:

Non les détecteurs de mouvements et de portes ne sont pas encore codés… Je fais ça dans la journée, ça me semble relativement simple à faire ^^

Merci pour les explications, c’est surtout le mocking qui me pose problème je crois ^^ Je vais essayer de finir un premier script de test et, si tu veux bien, je mettrai le lien ici pour que tu puisses me dire si ma manière de faire est correcte :slightly_smiling_face:

1 « J'aime »

Bonjour,

Une première version pour les capteurs est faite, il faudra peut-être peaufiner à l’avenir mais pour l’instant le résultat me parait bien :slightly_smiling_face:

Concernant les tests, voilà les fichiers :

@pierre-gilles si tu as un peu de temps devant toi pour vérifier les codes et me dire ce qui serait à ajouter/modifier ce serait vraiment super :wink:

Merci beaucoup :smile:

Edit : je suis en train de travailler sur le demo.json pour que le service puisse apparaitre sur le site de demo, d’ici ce midi je pense que ça peut être bon ^^

Re-edit : Normalement tout est bon.

Apparemment je n’ai pas les droits pour demander une review, donc je pose la PR ici :

https://github.com/GladysAssistant/Gladys/pull/812

Merci :slightly_smiling_face:

2 « J'aime »

Merci @billona ! Beau travail ! Je te fais une review en début de semaine prochaine :slight_smile:

1 « J'aime »

Bonjour,

Après beaucoup d’acharnement j’avance enfin sur les tests :smile:

J’aimerais pouvoir mocker la lib avrgirl-arduino pour vérifier mon script setup.js.

Voilà ce que j’ai fait :

Et dans setup.test.js j’ai utilisé proxyquire :

Cependant, j’ai l’impression que mes tests ne prennent pas mon mock en compte :

setup method
2020-06-04T14:16:20+0200 <info> index.js:18 (Server.<anonymous>) Server listening on port 6500
✓ Should upload an arduino code in the board (110ms)
2020-06-04T14:16:20+0200 <warn> setup.js:7 () Error: no Arduino 'mega' found.
at /home/Alexandre/Gladys/server/services/arduino/node_modules/avrgirl-arduino/lib/connection.js:30:25
at /home/Alexandre/Gladys/server/services/arduino/node_modules/avrgirl-arduino/lib/connection.js:70:12
at /home/Alexandre/Gladys/server/services/arduino/node_modules/avrgirl-arduino/lib/connection.js:191:26
at processTicksAndRejections (internal/process/task_queues.js:93:5)
✓ Should return an error (451ms)

Ensuite, pour pouvoir couvrir mes scripts d’envoi et d’écoute, je dois couvrir la partie

 if (!this.arduinosPorts[arduinoPath].isOpen) {
    this.arduinoParsers[arduinoPath].on('data', async (data) => {

de mon fichier. La logique est la même pour listen et send.

Mais pour le coup je galère un peu à voir comment couvrir ça…

Quelqu’un pourrait m’éclairer ? Merci beaucoup :slightly_smiling_face:

Il me semble que proxyquire ne fonctionne que sur le fichier qu’il require. Hors, dans ton fichier /server/services/arduino/lib/index.js, je ne vois aucun require à avrgirl-arduino.

Effectivement avrgirl-arduino n’est utilisé que dans le script /server/services/arduino/lib/setup.js, je n’ai donc pas fait de require dans /server/services/arduino/lib/index.js. Mais je ne vois pas comment résoudre ça, sachant que setup est une méthode de mon ArduinoManager.

Faut-il que je teste setup.js à part de l’ArduinoManager ? Inclure serialport et avrgirl-arduino comme propriété du manager et m’en servir pour tout définir après dans mes scripts ?

Les deux solutions sont possibles :slight_smile: A toi de voir la solution qui te parait la plus simple à mettre en place et à maintenir à l’avenir

Après en général ce qu’on faisait c’est qu’on mettait tous les require dans le “index.js” du module et qu’on les injectait en dépendance au Manager. Exemple: service z-wave

1 « J'aime »

C’est vrai que cette manière de faire me paraît beaucoup plus simple ^^ J’ai modifié mes scripts pour faire comme ça, tout à l’air de bien fonctionner :smile:

Maintenant il semblerait que ma couverture de code aie bizarrement diminué entre temps ^^ Du coup je travaille dessus et je te fais un retour quand tout me semble correct :slightly_smiling_face:

Bon, normalement je suis pas trop mal niveau tests ^^

Le plus gros qu’il me reste à couvrir concerne la lecture et l’envoi des données à la carte.

Typiquement ce sont des fonctions

port.on('open', function() {});

Par exemple dans server/services/arduino/lib/send.js :

Seulement je ne trouve pas de solution viable pour couvrir cette partie de code. Et c’est la plus grosse partie qu’il me reste à couvrir ^^

Une solution pour me dépanner ? :smile:

1 « J'aime »

Beau boulot :clap:

Deux solutions complémentaires :

  • Utiliser une fonction nommée que tu expose aux tests plutôt qu’une fonction anonyme ici.
function onPortOpen () {}
port.on('open', onPortOpen);
  • Mocker l’eventEmitter « port » et appeler dans les tests
port.emit('open');

Ce qui aura pour effet d’appeler la fonction :slight_smile: Attention de bien mocker aussi « port.write » avec fake.returns(0); par exemple

J’ai peur de ne pas comprendre certaines choses ^^

Dans mon SerialPortMock, j’ai rajouté

SerialPort.prototype.write = fake.resolves(null);

Concernant le

port.emit('open');

J’appelle ça où ?

Dans ArduinoManager.test.js, j’ai modifié mon test d’envoi de JSON

it('should send a JSON to the arduino', async () => {
    const sendSpy = spy(arduinoManager, 'send');
    await arduinoManager.send('/dev/ttyACM0', messageData, 1);
    arduinoManager.arduinosPorts['/dev/ttyACM0'].emit('open');
    assert.calledOnce(sendSpy);
    sendSpy.restore();
  });

Mais ensuite ?

Dans mon cas, port est un objet SerialPort… Je ne vois pas vraiment comment effectuer ce test :sweat_smile:

Hello !

Bon et bien voilà, selon le dernier rapport de codecov, il semble que mes tests soient enfin terminés ^^

@pierre-gilles Si tu vois quelque chose de manquant j’attends ton retour, autrement pour moi tout est bon pour une première version :smile:

Je voulais aussi dire merci ! Etant donné que c’est mon premier “vrai” dev en Node et Preact j’étais un peu perdu à certains moments je l’avoue. Donc merci pour votre patience, et j’ai hâte de voir le résultat de plusieurs soirées dev faire partie intégrante de Gladys 4 :smile:

3 « J'aime »

Tant mieux si tu t’en es sorti ! :slight_smile: Je vais regarder ça ! Bravo :clap:

1 « J'aime »

Pour tout ceux qui attendent le service Arduino, il est désormais disponible en build de test !

N’hésitez pas à tester et à faire des retours à @billona ici :slight_smile:

1 « J'aime »

Hello, sur le dernier build (image docker): le module arduino ne détecte plus mes ports USB.

Je sais sur quel port l’arduino se trouve.

Bus 001 Device 004: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter

Je suis le seul à avoir cette erreur?

J’ai tester vite fait, petit bug ( Juste après le setup d’un arduino Uno )

Est ce que le feature type peut être dépendant de la fonction ? Je trouve un peu idiot de sélectionner une feature alors que la function la définie déjà ( light pour une function Temperature :upside_down_face: )

Bonjour !!

Je reviens vers vous après une longue absence de ma part à cause du boulot ^^’

Je reprends donc le développement du service Arduino, en faisant en sorte d’avoir un résultat stable et parfait pour passage en prod :smile:

J’ai rebase mon dépôt local pour être à jour avec les dernières versions, je vais donc continuer de travailler dessus et je ferai des retours sur mon avancement :wink:

9 « J'aime »