Aller au contenu

Publier dans SquashTM

Maintenant que vous avez des résultats de tests parsés au format JSON de SquashTM, l'étape finale est de publier ces résultats dans votre instance SquashTM.

Ce que vous apprendrez dans cette section :

  • Configurer l'authentification par jeton API
  • Envoyer le fichier result.json à l'API de SquashTM
  • Vérifier que les résultats apparaissent dans SquashTM

Dans cet exemple, nous allons mettre à jour le script de parser pour qu'il publie également les résultats dans SquashTM via l'API.

Voir le script complet

Vous pouvez consulter le script complet avec la fonctionnalité de publication ici : parse_robot_results.py.

Exemple : GitLab CI/CD + Robot Framework

Étape 1 : Configurer l'URL SquashTM et l'authentification

Vous devez fournir vos identifiants SquashTM au pipeline afin qu'il puisse publier les résultats.

Si vous avez suivi la section Préparer SquashTM, vous devriez déjà avoir un jeton API.
Maintenant, vous allez configurer ces identifiants comme variables CI/CD GitLab.

Allez dans votre projet GitLab → Settings → CI/CD → Variables et ajoutez les variables suivantes :

Nom de variableValeurMaskedHidden
SQUASH_TM_URLhttps://votre-instance-squash.com
SQUASH_TM_API_TOKENVotre jeton API depuis SquashTM
SQUASH_TM_ITERATION_IDL'ID de votre itération dans SquashTM

Trouver l'ID d'itération

Vous pouvez trouver cet ID depuis l'itération que vous avez créée dans le guide des prérequis :

  • Depuis l'interface web : Voir Étape 3 (Interface Web). L'ID d'itération est visible dans l'URL lorsque vous ouvrez l'itération dans SquashTM, ou bien dans le menu "Informations" de l'itération.
  • Depuis l'API : Voir Étape 3 (API). L'ID d'itération est retourné dans le corps de la réponse API.

Étape 2 : Mettre à jour le script de parser pour publier les résultats

Mettez à jour votre script ci/parse_robot_results.py pour ajouter la fonctionnalité de publication.

Ajoutez d'abord les imports manquants en haut du fichier :

import os
import sys
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError

Puis ajoutez ces variables d'environnement et fonctions à votre script :

SQUASH_TM_URL = os.getenv('SQUASH_TM_URL')
SQUASH_TM_API_TOKEN = os.getenv('SQUASH_TM_API_TOKEN')
SQUASH_TM_ITERATION_ID = os.getenv('SQUASH_TM_ITERATION_ID')

SQUASH_TM_API_IMPORT_ENDPOINT = "api/rest/latest/import/results"

def check_tm_variables():
    if not SQUASH_TM_URL:
        print("""
SQUASH_TM_URL is not set.
Please set your SquashTM public URL, for example:
SQUASH_TM_URL=https://squash.example.com/
""")
        sys.exit(1)

    if not SQUASH_TM_ITERATION_ID:
        print("""
SQUASH_TM_ITERATION_ID is not set.
Please set the SQUASH_TM_ITERATION_ID environment variable, for example:
SQUASH_TM_ITERATION_ID=345
""")
        sys.exit(1)

    if not SQUASH_TM_API_TOKEN:
        print("""
No authentication configured for SquashTM.
Please set the SQUASH_TM_API_TOKEN environment variable, for example:
SQUASH_TM_API_TOKEN=<your_token>
""")
        sys.exit(1)

def upload_to_squash_tm(report):
    """Upload test results to SquashTM via POST request."""

    # Normalize base URL and endpoint to avoid missing/extra slashes
    base = SQUASH_TM_URL.strip('/')
    endpoint = SQUASH_TM_API_IMPORT_ENDPOINT.strip('/')
    iteration_id = str(SQUASH_TM_ITERATION_ID).strip('/')
    url = f"{base}/{endpoint}/{iteration_id}"

    try:
        json_data = json.dumps(report).encode('utf-8')
        auth_header = f"Bearer {SQUASH_TM_API_TOKEN}"

        request = Request(url, data=json_data, method='POST')
        request.add_header('Content-Type', 'application/json')
        request.add_header('Authorization', auth_header)

        with urlopen(request) as response:
            status = getattr(response, 'status', None)
            if status == 204:
                print(f"Results uploaded to SquashTM using Token auth (status: 204 No Content)")
                return
            else:
                body = response.read().decode('utf-8', errors='replace')
                print(f"Unexpected SquashTM response status: {status}")
                if body:
                    print("Response body (truncated to 2000 chars):")
                    print(body[:2000])
                sys.exit(1)

    except HTTPError as e:
        print(f"HTTP error uploading to SquashTM: {e.code} - {e.reason}")
        sys.exit(1)
    except URLError as e:
        print(f"Connection error uploading to SquashTM: {e.reason}")
        sys.exit(1)
    except Exception as e:
        print(f"Unexpected error uploading to SquashTM: {e}")
        sys.exit(1)

