Malgré le fait que tout le monde sait qu'il est important et nécessaire de tester votre logiciel, et beaucoup le font automatiquement depuis longtemps, il n'y a pas une seule recette dans les espaces ouverts de Habr pour mettre en place un tas de produits aussi populaires dans ce créneau que (notre préféré) GitLab et JUnit . Comblez cette lacune!

Introduction
Je vais d'abord décrire le contexte:
- Ătant donnĂ© que toutes nos applications fonctionnent dans Kubernetes, nous envisagerons d'exĂ©cuter des tests dans l'infrastructure appropriĂ©e.
- Pour l'assemblage et le déploiement, nous utilisons werf (dans le sens des composants d'infrastructure, cela signifie également automatiquement que Helm est impliqué).
- Je n'entrerai pas dans les dĂ©tails de la crĂ©ation directe de tests: dans notre cas, le client Ă©crit lui-mĂȘme les tests, et nous nous assurons uniquement qu'ils sont exĂ©cutĂ©s (et le rapport correspondant est disponible dans la demande de fusion).
à quoi ressemblera la séquence globale des actions?
- Assemblage de l'application - nous omettons la description de cette étape.
- Déployez l'application dans un espace de noms de cluster Kubernetes distinct et lancez les tests.
- Recherchez des artefacts et analysez un rapport JUnit par GitLab.
- Supprimer l'espace de noms créé précédemment.
Maintenant - Ă la mise en Ćuvre!
Personnalisation
Gitlab ci
Commençons par le fragment
.gitlab-ci.yaml
décrivant le déploiement de l'application et l'exécution des tests. La liste s'est avérée assez volumineuse, elle est donc complétée de maniÚre approfondie par des commentaires:
variables:
Kubernetes
Maintenant, dans le
.helm/templates
, créez un YAML avec Job -
tests-job.yaml
- pour exécuter les tests et les ressources Kubernetes dont il a besoin. Voir les explications aprÚs l'inscription:
{{- if eq .Values.global.run_tests "yes" }} --- apiVersion: v1 kind: ConfigMap metadata: name: tests-script data: tests.sh: | echo "======================" echo "${APP_NAME} TESTS" echo "======================" cd /app npm run test:ci cp report.xml /app/test_results/${CI_COMMIT_REF_SLUG}/ echo "" echo "" echo "" chown -R 999:999 /app/test_results/${CI_COMMIT_REF_SLUG} --- apiVersion: batch/v1 kind: Job metadata: name: {{ .Chart.Name }}-test annotations: "helm.sh/hook": post-install,post-upgrade "helm.sh/hook-weight": "2" "werf/watch-logs": "true" spec: activeDeadlineSeconds: {{ .Values.global.ci_timeout }} backoffLimit: 1 template: metadata: name: {{ .Chart.Name }}-test spec: containers: - name: test command: ['bash', '-c', '/app/tests.sh'] {{ tuple "application" . | include "werf_container_image" | indent 8 }} env: - name: env value: {{ .Values.global.env }} - name: CI_COMMIT_REF_SLUG value: {{ .Values.global.commit_ref_slug }} - name: APP_NAME value: {{ .Chart.Name }} {{ tuple "application" . | include "werf_container_env" | indent 8 }} volumeMounts: - mountPath: /app/test_results/ name: data - mountPath: /app/tests.sh name: tests-script subPath: tests.sh tolerations: - key: dedicated operator: Exists - key: node-role.kubernetes.io/master operator: Exists restartPolicy: OnFailure volumes: - name: data persistentVolumeClaim: claimName: {{ .Chart.Name }}-pvc - name: tests-script configMap: name: tests-script --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ .Chart.Name }}-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Mi storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }} volumeName: {{ .Values.global.commit_ref_slug }} --- apiVersion: v1 kind: PersistentVolume metadata: name: {{ .Values.global.commit_ref_slug }} spec: accessModes: - ReadWriteOnce capacity: storage: 10Mi local: path: /mnt/tests/ nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - kube-master persistentVolumeReclaimPolicy: Delete storageClassName: {{ .Chart.Name }}-{{ .Values.global.commit_ref_slug }} {{- end }}
Quelles ressources sont décrites dans cette configuration? Lors du déploiement, créez un espace de noms unique pour le projet (cela est également indiqué dans
.gitlab-ci.yaml
-
tests-${CI_COMMIT_REF_SLUG}
) et
tests-${CI_COMMIT_REF_SLUG}
:
- ConfigMap avec un script de test;
- Job avec une description de pod et la directive de
command
spécifiée, qui exécute simplement les tests; - PV et PVC , qui vous permet de stocker des données de test.
Faites attention Ă la condition d'introduction avec
if
au dĂ©but du manifeste - en consĂ©quence, les autres fichiers YAML du graphique Helm avec l'application doivent ĂȘtre enveloppĂ©s dans la construction
inverse afin qu'ils ne se déploient pas pendant les tests. Soit:
{{- if ne .Values.global.run_tests "yes" }} --- {{- end }}
Cependant, si les tests
nécessitent une certaine infrastructure (par exemple, Redis, RabbitMQ, Mongo, PostgreSQL ...) - leurs YAML peuvent
ĂȘtre dĂ©sactivĂ©s. DĂ©ployez-les dans un environnement de test ... bien sĂ»r, peaufiner comme vous le souhaitez.
Touche finale
Parce que jusqu'à présent, la compilation et le déploiement à l'aide de werf
ne fonctionnent que sur le serveur de build (avec gitlab-runner), et le pod avec les tests s'exécute sur l'assistant, vous devrez créer le répertoire
/mnt/tests
sur l'assistant et le donner au runner,
par exemple via NFS . Un exemple dĂ©taillĂ© avec des explications peut ĂȘtre trouvĂ© dans la
documentation du
K8s .
Le résultat sera:
user@kube-master:~$ cat /etc/exports | grep tests /mnt/tests IP_gitlab-builder/32(rw,nohide,insecure,no_subtree_check,sync,all_squash,anonuid=999,anongid=998) user@gitlab-runner:~$ cat /etc/fstab | grep tests IP_kube-master:/mnt/tests /mnt/tests nfs4 _netdev,auto 0 0
Personne n'interdit de faire une balle NFS directement sur le gitlab-runner, puis de la monter dans des pods.
Remarque
Vous pouvez vous demander, pourquoi tout compliquer avec la création de Job, si vous pouvez simplement exécuter le script de test directement sur le shell runner? La réponse est assez banale ...
Certains tests nécessitent un accÚs à l'infrastructure (MongoDB, RabbitMQ, PostgreSQL, etc.) pour vérifier l'exactitude du travail avec eux. Nous rendons les tests unifiés - avec cette approche, il devient facile d'inclure de telles entités supplémentaires. En plus de cela, nous obtenons une approche
standard dans le dĂ©ploiement (mĂȘme si vous utilisez NFS, montage de rĂ©pertoire supplĂ©mentaire).
Résultat
Que verrons-nous lorsque nous appliquerons la configuration préparée?
La demande de fusion affichera des statistiques récapitulatives sur les tests lancés dans son dernier pipeline:

Vous pouvez cliquer sur chaque erreur ici pour obtenir des détails:
NB : Un lecteur attentif remarquera que nous testons une application NodeJS, et dans les captures d'écran - .NET ... Ne soyez pas surpris: juste dans le cadre de la préparation de l'article, il n'y a pas eu d'erreurs lors du test de la premiÚre application, mais elles ont été trouvées dans une autre.Conclusion
Apparemment, rien de compliqué!
En principe, si vous avez déjà un shell-builder et que cela fonctionne, et que vous n'avez pas besoin de Kubernetes, le test de vissage sera une tùche encore plus simple que celle décrite ici. Et dans la
documentation de GitLab CI, vous trouverez des exemples pour Ruby, Go, Gradle, Maven et quelques autres.
PS
Lisez aussi dans notre blog: