Для выполнения этой стадии необходимо подготовиться.

  1. Устанавливаем sonarqube на сервер. Как вы это сделаете - на ваше усмотрение, я предпочитаю везде по возможности использовать docker, поэтому просто выполняю команду docker run -d -p 9000:9000 sonarqube

  2. Авторизуемся в админке sonarqube и настраиваем токены, для этого прямо в админке есть подробная инструкция.

  1. Добавьте необходимые строки для работы проекта с sonarqube в файл build.gradle, после чего в gradle у нас появляются новые таски для sonarqube:

После подготовки добавляем новую стадию в наш пайплайн.

variables:
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
  GIT_DEPTH: "0"
stages:
  - feature
  - feature-artefact
  - feature-clean-stand
  - feature-install-stand
  - test
feature development:
  tags:
    - feature
  stage: feature
  image: gradle:7.5.0-jdk11
  script:
    - cd rest-service
    - ./gradlew assemble

feature docker image:
  tags:
    - feature
  stage: feature-artefact
  script:
    - cd rest-service
    - ./gradlew jibDockerBuild
      
feature clean stand:
  tags:
    - feature
  stage: feature-clean-stand
  allow_failure: true
  script:
    - cd rest-service/.chart
    - helm uninstall docker-compose-feature --namespace=yamangulov-feature
  
feature install stand:
  tags:
    - feature
  stage: feature-install-stand
  script:
    - cd rest-service/.chart/
    - helm install docker-compose-feature docker-compose --namespace=yamangulov-feature --values=docker-compose/values-yamangulov-feature.yaml

testing:
  stage: test
  image: gradle:7.5.0-jdk11
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - cd rest-service
    - gradle sonarqube -Dsonar.qualitygate.wait=true
  rules:
    - if: '$CI_BUILD_REF_NAME != "main" && $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'

Стадия тестирования разворачивает приложение в docker- контейнере и затем выполняет в gradle таску для проведения unit-тестов (конечно, нужно их написать в приложении) и прочие проверки. После выполнения стадии необходимо зайти в админку и просмотреть результаты проверок (sonarqube очень подробно распишет вам, где что не так), если нужно - доработать код для устранения недостатков и запустить пайплайн снова.

Стадии для smoke и регрессионного тестирования

Сами по себе настройки этих стадий в файле gitlab-ci.yml довольно просты, мы просто поднимаем приложение в контейнере и запускаем нужные таски gradle, которые сами и выполнят нужные тесты:

variables:
  SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
  GIT_DEPTH: "0"
stages:
  - feature
  - feature-artefact
  - feature-clean-stand
  - feature-install-stand
  - test
  - smoke
  - regress
feature development:
  tags:
    - feature
  stage: feature
  image: gradle:7.5.0-jdk11
  script:
    - cd rest-service
    - ./gradlew assemble

feature docker image:
  tags:
    - feature
  stage: feature-artefact
  script:
    - cd rest-service
    - ./gradlew jibDockerBuild
      
feature clean stand:
  tags:
    - feature
  stage: feature-clean-stand
  allow_failure: true
  script:
    - cd rest-service/.chart
    - helm uninstall docker-compose-feature --namespace=yamangulov-feature
  
feature install stand:
  tags:
    - feature
  stage: feature-install-stand
  script:
    - cd rest-service/.chart/
    - helm install docker-compose-feature docker-compose --namespace=yamangulov-feature --values=docker-compose/values-yamangulov-feature.yaml

testing:
  stage: test
  image: gradle:7.5.0-jdk11
  cache:
    key: "${CI_JOB_NAME}"
    paths:
      - .sonar/cache
  script:
    - cd rest-service
    - gradle sonarqube -Dsonar.qualitygate.wait=true
  rules:
    - if: '$CI_BUILD_REF_NAME != "main" && $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'

smoke testing:
  stage: smoke
  image: gradle:7.5.0-jdk11
  script:
    - cd rest-service
    - gradle clean integrationTest --tests "*smokeTest*"
  rules:
    - if: '$CI_BUILD_REF_NAME != "main" && $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'

regression testing:
  stage: regress
  image: gradle:7.5.0-jdk11
  script:
    - cd rest-service
    - gradle clean integrationTest --tests "*regressionTest*"
  rules:
    - if: '$CI_BUILD_REF_NAME != "main" && $CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "merge_request_event"'

Интерес здесь представляют только строки, которые запускают выборочно одну отдельно взятую таску gradle по ее названию и выполняют в ней только один выбранный по шаблону тест.. Сложность этих стадий не в их настройке, а в выполнении самих тестов. И здесь приходят на помощь testcontainers - очень полезная библиотека, которая позволяет поднимать специальные контейнеры для интеграционных тестов. Настройки для подключения библиотеки вы можете увидеть в образце файла build.gradle из предыдущей части этой статьи. Написание самих интеграционных тестов может иногда представлять некоторую сложность и зависит от функционала вашего приложения. Как вариант, приведу в качестве образчика, два класса, описывающие, как это делал я для моего приложения:

PostgresContainerWrapper и TestContainer

В основном можно считать, что для большинства приложений выполненных стадий для пайплайна gitlab ci/cd вполне достаточно, если приложения не предполагают достаточно высокой нагрузки. Если речь идет о высоконагруженном приложении, то без нагрузочных тестов уже не обойтись. Тогда необходимо добавить еще одну стадию для них. Поэтому я планирую через некоторое время дополнить статью четвертой завершающей частью, где и будет описываться мой опыт по выполнению нагрузочного тестирования и включения его в пайплайн.

В заключение приглашаю всех на бесплатный урок от моих коллег из OTUS, где в процессе занятия пройдёмся по метрикам и конечным точкам для работы с приложением. Ощутим мощь актуатора и даже напишем свой "индикатор здоровья". Регистрация на урок доступна по ссылке ниже.

Комментарии (0)