Aller au contenu

Test Runner

perfshop-test-runner est le container d'exécution où tous les tests Robot Framework et pytest tournent réellement. C'est une image custom buildée localement à partir du Dockerfile dans test-runner/ — elle n'est pas pullable depuis un registry public.

Son rôle unique : recevoir des scripts Python (pytest) ou Robot Framework par deux canaux distincts (SSH pour Squash Orchestrator, docker exec pour Scripts UI), les exécuter en pilotant Selenium, et produire des artefacts (logs, rapports) lisibles par les autres services de la stack.

Source de vérité

Cette page est tirée du fichier test-runner/Dockerfile, du bloc perfshop-test-runner dans les fichiers compose, et de test-runner/docker-entrypoint.sh.

Dockerfile custom

Base et dépendances système

FROM python:3.11-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
    openssh-server \
    git \
    && rm -rf /var/lib/apt/lists/*

Trois paquets système uniquement :

Paquet Usage
python:3.11-slim (base) Runtime Python et pip
openssh-server Permet à Squash Orchestrator de se connecter via SSH
git Nécessaire pour squash-tf-services qui peut cloner des dépôts SCM

Pas de navigateur local dans le container — Selenium tourne dans perfshop-selenium, le test-runner est client WebDriver uniquement.

Dépendances Python — deux profils pédagogiques

RUN pip install --no-cache-dir \
    robotframework==7.0 \
    robotframework-seleniumlibrary==6.3.0 \
    robotframework-requests==0.9.6 \
    robotframework-jsonlibrary==0.5 \
    pytest==8.0 \
    selenium==4.18.1 \
    requests==2.31.0 \
    allure-robotframework \
    squash-tf-services

Le commentaire du Dockerfile est explicite : « Dépendances QA — deux profils d'étudiants. Profil débutant : robotframework + SeleniumLibrary + RequestsLibrary + JsonLibrary. Profil avancé : pytest + selenium ».

Profil Librairies Usage typique
Débutant Robot Framework 7.0 + SeleniumLibrary 6.3.0 + RequestsLibrary 0.9.6 + JsonLibrary 0.5 Tests rédigés en syntaxe mot-clé (table-driven), facile à lire sans expérience Python
Avancé pytest 8.0 + selenium 4.18.1 + requests 2.31.0 Tests rédigés en Python, fixtures, paramétrisation, contrôle fin

Les deux profils cohabitent dans le même container — rien n'empêche un étudiant de commencer par Robot Framework puis de migrer progressivement vers pytest à mesure qu'il monte en compétence.

Deux dépendances complémentaires :

  • allure-robotframework : génère des rapports Allure à partir des résultats Robot Framework — peut être utilisé par les étudiants qui veulent expérimenter un reporting visuel alternatif.
  • squash-tf-services : services côté client nécessaires pour que le test-runner soit compatible avec l'orchestration Squash TF (clone SCM automatique, retour structuré des résultats).

Versions verrouillées

Toutes les versions sont pinnées dans le Dockerfile. C'est volontaire — la reproductibilité est essentielle pour l'usage pédagogique : un étudiant qui apprend avec RF 7.0 doit retrouver exactement le même comportement le lendemain, et un formateur doit pouvoir se fier aux comportements documentés.

Configuration OpenSSH

RUN mkdir -p /var/run/sshd && \
    echo 'root:perfshop' | chpasswd && \
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config && \
    sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config

Trois modifications :

Action Effet
echo 'root:perfshop' \| chpasswd Définit le mot de passe root à perfshop (pour l'orchestrateur)
PermitRootLogin yes Autorise le login SSH direct en root
PasswordAuthentication yes Autorise l'authentification par mot de passe (par défaut désactivée sur les images Debian récentes)

Accès root par mot de passe — cadre strictement pédagogique

Le commentaire du Dockerfile est explicite : « Accès root avec password "perfshop" — usage pédagogique uniquement. Le container n'est pas exposé vers l'extérieur (réseau Docker interne) ». Dans un déploiement production réel (même interne), il faudrait basculer sur l'authentification par clé SSH et créer un utilisateur dédié non-root. Pour PerfShop, cette configuration est acceptable parce que le container n'expose aucun port à l'hôte (le 22 est interne), et que l'objectif est pédagogique.

Entrypoint et propagation des variables

COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

Le commentaire du Dockerfile explique : « sshd n'hérite pas des variables Docker. docker-entrypoint.sh écrit /etc/environment au démarrage pour que robot et pytest les voient dans les sessions SSH lancées par l'orchestrateur ».

C'est un piège classique de l'intégration SSH dans un container Docker : quand sshd accepte une connexion entrante et forke un shell, ce shell n'hérite pas des variables d'environnement positionnées par Docker Compose (elles sont uniquement dans le process PID 1). L'entrypoint contourne ce problème en écrivant toutes les variables utiles dans /etc/environment, qui est lu par pam_env à chaque login.

Concrètement, les variables SELENIUM_REMOTE_URL, PERFSHOP_FRONTEND_INTERNAL, PUBLIC_API_URL, PERFSHOP_LANG sont ainsi disponibles à la fois dans une session docker exec et dans une session SSH — garantissant un comportement cohérent entre les deux canaux d'exécution.

Le service dans le compose

perfshop-test-runner:
  image: perfshop-test-runner:latest
  build:
    context: ./test-runner
    dockerfile: Dockerfile
  container_name: perfshop-test-runner
  environment:
    - SELENIUM_REMOTE_URL=http://perfshop-selenium:4444/wd/hub
    - PERFSHOP_FRONTEND_INTERNAL=${PERFSHOP_FRONTEND_INTERNAL:-http://perfshop-frontend:80}
    - PUBLIC_API_URL=${PUBLIC_API_URL:-http://localhost:8080}
    - PERFSHOP_LANG=${PERFSHOP_LANG:-fr}
  volumes:
    - ./test-runner/scripts:/scripts
    - ./test-runner/logs:/rf-logs
  entrypoint: ["/usr/local/bin/docker-entrypoint.sh"]
  command: ["/usr/sbin/sshd", "-D", "-e"]

Commande et entrypoint

L'entrypoint écrit /etc/environment puis lance /usr/sbin/sshd -D -e :

Flag Effet
-D Daemon mode — reste en foreground (obligatoire pour que le container ne se termine pas)
-e Logs sur stderr (au lieu de syslog) — capturés par Docker et donc par Promtail / Vector

Le container ne fait rien d'autre que tourner sshd et attendre des connexions (SSH ou docker exec). C'est le même principe que perfshop-jmeter qui tourne tail -f /dev/null en attendant des tirs — le container n'a pas de « service métier » propre, il sert uniquement de substrat d'exécution.

Variables d'environnement propagées

Variable Rôle Visibilité
SELENIUM_REMOTE_URL URL du hub WebDriver Utilisée par Robot Framework et pytest pour ouvrir un navigateur distant
PERFSHOP_FRONTEND_INTERNAL URL interne du frontend Les tests naviguent vers http://perfshop-frontend:80 (DNS Docker)
PUBLIC_API_URL URL publique du backend Utile si un test fait des assertions sur une URL canonique
PERFSHOP_LANG Langue courante Permet à un test de choisir les bons sélecteurs i18n (FR ou EN)

Volumes

Volume Montage Rôle
./test-runner/scripts (bind mount) /scripts Scripts de test partagés — volume lu par le test-runner (exécution) et écrit par Forgejo-seed (push initial des scripts dans le dépôt Git)
./test-runner/logs (bind mount) /rf-logs Logs et rapports — écrits par Robot Framework et pytest à chaque exécution, lus par Promtail (Loki) et Vector (OpenSearch)

Le WORKDIR du Dockerfile est /scripts, donc toute exécution docker exec ou SSH démarre directement dans le dossier des scripts.

Les deux modes d'exécution

Mode 1 — docker exec depuis Scripts UI

sequenceDiagram
  autonumber
  participant SUI as perfshop-scripts-ui<br/>(Node.js)
  participant SOCK as /var/run/docker.sock
  participant TR as perfshop-test-runner
  participant SEL as perfshop-selenium

  SUI->>SOCK: POST /containers/perfshop-test-runner/exec<br/>{cmd: ["robot", "--outputdir", "/rf-logs/...", "login.robot"]}
  SOCK->>TR: exec dans /scripts
  TR->>TR: Lit variables depuis /etc/environment
  TR->>SEL: POST /wd/hub/session
  SEL-->>TR: Session Chrome
  TR->>SEL: Commands WebDriver
  TR->>TR: Écrit log.html, report.html, output.xml dans /rf-logs/
  TR-->>SUI: Exit code + stdout

Avantages : - Pas de credentials à gérer côté Scripts UI (utilise le socket Docker) - Rapide et léger

Mode 2 — SSH depuis Squash Orchestrator

sequenceDiagram
  autonumber
  participant ORCH as perfshop-orchestrator
  participant TR as perfshop-test-runner (sshd)
  participant SEL as perfshop-selenium

  ORCH->>TR: SSH root@perfshop-test-runner<br/>(password perfshop)
  TR->>TR: pam_env lit /etc/environment
  ORCH->>TR: SCP script.robot → /scripts/tmp/
  ORCH->>TR: exec "robot --outputdir /rf-logs/... script.robot"
  TR->>SEL: POST /wd/hub/session
  SEL-->>TR: Session Chrome
  TR->>TR: Exécute le test
  TR-->>ORCH: Exit code + output.xml
  ORCH-->>ORCH: Parse output.xml et retourne à Squash TM

Avantages : - Compatible avec l'architecture distribuée Squash TF (le runner pourrait théoriquement être sur une autre machine) - Format de résultats structuré (output.xml) directement parsable par Squash TM

Pas d'exposition de ports

# Aucun "ports:" dans le bloc perfshop-test-runner

Le container n'expose aucun port à l'hôte. Le port 22 est uniquement accessible depuis le réseau Docker interne — l'orchestrateur s'y connecte via perfshop-test-runner:22. Aucun utilisateur externe ne peut atteindre sshd.

Logs collectés par deux pipelines

Les fichiers écrits dans /rf-logs/ sont collectés simultanément par Promtail et Vector :

  • Promtail → Loki : le job rf-runner-log de Promtail tail les fichiers /rf-logs/*.log (voir ../observability/loki.md)
  • Vector → OpenSearch : Vector collecte les logs du container perfshop-test-runner via son Docker source (sortie stdout + stderr du sshd)

Ces deux flux sont complémentaires : - Loki est optimal pour « chercher toutes les exécutions du test login.robot des 10 dernières minutes » - OpenSearch permet des agrégations structurées type « combien de tests PASS vs FAIL par jour sur la dernière semaine »

Image non pullable depuis un registry public

Le tag perfshop-test-runner:latest est local au poste de build. Aucun push vers Docker Hub ou autre registry n'est effectué. Le build.sh lance docker build sur le dossier test-runner/ à chaque déploiement. C'est aligné avec la philosophie PerfShop : tout est reproductible à partir du code source, aucune dépendance à un registry tiers.

Pour aller plus loin

  • Selenium — le moteur WebDriver piloté par le test-runner
  • Squash Orchestrator — l'un des deux déclencheurs
  • Scripts UI — l'autre déclencheur (via docker exec)
  • Loki — pipeline de collecte des logs /rf-logs/*.log
  • OpenSearch — pipeline alternatif via Vector