Halte aux régressions
- 5 minutes de lecture
Pour garantir la qualité du code d’un logiciel, rien de mieux que la validation par les tests. Ces derniers peuvent être de différentes natures (fonctionnels, intégration, unitaires, performance, etc.) et permettent de respecter une série d’exigences que s’imposent les développeurs pour maintenir et faire évoluer ledit logiciel dans la bonne direction.
Dans cet article, je souhaite explorer le système de tests tel qu’il est (et
a été) implémenté dans PostgreSQL et comment le réemployer dans la rédaction d’une
extension communautaire. Si vous ne connaissiez pas l’outil pg_regress
, il
n’aura plus de secret pour vous !
Aux origines des tests de régression
Avant même l’émergence du plus avancé des systèmes de bases de données open-source
du monde que l’on connait, le projet Berkeley POSTGRES disposait déjà d’un
répertoire src/regress/regress
dans sa dernière version connue. Celui-ci fut
définitivement adopté sous la forme de src/test/regress
lors de la reprise du
projet Postgre95 par les deux étudiants Andrew Yu et Jolly Chen.
Ce n’est pas anodin, car ce répertoire existe encore dans les versions modernes et porte toujours les mêmes responsabilités, à savoir : s’assurer que les fonctionnalités de PostgreSQL ne présentent aucune régression à chaque patch ou nouvelle version majeure. Ce système de test est relativement simple à appréhender et très répandu dans le milieu du développement des logiciels libres.
Il repose sur les fichiers de tests au format SQL et des fichiers de sorties au
format OUT. L’astuce consiste à exécuter le code SQL sur une instance en cours
d’exécution et de capter la sortie standard dans un fichier de résultat. Pour
chaque test (sql
), le fichier de résultat (result
) est ensuite comparé au
résultat attendu du test (expected
) à l’aide de la méthode diff
.
Ce traitement est réalisé depuis la version 7.1 par l’utilitaire pg_regress.sh
.
À l’origine, ce dernier était un simple script shell responsable de monter
une instance PostgreSQL temporaire au besoin, de rapprocher les fichiers SQL de
leurs résultats OUT et de fournir un résumé des tests. Le script fut intégralement
remplacé par son équivalent pg_regress
réécrit en C à la sortie de la
version 8.2, pour faciliter notamment :
- La validation des tests sur un environnement Windows sans émulateur de shell
tel que
mingw
- La mise à disposition d’un outil prêt à l’emploi avec l’installation de PostgreSQL, sans les dépendances systèmes requises par l’ancien script
- L’implémentation de nouvelles améliorations comme l’exécution concurrente des tests ou un résultat plus conviviale
Lors d’une compilation des binaires d’une version quelconque de PostgreSQL, il
est possible de valider tout ou partie des fonctionnalités à l’aide de la commande
make check
ou make installcheck
. La première des deux commandes créée une
instance temporaire alors que la seconde va exécuter les tests sur une instance
en cours d’exécution.
make check
PATH="tmp_install/var/lib/pgsql-14.2/bin:src/test/regress:$PATH" \
LD_LIBRARY_PATH="tmp_install/var/lib/pgsql-14.2/lib:$LD_LIBRARY_PATH" \
../../../src/test/regress/pg_regress \
--temp-instance=./tmp_check \
--inputdir=. --bindir= --dlpath=. \
--max-concurrent-tests=20 \
--make-testtablespace-dir \
--schedule=./parallel_schedule
============== removing existing temp instance ==============
============== creating temporary instance ==============
============== initializing database system ==============
============== starting postmaster ==============
running on port 58082 with PID 24013
============== creating database "regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries ==============
test tablespace ... ok 165 ms
parallel group (20 tests):
boolean ... ok 47 ms
char ... ok 40 ms
name ... ok 41 ms
varchar ... ok 38 ms
text ... ok 34 ms
int2 ... ok 24 ms
int4 ... ok 23 ms
int8 ... ok 55 ms
oid ... ok 43 ms
float4 ... ok 60 ms
...
parallel group (2 tests):
event_trigger ... ok 59 ms
oidjoins ... ok 119 ms
test fast_default ... ok 71 ms
test stats ... ok 620 ms
============== shutting down postmaster ==============
============== removing temporary instance ==============
...
=======================
All 210 tests passed.
=======================
Tester son extension avec PGXS
En plusieurs années, l’outil pg_regress
s’est étendu aux fonctionnalités annexes
du projet PostgreSQL, comme les langages embarqués (plpgsql
, plperl
, etc.) ou
les contributions communautaires.
Le système PGXS propose aux membres de la communauté d’enrichir leurs
Makefile
avec des règles de compilation, d’installation et de validation par
pg_regress
. Dans un projet, il est ainsi recommandé d’inclure les directives
du PGXS pour bénéficier de la règle installcheck
responsable des tests.
Prenons l’exemple de la contribution pgstattuple
avec la définition de son
Makefile. Ce dernier contient les quelques variables nécessaires pour la
compilation et l’installation, puis inclut les règles pgxs.mk
si le système
est utilisé.
# contrib/pgstattuple/Makefile
REGRESS = pgstattuple
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pgstattuple
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
Avec cette configuration par défaut, l’outil pg_regress
part à la recherche des
fichiers sql/
dans le répertoire courant, et les exécute sur l’instance pour
ensuite comparer ses résultats avec les fichiers expected/
. Le contenu du
fichier expected/pgstattuple.out
peut être consulté directement dans le code
source de PostgreSQL.
pgstattuple
├── expected
│ └── pgstattuple.out
├── results
│ └── pgstattuple.out
└── sql
└── pgstattuple.sql
Lançons les tests de l’extension avec le système PGXS :
cd contrib/pgstattuple
make USE_PGXS=1 install installcheck
./lib/pgxs/src/makefiles/../../src/test/regress/pg_regress \
--inputdir=./ --bindir='./bin' \
--dbname=contrib_regression pgstattuple
(using postmaster on Unix socket, default port)
============== dropping database "contrib_regression" ==============
DROP DATABASE
============== creating database "contrib_regression" ==============
CREATE DATABASE
ALTER DATABASE
============== running regression test queries ==============
test pgstattuple ... ok 167 ms
=====================
All 1 tests passed.
=====================
Pensez-y !
Vous souhaitez développer votre propre extension pour révolutionner PostgreSQL ? Pensez à écrire vos tests avec le framework PGXS ! La documentation est très fournie à ce sujet pour prendre en main les variables d’environnement. De plus, depuis la version PostgreSQL 9.4, il est possible de bénéficier de standard TAP pour rédiger vos tests.
Les extensions sont nombreuses et ce n’est jamais une mauvaise idée de s’inspirer des contributions maintenues dans le projet PostgreSQL. Je recommande également la série d’articles rédigée par Manuel Kniep pour comprendre le processus complet de l’écriture d’une extension ou la conférence de Lætitia Avrot sur l’extension pgwaffles créée à l’occasion du FOSDEM 2021.