Cloud Services

Cloudy Lundi II: Une introduction à Pester

Au fil des années, j'ai constaté que malgré un script bien testé et indépendamment du soin que tu apportes à l'écriture de ton code, il peut y avoir quelques cas marginaux qui sont oubliés ou qui ne se produisent que rarement. C'est particulièrement vrai si tu testes tes scripts manuellement. De plus, il se peut que ton script d'implémentation ait été exécuté sans erreur, mais qu'il ait réellement répondu à l'exigence commerciale initiale?

Si tu ne connais pas encore Pester, cet article te donnera un aperçu de ce qu'est Pester, de ce que tu peux en faire et pourquoi c'est une bonne idée de l'apprendre et de l'implémenter dans ton environnement. Si tu connais déjà Pester, tu trouveras dans cet article un bref aperçu de la manière dont nous l'avons implémenté dans le département Windows Operations & Engineering de Swisscom.

Dans cet article, j'explique d'abord les concepts de base derrière Pester et je parle des différents cas d'utilisation de Pester. Dans la deuxième partie de cet article, j'expliquerai comment nous utilisons Pester dans mon équipe (Windows Operations & Engineering) chez Swisscom. Je montrerai comment nous utilisons Pester pour tester un grand framework que nous utilisons, et comment Pester nous aide à mesurer la conformité de nos serveurs.

Qu'est-ce que Pester?

Pester est un framework d'unité de test pour PowerShell. Il nous donne la possibilité d'écrire du code qui automatise le test de nos scripts. Cela permet de vérifier automatiquement si notre script fonctionne réellement comme prévu (ou non). C'est une fonctionnalité géniale que les développeurs utilisent depuis des années, et PowerShell a enfin obtenu son framework de test unitaire: Pester.

L'histoire derrière Pester est très intéressante: Pester était un projet communautaire open source qui a été forcé par Microsoft et livré avec Windows 10. C'est vraiment une grande chose, car Microsoft n'avait jamais intégré officiellement des projets communautaires dans son système d'exploitation. Et on adore ça ! 🙂

Cas d'utilisation Pester

Pester est généralement utilisé pour répondre à deux questions principales:

Comment puis-je m'assurer que le code que j'ai écrit fonctionne réellement comme prévu ?C'est ce que nous appelons généralement les tests unitaires. Le principe est simple : tu veux t'assurer que le code fonctionne dans tous les cas. Que tous les paramètres ont été testés. Qu'en cas d'erreur, le script se termine correctement avec un message d'erreur spécifique. Tu veux aussi t'assurer que le script renvoie les valeurs et les types que tu attends, et que 100% (ou peut-être un peu moins) de ton code est couvert par tes tests. De cette façon, tu peux garantir que ton script fonctionnera en production et qu'il n'échouera pas.

La deuxième question serait:

Comment puis-je m'assurer que ce que j'ai configuré avec mon script fait vraiment ce que nous avons l'intention de faire ? Cela peut sembler un peu vague, mais tu as peut-être un script qui configure un serveur pour qu'il applique certaines normes prédéfinies. Il définit des clés d'enregistrement, des règles de pare-feu, des serveurs WSUS, des paramètres de sauvegarde, etc. C'est une bonne idée de vérifier si la communication avec les serveurs externes fonctionne, par exemple si les règles de pare-feu implémentées ont effectivement ouvert les bons ports et si la communication entre ton serveur et la ressource distante a effectivement lieu. L'ouverture des ports est une action qui fournit un service à nos clients/utilisateurs finaux, et il est judicieux de s'assurer que ce service fonctionne réellement avant de livrer le serveur au client.

C'est ce qu'on appelle la "validation opérationnelle".

Dans la prochaine partie, je te montrerai comment nous l'avons mis en œuvre chez Swisscom dans nos tâches quotidiennes dans le domaine des opérations.

Pester chez Swisscom

