Pour faire des tests unitaires, la logithèque de n'importe quel langage est plus que suffisante. Pour des tests fonctionnels, d'un coup, ça devient plus compliqué. Pour des images Docker, bah, il n'existe rien d'officiel.
"Ce qui n'a pas été testé n'existe pas" - Albert Hofmann
Goss est un outil de test tout simple, destiné à être embarqué dans un contexte précis : un conteneur ou un serveur.
Goss utilise des jeux de tests en YAML, avec la possibilité de passer des arguments en ligne de commande.
Comme toutes les applications golang, c'est un gros binaire autonome, ce qui permet de le poser le contexte voulu, de l'utiliser, puis de le supprimer. Dans notre cas, là, il est possible de le monter dans un volume dans un conteneur , avec son dossier de tests.
En travaillant avec des volumes, on peut tester une image sans devoir la modifier, ni perdre du temps à recopier des éléments éphémères.
Pour emballer tout ça, et surtout pouvoir l'utiliser sans trop de soucier des détails, voici les différentes taches make
pouvant être utilisé, comme dans le projet docker-ruby .
On télécharge le binaire dans la bonne version
GOSS_VERSION := 0.3.5 bin/goss: mkdir -p bin curl -o bin/goss -L https://github.com/aelsabbahy/goss/releases/download/v$\{GOSS_VERSION}/goss-linux-amd64 chmod +x bin/goss
Ensuite, on lance le test
test: bin/goss @rm -rf tests/vendor @docker run --rm -t \ -v `pwd`/bin/goss:/usr/local/bin/goss \ -v `pwd`/tests:/goss \ -w /goss \ bearstech/ruby-dev:2.4 \ goss -g ruby-dev.yaml --vars vars/2_4.yaml validate --max-concurrent 4 --format documentation
On instancie une image avec un TTY -t
qui sera nettoyée une fois l'action terminée --rm
. Un premier volume est monté avec le binaire goss
. Le dossier tests
est monté et devient le dossier courant -w
. Goss est directement lancé avec son jeu de tests -g
, une variable --vars
, une commande validate
, et un affichage lisible par un être humain --format documentation
le jeu de tests se contente de lister les différents tests
gossfile: ruby_version.yaml: {} git.yaml: {} bundle_install.yaml: {}
le test de version est tout simple :
command: ruby -v: exit-status: 0 stdout: - /ruby 2\.{{ .Vars.ruby_version_minor }}.*/
On lance une commande ruby -v
, et on s'attend à un résultat.
Le test d'installation est à peine plus complexe :
command: "cd test_install_json && ./install_json.sh": exit-status: 0 timeout: 120000 stdout: - /.*(Bundle complete!)|(Your bundle is complete!).*/ - /.*{"hello":"world"}.*/
Les one liners, ça va un moment, du coup, c'est un gros shell qui va lancer les actions.
apt-get update apt-get install -y libgmp-dev bundle install --path=vendor bundle exec ruby -e "require 'json'; puts ({hello: 'world'}).to_json"
Avec ça, on teste la compilation d'un module avec du code en C, puis on l'utilise.
On peut considérer qu'une image de build pour Ruby qui arrive à compiler une extension avec du code en C, puis à l'utiliser, est testée.
"Jobs done" - Georges W Bush