Автоматизация тестирования: «беспилотник» Acronis Kernel

648ee6b4bc144ea3b2c5ab7a095c2b73.jpg

(http://bp-la.ru/bespilotnyj-apparat-danem)


Билд => Тест => Не пройден => и километры логов, разбросанных по разным системам, и десятки минут сведения концов с концами в поисках причины сбоя. Знакомо?


А если иначе?


Билд => Тест => Не пройден => Тикет в JIRA — и разработчик берет баг в работу, потому как вся информация у него уже есть.


Работая в команде Acronis Kernel, я задался целью создать именно такой автотест.
Под катом — моя история.


Введение


Тестирование программного обеспечения — это исследование с целью снабдить заинтересованные стороны (Stakeholders, далее Заказчики) информацией о качестве продукта или услуги (из Википедии).
Заказчики воспринимают результаты тестирования по-разному:


  • Продукт менеджер смотрит, какие фичи продукта готовы к релизу, а какие придется упростить \ отложить \ выбросить.
  • Тест менеджера интересуют детали исследования: типы выполненных тестов, покрытие кода \ требований, затраченное время, детальные результаты, а также любые сбои \ ошибки \ сложности, которые могут негативно отразиться на объективности результата тестов.
  • Разработчику нужны дефекты: понятно описанные, воспроизводимые, включающие всю необходимую для фикса информацию.
  • Тестировщик получает задачу, выполняет тест, анализирует результат, репортит баги. По возможности, расширяет тестовое покрытие путем добавления новых тестов или тестовых окружений (сред).

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


  1. Тесты стартуют сразу по появлению новой сборки продукта;
  2. Время выполнения тестов определяется принятым в компании процессом разработки, но не должно превышать среднего времени между появлениями новой сборки;
  3. Обнаруженные ошибки автоматически анализируются, уже известные ошибки приписываются к существующим дефектам, остальные регистрируются в виде новых дефектов — в течение считанных минут после обнаружения;
  4. Результаты тестов отмечаются на «Карте качества продукта».

Здесь, в команде Acronis Kernel, мы построили такой процесс — не сразу, конечно.
Сперва расскажу, с чего мы начинали.


Prehistoric


13f18fa89d58429bab42cbbf90af0215.png

(http://spongebob.wikia.com/wiki/Primitive_Sponge)


Машинерия


  • [велосипед] Control Center (СС) — написанный на питоне планировщик задач, также хранит тест планы и рисует отчеты
  • [велосипед] AutoTest Management System (ATMS) — java-based менеджер виртуальных и физических ресурсов
  • [велосипед] Кастомный DSL для настройки тестового окружения
  • [велосипед] Кастомный Python unittest-based фреймворк для написания собственно тестов, с XML конфигами. Кое-где в конфиги была встроена логика теста
  • [велосипед] Кастомная версия TestLink — здесь, по идее, должны жить подробные описания тест кейсов и результаты их выполнения. По факту, использовался в основном для получения уникального ID сценария (группы тестов)
  • Виртуальные машины на ESX-i

Работало это все примерно так


  1. Появилась новая сборка.
  2. CC отмечал появление сборки, и, согласно хранящемуся в нем же плану тестирования, создавал новые задачи в Testlink.
  3. ATMS находил задачи в TestLink и запрашивал для них ресурсы у гипервизора. Очередей задач не было: кто успел захватить ресурс, тот и прав.
  4. Получив требуемый набор VM, ATMS настраивал в них Guest OS. Рецепт настройки задавался в виде кастомного DSL.
  5. Далее управление передавалось Python библиотеке, которая завершала конфигурирование окружения, деплоила билд и запускала тесты.
  6. По завершению тестов, АТМС собирал логи и результаты теста, обновлял статус задачи в TestLink.
  7. CC видел завершение задачи в TestLink, забирал результаты, обновлял свою базу статистики и отправлял письмом отчет о результатах тестирования. Позже Control Center взял на себя функции TestLink, и задачи стали создаваться в его внутренней базе, эмулирующей Testlink для клиента — ATMS.

Тесты шли несколько часов, часто давая случайный (невоспроизводимый) результат. Для анализа фейлов проходили целый квест с посещением ATMS, CC, шары с логами, детальным разбором логов и поиском аналогичных багов в Jira — все врукопашную.


Зарегистрированные сбои иногда воспроизводились, чаще — нет. По большинству заведенных багов разработчики просили уточнить шаги, предоставить виртуальную машину или приложить забытые логи.


Примерно раз в неделю ATMS падал. Если тест завис, или по другой причине ресурсы не освободились, приходилось вручную удалять виртуальные машины, снимать задачу в АТМС и обнулять счетчик занятости хоста.


Сравнить результаты тестов на разных сборках можно было по статичным email-репортам с графиком Тип результата / Номер сборки, или перебирая результаты вручную в СС. Чтобы сравнить результаты одного и того же теста на разных операционных системах, приходилось вручную просматривать логи тестов с каждой ОС.


В результате, девелоперы не доверяли автотестам, более полагаясь на ручной запуск собственных тестов на своем окружении. Подобная «механизация» меня никак не устраивала, ситуацию надо было исправлять.


Brave New World


b78bf1f397c7410da94adc6509eb3ed9.png

(http://dkrack.wikispaces.com/Brave+New+World)


В основу архитектуры новой системы автотестов легли:


  • Jenkins — планировщик задач, менеджер ресурсов, хранитель истории тестов и детальных результатов
  • Виртуальные машины на ESX-i
  • Python, Pytest — поиск тестов по тегам, параметризованный запуск, контроль исполнения и вывод результата в формате junit.xml (стандартный формат для Jenkins)
  • JIRA — результаты теста в виде багов, метрики успешности проекта

0 (ноль) велосипедов.


Путь задачи


  1. При успешной сборке билдсервер (тоже Jenkins) стартует проект на тестовом Jenkins, ставя тест в очередь.
  2. Тестовый Jenkins резервирует ресурсы (VM linked clone), выкачивает свежий код тестов из SVN, запускает CMD скрипт для настройки окружения и зовет pytest.
  3. Pytest с помощью встроенной функции test discovery подбирает кейсы и стартует тест. Код фреймворка выполняется на Gate VM — контрольной машине, а System Under Test (в нашем случае kernel driver) разворачивается на Test VM, чтобы в случае BSOD не потерять результаты.
    • Стандартная python logging библиотека пишет info лог и debug лог в два разных файла:
      a) Info лог содержит шаги теста и отвечает двум требованиям: 1) human readable формат, 2) информации достаточно для воспроизведения сбоя.
      b) Debug лог включает таймштамп, адрес \ номер строки выполняемого кода и развернутое сообщение. Лог позволяет отследить детальную историю событий, прямо не относящихся к сути теста, но влияющих на результат: удалось ли установить соединение, сколько времени выполнялся ребут, etc.
    • Тест останавливается при обнаружении первого же сбоя (результат assert = False). Pytest записывает результат + трейс в junit xml.
  4. Jenkins (JUnit Plugin) публикует отчет и стартует python скрипт по репорту багов.
  5. Скрипт ищет уже известные открытые баги в Jira, если находит — оставляет комментарий «Воспроизведено там-то», если нет — регистрирует новый баг. Сообщение об ошибке (pytest assert) идет в заголовок, шаги из Info лога — в описание, сами логи теста и драйверов аттачатся к багу.

