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

Итак, что имеем:

  1. Десятки Embedded устройств в которых нужно проводить тестирование новой версии FirmWare (если быть точнее — ежедневная сборка прошивки)
  2. В виду особенностей процедуры загрузки FW может потребоваться необходимость сбросить питание (т.н. режим загрузки прошивки в режиме Power On Capture)
  3. Хотелось бы в некоторые конкретные моменты времени по ходу выполнения тестового скрипта имитировать нажатия на механические кнопки размещенные на отладочной плате Embededed системы

Зачем может быть нужен пункт 3? В моем случае задача следующая — в случае возникновения критического Exception выполнения кода система «встает» в полумертвое состояние из которого она не выйдет пока ей не сбросят питание (еще одна причина для управления питанием). Но самое интересное в том что если в таком режиме нажать специально предназначенную для этого механическую кнопку — в последовательный порт будет выдан т.н. Exception лог — отладочная информация по которой можно будет попробовать понять в каком месте по коду произошло исключение.

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

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

Анализ схемы отладочной платы показал что кнопка просто замыкает GPIO линию подтянутую к +3.3 В на GND. Значит если «подпаяться» к кнопке и с помощью реле замыкать GPIO линию на землю — то будет то что нужно.

Далее встал вопрос выбора устройства / модуля для управления к которому выдвигались следующие требования:

  • Максимальное число реле (нужно по 2 шт на каждое устройство, а устройств десятки)
  • Доступ по Ethernet
  • Управление URL командами
  • Возможность копировать и масштабировать систему

По традиции остановились на модуле Etherent реле Laurent-128:



Модуль по всем параметрам нас послностью устроил: можно управлять сразу 14-тью устройствами (одно реле на питание, другое на нажатие кнопки) с помощью URL команд (очень удобно для скрптовых языков на которых написана автоматизация тестирования).

Схема подключения и связи отладочной платы тестируемого устройства и модуля управления показана на рисунке ниже:



«Подпайка» к контактам механической кнопки на примере одного из тестируемых устройств выглядит так:



Ура! Мехническая часть сделана. Осталось дело за малым — дописать код тестовых процедур так что бы в случае необходимости (загрузка образа прошивки после сброса питания или запись отладки по нажатию кнопки) подать команду на включение / выключение нужного реле.

Синтаксис URL команд управления простой и очевидный. Например, для того чтобы включить реле под номер 4 нужно использовать следующий HTTP адреc:

http://192.168.0.101/cmd.cgi?psw=Laurent&cmd=REL,4,1

А вот и простая функция на Perl которая вызывается из главной тестовой процедуры если нужно «дернуть» реле:

#---------------------------------------------------------------#
# FUNCTION:: click rele
# PARAM1: Laurent IP adress
# PARAM2: RELE ID
# PARAM3: 0 / 1  - what to do with rele
#---------------------------------------------------------------#
sub func_click_pwr_rele {
  my ( $_IN_IP, $_IN_RELE, $_IN_VALUE ) = @_;
  my $url;

  $url = "http://".$_IN_IP."/cmd.cgi?cmd=REL,".$_IN_RELE.",".$_IN_VALUE; 
  
  my $content = get $url;
  if( defined $content ) {
  }
  else {
    func_put_reslog( "ERROR! Can't manage RELE at adress $url", "BAD" );    
  }
}

Отмечу что система работает очень надежно без сбоев и зависаний. Laurent-128 и ранее использовавшиеся Laurent-112 (на 12 реле) отработали по паре лет без сбоев и остановок с учетом ежедневной работы.

