Aller au contenu

Quality gate

La quality gate est l'un des composants de Squash Orchestrator. Elle peut être utilisée pour affiner les conditions de l'échec ou du succès d'un pipeline comprenant l'étape de l'exécution des tests. La quality gate permet de définir des règles d'évaluation qui précisent le seuil de succès attendu et qui filtrent les tests à évaluer. Ainsi, on peut choisir de faire échouer un pipeline à l'étape des tests dans le cas où moins de 90% des tests d'importance très haute sont en succès. Pour cela, un fichier de définition doit être fourni à la quality gate.

Fichier de définition de la quality gate

Ce fichier doit être au format YAML (.yaml ou .yml) et définir au moins une quality gate qui comporte au moins une règle. Voici l'exemple d'une définition basique :

qualitygates:
 - name: my.quality.gate
   rules:
   - name: JUnit tests
     rule:
       scope: (test.technology=='junit') && (test.importance=='VERY_HIGH')
       threshold: 95%
       failure-status: [failure]

Une seule quality gate, my.quality.gate, est définie dans ce fichier. Elle contient une règle, JUnit tests, qui s'applique à des tests JUnit d'importance très haute. La quality gate sera en succès si au moins 95% des tests sont évalués comme en succès.

Parmi les paramètres, .rules.name et .rule.failure-status sont facultatifs. Si une règle n'a pas de nom, elle se verra attribuer un UUID à la place ; si failure-status est omis, sa valeur par défaut sera ['failure', 'error', 'blocked'].

Un fichier de définition peut définir plusieurs quality gates, et une quality gate peut comporter autant de règles que nécessaire.

Définition du seuil et du filtre

Le seuil (threshold) d'une règle est un pourcentage compris entre 0% et 100%.

Le filtre (scope) d'une règle utilise les fonctions et les expressions qui sont décrites dans la documentation d'OpenTestFactory.

La quality gate utilise le contexte test de l'orchestrateur, dont les properties sont détaillées dans le tableau ci-dessous. Depuis ce contexte, on peut également faire appel aux propriétés du plan de test (itération ou suite de tests) en utilisant test.collection et aux datasets ou CUF en recourant à test.data.

Disponibilité des propriétés

️L'ensemble de ces priorités est disponible pour Squash TM 6.0 ou postérieure.
Pour les versions plus anciennes, seules test.technology, test.uses, test.runs-on et test.job sont utilisables.

Légende

️‡ indique une property ou une valeur disponible avec les composants Premium. Une vue d'ensemble des fonctionnalités Premium est disponible ici. Pour en bénéficier ou demander plus d'informations, consulter notre site ou nous contacter.

Propriété Type Description Valeur
test
test.technology string Technologie du test. cucumber, cucumber5, cypress, junit, postman, robotframework, skf, soapui, agilitest‡, katalon‡, ranorex‡, uft‡
test.uses string Action utilisée pour exécuter le test. Voir les actions des providers dans la documentation d'OpenTestFactory.
test.runs-on object Tags de l'environnement d'exécution Utiliser la fonction contains() pour filtrer.
test.managed boolean Indicateur de test géré par un référentiel de test true si et seulement si le test est géré par Squash TM (c'est-à-dire qu'il est lancé lors de l'exécution d'un cas de test Squash TM auquel il est lié).
test.job string Nom du job exécutant le test.
test.name string Nom du cas de test dans Squash TM. Voir le champ respectif dans l'espace "Cas de test".
test.technology-name string Nom de la technologie du test automatisé affiché dans Squash TM. Voir la liste déroulante "Technologie du test auto." du bloc "Automatisation" du cas de test.
test.reference string Référence du cas de test dans Squash TM. Voir le champ "Référence du test auto." du bloc "Automatisation" du cas de test.
test.importance string Importance du cas de test dans Squash TM. VERY_HIGH, HIGH, MEDIUM, LOW
test.nature string Nature du cas de test dans Squash TM. NAT_UNDEFINED, NAT_FUNCTIONAL_TESTING, NAT_BUSINESS_TESTING, NAT_USER_TESTING, NAT_NON_FUNCTIONAL_TESTING, NAT_PERFORMANCE_TESTING, NAT_SECURITY_TESTING, NAT_ATDD
test.type string Type du cas de test dans Squash TM. TYP_UNDEFINED, TYP_COMPLIANCE_TESTING, TYP_CORRECTION_TESTING, TYP_REGRESSION_TESTING, TYP_EVOLUTION_TESTING, TYP_END_TO_END_TESTING, TYP_PARTNER_TESTING
test.path object Chemin du cas de test dans Squash TM (espace "Cas de test"). Utiliser la fonction contains() pour filtrer.
test.collection
test.collection.path object Chemin du plan de test (itération ou suite) dans Squash TM (espace "Campagnes"). Utiliser la fonction contains() pour filtrer.
test.collection.type string Type du plan de test (itération ou suite) dans Squash TM. iteration, test suite
test.collection.uuid string UUID du plan de test dans Squash TM. Voir le champ "UUID" du bloc "Informations" de l'itération ou de la suite de tests.
test.data
test.data.DSNAME string Nom du jeu de données dans Squash TM. Voir le champ "NOM" du bloc "Paramètres et jeux de données" du cas de test.
test.data.DS_{param_name} string Nom du paramètre dans Squash TM. Tel que défini dans le bloc "Paramètres et jeux de données" du cas de test.
test.data.TC_REFERENCE string Référence du test dans Squash TM. Voir le champ "Référence du cas de test" au-dessus du bloc "Informations" du cas de test.
test.data.TC_UUID string UUID du cas de test.
test.data.TC_CUF_{CUF_CODE} string Champ personnalisé du cas de test dans Squash TM.
test.data.TS_CUF_{CUF_CODE} string Champ personnalisé de la suite de tests dans Squash TM.
test.data.IT_CUF_{CUF_CODE} string Champ personnalisé de l'itération dans Squash TM.
test.data.CPG_CUF_{CUF_CODE} string Champ personnalisé de la campagne dans Squash TM.