Приведу схему для наглядности:


1ea336bf57884e55a744b767861bf8e6.png

(© Acronis)


Имя бага добавляется суффиксом к имени VM, так что девелоперы легко могут найти машину при необходимости. Машинка, на которой воспроизвелся уже известный баг, будет автоматически удалена через три дня. Машинка с новым багом будет автоматически удалена после того, как разработчик переведет ее в статус Resolved, а соответствующий тест пройдет без ошибок.


Пример автоматически заведенного бага


dff1eaf2e54c48799f5fc2079293cedd.png

(© Acronis)


Раньше автоматизатор вынужден был 80–90% времени тратить на ручной разбор результатов тестов. Теперь достаточно посмотреть на список багов в Jira. Баг продукта идет разработчикам, сбой тестов автоматизатор забирает себе. Если какой-то информации в баг репорте не хватает, не нужно учить людей заводить баги иначе — достаточно изменить код.


Пример общения разработчика с автоматическим баг репортером


ad359075a02f42e88fc722a4e6ba9502.png

(© Acronis)


Поддержка тестов свелась к обработке в коде еще неучтенных видов сбоев. Corner cases будут всегда, это надо понимать, и не стоит ставить целью избавление от 100% сбоев автотеста\тестовой инфраструктуры. Достаточно превратить эти сбои в конкретные action items — баги в Jira, в нашем случае, и исправлять их один за другим.


Карта качества продукта


Общий обзор состояния тестируемых компонент теперь можно получить, взглянув на Jenkins dashboard:


8cc1116605ce42c69163926abd0709f1.png

(© Acronis)


Дашборд реализован с помощью плагина https://wiki.jenkins-ci.org/display/JENKINS/Dashboard+View.


Возможно не все читатели знакомы с Jenkins, так что поясню значения колонок:


  • S (Status)  — результат последней сборки (в нашем случае теста);
  • Name — название теста;
  • W (Weather) — иконографика, показывающая историю качества сборки, на 5 сборок назад. Солнышко означает, что все 5 сборок успешны, грозовая туча — все 5 сборок плохи;
  • Build Parameters — в нашем случае указан путь, соответствующий ветке кода и содержащий номер сборки;
  • Last Duration — время выполнения последней сборки, начиная с момента постановки заказа в очередь, и до момента завершения сбора логов с последнего окружения и отправки отчета о результатах теста;
  • Build Description — в описание сборки автотест добавляет номера багов, автоматически заведенных в Jira, с указанием, новый ли это баг (new), или уже известный (upd);
  • Last Success, Last Failure — как давно была сделана последняя успешная / неуспешная сборка.

Результаты


Систему, которую я описал выше, мы построили и отладили к концу осени прошлого года, и затем активно добавляли новые сценарии для тестирования. С февраля 2016 года я перешел full time на другой проект.


За время моего отсутствия (полгода):


  • Найдено и заведено автоматически 129 корректных багов — примерно по одному новому багу каждый рабочий день.
  • Из других источников заведено 48 багов.

Проект полгода жил и развивался усилиями только разработчиков, без единого тестировщика. Разработчики самостоятельно добавили новый компонент, создав Jenkins проекты и Pyhton код по аналогии с существующими.


Некорректных багов за это время тоже заведено довольно много, в основном дубликатов, рожденных некорректным сетапом нового теста или отказами тестового сервера. Однако это уже тема для отдельной статьи.

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

© Habrahabr.ru