على الرغم من حقيقة أن الجميع يعلم جيدًا أن اختبار برنامجك أمر مهم وضروري، وأن الكثيرين يقومون بذلك تلقائيًا لفترة طويلة، إلا أنه في اتساع نطاق حبر لم تكن هناك وصفة واحدة لإعداد مجموعة من هذه المنتجات الشائعة في هذا المكان المخصص هو GitLab وJUnit (المفضل لدينا). دعونا ملء هذه الفجوة!
استهلالي
أولاً، اسمحوا لي أن أقدم بعض السياق:
نظرًا لأن جميع تطبيقاتنا تعمل على Kubernetes، فسنفكر في إجراء اختبارات على البنية التحتية المناسبة.
للتجميع والنشر نستخدم werf (فيما يتعلق بمكونات البنية التحتية، فهذا يعني تلقائيًا أيضًا أن شركة Helm متورطة).
لن أخوض في تفاصيل الإنشاء الفعلي للاختبارات: في حالتنا، يكتب العميل الاختبارات بنفسه، ونحن نضمن فقط إطلاقها (ووجود تقرير مطابق في طلب الدمج).
كيف سيبدو التسلسل العام للإجراءات؟
بناء التطبيق – سنغفل وصف هذه المرحلة.
انشر التطبيق على مساحة اسم منفصلة لمجموعة Kubernetes وابدأ الاختبار.
البحث عن القطع الأثرية وتحليل تقارير JUnit باستخدام 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 باستخدام Job - tests-job.yaml — لتشغيل الاختبارات وموارد Kubernetes التي يحتاجها. انظر التوضيحات بعد الإدراج:
أي نوع من الموارد الموصوفة في هذا التكوين؟ عند النشر، نقوم بإنشاء مساحة اسم فريدة للمشروع (يشار إلى ذلك في .gitlab-ci.yaml - tests-${CI_COMMIT_REF_SLUG}) وطرحها:
خريطة التكوين مع البرنامج النصي للاختبار.
وظيفة مع وصف الكبسولة والتوجيه المحدد command، الذي يقوم فقط بإجراء الاختبارات؛
الكهروضوئية والبلاستيكيةوالتي تسمح لك بتخزين بيانات الاختبار.
انتبه إلى الشرط التمهيدي مع if في بداية البيان - وفقًا لذلك، يجب تضمين ملفات YAML الأخرى الخاصة بمخطط Helm مع التطبيق يعكس التصميم بحيث لا يتم نشرها أثناء الاختبار. إنه:
{{- if ne .Values.global.run_tests "yes" }}
---
я другой ямлик
{{- end }}
ومع ذلك، إذا كانت الاختبارات تتطلب بعض البنية التحتية (على سبيل المثال، Redis وRabbitMQ وMongo وPostgreSQL...) - يمكن أن تكون YAMLs الخاصة بهم لا أطفأ. قم بنشرها في بيئة اختبار أيضًا... وقم بتعديلها كما تراه مناسبًا بالطبع.
اللمسة النهائية
لأن التجميع والنشر باستخدام werf يعمل في الوقت الحالي فقط على خادم البناء (باستخدام gitlab-runner)، ويتم تشغيل الكبسولة مع الاختبارات على الخادم الرئيسي، وسوف تحتاج إلى إنشاء دليل /mnt/tests على السيد واعطائها للعداء، على سبيل المثال، عبر NFS. يمكن العثور على مثال مفصل مع التوضيحات في وثائق K8.
لا أحد يمنع مشاركة NFS مباشرة على gitlab-runner، ثم تركيبها في القرون.
لاحظ
ربما تتساءل عن سبب تعقيد كل شيء عن طريق إنشاء وظيفة إذا كان بإمكانك ببساطة تشغيل برنامج نصي مع اختبارات مباشرة على مشغل الصدفة؟ الجواب تافه جدا..
تتطلب بعض الاختبارات الوصول إلى البنية التحتية (MongoDB، RabbitMQ، PostgreSQL، وما إلى ذلك) للتحقق من أنها تعمل بشكل صحيح. نحن نجعل الاختبار موحدًا - وبهذا النهج، يصبح من السهل تضمين مثل هذه الكيانات الإضافية. بالإضافة إلى هذا نحصل على معيار نهج النشر (حتى في حالة استخدام NFS، تركيب إضافي للدلائل).
نتيجة
ماذا سنرى عندما نطبق التكوين المعد؟
سيعرض طلب الدمج إحصائيات ملخصة للاختبارات التي يتم إجراؤها في أحدث مسار له:
يمكن النقر على كل خطأ هنا للحصول على التفاصيل:
NB: سيلاحظ القارئ اليقظ أننا نختبر تطبيق NodeJS، وفي لقطات الشاشة - .NET... لا تتفاجأ: كجزء من إعداد المقالة فقط، لم يتم العثور على أي أخطاء في اختبار التطبيق الأول، ولكن تم العثور عليهم في مكان آخر.
اختتام
كما ترون، لا شيء معقد!
من حيث المبدأ، إذا كان لديك بالفعل أداة تجميع الصدفة وهي تعمل، لكنك لا تحتاج إلى Kubernetes، فإن إرفاق الاختبار بها سيكون مهمة أبسط مما هو موضح هنا. و في وثائق GitLab CI ستجد أمثلة لـ Ruby وGo وGradle وMaven وبعض الآخرين.