Παρά το γεγονός ότι όλοι γνωρίζουν πολύ καλά ότι η δοκιμή του λογισμικού σας είναι σημαντική και απαραίτητη, και πολλοί το κάνουν αυτόματα εδώ και πολύ καιρό, στην απεραντοσύνη του Habr δεν υπήρχε ούτε μία συνταγή για τη δημιουργία ενός συνδυασμού τέτοιων δημοφιλών προϊόντων στο αυτή η θέση ως (το αγαπημένο μας) GitLab και JUnit . Ας καλύψουμε αυτό το κενό!
εισαγωγικός
Αρχικά, επιτρέψτε μου να δώσω κάποιο πλαίσιο:
Δεδομένου ότι όλες οι εφαρμογές μας εκτελούνται στο Kubernetes, θα εξετάσουμε το ενδεχόμενο εκτέλεσης δοκιμών στην κατάλληλη υποδομή.
Για συναρμολόγηση και ανάπτυξη χρησιμοποιούμε werf (όσον αφορά τα στοιχεία υποδομής, αυτό σημαίνει αυτόματα ότι εμπλέκεται και η Helm).
Δεν θα υπεισέλθω στις λεπτομέρειες της πραγματικής δημιουργίας δοκιμών: στην περίπτωσή μας, ο πελάτης γράφει ο ίδιος τις δοκιμές και διασφαλίζουμε μόνο την εκκίνησή τους (και την παρουσία αντίστοιχης αναφοράς στο αίτημα συγχώνευσης).
Πώς θα μοιάζει η γενική ακολουθία των ενεργειών;
Κατασκευή της εφαρμογής - θα παραλείψουμε την περιγραφή αυτού του σταδίου.
Αναπτύξτε την εφαρμογή σε έναν ξεχωριστό χώρο ονομάτων του συμπλέγματος Kubernetes και ξεκινήστε τη δοκιμή.
Αναζήτηση τεχνουργημάτων και ανάλυση αναφορών JUnit με το GitLab.
Διαγραφή χώρου ονομάτων που δημιουργήθηκε προηγουμένως.
Τώρα - στην υλοποίηση!
προσαρμογή
GitLab CI
Ας ξεκινήσουμε με ένα απόσπασμα .gitlab-ci.yaml, το οποίο περιγράφει την ανάπτυξη της εφαρμογής και την εκτέλεση δοκιμών. Η λίστα αποδείχθηκε αρκετά ογκώδης, επομένως συμπληρώθηκε διεξοδικά με σχόλια:
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
Τώρα στον κατάλογο .helm/templates ας δημιουργήσουμε YAML με την εργασία - tests-job.yaml — για την εκτέλεση δοκιμών και των πόρων Kubernetes που χρειάζεται. Δείτε τις εξηγήσεις μετά την καταχώριση:
Τι είδους πόροι περιγράφεται σε αυτή τη διαμόρφωση; Κατά την ανάπτυξη, δημιουργούμε έναν μοναδικό χώρο ονομάτων για το έργο (αυτό υποδεικνύεται στο .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) και ξεδιπλώστε το:
ConfigMap με σενάριο δοκιμής?
Δουλειά με περιγραφή του pod και της καθορισμένης οδηγίας command, το οποίο απλώς εκτελεί τις δοκιμές.
Φ/Β και PVC, που σας επιτρέπουν να αποθηκεύετε δεδομένα δοκιμής.
Δώστε προσοχή στην εισαγωγική συνθήκη με if στην αρχή του δηλωτικού - κατά συνέπεια, άλλα αρχεία YAML του διαγράμματος Helm με την εφαρμογή πρέπει να είναι τυλιγμένα σε ΑΝΤΙΣΤΡΟΦΗ σχεδιάστε έτσι ώστε να μην αναπτύσσονται κατά τη διάρκεια της δοκιμής. Αυτό είναι:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
Ωστόσο, εάν οι δοκιμές απαιτούν κάποια υποδομή (για παράδειγμα, Redis, RabbitMQ, Mongo, PostgreSQL...) - τα YAML τους μπορούν να είναι όχι σβήνω. Αναπτύξτε τα και σε ένα δοκιμαστικό περιβάλλον... προσαρμόζοντάς τα όπως σας ταιριάζει, φυσικά.
Τελική αφή
Επειδή συναρμολόγηση και ανάπτυξη με χρήση εργασιών werf προς το παρόν μόνο στον διακομιστή κατασκευής (με το gitlab-runner) και το pod με δοκιμές εκκινείται στον κύριο, θα χρειαστεί να δημιουργήσετε έναν κατάλογο /mnt/tests στον κύριο και δώσε το στον δρομέα, για παράδειγμα, μέσω NFS. Ένα λεπτομερές παράδειγμα με επεξηγήσεις μπορείτε να βρείτε στο τεκμηρίωση K8s.
Κανείς δεν απαγορεύει να δημιουργήσετε ένα κοινόχρηστο στοιχείο NFS απευθείας στο gitlab-runner και στη συνέχεια να το τοποθετήσετε σε pods.
Σημείωση
Μπορεί να ρωτάτε γιατί να περιπλέκετε τα πάντα δημιουργώντας μια Εργασία, εάν μπορείτε απλώς να εκτελέσετε ένα σενάριο με δοκιμές απευθείας στο πρόγραμμα εκτέλεσης του κελύφους; Η απάντηση είναι πολύ ασήμαντη...
Ορισμένες δοκιμές απαιτούν πρόσβαση στην υποδομή (MongoDB, RabbitMQ, PostgreSQL, κ.λπ.) για να επαληθευτεί ότι λειτουργούν σωστά. Κάνουμε τις δοκιμές ενοποιημένες - με αυτήν την προσέγγιση, γίνεται εύκολο να συμπεριληφθούν τέτοιες πρόσθετες οντότητες. Εκτός από αυτό, παίρνουμε πρότυπο προσέγγιση ανάπτυξης (ακόμα και αν χρησιμοποιείτε NFS, πρόσθετη προσάρτηση καταλόγων).
Αποτέλεσμα
Τι θα δούμε όταν εφαρμόσουμε την προετοιμασμένη διαμόρφωση;
Το αίτημα συγχώνευσης θα εμφανίζει συνοπτικά στατιστικά στοιχεία για δοκιμές που εκτελούνται στην τελευταία του σειρά:
Κάθε σφάλμα μπορεί να γίνει κλικ εδώ για λεπτομέρειες:
NB: Ο προσεκτικός αναγνώστης θα παρατηρήσει ότι δοκιμάζουμε μια εφαρμογή NodeJS και στα στιγμιότυπα οθόνης - .NET... Μην εκπλαγείτε: απλώς κατά την προετοιμασία του άρθρου, δεν βρέθηκαν σφάλματα στη δοκιμή της πρώτης εφαρμογής, αλλά βρέθηκαν σε άλλο.
Συμπέρασμα
Όπως μπορείτε να δείτε, τίποτα περίπλοκο!
Κατ 'αρχήν, εάν έχετε ήδη έναν συλλέκτη κελύφους και λειτουργεί, αλλά δεν χρειάζεστε το Kubernetes, η προσάρτηση της δοκιμής σε αυτόν θα είναι ακόμη πιο απλή από ό,τι περιγράφεται εδώ. Και στο Τεκμηρίωση GitLab CI θα βρείτε παραδείγματα για Ruby, Go, Gradle, Maven και μερικά άλλα.