Maintenant que nous avons abordé certains des concepts de base des tests unitaires, nous pouvons voir comment nous les avons mis en œuvre dans notre équipe, Windows Operations & Engineering chez Swisscom.

Tests d'unité chez Swisscom

Dans mon équipe actuelle (Windows Operations & Engineering), tous les ingénieurs utilisent un framework de construction personnalisé pour écrire nos scripts. Cela nous aide à garder nos scripts cohérents dans toute l'équipe et à garantir que le scripteur fait la même expérience pour chaque script qu'il écrit (comportement du journal, fichier de configuration, sorties, etc.) et que l'opérateur qui exécute le script (le cas échéant) fait également la même expérience, indépendamment de la personne qui a écrit le script.

Comme plusieurs ingénieurs dépendent de mon framework, il est important que chaque modification que moi ou l'un de mes collègues introduise dans le référentiel soit sans erreur. A ce stade, nous commençons à parler de l'écriture des tests unitaires avec Pester.

Pour tester notre framework, nous avons environ 50 tests qui testent différentes choses du framework. Des choses comme créer un nouveau script, l'exécuter, vérifier si les fichiers journaux sont créés, si le fichier journal contient notre sortie standard, etc...

La sortie d'un test Pester ressemble à peu près à celle de la capture d'écran ci-dessous.

Figure 1 Résultats du test Pester

Le violet représente l'information, le vert signifie que le test a été réussi et le rouge qu'il a échoué.

Je tiens à souligner qu'un point rouge (qui indique que ton test a échoué) n'est en fait pas une mauvaise chose. Cela signifie simplement que le test Pester a trouvé quelque chose qui doit être corrigé dans ton script, et non pas un utilisateur final ou, pire encore, un client qui aurait découvert l'erreur en premier.

Tu trouveras une version simplifiée d'un des tests que j'ai écrit ici.

Le bloc décrire ajoute un niveau d'information (la partie violette de la sortie), et le test lui-même est toujours effectué dans un bloc it. Si le bloc it est testé, la sortie est verte. Dans le cas contraire, elle sort en rouge. Le texte ajouté à côté du bloc "décrire" ou "it" est informatif et peut être tout ce qui t'aide à expliquer quel test tu appelles et ce qu'il fait.

Dans l'extrait de code ci-dessus, je vérifie simplement si la variable $testFolder contient un sous-dossier appelé "logs". Je transmets mon expression au mot-clé "should". Ce mot-clé évalue la condition de test et soit renvoie une erreur, soit confirme mon test.

Même si la syntaxe de pester est facile à comprendre, cela ne signifie pas qu'il ne peut pas être utilisé pour effectuer des tâches complexes.

Dans ce prochain extrait de code, nous effectuons encore quelques vérifications supplémentaires.

Elle garantit que le framework avec lequel nous créons nos modèles de scripts génère effectivement le script dans le format que nous attendons et qu'il génère le message correspondant dans le fichier journal lorsque le script est appelé. Dans ce cas particulier, je vérifie s'il y a deux messages différents. Si un seul d'entre eux est présent, le test global échoue.

J'utilise les tests unitaires pour vérifier des blocs de code ou des fonctions complètes. En général, j'essaie de procéder selon le modèle suivant: Un bloc "décrire" pour tester une fonction, et un bloc "it" pour chaque fonction de cette fonction que je veux tester.

Validation opérationnelle chez Swisscom

Lors de la validation opérationnelle, tu n'écris pas le code Pester pour tester le script que tu as écrit, mais pour vérifier si les modifications ou les implémentations que ton script effectue correspondent réellement à ton besoin commercial initial. Si tu crées une règle de pare-feu pour ouvrir un port spécifique dans le seul but d'accéder à un serveur Web et de lire les données d'une base de données, tu veux être sûr de pouvoir réellement interagir avec ce serveur Web et de récupérer les données dont tu as besoin. Si tu as réussi à mettre en place la règle de pare-feu et à ouvrir les bons ports, mais qu'un autre pare-feu se trouve entre ton serveur client et ton serveur Web ou que le câble réseau est simplement débranché, tu ne pourras pas offrir le service prévu, même si tu as réussi à mettre en place la règle de pare-feu.

