Trots det faktum att alla mycket väl vet att det är viktigt och nödvändigt att testa din mjukvara, och många har gjort det automatiskt under lång tid, fanns det inte ett enda recept för att sätta upp en kombination av så populära produkter i Habr. denna nisch som (vår favorit) GitLab och JUnit . Låt oss fylla denna lucka!
inledande
Låt mig först ge lite sammanhang:
Eftersom alla våra applikationer körs på Kubernetes kommer vi att överväga att köra tester på lämplig infrastruktur.
För montering och driftsättning använder vi werf (när det gäller infrastrukturkomponenter betyder detta också automatiskt att Helm är inblandat).
Jag kommer inte att gå in på detaljerna för det faktiska skapandet av tester: i vårt fall skriver kunden testerna själv, och vi säkerställer bara att de lanseras (och närvaron av en motsvarande rapport i sammanslagningsbegäran).
Hur kommer den allmänna handlingsföljden att se ut?
Bygga applikationen - vi kommer att utelämna beskrivningen av detta steg.
Distribuera programmet till ett separat namnområde i Kubernetes-klustret och börja testa.
Söker efter artefakter och analyserar JUnit-rapporter med GitLab.
Ta bort ett tidigare skapat namnområde.
Nu - till genomförandet!
justering
GitLab CI
Låt oss börja med ett fragment .gitlab-ci.yaml, som beskriver driftsättning av programmet och körning av tester. Listan visade sig vara ganska omfattande, så den kompletterades grundligt med kommentarer:
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
Nu i katalogen .helm/templates låt oss skapa YAML med Job - tests-job.yaml — att köra tester och de Kubernetes-resurser som behövs. Se förklaringar efter listning:
Vilken typ av resurser beskrivs i den här konfigurationen? Vid implementering skapar vi ett unikt namnområde för projektet (detta anges i .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) och rulla ut den:
ConfigMap med testskript;
Jobb med en beskrivning av podden och det specificerade direktivet command, som bara kör testerna;
PV och PVC, som låter dig lagra testdata.
Var uppmärksam på det inledande villkoret med if i början av manifestet - följaktligen måste andra YAML-filer i Helm-diagrammet med applikationen vara inslagna i omvänd designa så att de inte distribueras under testning. Det är:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Men om testerna kräver viss infrastruktur (till exempel Redis, RabbitMQ, Mongo, PostgreSQL...) - deras YAML kan vara ingen Stäng av. Distribuera dem i en testmiljö också... justera dem som du tycker är lämpligt, förstås.
Slutlig touch
Därför att montering och driftsättning med werf fungerar för närvarande endast på byggservern (med gitlab-runner), och podden med tester startas på mastern, måste du skapa en katalog /mnt/tests på mästaren och ge den till löparen, till exempel via NFS. Ett detaljerat exempel med förklaringar finns i K8s dokumentation.
Ingen förbjuder att göra en NFS-share direkt på gitlab-runner och sedan montera den i pods.
Notera
Du kanske frågar varför komplicera allt genom att skapa ett jobb om du helt enkelt kan köra ett skript med tester direkt på skallöparen? Svaret är ganska trivialt...
Vissa tester kräver åtkomst till infrastrukturen (MongoDB, RabbitMQ, PostgreSQL, etc.) för att verifiera att de fungerar korrekt. Vi gör testning enhetlig - med detta tillvägagångssätt blir det lätt att inkludera sådana ytterligare enheter. Utöver detta får vi standard distributionsmetod (även om du använder NFS, ytterligare montering av kataloger).
Resultat
Vad kommer vi att se när vi tillämpar den förberedda konfigurationen?
Sammanslagningsbegäran kommer att visa sammanfattande statistik för tester som körs i dess senaste pipeline:
Varje fel kan klickas här för detaljer:
NB: Den uppmärksamma läsaren kommer att märka att vi testar en NodeJS-applikation, och i skärmdumparna - .NET... Bli inte förvånad: precis som en del av förberedelsen av artikeln hittades inga fel vid testning av den första applikationen, men de hittades i en annan.
Slutsats
Som du kan se, inget komplicerat!
I princip, om du redan har en skalsamlare och den fungerar, men du inte behöver Kubernetes, blir det en ännu enklare uppgift att koppla testning till den än vad som beskrivs här. Och i GitLab CI-dokumentation du hittar exempel för Ruby, Go, Gradle, Maven och några andra.