Обсуждая реализацию автотестирования в нашей компании, была предложена идея визуализации результатов с помощью светофора. Данный инструмент прост и понятен каждому, да и к тому же производит небольшой вау эффект. Под катом будет история внедрения светофора в нашу систему автотестов.

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

Светофор стоит недешево. Данная модель обошлась нам почти в 13000 р. Большим плюсом такого светофора является его компактность. Толщина светофора, включая козырьки, составляет 275 мм. Без козырьков 138 мм. Длина 840 мм. В комплекте идут кронштейны, с помощью которых мы повесили его на….шкаф.
Для управления светофором решили использовать плату дискретных входов-выходов «Quartech – Jackpot – USB», разработанную нашими друзьями.


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

Был разработан и реализован расширяемый протокол управления, позволяющий при помощи этой платы управлять не только светофором, но и множеством других периферийных устройств (питание камер наблюдения, системы управления освещением, различные кнопки и датчики на демонстрационных макетах).
Система автоматического тестирования написана на языке python3. С периодичностью в одну минуту проверяется наличие новой ревизии в репозитории. Если такая присутствует, она выкачивается, и на нее «натравливаются» тесты. Тесты — это отдельные скрипты на все том же python3, между которыми есть зависимости. Благодаря зависимостям тесты выстраиваются в определенную последовательность: сначала запускается тест, осуществляющий сборку проекта; следом за ним — «быстрые» тесты; в последнюю очередь — все остальные. Результаты выполнения тестов помещаются в базу данных (sqlite).
Отдельный скрипт реализует web-сервер, который визуализирует результаты выполнения тестов.

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

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

Поиск и покупка светофора
В интернете огромное количество предложений по покупке светофора. Мы не стали заморачиваться и собирать свой, а сразу купили готовый.
Технические характеристики транспортного светодиодного светофора ГОСТ Р 52282-2004:
• Минимальное энергопотребление светофора: не более 6Вт (красная и желтая секция) и 8Вт (зеленая секция) на секцию;
• Рабочее напряжение питания: 220В переменного тока, в соответствии с ГОСТ 13109. По испытаниям, электрическая прочность изоляции выдерживает напряжение не менее 1500В с частотой 50Гц без пробоев в течении 1 мин;
• Гарантия от производителя 3 года. Срок службы светофоров не менее 12 лет. Используются долговечные энергосберегающие светодиодные излучатели (СИД).Средний срок службы светодиодов – 100 000 часов;
• Диапазон рабочих температур светодиодных светофоров: от – 60 С до +60 С;
• Светотехнические параметры светофоров, осевая сила света излучателей дорожных светофоров в соответствии с ГОСТ Р 52282-2004;
• Малый вес светофора не более 8 кг;
• Рабочее напряжение питания: 220В переменного тока, в соответствии с ГОСТ 13109. По испытаниям, электрическая прочность изоляции выдерживает напряжение не менее 1500В с частотой 50Гц без пробоев в течении 1 мин;
• Гарантия от производителя 3 года. Срок службы светофоров не менее 12 лет. Используются долговечные энергосберегающие светодиодные излучатели (СИД).Средний срок службы светодиодов – 100 000 часов;
• Диапазон рабочих температур светодиодных светофоров: от – 60 С до +60 С;
• Светотехнические параметры светофоров, осевая сила света излучателей дорожных светофоров в соответствии с ГОСТ Р 52282-2004;
• Малый вес светофора не более 8 кг;

Светофор стоит недешево. Данная модель обошлась нам почти в 13000 р. Большим плюсом такого светофора является его компактность. Толщина светофора, включая козырьки, составляет 275 мм. Без козырьков 138 мм. Длина 840 мм. В комплекте идут кронштейны, с помощью которых мы повесили его на….шкаф.
Электроника
Для управления светофором решили использовать плату дискретных входов-выходов «Quartech – Jackpot – USB», разработанную нашими друзьями.


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