Chez Windows Operations & Engineering, nous utilisons la validation opérationnelle pour nous assurer que nos serveurs respectent nos normes (sécurité, configuration, etc.). Nous pouvons ainsi garantir que le serveur que nous fournissons est conforme à nos normes. Les mêmes tests sont utilisés dans une étape ultérieure pour s'assurer qu'il n'y a pas d'écart de configuration.

Les tests consistent en une série de scripts Pester qui sont utilisés sur un ou plusieurs serveurs. Un script exécute les tests Pester et recueille les données dans un format XML standard (NunitXML). Ce XML standard nous permet d'automatiser les résultats de nos tests et d'en faire de superbes rapports!

J'ai écrit une classe PowerShell qui nous permet de créer soit un rapport individuel par serveur, soit un rapport global qui peut être généré dans différents formats (docx, html, etc.).

Le rapport individuel est basé sur un projet open source appelé "ReportUnit", et tu peux voir un exemple ci-dessous.

Figure 2 Résultats de tests individuels

En cas de besoin, nous pouvons créer très rapidement un rapport sur un serveur spécifique et voir immédiatement si tout est conforme à nos attentes. Mais même si le rapport a l'air vraiment bien, ce n'est pas celui que j'utilise le plus.

Le rapport que j'utilise le plus est le rapport global. Il nous permet d'avoir une vue d'ensemble de tout notre environnement en un seul coup d'œil. Le rapport se compose de 5/6 pages par serveur. Cela signifie qu'il peut être assez volumineux. Comme il peut devenir si volumineux, je ne montre que les parties les plus intéressantes de ces rapports.

Tu trouveras ci-dessous un extrait de l'une des premières pages du rapport. Il contient un tableau qui énumère tous les serveurs qui sont en échec. (ce qui signifie qu'au moins un ou plusieurs tests ont échoué). En utilisant la ligne 'PercentageSuccess', nous pouvons rapidement voir le taux moyen de conformité par serveur que nous avons.

Illustration 3 Aperçu global du test

Cela nous permet de voir rapidement où quelque chose n'est pas configuré correctement. Chaque serveur contient un rapport détaillé de chaque test. Il contient l'état de réussite du test, le temps qu'il a fallu pour l'exécuter et une brève description. (Comme montré ci-dessous).

Figure 4 Aperçu détaillé du test

En utilisant des couleurs claires, les tests qui ont échoué sont immédiatement visibles. A la fin, il y a une vue détaillée des tests qui ont échoué avec une courte description, comme tu peux le voir sur la capture d'écran ci-dessous.

Figure 5 Vue détaillée des tests qui ont échoué

Cette méthode nous permet de vérifier l'état actuel de nos serveurs et d'identifier un serveur qui a été mal configuré (ou modifié) depuis son déploiement. Si cela concerne un grand nombre de serveurs, nous le verrons dans le rapport global et nous pourrons alors fournir une solution à temps pour tout le groupe de serveurs.

J'aimerais savoir si tu as implémenté Pester dans ton environnement et si oui, comment l'utilises-tu dans ton environnement? Uniquement des tests unitaires? Ou aussi pour la validation opérationnelle? N'hésite pas à partager tes expériences avec nous!

J'espère que tu as lu cet article avec autant de plaisir que j'en ai eu à l'écrire, et j'ai hâte de lire ton implémentation de Pester dans la section des commentaires ci-dessous.

Stéphane Van Gulick

Stéphane Van Gulick

DevOps Engineer III

Plus d’articles getIT

Prêts pour Swisscom

Trouve le Job ou l’univers professionnel qui te convient. Où tu veux co-créer et évoluer.

Ce qui nous définit, c’est toi.

Vers les univers professionnels

Vers les postes vacants cybersécurité