Newman и Continuous Integration на примере Atlassian Bamboo. Изобретение велосипеда



    Введение


    В недавней статье наш боевой товарищ actopolus рассказал о том, как мы научились применять Postman для реализации функционального тестирования нашего API проекта. Научившись писать функциональные тесты, и написав их порядка полутора сотен, мы решили, что настало то самое время — время прикрутить эти тесты к нашим CI-сборочкам.


    Вообще, изначально процесс интеграции Postman-тестов в сборки можно было разбить на 3 простых этапа:


    1. Формирование production-ready коллекции тестов для Postman
    2. Подготовка docker-образа среды для запуска тестов
    3. Написание тасков для того, чтобы собрать всё воедино и запускать на агентах

    Однако, нами не был учтён один очень важный нюанс — у нас не было инструмента для измерения покрытия нашего кода Postman-тестами. Без информации о том, насколько хорошо мы покрываем тестами код, нам было сложно понять где мы находимся сейчас и к чему нам нужно стремиться. Следовательно, план был дополнен ещё одним пунктом:


    1. Написание тасков для того, чтобы собрать всё воедино и запускать на агентах.


    1. Коллекция тестов


    Итак, приступим к самому процессу. С первым пунктом наша команда справилась героически быстро, тем более, что production-ready версия не так уж сильно отличалась от dev, в том смысле, что качество тестов, которое мы писали в Postman для «пробы пера» оказалось достаточно высоким. О том, как правильно писать Postman-тесты и что к чему, уже рассказывал actopolus в своей статье Введение в Postman. Каким же образом запустить Postman из консоли? Ответ прост — никак. Но, к счастью, есть специальная консольная утилита, которая умеет почти всё тоже самое, что и Postman, и имя ей… Newman!
    Именно благодаря Newman мы и будем проводить интеграцию Postman-тестов в CI.

    2. Docker


    Тем временем я принялся за докер образ. Сначала был собран собственный образ на базе alpine, на котором были проведены первичные запуски. После чего я обнаружил, что в недрах докер-хаба таки есть уже готовый образ с Newman, собранный на все том же alpine, но более легковесный. Казалось, задача свелась лишь к тому, чтобы слить уже существующий образ с докер-хаба в наш локальный хаб, однако, выяснилось, что он не подходит нам в чистом виде из-за несоответствия стандартам, принятым внутри компании. Поэтому пришлось всё же собрать свой образ. Для этого прежде всего мы сменили базовый образ на наш alpine который используется у нас во всех образах подобного рода. Следующим шагом мы выпилили все неиспользуемые компоненты и сменили точку входа таким образом, чтобы нам было достаточно передать образу только параметры для newman, не передавая всю строку запуска. Именно так и получился образ, который нас устроил по всем параметрам и попал в наш докер-хаб.

    3. Кочергатор для измерения покрытия


    После неудачных попыток родить ежа прикрутить к newman-тестам библиотеку c3 от codeception, я решил, что пожалуй быстрее будет изобрести велосипед написать свою библиотеку для сбора покрытия тестов newman (согласен, звучит очень по-профански).


    Почему я решил изобрести велосипед:


    1. Простота использования. Если вам необходимо родить пару ежей против шерсти для того, чтобы подключить измерение покрытия кода тестами в вашем приложении, вероятнее всего с реализацией что-то не так. Наша библиотека подключается 1ой строкой.
    2. Так как у нас не один, а множество проектов, мы можем учесть все их особенности в библиотеке, что в последствие позволит легко её использовать.
    3. Мы сами гарантируем поддержку работоспособности библиотеки. Она не исчезнет никуда через полгода и мы всегда сможем перенести её на новую версию php.

    «Чего тянуть кота за яйца?» — подумал я и решил начать писать кочергатор для измерения покрытия, тем более, что большая часть работы (пожалуй все 90%) для такой цели уже реализована в библиотеке php-code-coverage, использующей в своей основе xDebug. Осталось лишь немного переложить её на свой лад.


    Итак, наш кочергатор будет состоять из 2х частей. Первая будет отвечать за сбор и подготовку отчетов о запущенных во время прохождения теста файлах и строках, вторая будет представлять из себя CLI-приложение, которое будет собирать все отчеты воедино и форматировать в указанный формат.



    Как это работает в библиотеке SebastianBerghmann?


    По сути, php-codecoverage это надстройка над парой драйверов на выбор (phpdbg, xDebug). Суть проста, вы инициализируете скрипт на сбор информации о выполняемых (и не выполняемых) строках, и на выходе получаете массив с этими данными. Библиотека php-codecoverage создана для того, чтобы из этих массивов делать сексуальные отчеты в форматах xml, html, json и text. Она также разделена на 2 части, и также одна часть занимается сбором информации, а вторая форматированием.



    Что делает наш велосипед?


    • Подключается одной строкой
      $coverage = new Coverage();
    • Имеет дефолтную конфигурацию
    • Начинает слушать тогда и только тогда, когда встречает в заголовке запроса определенный флаг.
    • Складывает все отчеты туда, куда мы ему скажем.
    • CLI — умеет не только собирать отчеты, но и чистить за собой.

    Для того, чтобы всё это богатство заработало, нам пришлось добавить в наши тесты заголовок-маркер.

    Выглядеть это стало вот так:




    «Скомпилированные» отчёты позволяют посмотреть в каком тесте запускаются те или иные строки кода и выглядят следующим образом:


    Так выглядит экран с покрытием кода




    Так выглядит покрытие кода по папкам

    Отчёты генерируются утилитой, которая входит в состав пакета php-code-coverage.
    Если уважаемому читателю будет интересно, то мы расскажем про то, как работает этот кочергатор в отдельной небольшой статье.

    Итак с пунктом 3 мы тоже разобрались. Остался не менее интересный пункт… 4ый

    Пункт 4ый, драматический


    Для того чтобы реализовать нормальное функциональное тестирование проекта и оценку покрытия давайте посмотрим на схему того, как же оно все-таки работает.



    1. Итак, сначала кодовая база сливается из GIT-репозитория на агент BAMBOO и далее на нем происходит сборка проекта.


    В нашем случае собирается composer и происходит обработка файлов конфигурации под Development окружение. Именно на этом этапе мы подменяем в наших тестах значение заголовка PHPNEMWMAN_OFF на PHPNEWMAN_ON (это потому, что билд-план призван замерять покрытие, однако не стоит это делать в билд-плане, который своей целью ставит именно сборку проекта, т.к. измерение покрытия значительно замедляет процесс сборки).


    sed -i -e "s/Phpnewman-Off/Phpnewman-On/" ./code/newman/collection.json

    2. Следующим шагом собранный проект выливается в хранилище артефактов. Делается это для того, чтобы не собирать его каждый раз, для каждого отдельного таска.


    3. После того как собранный проект благополучно слит в артефактори, следующий таск также благополучно его оттуда сливает и выгружает на тестовый бэкенд.


    4. Следующий таск также сливает проект из артефактори и запускает на нем newman-тесты. Нужно сразу отметить, что ходить эти тесты будут не на localhost bamboo-агента, а на тестовый бэкенд, куда мы вылили проект шагом ранее. Тесты запускаются в докер-контейнере.


    Запустить тесты в докер-контейнере можно достаточно просто:

    
    docker pull docker-hub-utils.kolesa:5000/build/nodejs/newman:latest
    #Скачиваем образ из репозитория
    
    docker run \ #запускаем контейнер
    --rm \ #удаляем контейнер сразу после остановки
    --volume $(pwd):/code \ #монтируем корень агента в папку /code в контейнере
    --volume /etc/passwd:/etc/passwd:ro \ #монтируем passwd
    --volume /etc/group:/etc/group:ro  \#монтируем group
    --user $(id -u):$(id -g) \ #устанавливаем пользователя и группу, от имени которой действуем в контейнере
    --interactive \ #режим запуска - интерактивный
    docker-hub-utils.kolesa-team.org:5000/build/nodejs/newman:latest \
        run collection.json --folder Tests -r junit,html --reporter-junit-export _out/newman-report.xml --reporter-html-export _out/newman-report.html -e _envs/qa.json -x

    Строку запуска newman разберем отдельно:

    
    run collection.json #Запустить тесты из файла collection.json
     --folder Tests #Директория в json-объекте(collection.json) где лежат тесты
     -r junit,html #Отчеты о прохождении (не покрытие!) тестов готовим в 2х форматах
     --reporter-junit-export _out/newman-report.xml #указываем явно, куда сложить отчет
     --reporter-html-export _out/newman-report.html #указываем явно, куда сложить отчет
     -e _envs/qa.json  #указываем json с переменными окружения
     -x #возвращать exit-code основываясь на результате прохождения тестов
    

    После этих манипуляций на нашем тестовом бэкенде сформируется коллекция COV-отчётов, совпадающая численно с количеством запросов к бэкенду.

    Осталось всего-ничего собрать все эти cov-отчеты в один большой жирный отчет.
    Для простоты понимания в скрипте ниже будем использовать `SCP`.

    Итак, сбор отчетов происходит следующим образом:

    
    BRANCH_NAME=$(echo "${bamboo.currentBranch}" | sed 's|/|-|g' | sed 's@\(.*\)@\L\1@') 
    #кладём имя ветки из бамбу в переменную окружения
    
    echo "BRANCH NAME IS $BRANCH_NAME" 
    #пишем имя ветки в логи
    
    ssh www-data@testing.backend.dev "php /srv/www/$BRANCH_NAME/vendor/wallend/newman-php-coverager/phpnewman --collect-reports merge /srv/www/$BRANCH_NAME/phpnewman --clover /srv/www/$BRANCH_NAME/newman/_output/clover.xml --html /srv/www/$BRANCH_NAME/newman/_output/html"
    #запускаем сборку отчётов на удалённом бэкенде
    
    scp www-data@testing.backend.dev:/srv/www/$BRANCH_NAME/newman/_output/clover.xml ./clover.xml
    scp -r www-data@testing.backend.dev:/srv/www/$BRANCH_NAME/newman/_output/html ./
    # сливаем готовые отчёты на агент
    
    ssh www-data@testing.backend.dev "rm -r /srv/www/$BRANCH_NAME/newman/_output/html && rm /srv/www/$BRANCH_NAME/phpnewman/* && rm /srv/www/$BRANCH_NAME/newman/_output/clover.xml"
    #чистим за собой на бэкенде
    

    Для того, чтобы в сборке были доступны ваши отчёты, необходимо расшарить артефакты с этими отчётами:



    далее мы можем использовать эти артефакты для автоматического парсинга и дальнейшей визуализации покрытия кода в нашей сборочке. Для этого достаточно поставить галочку и указать файл с xml-отчётом покрытия.



    На выходе получаем вот такую красоту (В данном случае аналогичные операции проделаны для отчетов UNIT-тестов).

    Важно!


    В нашем проекте я разделил на 2 разных билд-плана тесты без измерения покрытия и тесты с включенным измерением покрытия. Покрытие измеряется только для мастер-ветки. Запускается билд-план с измерением покрытия каждый день по расписанию. Всё это сделано по причине того, что тесты с включенным покрытием проходят значительно дольше!

    Заключение


    Подводя итог проделанной работы, хочу отметить лишь несколько фактов.


    Факт первый. Нет ничего сложного в том чтобы прикрутить к Continuous Intgration новый, понравившийся вам инструмент. Было бы желание.


    Факт второй. Если чего-то в инструменте нет из коробки, то совсем не обязательно, что доработать это самому окажется сложным и муторным занятием. Иногда, если разобраться, то всё решается в пару-тройку десятков строк кода. Добавьте сюда огромный профит от использования инструмента, когда всё заработает. Ну и плюс ко всему это ещё один повод прокачать свои навыки.


    Факт третий. Никто не утверждает что newman это панацея от всех бед, и что он лучший в качестве инструмента функционального тестирования. Однако, мы попробовали — и нам понравилось, особенно после того как он был прикручен к CI!


    Ну и, конечно же, мы будем рады, если наша библиотека принесет вам пользу. А если у вас возникнет необходимость ее доработать – feel free to contribute!

    «Колёса Крыша Маркет»
    71.86
    Компания
    Share post

    Comments 14

      +3
      Интересно, жду следующую отдельную статью про кочергатор.
        0
        Спасибо, интересно. Где же все же почитать поподробней (не в документации, а на примерах) как через bamboo делать, например, все для тестирования и деплоя RoR-приложения? Слишком запутанный интерфейс, чтобы разобраться на интуиции.
          0
          К сожалению, не могу подсказать какой-то специализированной литературы по Atlassian Bamboo, помимо официальной документации (тут).
          В общих чертах суть достаточно проста: «Bamboo позволяет переложить все те таски, которые вы выполняете вручную, на шаблон автоматизации».
          Для начала следует разбить все действия которые вы совершаете для ручной сборки, тестирования и деплоя на отдельные таски, и сгруппировать их по назначению. Далее, совместно с документацией, можно уже поработать над их реализацией. Всё не так сложно, как кажется на первый взгляд.
            0
            Я вот не понимаю, вот есть например выделенный сервер с Bamboo и вот такой плагин github.com/drscream/bamboozled-ruby-plugin — предполагается, что таски будут выполнятся на том же сервере, где установлен Bamboo или все же как-то можно выполнить все через этот плагин на удаленном сервере и получить результат? Просто цена сервера с одним удаленным агентом уже ого-го-го — $880…
              0

              Мы немного отдаляемся от темы публикации, но в вашем случае всё зависит именно от типа подписки Bamboo. Запускать таски на удаленных агентах при локальной подписке, увы, не получится.

                0
                Извиняюсь, что отклоняюсь, но мало пишут про Bambo. В общем-то, я думаю, что и при локальной подписке можно решать все задачи по деплою и тестам используя SSH таски и SCP для загрузки нового кода, тестирования и получения отчета можно наверное сделать отдельные Job для парсинга результатов тестов. Либо, как вариант, на development сервере развернуть отдельно bamboo и стек приложения и запускать таски локально.
                  0
                  В статье есть яркий пример с использование докера, можно посмотреть в его сторону, если вопрос в наличии софта на локальной машине. Если же вопрос в разделении задач по хостам, смысл тащить файлы для деплоя с локального агента на другой хост, чтобы оттуда все равно вылить на финальный хост.
                    0
                    Смысл тащить код на удаленные серверы есть когда development-серверов несколько, а bamboo один и он привязан к JIRA, Confluence, Bitbucket и HipChat.
                      0
                      Возможно мы друг друга недопонимаем, но никто не мешает с локального агента выливать хоть на сто хостов. Не вижу принципиальной разницы между локальным и удаленным агентом. Причем лить можно как напрямую (scp), так и через «голден-севрер» с которым просто синхранизируются dev-сервера.
                0

                На примерах не покажу, но мне кажется, что если пробить сетевой доступ между сервером Bamboo и удаленным, никто не мешает локальному агенту ходить по ssh и что-то там делать

                  0
                  Но локальный агент в этот момент всё равно будет занят, а так-то конечно, никто не мешает ходить по ssh на другой хост, а оттуда на другой, а оттуда еще на другой… вот только зачем? Если вопрос в том, что не хочется весь необходимый софт держать на машине с bamboo, тогда уж не проще ли делать что-либо в докер контейнере, который можно запускать локально или вынести вообще в swarm или kubernetes?
            +1
            А велосипед в гитхабе будет?
              0
              Наверняка будет!
              +1
              Крутяк

              Only users with full accounts can post comments. Log in, please.