Был разработан и реализован расширяемый протокол управления, позволяющий при помощи этой платы управлять не только светофором, но и множеством других периферийных устройств (питание камер наблюдения, системы управления освещением, различные кнопки и датчики на демонстрационных макетах).
Описание протокола управления
Весь обмен производится в режиме запрос-ответ со стороны ПК, либо в режиме потоковой выдачи данных в специальном режиме.
Полнодуплексный обмен по USB через виртуальный COM-порт, открытый на скорости 9600кб/c.
Обмен между любыми устройствами происходит в режиме прямого подключения. Все сообщения на транспортном уровне имеют стандартизированный формат:
Битовое поле текущего статуса имеет следующие поля:
бит 0: 0 — нормальная работа, 1 — ошибка
бит 1: 0 — режим ожидания запроса, 1 — режим потоковой выдачи данных
Каждая команда состоит из поля «Номер команды» и опционального поля «Данные команды». Четные номера команд — запросы, нечетные — ответы.
Если ответ на команду не получен в течение защитного интервала, то подключенное устройство считается потерянным.
Управление выходными линиями платы.
В виртуальный COM-порт необходимо послать команду 0х0A с данными, соответствующими требуемому состоянию выходных линий. Если требуется подать сигнал только на нулевую линию, то в байте данных команд необходимо передать 0х01. Таким образом, вся команда будет иметь следующий вид:
0х7Е 0х02 0х00 0х0А 0х01 0x8B
в ответ на эту команду при возможности её выполнения плата ответит командой 0х0С с данными, соответствующими состоянию установленных выходных линий:
0х7Е 0х02 0х00 0х0С 0х01 0x8D
либо, при невозможности выполнения, сообщит об ошибке:
0х7Е 0х00 0х01 0x7F
Физический уровень
Полнодуплексный обмен по USB через виртуальный COM-порт, открытый на скорости 9600кб/c.
Транспортный уровень
Обмен между любыми устройствами происходит в режиме прямого подключения. Все сообщения на транспортном уровне имеют стандартизированный формат:
Поле |
Стартовый байт |
Размер команды (номер + данные) |
Текущий статус |
Номер команды |
Данные команды |
Контрольная сумма |
Размер |
1 |
1 |
1 |
1 |
0-254 |
1 |
Значение |
0x7E |
1 — 255 0 — ошибка |
Битовое поле, определяющее текущее состояние каждого типа устройств |
1 — 255 0 — ошибка |
Определяется командой |
Cумма всех предыдущих полей сообщения, включая стартовый байт |
Битовое поле текущего статуса имеет следующие поля:
бит 0: 0 — нормальная работа, 1 — ошибка
бит 1: 0 — режим ожидания запроса, 1 — режим потоковой выдачи данных
Командный уровень.
Каждая команда состоит из поля «Номер команды» и опционального поля «Данные команды». Четные номера команд — запросы, нечетные — ответы.
Номер команды |
Описание команды |
Данные |
0x01 |
Запрос типа устройства |
нет |
0x02 |
Ответ типа устройства |
1 байт: 0 — ошибка 1 — измерительная часть 2 — интерфейсная часть 3 — ПК |
0x03 |
Запрос серийного номера |
нет |
0x04 |
Ответ серийного номера |
2 байта |
0x05 |
Запрос версии софта |
нет |
0x06 |
Ответ версии софта |
2 байта |
0x07 |
Запрос версии железа |
нет |
0x08 |
Ответ версии железа |
2 байта |
0x0A |
Установка состояния порта |
1 байт |
0x0B |
Запрос состояния порта |
нет |
0x0C |
Ответ состояния порта |
1 байт |
0x0D |
Включить пищалку, мс |
1-2 байта |
0x0E |
Запрос состояния джамперов |
нет |
0x0F |
Ответ состояния джамперов |
1 байт |
0x10 |
Запрос состояния входов (оптопар) |
нет |
0x11 |
Ответ состояния входов |
1 байт |
0х12 |
Запрос количества фронтов входов |
1 байт (номер входа) |
0х13 |
Ответ количества фронтов входов |
5 байт: 1-й байт — номер входа 2-3 байты — количество передних фронтов 4-5 байты — количество задних фронтов |
0х14 |
Пакетный запрос состояния входов и счетчиков количества фронтов |
нет |
0х15 |
Ответ на пакетный запрос состояния входов и счетчиков количества фронтов |
33 байта: 1-й байт — состояние входов 2-17 байты — количество передних фронтов по 2 байта на вход начиная с нулевого 18-33 байты — количество задних фронтов по 2 байта на вход начиная с нулевого |
0х16 |
Сброс счетчиков фронтов |
Нет (в ответ выдается команда 0х15 с нулевыми значениями счетчиков) |
0х20 |
Установка битов автоматического мигания выходов |
1 байт |
0х21 |
Запрос установленных битов мигания выходов |
нет |
0х22 |
Ответ установленных битов мигания выходов |
1 байт |
0х23 |
Установка периода мигания выхода |
3 байта: 1-й байт — номер выхода 2-3 байты — период в мс По умолчанию период равен 500мс. Если байты 2-3 равны 0, то устанавливается период по-умолчанию |
0х24 |
Ответ периода мигания выхода |
3 байта (аналогично команде 0х23) |
Если ответ на команду не получен в течение защитного интервала, то подключенное устройство считается потерянным.
Пример:
Управление выходными линиями платы.
В виртуальный COM-порт необходимо послать команду 0х0A с данными, соответствующими требуемому состоянию выходных линий. Если требуется подать сигнал только на нулевую линию, то в байте данных команд необходимо передать 0х01. Таким образом, вся команда будет иметь следующий вид:
0х7Е 0х02 0х00 0х0А 0х01 0x8B
в ответ на эту команду при возможности её выполнения плата ответит командой 0х0С с данными, соответствующими состоянию установленных выходных линий:
0х7Е 0х02 0х00 0х0С 0х01 0x8D
либо, при невозможности выполнения, сообщит об ошибке:
0х7Е 0х00 0х01 0x7F
Система тестирования
Система автоматического тестирования написана на языке python3. С периодичностью в одну минуту проверяется наличие новой ревизии в репозитории. Если такая присутствует, она выкачивается, и на нее «натравливаются» тесты. Тесты — это отдельные скрипты на все том же python3, между которыми есть зависимости. Благодаря зависимостям тесты выстраиваются в определенную последовательность: сначала запускается тест, осуществляющий сборку проекта; следом за ним — «быстрые» тесты; в последнюю очередь — все остальные. Результаты выполнения тестов помещаются в базу данных (sqlite).
Отдельный скрипт реализует web-сервер, который визуализирует результаты выполнения тестов.