Ce que le code ci-dessus impose et garantit :

  • check_tm_variables() :

    • Requiert SQUASH_TM_URL pour cibler votre instance SquashTM
    • Requiert SQUASH_TM_ITERATION_ID pour construire l'URL de l'API d'import des résultats
    • Requiert SQUASH_TM_API_TOKEN pour s'authentifier
    • Échoue rapidement avec des instructions claires (code de sortie 1) si quelque chose manque
  • upload_to_squash_tm(report) :

    • Construit l'en-tête Authorization avec le token d'authentification
    • Traite HTTP 204 No Content comme un succès ; tout autre statut enregistre les détails et sort avec le code 1

Mettez à jour la fonction main() :

def main():
    """Main function."""
    check_tm_variables()

    tests = parse_tests('xunit.xml')

    attachments = create_attachments()

    report = {
        'automated_test_suite': {
            'attachments': attachments
        },
        'tests': tests
    }

    with open('result.json', 'w', encoding='utf-8') as f:
        json.dump(report, f, indent=2, ensure_ascii=False)

    print(f"{len(tests)} test(s) parsed")
    print(f"result.json created with {len(attachments)} attachment(s)")

    upload_to_squash_tm(report)

Ce que ces ajouts font :

  • check_tm_variables() : Vérifie que les variables d'environnement sont configurées
  • upload_to_squash_tm() : Envoie le rapport JSON à l'API de SquashTM en utilisant l'authentification par Jeton API
  • main() mis à jour : Crée maintenant les pièces jointes et upload vers SquashTM après le parsing
  • Gestion des erreurs : Sort avec un code d'erreur si l'upload échoue

Étape 3 : Vérifier le job du pipeline

Le job parse-and-publish que vous avez créé précédemment a déjà tout ce dont il a besoin.
Le script publiera automatiquement les résultats si les variables d'environnement sont définies.

Ce qui se passe :

  1. Le script parse les résultats de tests depuis xunit.xml
  2. Crée des pièces jointes depuis les fichiers de rapport de test
  3. Sauvegarde tout dans result.json
  4. Tente d'uploader vers SquashTM en utilisant les identifiants configurés
  5. Fait échouer le job si l'upload échoue (à cause de allow_failure: false)

Commitez votre script de parser mis à jour :

git add ci/parse_robot_results.py
git commit -m "Add SquashTM publishing to parser"
git push

Vérifier la publication

  1. Allez dans votre projet GitLab
  2. Naviguez vers Build → Pipelines
  3. Cliquez sur le dernier pipeline
  4. Cliquez sur le job parse-and-publish
  5. Vérifiez les logs pour le message de succès : Results uploaded to SquashTM using Token auth (status: 204 No Content)

Étape 4 : Vérifier dans SquashTM

  1. Connectez-vous à SquashTM
  2. Naviguez vers votre projet
  3. Allez dans Exécutions → Projet → Campagne → Itération → Suites automatisées
  4. Vous devriez voir une nouvelle suite automatisée avec vos résultats de tests

automated-suite

Pour plus de détails sur l'analyse des résultats de tests automatisés dans SquashTM, consultez Analyser les résultats CI/CD.

Ce que vous avez accompli

Votre intégration CI/CD complète fonctionne maintenant :

  • Les tests s'exécutent automatiquement dans votre pipeline
  • Les résultats sont parsés au format JSON de SquashTM
  • Les résultats sont publiés dans SquashTM via l'API
  • Les rapports de tests sont attachés pour faciliter le débogage
  • Tout est automatisé à chaque commit

Félicitations ! Vous avez maintenant une intégration CI/CD entièrement automatisée avec SquashTM.

Bonus : Dépannage

Si vous rencontrez des problèmes lors de l'intégration, consultez la page Dépannage pour des solutions aux problèmes courants.