Trotz der Tatsaach, datt jidderee ganz gutt weess datt d'Tester vun Ärer Software wichteg an néideg ass, a vill hunn et automatesch fir eng laang Zäit gemaach, an der Wäisheet vun Habr gouf et keen eenzegt Rezept fir eng Kombinatioun vun esou populäre Produkter opzestellen. dës Nisch als (eise Liiblings) GitLab an JUnit. Loosst eis dës Lück ausfëllen!
Aféierung
Als éischt, loosst mech e puer Kontext ginn:
Well all eis Uwendungen op Kubernetes lafen, wäerte mir iwwerleeën Tester op déi entspriechend Infrastruktur ze lafen.
Fir Assemblée an Deployment benotze mir werf (wat d'Infrastrukturkomponenten ugeet, heescht dat och automatesch datt Helm involvéiert ass).
Ech wäert net an d'Detailer vun der aktueller Schafung vun Tester goen: an eisem Fall schreift de Client d'Tester selwer, a mir garantéieren nëmmen hir Start (an d'Präsenz vun engem entspriechende Bericht an der Fusiounsufro).
Wéi gesäit déi allgemeng Sequenz vun Aktiounen aus?
D'Applikatioun bauen - mir wäerten d'Beschreiwung vun dëser Etapp ausgoen.
Deploy d'Applikatioun op e separaten Nummraum vum Kubernetes Cluster a fänkt un ze testen.
Sich no Artefakte a parsing JUnit Berichter mat GitLab.
E virdrun erstallt Nummraum läschen.
Elo - zur Ëmsetzung!
Upassung
GitLab CI
Loosst eis mat engem Fragment ufänken .gitlab-ci.yaml, déi beschreift d'Deployment vun der Applikatioun an d'Lafen Tester. D'Oplëschtung huet sech als zimlech voluminös erausgestallt, sou datt et grëndlech mat Kommentaren ergänzt gouf:
variables:
# объявляем версию werf, которую собираемся использовать
WERF_VERSION: "1.0 beta"
.base_deploy: &base_deploy
script:
# создаем namespace в K8s, если его нет
- kubectl --context="${WERF_KUBE_CONTEXT}" get ns ${CI_ENVIRONMENT_SLUG} || kubectl create ns ${CI_ENVIRONMENT_SLUG}
# загружаем werf и деплоим — подробнее об этом см. в документации
# (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:-''}"
# передаем переменную `run_tests`
# она будет использоваться в рендере Helm-релиза
--set "global.run_tests=${RUN_TESTS:-no}"
--set "global.env=${CI_ENVIRONMENT_SLUG}"
# изменяем timeout (бывают долгие тесты) и передаем его в релиз
--set "global.ci_timeout=${CI_TIMEOUT:-900}"
--timeout ${CI_TIMEOUT:-900}
dependencies:
- Build
.test-base: &test-base
extends: .base_deploy
before_script:
# создаем директорию для будущего отчета, исходя из $CI_COMMIT_REF_SLUG
- mkdir /mnt/tests/${CI_COMMIT_REF_SLUG} || true
# вынужденный костыль, т.к. GitLab хочет получить артефакты в своем build-dir’е
- mkdir ./tests || true
- ln -s /mnt/tests/${CI_COMMIT_REF_SLUG} ./tests/${CI_COMMIT_REF_SLUG}
after_script:
# после окончания тестов удаляем релиз вместе с Job’ом
# (и, возможно, его инфраструктурой)
- 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
# мы разрешаем падения, но вы можете сделать иначе
allow_failure: true
variables:
RUN_TESTS: 'yes'
# задаем контекст в werf
# (https://werf.io/how_to/gitlab_ci_cd_integration.html#infrastructure)
WERF_KUBE_CONTEXT: 'admin@stage-cluster'
tags:
# используем раннер с тегом `werf-runner`
- werf-runner
artifacts:
# требуется собрать артефакт для того, чтобы его можно было увидеть
# в пайплайне и скачать — например, для более вдумчивого изучения
paths:
- ./tests/${CI_COMMIT_REF_SLUG}/*
# артефакты старше недели будут удалены
expire_in: 7 day
# важно: эти строки отвечают за парсинг отчета GitLab’ом
reports:
junit: ./tests/${CI_COMMIT_REF_SLUG}/report.xml
# для упрощения здесь показаны всего две стадии
# в реальности же у вас их будет больше — как минимум из-за деплоя
stages:
- build
- tests
build:
stage: build
script:
# сборка — снова по документации по werf
# (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
tags:
- werf-runner
except:
- schedules
run tests:
<<: *test-base
environment:
# "сама соль" именования namespace’а
# (https://docs.gitlab.com/ce/ci/variables/predefined_variables.html)
name: tests-${CI_COMMIT_REF_SLUG}
stage: tests
except:
- schedules
Kubernetes
Elo am Dossier .helm/templates loosst eis YAML mam Job erstellen - tests-job.yaml - Tester auszeféieren an d'Kubernetes Ressourcen déi et brauch. Kuckt Erklärungen no der Oplëschtung:
Wéi eng Ressourcen an dëser Configuratioun beschriwwen? Beim Ofbau kreéiere mir en eenzegaartegen Nummraum fir de Projet (dëst gëtt an .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) a rullt et aus:
ConfigMap mat Test Schrëft;
Aarbecht mat enger Beschreiwung vum Pod an der spezifizéierter Direktiv command, déi just d'Tester leeft;
PV an PVC, déi Iech erlaabt Testdaten ze späicheren.
Opgepasst op d'Aféierungskonditioun mat if um Ufank vum Manifest - deementspriechend mussen aner YAML Dateien vum Helm Chart mat der Applikatioun agewéckelt ginn ëmgedréint Design sou datt se net während dem Test ofgesat ginn. Dat ass:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Allerdéngs, wann d'Tester verlaangen puer Infrastruktur (zum Beispill Redis, RabbitMQ, Mongo, PostgreSQL ...) - hir YAMLs kënne sinn Net ausmaachen. Deploy se och an en Testëmfeld ... ajustéiert se wéi Dir passt, natierlech.
Finale Touch
Well Assemblée an Deployment mat werf Wierker fir de Moment nëmmen um Build Server (mat gitlab-runner), an de Pod mat Tester gëtt um Master gestart, musst Dir e Verzeechnes erstellen /mnt/tests op de Meeschter a gitt et dem Leefer, zum Beispill, iwwer NFS. En detailléiert Beispill mat Erklärungen fannt Dir an K8s Dokumentatioun.
Keen verbitt en NFS Deelen direkt op gitlab-runner ze maachen, an dann an Pods montéieren.
Remarque
Dir frot Iech vläicht firwat alles komplizéiert gëtt andeems Dir en Job erstellt, wann Dir einfach e Skript mat Tester direkt op de Shell Runner ausféiere kënnt? D'Äntwert ass ganz trivial ...
E puer Tester erfuerderen Zougang zu der Infrastruktur (MongoDB, RabbitMQ, PostgreSQL, etc.) fir z'iwwerpréiwen datt se richteg funktionnéieren. Mir maachen Testen vereenegt - mat dëser Approche gëtt et einfach sou zousätzlech Entitéiten ze enthalen. Zousätzlech zu dëser, mir kréien Standard Deployment Approche (och wann Dir NFS benotzt, zousätzlech Montage vun Verzeichnungen).
Resultat
Wat wäerte mir gesinn wa mir déi preparéiert Konfiguratioun uwenden?
D'Fusiounsufro weist Resuméstatistike fir Tester déi a senger leschter Pipeline lafen:
All Feeler kann hei geklickt ginn fir Detailer:
NB: Den opmierksamen Lieser mierkt datt mir eng NodeJS Applikatioun testen, an an de Screenshots - .NET ... Sidd net iwwerrascht: et ass just datt beim Virbereedung vum Artikel keng Feeler fonnt goufen beim Testen vun der éischter Applikatioun, awer si goufen an engem aneren fonnt.
Konklusioun
Wéi Dir gesitt, näischt komplizéiert!
Am Prinzip, wann Dir schonn e Shell Sammler hutt an et funktionnéiert, awer Dir braucht keng Kubernetes, d'Tester befestegt ass eng nach méi einfach Aufgab wéi hei beschriwwen. An an GitLab CI Dokumentatioun Dir fannt Beispiller fir Ruby, Go, Gradle, Maven an e puer anerer.