Appliquer la quality gate à un workflow

Transmettre le fichier de définition au service

Pour appliquer une quality gate à un workflow, il faut d'abord transmettre le fichier de définition au service. Il existe deux possibilités pour le faire :

1) Charger le fichier au lancement de l'orchestrateur. Il suffit alors d'ajouter deux paramètres dans la commande de démarrage :

  • le point de montage du fichier de définition (en local) sur l'image de l'orchestrateur ;
  • la variable d'environnement QUALITYGATE_DEFINITIONS qui prendra pour valeur le chemin d'accès du fichier sur l'image.
docker run ... \
           -v /path/to/qg_def/my_qualitygate.yaml:/app/qualitygate/my_qualitygate.yaml \
           -e QUALITYGATE_DEFINITIONS=/app/qualitygate/my_qualitygate.yaml \
           ...
docker run ... ^
           -v d:\path\to\qg_def\my_qualitygate.yaml:/app/qualitygate/my_qualitygate.yaml ^
           -e QUALITYGATE_DEFINITIONS=/app/qualitygate/my_qualitygate.yaml ^
           ...
docker run ... `
           -v d:\path\to\qg_def\my_qualitygate.yaml:/app/qualitygate/my_qualitygate.yaml `
           -e QUALITYGATE_DEFINITIONS=/app/qualitygate/my_qualitygate.yaml `
           ...

Deux quality gates sont toujours chargées au lancement du service : strict, qui évalue tous les tests exécutés en utilisant un seuil de 100% et les failure-status par défaut, et passing, dont le seuil de succès est de 0% et qui retournera un résultat passant quels que soient les résultats de l'exécution.

2) Spécifier le fichier via l'option --using de la commande opentf-ctl get qualitygate (détaillée ci-dessous).

Warning

Si le fichier de définition est transmis au service par la commande get qualitygate, seules les quality gates définies dans ce fichier peuvent être utilisées. Les quality gates au niveau du service deviennent inaccessibles.

Evaluer le résultat d'exécution

Pour évaluer le résultat d'exécution des tests d'un workflow, on se servira de la commande opentf-ctl get qualitygate, disponible au sein des outils de l'orchestrateur.

La commande opentf-ctl get qualitygate {workflow_id} {options} évalue un workflow en utilisant l'ensemble des règles de la quality gate spécifiée par l'utilisateur. Elle retourne le résultat d'évaluation pour chaque règle ainsi que le résultat d'évaluation général :

opentf-ctl get qualitygate a13f0572-b23b-40bc-a6eb-a12429f0143c --mode my.quality.gate
RULE,RESULT,TESTS_IN_SCOPE,TESTS_FAILED,TESTS_PASSED,SUCCESS_RATIO
JUnit tests,FAILURE,50,10,40,80.0%
Workflow a13f0572-b23b-40bc-a6eb-a12429f0143c failed the quality gate using mode my.quality.gate.

Le paramètre obligatoire de la commande est {workflow_id}, l'UUID du workflow à évaluer.

Les options sont les suivantes :

  • --mode ou -m. Le nom (name) de la quality gate.
  • --using ou -u. Le chemin du fichier de définition de l'utilisateur.
  • --output wide ou -o wide. Ajoute dans le retour de la commande deux colonnes : THRESHOLD et SCOPE.

Info

On peut également utiliser l'option --output custom-columns pour spécifier les colonnes que l'on veut obtenir : voir la documentation d'OpenTestFactory.

L'option --mode devient obligatoire si le fichier de définition est transmis via l'option --using. Si ce dernier a été chargé au niveau de service, la quality gate strict sera utilisée si --mode n'est pas spécifiée.

Chaque règle retourne FAILURE, SUCCESS, ou NOTEST (si aucun test correspondant au filtre n'a été trouvé). Le résultat général est FAILURE ("workflow failed the quality gate") si au moins une règle est en échec et SUCCESS ("worklow passed the quality gate") si toutes les règles sont en succès. Si toutes les règles retournent NOTEST, le résultat général est également NOTEST ("workflow contains no test matching quality gate scopes").

Les codes retour de la commande get qualitygate sont :

  • 0 si le workflow a passé la quality gate avec succès ou si le résultat général est NOTEST ;
  • 101 si le workflow est toujours en cours d'exécution ;
  • 102 si la quality gate est en échec pour le workflow.

Exemples

Application d'une quality gate définie par l'utilisateur

Prenons un pipeline qui exécute des tests Selenium et des tests Robot Framework au sein d'une même itération Squash TM. On veut que le pipeline passe si :

  • au moins 90% de tests avec le tag Selenium d'importance haute et très haute sont en succès ;
  • au moins 75% de tests Robot Framework qui n'utilisent pas le jeu de données API tests sont en succès.

Supposons qu'une telle quality gate n'existe pas dans le fichier de définition chargé au niveau de l'orchestrateur.

Dans ce cas, l'utilisateur doit d'abord créer son propre fichier de définition :

qualitygates:
 - name: custom.quality.gate
   rules:
   - name: Selenium tests
     rule:
       scope: (test.data.TC_CUF_TAG=='Selenium') && ((test.importance=='VERY_HIGH') || (test.importance=='HIGH'))
       threshold: 90%
       failure-status: [failure]
   - name: RobotFramework
     rule:
       scope: (test.technology=='robotframework') && (test.data.DSNAME!='API tests')
       threshold: 75%
       failure-status: [failure]

Information

Au lieu de la condition ((test.importance=='VERY_HIGH') || (test.importance=='HIGH')), on peut aussi utiliser contains(fromJSON('["HIGH", "VERY_HIGH"]'), test.importance).

Ensuite, s'il sauvegarde le fichier comme custom_quality_gate.yaml, il doit passer son chemin à la commande opentf-ctl get qualitygate :

opentf-ctl get qualitygate {workflow_id} --mode custom.quality.gate --using /home/user/custom_quality_gate.yaml --output wide 

Dans cet exemple, l'option --output wide est utilisée et le retour de la commande contient, en plus des informations sur l'exécution, le seuil et le filtre définis par l'utilisateur :

RULE,RESULT,TESTS_IN_SCOPE,TESTS_FAILED,TESTS_PASSED,SUCCESS_RATIO,THRESHOLD,SCOPE
Selenium tests,SUCCESS,20,2,18,90.0%,90%,(test.data.TC_CUF_TAG=='Selenium') && ((test.importance=='VERY_HIGH') || (test.importance=='HIGH'))
RobotFramework,SUCCESS,40,5,35,87.5%,75%,(test.technology=='robotframework') && (test.data.DSNAME!='API tests')
Workflow {workflow_id} passed the quality gate using mode custom.quality.gate.

Application d'une règle à l'ensemble des tests du workflow

Si l'on veut appliquer une règle à l'ensemble des tests exécutés au sein d'un workflow, il suffit de passer au paramètre scope la valeur true :

qualitygates:
 - name: my.quality.gate
   rules:
   - name: All tests
     rule:
       scope: 'true'
       threshold: 85%

Filtrage sur les paths

La quality gate permet d'ajouter des filtres sur les chemins des cas de test et/ou des itérations et des suites de test dans Squash TM. Pour ce faire, il faut utiliser la fonction contains(search, item) en indiquant l'élément du chemin (nom du dossier) sur lequel on veut filtrer.

Ainsi, cette règle évalue les cas de test qui se trouvent dans les dossiers TNR_main et TNR_smoketest du projet WebApp dans l'espace "Cas de test" de Squash TM:

qualitygates:
 - name: my.quality.gate
   rules:
   - name: TNR
     rule:
       scope: (contains(test.path, 'TNR_main') || contains(test.path, 'TNR_smoketest')) && contains(test.path('WebApp')) 
       threshold: 95%

De même, pour ajouter des filtres sur les chemins des itérations et/ou des suites de test, on utilisera la fonction contains() avec la property test.collection.path. Par exemple, la règle suivante s'applique aux cas de test de l'itération Dropdowns :

qualitygates:
 - name: my.quality.gate
   rules:
   - name: Dropdowns
     rule:
       scope: (test.collection.type=='iteration') && contains(test.collection.path, 'Dropdowns')
       threshold: 100%

Utilisation de la quality gate dans un pipeline Jenkins

Il est possible d'appliquer la quality gate au sein d'un pipeline Jenkins en utilisant la commande opentf-ctl get qualitygate. L'utilisateur doit disposer d'une instance Jenkins reliée à l'orchestrateur à l'aide du plugin opentestfactory-orchestrator-2.1.0.hpi et s'assurer que les outils de l'orchestrateur (opentf-tools) sont disponibles dans l'environnement d'exécution Jenkins.

Info

On se reportera aux parties respectives de la présente documentation pour l'installation du plugin, la configuration du plugin et les appels à l'orchestrateur depuis Jenkins.

Une fois la communication entre Jenkins et l'orchestrateur établie, il suffit d'ajouter un appel à la quality gate au sein du pipeline en lui passant l'UUID du workflow exécuté.

Voici l'exemple d'un pipeline qui lance le workflow squash_sample_tests.yaml et applique la quality gate sample.quality.gate (chargée au niveau de l'orchestrateur) au workflow exécuté :

pipeline {
  agent any
  environment {
    WORKFLOW_ID = ''
  }
  stages {
    stage('Run OTF workflow'){
      steps {
        script {
          WORKFLOW_ID = runOTFWorkflow(
            workflowPathName: 'squash_sample_tests.yaml',
            workflowTimeout: '300S',
            serverName:'Orchestrator',
            jobDepth: 2,
            stepDepth: 3,
            dumpOnError: true
          ) 
        }
      }
    }
    stage('Apply quality gate'){
      steps {
        script {
          def qg_command = "opentf-ctl get qualitygate $WORKFLOW_ID --mode sample.quality.gate"
          def qg_result = sh(returnStdout: true, script: qg_command)
          echo "$qg_result"
        }
      }
    }
  }
}

Ce pipeline utilise la variable d'environnement WORKFLOW_ID qui peut être passée d'une étape à l'autre. Sa valeur (UUID du workflow exécuté) est récupérée depuis la fonction runOTFWorkflow() et transmise à la commande get qualitygate. Le résultat d'exécution de celle-ci est également récupérée dans une variable et affichée dans la console.

Si la quality gate est en échec, elle retourne le code d'erreur 102 et fait échouer le pipeline. Si la quality gate est en succès ou ne trouve aucun test à évaluer, elle retourne le code 0 et le pipeline se termine en succès (ou continue s'il y a d'autres étapes qui suivent).

On peut choisir de ne pas arrêter le pipeline même si le workflow ne passe pas la quality gate. Dans ce cas, le script shell doit être exécuté avec l'option returnStatus: true au lieu de returnStdout: true. Le step retournera alors le code retour du script, qui pourra être traité dans les étapes ultérieures.

Utilisation de la quality gate dans un pipeline GitLab

Il est également possible (et même conseillé) d'appliquer la quality gate à un workflow exécuté au sein d'un pipeline GitLab. Un guide détaillé sur l'intégration de Squash Orchestrator avec GitLab CI est disponible dans la documentation d'OpenTestFactory.

Voici l'exemple d'un fichier .gitlab-ci.yml qui exécute le workflow my_workflow.yaml et applique la quality gate, définie dans un fichier utilisateur au sein du projet, chaque fois que le projet est modifié :

default:
  image: python:3.12

stages:
  - test

opentf-workflow:
  stage: test
  script:
    - pip install opentf-tools
    - RESULT=$(opentf-ctl run workflow .opentf/workflows/my_workflow.yaml --watch)
    - WORKFLOW_ID=$(echo $RESULT | head -n 1 |awk -F ' ' '{print $2}')
    - opentf-ctl get qualitygate $WORKFLOW_ID --mode sample.quality.gate --using .opentf/qualitygates/my_quality_gate.yaml

La commande pip install vérifie que la version la plus récente des outils de l'orchestrateur est disponible sur le runner, et la commande opentf-ctl run... exécute le workflow avec l'option --watch pour suivre l'exécution. L'UUID du workflow est ensuite récupéré dans la variable WORKFLOW_ID depuis le retour de la commande.

Enfin, la quality gate sample.quality.gate, définie dans le fichier my_quality_gate.yaml, est appliquée au workflow et son retour est affiché. Si le workflow ne passe pas la quality gate, le code d'erreur 102 sera retourné et le pipeline sera en échec. Sans la quality gate, le pipeline sera toujours en succès, quels que soient les résultats des tests.

Publication des résultats de la quality gate dans une merge request

Les résultats de la quality gate peuvent être publiés dans une merge request de GitLab : il suffit de compléter la commande get qualitygate en lui passant les paramètres --plugin gitlab:... demandés. Le pipeline concerné doit être un merge request pipeline.

Voici l'exemple d'un fichier .gitlab-ci.yml qui exécute le workflow my_workflow.yaml et applique la quality gate définie au niveau du service chaque fois qu'un commit est poussé sur la branche de la merge request. Les résultats de la quality gate sont ensuite publiés dans cette merge request sous forme d'une note :

default:
  image: python:3.12

stages:
  - test

opentf-workflow:
  stage: test
  script:
    - pip install opentf-tools
    - RESULT=$(opentf-ctl run workflow .opentf/workflows/my_workflow.yaml --watch)
    - WORKFLOW_ID=$(echo $RESULT | head -n 1 |awk -F ' ' '{print $2}')
    - opentf-ctl get qualitygate $WORKFLOW_ID --mode sample.quality.gate \
      --plugin gitlab:keep-history=true \
      --plugin gitlab:token={authentication token} \
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'

--plugin gitlab:keep-history est l'unique paramètre obligatoire. S'il vaut true, l'historique des résultats de la quality gate définie par --mode sera gardé dans les notes de la merge request. S'il vaut false, une seule note sera ajoutée à la merge request et sera mise à jour chaque fois que la quality gate est évaluée.

Le paramètre --plugin gitlab:token permet de définir le token d'accès au projet si c'est nécessaire.

L'instance de GitLab, le projet et la merge request sont récupérés par défaut depuis les variables d'environnement prédéfinies de GitLab (à savoir CI_SERVER_URL, CI_MERGE_REQUEST_PROJECT_ID et CI_MERGE_REQUEST_IID). Il est toutefois possible de définir sa propre instance GitLab, l'ID du projet et l'IID de la merge request en utilisant les paramètres gitlab:server, gitlab:project et gitlab:mr.

On peut aussi ajouter à la merge request un label qui affiche le statut de la quality gate. Il faut d'abord créer, au niveau du projet GitLab, trois labels correspondant aux statuts possibles de la quality gate : {prefix}::Passed, {prefix}::Failed et {prefix}::No test. C'est à l'utilisateur de choisir le préfixe. Ensuite, il faut ajouter à la commande get qualitygate le paramètre --plugin gitlab:label={prefix}.

Il est également possible de publier les résultats de la quality gate dans l'issue liée à la merge request. Voici l'exemple d'un pipeline qui exécute le workflow my_workflow.yaml, applique la quality gate à ce workflow et envoie les résultats vers l'issue correspondante. L'IID de l'issue est récupéré depuis la description de la merge request, qui doit le contenir par défaut :

default:
  image: python:3.12

stages:
  - test

opentf-workflow:
  stage: test
  script:
    - pip install opentf-tools
    - RESULT=$(opentf-ctl run workflow .opentf/workflows/my_workflow.yaml --watch)
    - WORKFLOW_ID=$(echo $RESULT | head -n 1 |awk -F ' ' '{print $2}')
    - MR_DATA="$(curl --header "PRIVATE-TOKEN:{authentication token}" \ "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID" | sed 's/\\"//g')"
    - ISSUE_IID=$(python -c "import json; data = json.loads('$MR_DATA'); print(data.get('description'))" | head -1 | sed 's/.*#//')
    - opentf-ctl get qualitygate $WORKFLOW_ID --mode sample.quality.gate \
      --plugin gitlab:keep-history=false \
      --plugin gitlab:issue=$ISSUE_IID
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'

La liste complète des options GitLab de la commande opentf-ctl get qualitygate est disponible dans la documentation d'OpenTestFactory.