Kuigi kĂ”ik teavad, et oma tarkvara testimine on oluline ja vajalik, ning paljud teevad seda automaatselt, ei leidunud Habras ĂŒhtegi retsepti, kuidas seadistada selliste populaarsete toodete nagu (meie lemmik) GitLab ja JUnit kombinatsiooni. TĂ€idame selle tĂŒhiku!

Sissejuhatus
Alustuseks mÀÀratlen konteksti:
- Kuna kÔik meie rakendused töötavad Kuberneteses, kÀsitleme testide kÀivitamist vastavas infrastruktuuris.
- Kogumise ja juurutamise jaoks kasutame (infrastruktuuri komponente arvestades tÀhendab see automaatselt, et on kaasatud ka Helm).
- Ei sĂŒvene testide loomise ĂŒksikasjadesse: meie puhul kirjutab klient testid ise ja me tagame vaid nende kĂ€ivitamise (ja vastava aruande olemasolu merge request'is).
Milline nĂ€eb vĂ€lja ĂŒldine tegevuste jĂ€rjekord?
- Rakenduse kogumine â selle etapi kirjeldust jĂ€tame vĂ€lja.
- Rakenduse juurutamine Kubernetes klastris eraldi namespace'i ja testimise kÀivitamine.
- Artefaktide otsimine ja JUnit aruande parsimine GitLabis.
- Varasemalt loodud namespace'i kustutamine.
NĂŒĂŒd â elluviimise juurde!
Seadistamine
GitLab CI-d
Alustame fragmentist .gitlab-ci.yaml, mis kirjeldab rakenduse juurutamist ja testide kĂ€ivitamist. Loetelu osutus ĂŒsna mahukaks ning on seetĂ”ttu pĂ”hjalikult tĂ€iendatud kommentaaridega:
muutujad:
# deklareerime werf versiooni, mida kavatseme kasutada
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
skript:
# loome namespace K8s, kui seda ei ole
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# laadime werfi ja deploime â rohkem selle kohta leiate dokumentatsioonist
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#deploy-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf deploy --stages-storage :local
--namespace ${CI_ENVIRONMENT_SLUG}
--set "global.commit_ref_slug=${CI_COMMIT_REF_SLUG:-''}"
# edastame muutujat `run_tests`
# seda kasutatakse Helm-release'i renderdamisel
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# muudame timeout'i (mÔnikord on testid pikad) ja edastame selle release'ile
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
sÔltuvused:
- Build
.test-base: &test-base
laiendab: .base_deploy
before_script:
# loome kausta tulevase raporti jaoks, lÀhtudes $CI_COMMIT_REF_SLUG'ist
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# sunnitud lahendus, kuna GitLab tahab saada artefakte oma build-dirâist
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# pÀrast testide lÔppu eemaldame release koos Job'iga
# (ja vÔimalikult ka selle infrastruktuuriga)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf dismiss --namespace ${CI_ENVIRONMENT_SLUG} --with-namespace
# lubame tÔrkeid, kuid saate teha teisiti
allow_failure: true
muutujad:
RUN_TESTS: 'yes'
# seadistame konteksti werf'is
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
sildid:
# kasutame runnerit sildiga `werf-runner`
- werf-runner
artefaktid:
# vajalik on koguda artefakt, et seda vÔiks nÀha
# pipeline'is ja alla laadida â nĂ€iteks pĂ”hjalikumaks uurimiseks
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# artefaktid, mis on vanemad kui nÀdal, kustutatakse
expire_in: 7 day
# oluline: need read vastutavad GitLabi raporti töötlemise eest
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# lihtsustamiseks on siin nÀidatud vaid kaks etappi
# tegelikult on teil neid rohkem â vĂ€hemalt deploimise tĂ”ttu
etapid:
- build
- tests
build:
etapp: build
skript:
# ehitamine â uuesti vastavalt werfi dokumentatsioonile
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#build-stage)
- type multiwerf && source <(multiwerf use ${WERF_VERSION})
- werf version
- type werf && source <(werf ci-env gitlab --tagging-strategy tag-or-branch --verbose)
- werf build-and-publish --stages-storage :local
sildid:
- werf-runner
vÀlja arvatud:
- schedules
kÀivita testid:
<<: *test-base
keskkond:
# "endiselt sool" namespace'i nimetamisel
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
etapp: tests
vÀlja arvatud:
- schedulesKubernetes
NĂŒĂŒd kaustas .helm/templates loome YAML Job'iga â tests-job.yaml â testide kĂ€ivitamiseks ja vajalikeks Kubernetes'i ressurssideks. Selgitused on loetletud jĂ€rgnevalt:
{{- if eq .Values.global.run_tests "yes" }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: tests-script
data:
tests.sh: |
echo "======================"
echo "${APP_NAME} TESTID"
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 }} Milliseid ressursse on selles konfiguratsioonis kirjeldatud? Deployimisel loome projekti jaoks ainulaadse nimi ({see on juba loetletud .gitlab-ci.yaml â tests-${CI_COMMIT_REF_SLUG}) ja viime selle sisse:
- ConfigMap testiskripti;
- Töö pod'i kirjeldust ja mÀÀratud direktiivi
kÀsk, mis kÀivitab testid; - PV ja PVC, mis vÔimaldavad testide andmete salvestamist.
Pange tĂ€hele tingimuslauset if manifesti alguses â vastavalt sellele peavad teised Helm chart'i YAML-failid olema mĂ€hitud vastandlikku struktuuri, et need ei deployitaks testimise ajal. See tĂ€hendab:
{{- if ne .Values.global.run_tests "yes" }}
---
siin on teine yaml
{{- end }}Siiski, kui testid nĂ”uavad mingit infrastruktuuri (nt Redis, RabbitMQ, Mongo, PostgreSQLâŠ) â nende YAML-id vĂ”ivad ei vĂ€lja lĂŒlitama. Laadige ja neid testimiskeskkonnas⊠muidugi kohandage vastavalt oma soovidele.
LÔppviimistlus
Kuna kogumine ja juurutamine werf'i abil töötab praegu seda build-serveris (gitlab-runner'i kaudu), samas kui pod testide jaoks kÀivitatakse masteris, tuleb luua kataloog /mnt/tests masteris ja anda see runner'ile, nÀiteks NFS kaudu. Lahtise nÀitena koos selgitustega leiate .
Tulemuseks saab olema:
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 0Keegi ei keela teha NFS-shaari otse gitlab-runneris ja seejÀrel mountida see pod'idena.
MĂ€rkus
VĂ”ib-olla kĂŒsite, miks ĂŒldse keeruliseks teha Job'i loomisega, kui saab lihtsalt kĂ€ivitada skripti testide jaoks otse shell-runneris? Vastus on piisavalt triviaalneâŠ
MĂ”ned testid vajavad infrastruktuuri (MongoDB, RabbitMQ, PostgreSQL jne) poole pöördumist, et kontrollida nendega töötamise Ă”iguspĂ€rasust. Teeme testimise ĂŒhtseks â sellise lĂ€henemisega on sarnaste lisasĂŒsteemide kaasamine lihtne. Lisaks saame tavaline juurde lĂ€henemise juurutamisel (isegi kui kasutatakse NFS'i ning lisakatkeste monteerimist).
Tulemus
Mida me nÀeme, kui rakendame ettevalmistatud konfiguratsiooni?
Merge request'is kuvatakse kokkuvÔtlik statistika testide kohta, mis kÀivitati selle viimases torustikus:

Iga vea peal saab klikida, et saada rohkem detaile:

NB: Hoolikas lugeja mĂ€rkab, et testime NodeJS rakendust, samal ajal kui ekraanipiltidel on .NET... Ăra ĂŒllatu, et lihtsalt artikli ettevalmistamisel ei olnud esimeses rakenduses vigu, kuid leidsime need teisest.
KokkuvÔte
Nagu nÀha, pole midagi keerulist!
PĂ”himĂ”tteliselt, kui teil on juba shell-kogum ja see töötab, ning Kubernetes pole vajalik â testimise lisamine sellele on veelgi lihtsam ĂŒlesanne, kui siin kirjeldatud. Ja leiate Ruby, Go, Gradle, Maven ja teiste jaoks nĂ€iteid.
P.S.
Lugege ka meie blogist:
- «»;
- «»;
- «».
Allikas: habr.com