Этот же web-сервер научили формировать сводку по совокупности тестов. Данная возможность используется для управления светофором.
Под катом код скрипта для управления светофором:
#! /usr/bin/env python3
import sys, os, termios, threading, time, http.client
if len(sys.argv)<=1:
sys.exit("Usage: {0} CONFIG-FILE".format(sys.argv[0]))
exec(open(sys.argv[1], "rt").read())
portfd=os.open(serialport, os.O_RDWR)
# Configure serial port - make it "raw", set 9600 baud rate and 8N1
iflag,oflag,cflag,lflag,ispeed,ospeed,cc=tuple(termios.tcgetattr(portfd))
iflag&=~(termios.IGNBRK|termios.BRKINT|termios.PARMRK|termios.ISTRIP|termios.INLCR|termios.IGNCR|termios.ICRNL|termios.IXON)
oflag&=~(termios.OPOST)
lflag&=~(termios.ECHO|termios.ECHONL|termios.ICANON|termios.ISIG|termios.IEXTEN)
cflag&=~(termios.CSIZE|termios.PARENB|termios.CSTOPB)
cflag|=termios.CS8
ispeed=termios.B9600
ospeed=termios.B9600
termios.tcsetattr(portfd, termios.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc])
# Current state of traffic light:
# 0 - fail (red light)
# 1 - success (green light)
# 2 - in progress (yellow light)
# 3 - no data (blinking yellow)
state=3
RED=0
YELLOW=1
GREEN=2
def trafficLightControl(light):
cmd=[0x7E, 0x02, 0xFF, 0x0A]
if light==RED:
cmd.append(1)
elif light==YELLOW:
cmd.append(2)
elif light==GREEN:
cmd.append(4)
else:
cmd.append(0)
cmd.append(sum(cmd)&0xFF)
os.write(portfd, bytes(cmd))
def controlThreadProc():
while True:
if state==0:
trafficLightControl(RED)
elif state==1:
trafficLightControl(GREEN)
elif state==2:
trafficLightControl(YELLOW)
else:
trafficLightControl(YELLOW)
time.sleep(1.5)
trafficLightControl(None)
time.sleep(1.5)
controlThread=threading.Thread(target=controlThreadProc)
controlThread.start()
def pollThreadProc():
global state
connection=None
while True:
try:
if connection is None:
connection=http.client.HTTPConnection(server)
connection.request("GET", "/{0}/status?test={1}".format(project, ",".join(tests)))
r=connection.getresponse().readall()
state=int(r.decode("ascii"))
except:
state=3
connection=None
time.sleep(5)
pollThread=threading.Thread(target=pollThreadProc)
pollThread.start()
В конфигурационном файле указывается адрес сервера и список тестов, за которыми будет следить светофор.
server="192.168.2.245"
project="tvz-win-trunk"
tests=['build', 'xmlcheck', 'qdebug', 'runss', 'runssc', 'tr_en', 'trcyr_en', 'warning1', 'warning10', 'warning100', 'xmldeps', 'issue16683a', 'issue17071', 'issue16796', 'runmain', 'issue17319', 'issue17318', 'issue17396a', 'smartstation_su', 'xmlrpcdoc_ss', 'src_encoding', 'issue17241', 'issue17228']
serialport="/dev/ttyUSB0"
Логика работы светофора в системе тестов очень проста:
- Красный – тест провален
- Желтый – идёт прогон тестов или перепроверка теста
- Зеленый – все тесты успешно завершились
- Мигание желтым – отсутствует соединение с сервером
Итоги

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