А вот и пример такого Exception который был выявлен в ходе выполнения тестов с внеочередной ежедневной сборкой прошивки. После того как тестовому скрипту стало ясно что по последовательному порту от устройства ответа нет (т.е. оно «померло») была предпринята попытка нажатия аварийной механической кнопки для записи отладки и это сработало — итоговый тестовый отчет формируемый самим тестовым скриптом наполнился полезной информацией от месте возможного падения системы для последующего анализа командой разработчиков:

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


  1. iig
    26.11.2019 15:05
    +1

    Чтобы не припаивать провод прямо на кнопку, можно развести пятаки под диагностический разъем.


  1. lingvo
    26.11.2019 16:32

    То, чего все больше всего боялись — свершилось. Continuous Integration добралась до FW.
    Все таки ежедневные сборки прошивки — это пока еще дичайшая дичь. Чтобы полностью проверить прошивку, надо бы тестовый стенд по сложности в 2 раза сложнее, чем подопытное устройство.


    1. iig
      26.11.2019 19:12

      Чтобы полностью проверить прошивку, надо бы тестовый стенд по сложности в 2 раза сложнее, чем подопытное устройство.


      Ок. А разве CI на стенде запрещает обычную человеческую проверку?
      И даже стенд из ардуины помогает найти некоторые косяки.


    1. OloloFine
      26.11.2019 20:13

      Ну чего всего в два раза то? У нас например в стенде на пяток устройств — кнопки жимкают 16-канальные i2c PWM контроллеры, питаловом управляют они-же и USB хабы поддерживающие управление питанием портов, 7-ми-сегментники и светодиоды трекаются видеокамерой и все это счастье обмазано JS-фреймворком на промисах, разруливающий свистопляску номеров TTYUSB_N по USB-топологии, выставляющим примитивы похожие на selenium — waitForUARTtext, waitForPixel, powerCycle, buttonPress… Cбоку CI конвеер собирает из С кода + React-вебморды, после вебпака гзипуемого и транслируемого в C-литералы. Все это крееепко сложнее ESP8266+PIC прибора который тестируется.

      P.S. есть идеи выложить фремворк в паблик, но как-то не заморачивался думая что мало кто в эмбеде по CI упарывается


      1. KF-121
        27.11.2019 13:33

        Вообще тоже интресно посмотреть технологию и фреймворк. Сами нечто похожее делаем, только на базе Миландра


        1. OloloFine
          27.11.2019 19:03

          ок, начну чуть издалека, сорри за фуражку Капитана Очевидности во многих моментах, имхо на них стоит сделать акцент.

          «Железячные тестовые стенды» и тестируемые приборы, в отличии от «тестирования кодом кода», часто не совсем детерминированные — взаимные наводки, плохие контакты, помехи, коты и всякое такое, поэтому:

          — принцип KISS на первом плане — чем меньше мы навесим тестовой обвязки — тем лучше, стараемся максимально снять инфы по визуальному каналу (вебкамера смотрит на экран тестируемых приборов и их светодиоды), там где можно тестировать демоборды или что-то с питанием от USB — берем USB хаб управляющий питанием по каждому порту (например Dlink H7 в сером корпусе) — $20 за 7 каналов управления питанием и проброса UART-или-что-там-на-борде в систему

          — никаких плат разложенных по столам/полкам стендов — во первых коты, во вторых маппинг экранов/светодиодов в пиксели видеокамеры будет слетать. Например, собираем тестовые «лотки» из корпусов от старых CD приводов, и вставляем их в старый ATX корпус, где напротив них стационарно висит вебкамера (см фото). На веб-камеру стоит нацепить полярик, и не особо совать все это под солнечный свет (цвета пикселей будут уходить)

          — только качественные и короткие USB провода

          Фото
          image
          image


          1. KF-121
            28.11.2019 10:00

            Спасибо, за детальный ответ. его можно и расписать в виде отдельной статьи.


            1. OloloFine
              28.11.2019 18:01

              Увы, статьей аккаунт не позволяет. По свободе заделаю git-репозиторий с кодом и примером «как помигать светодиодом» под автотестами.


    1. alexac
      26.11.2019 22:29

      Ну уж скажите, дичь. Давайте я расскажу вам, как это все живет у нас.

      Для начала масштаб проблемы. У нас пяток классов устройств, у каждого — своя система. Одновременно для каждой системы ведется разработка над текущим релизом, следующим мажорным релизом и опционально следующим мажорным релизом + 1. Помимо этого есть минорные релизы, над котороыми работа может начаться одновременно с мажорным. Плюс специальные ветки для бета-версий, фиксов безопасности и отдельные ветки для фабрик, чтобы не показывать им весь софт до релиза. Это все дает примерно с десяток активных каналов разработки для каждого класса устройств. Примерно каждый год выходит несколько новых моделей почти во всех классах, поддержка старых осуществляется в течение нескольких лет. Это дает до нескольких десятков поддерживаемых моделей устройств на класс. У каждой системы есть несколько вариантов, для пользователей, для фабричного тестирования, для разработчиков, etc. Итого мы ежедневно получаем примерно 30-50 сборок систем в день и примерно 100 моделей устройств, на которых нужно проверить, что интересующие нас варианты систем хотя бы базово работают. Сейчас у нас больше 250 устройств, которые висят подключенными на почти трех десятках серверов и работают в CI. Осложняется дело необходимым на все это временем. Сборка всех изменений за сутки занимает примерно 6-8 часов, сборка всего — 13 часов. Еще 2-4 часа на то, чтобы смастерить образы системы для всех вариантов и для всех устройств. Отдельная история про построение OTA патчей и загрузку всего этого дела в архив, это идет в фоне и может занимать до суток. erase-install на одно устройство занимает примерно полчаса. Минимальный набор тестов еще минут 15.

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

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

      Ну и да, мы единственная команда, которая проверяет все поддерживаемые устройства. Правда и набор тестов у нас скудный. Чтобы его пройти образ должен успешно установиться на устройство, не жрать 100% cpu, не крешиться в цикле, а процесс UI должен запуститься и не падать. Мы буквально отвечаем на вопрос «а пригоден ли билд к дальнейшему тестированию?», зато для всего.

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


      1. lingvo
        26.11.2019 22:45

        Мы буквально отвечаем на вопрос «а пригоден ли билд к дальнейшему тестированию?», зато для всего.

        В том-то и дело, что при этом по аналогии с софтом может возникнуть ложная уверенность, что раз CI "дала добро", можно смело начинать выкатывать OTA на пользовательские устройства, хотя это на самом деле только самый базовый уровень тестирования и в реале экономит не так уж много времени, если думать об "успешно установиться на устройство, не жрать 100% cpu, не крешиться в цикле, а процесс UI должен запуститься и не падать" еще на этапе архитектуры, а не кодирования.


        1. OloloFine
          26.11.2019 23:07

          ложная уверенность — плохо, но это к теории тестирования)) для OTA имхо как минимум один тест — «способен ли новый билд посредством OTA откатиться на старый» должен быть автоматизирован в пайплайне


          1. lingvo
            27.11.2019 00:11

            — «способен ли новый билд посредством OTA откатиться на старый» должен быть автоматизирован в пайплайне

            И вот у меня почему-то на 99% уверенности, что комментатор выше это не тестирует на своей CI ферме. :-)


            1. alexac
              27.11.2019 10:45

              У нас в принципе нет механизмов даунгрейда версии. Нужен даунгрейд — бэкап данных/erase-install/восстановление бэкапа. Ну и все прекрасно понимают, что то что мы тестируем — позволяет поймать то, что билд совсем сломан, а не проверить то, что он хороший. Учитывая, что главные каналы обновления получают свежие сборки один раз в день, это просто ответ на вопрос, могут ли разработчики продолжать работать на сегодняшнем билде или лучше остаться на предыдущем.


              1. OloloFine
                27.11.2019 19:07

                Тут дело не в даунгрейде версии, а в работоспособности OTA в новой версии — не сможем откатиться на старую (пусть и под новым номером) — значит багфикс и новую версию тоже не втянем, канал ОТА лег, уже проданные приборы — кирпичи.


                1. alexac
                  27.11.2019 21:15

                  Вот это, кстати, интересный кейс. Было бы интересно его тестировать. В текущем варианте мы этого не можем сделать, так как чтобы протестировать OTA, надо собрать еще одну новую версию и сделать патчи с текущей версии на новую. Я полагаю, этот кейс обязательно входит в финальное ручное тестирование апдейтов, которые уходят пользователям.


  1. Punk_Joker
    27.11.2019 13:37

    Тема автоматизации тестирования весьма интересная, но ожида прочитать что-то большее, чем примитивное заыкание 2х реде для имитации кнопки и сброса питания. Раз уж такая тема, никому не приходилось реализовывать USB хост для FTDI на стороне МК? Попадался драйвер для этого дела под USB стек для ST. Но больше интересует, есть ли в наличии внешние микрухи, чтобы просто подключить к МК по уарту и не париться с реализацией всего этого?