Un test Rego est une règle dont le nom commence par test_ : opa test les
évalue toutes, et un test réussit si sa règle vaut true. Les tests sont le
seul filet contre les erreurs que Rego ne signale pas, comme la faute de chemin
qui laisse tout passer ou le conflit qui n'apparaît qu'avec certaines entrées.
Cette leçon teste la politique kubernetes.validation des leçons précédentes :
écriture des tests, cas positifs et négatifs, couverture et seuil en
CI, puis les pièges d'un test qui passe sans rien prouver. Mesuré avec
OPA 1.21.1.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Écrire des tests Rego avec des règles
test_etwith input as. - Couvrir chaque règle par un cas accepté et un cas refusé.
- Mesurer la couverture et imposer un seuil en CI.
- Reconnaître un test qui passe sans rien vérifier.
Prérequis
Section intitulée « Prérequis »Les leçons La CLI opa et Pièges de l'évaluation.
Comment s'écrit un test Rego ?
Section intitulée « Comment s'écrit un test Rego ? »Un test vit dans un fichier _test.rego, à côté de la politique, dans un
package distinct qui importe celui qu'il teste. Chaque test est une
règle préfixée par test_ ; le mot-clé with input as fournit le
document d'entrée, sans fichier JSON séparé. Voici la politique du fil rouge,
rangée dans policy/validation.rego :
package kubernetes.validation
# Valeur par défaut : refus si aucune règle `allow` ne s'évalue à vraidefault allow := false
# Namespaces interdits pour les Deploymentsnamespaces_interdits := {"default", "kube-system"}
allow if { input.kind == "Deployment" label_app_present not namespace_interdit}
label_app_present if input.metadata.labels.app
namespace_interdit if input.metadata.namespace in namespaces_interditsEt ses tests, dans policy/validation_test.rego. Une fonction de
fabrique, deploiement, évite de répéter le même document à chaque cas :
package kubernetes.validation_test
import data.kubernetes.validation
deploiement(namespace, labels) := { "kind": "Deployment", "metadata": {"name": "api", "namespace": namespace, "labels": labels},}
test_deploiement_conforme_accepte if { validation.allow with input as deploiement("production", {"app": "api"})}
test_namespace_default_refuse if { not validation.allow with input as deploiement("default", {"app": "api"})}
test_label_app_absent_refuse if { not validation.allow with input as deploiement("production", {"team": "web"})}
test_pod_refuse if { not validation.allow with input as {"kind": "Pod", "metadata": {"namespace": "production", "labels": {"app": "api"}}}}Chaque condition de allow a son cas refusé, et la règle entière a son
cas accepté. Le test du refus s'écrit avec not : allow vaut
false grâce au default, et not false est vrai.
Lancer les tests avec opa test
Section intitulée « Lancer les tests avec opa test »opa test prend un dossier, charge politiques et tests, et évalue chaque
règle test_. Sans option, il n'affiche que le bilan ; -v détaille
chaque test avec son fichier, sa ligne et sa durée :
opa test policy/# PASS: 4/4opa test policy/ -vpolicy/validation_test.rego:10:data.kubernetes.validation_test.test_deploiement_conforme_accepte: PASS (357.385µs)policy/validation_test.rego:14:data.kubernetes.validation_test.test_namespace_default_refuse: PASS (367.279µs)...PASS: 4/4L'option --run filtre les tests par expression régulière sur leur
nom : opa test policy/ -v --run 'namespace' ne lance que
test_namespace_default_refuse. Les appels à print dans une règle ou un
test ne s'affichent qu'avec -v, sous le test concerné : c'est l'outil de
mise au point, à retirer ensuite.
Pourquoi un cas accepté par règle est indispensable
Section intitulée « Pourquoi un cas accepté par règle est indispensable »Un jeu de tests qui ne contient que des refus ne protège pas d'une faute de
chemin. Mesuré en remplaçant labels.app par labels.ap dans la politique :
label_app_present ne se déclenche plus jamais, allow vaut toujours false,
et les trois tests de refus passent encore. Seul le test positif
échoue :
policy/validation_test.rego:10:data.kubernetes.validation_test.test_deploiement_conforme_accepte: FAIL (267.273µs)--------------------------------------------------------------------------------PASS: 3/4FAIL: 1/4opa test sort alors avec le code 2, ce qui bloque une CI. La règle à
retenir : chaque décision a au moins un cas accepté et un cas
refusé, et pour une condition numérique, un cas de chaque côté de la
frontière, là où se cachent les conflits de règles.
Remplacer une donnée ou une règle avec with
Section intitulée « Remplacer une donnée ou une règle avec with »with ne remplace pas seulement input : il peut substituer une
règle ou une valeur de data le temps d'une évaluation. Un test peut
ainsi vérifier le comportement de la politique avec une autre liste de
namespaces, sans toucher au fichier :
package kubernetes.validation_data_test
import data.kubernetes.validation
test_namespace_interdit_remplace if { validation.allow with input as {"kind": "Deployment", "metadata": {"namespace": "default", "labels": {"app": "api"}}} with validation.namespaces_interdits as {"kube-system"}}Le namespace default ne figure plus dans la liste remplacée, et le
Deployment est accepté : le test passe. C'est la façon de tester une politique
qui lit des données externes, chargées avec -d en production, sans
dépendre d'un fichier réel.
Mesurer la couverture
Section intitulée « Mesurer la couverture »opa test --coverage rend un rapport JSON : le pourcentage global dans
coverage, et pour chaque fichier les lignes non couvertes dans
not_covered. Mesuré en ne gardant que le test du namespace default :
opa test policy/ --coverage | jq '.coverage'# 90opa test policy/ --coverage --threshold 95# Code coverage threshold not met: got 90.00 instead of 95.00 (code 2)La ligne non couverte est la ligne 9, l'en-tête de allow : aucun test
n'y entre jusqu'au bout, puisque le seul cas restant échoue avant. L'option
--threshold transforme la mesure en contrôle de CI. Une couverture à
100 % ne prouve pas que les tests sont bons, seulement que chaque ligne a été
évaluée au moins une fois.
Quels tests passent sans rien vérifier ?
Section intitulée « Quels tests passent sans rien vérifier ? »Un test Rego échoue quand sa règle n'est pas vraie, y compris quand elle est
undefined. Une faute dans le nom d'une règle testée en positif est donc
attrapée : validation.alow vaut undefined, et le test est en échec. Mais la
même faute sous not passe :
package kubernetes.not_test
import data.kubernetes.validation
# ❌ « alow » n'existe pas : not undefined est vrai, le test passe sans rien testertest_faute_sous_not if { not validation.alow with input as {"kind": "Deployment", "metadata": {"labels": {}}}}Mesuré : PASS, et ni opa check --strict ni Regal ne signalent le nom
inconnu, puisque data.kubernetes.validation.alow est un chemin valide. C'est
le second argument pour les cas positifs : un test de refus seul ne
prouve pas que la règle existe.
Un test dont le nom commence par todo_ est ignoré et marqué
SKIPPED. Attention au code de retour : mesuré, opa test sort en 2 dès
qu'un test est ignoré, même si tous les autres passent. Un test laissé en
todo_ bloque donc la CI, ce qui est voulu : Regal le signale aussi, par sa
règle todo-test.
À retenir
Section intitulée « À retenir »- Un test est une règle
test_dans un fichier_test.rego, qui importe le package testé ;with input asfournit l'entrée. opa test policy/donne le bilan,-vle détail et lesprint,--runfiltre par nom.- Chaque décision a un cas accepté et un cas refusé : des refus seuls laissent passer une faute de chemin.
withremplace aussi une règle ou une donnée dedata.--coverage --thresholdimpose une couverture minimale, en code 2.- Un
notsur une règle mal nommée passe toujours ; un testtodo_fait sortiropa testen 2.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Linter avec Regal
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications