В данной статье речь пойдёт об опыте автоматизации функционального и нагрузочного тестирования API протокола RTLSCP. Серверная часть системы локального позиционирования RealTrac состоит из основного (core) сервера, который связывается с устройствами по протоколу INCP (InterNanoCom Protocol) и сервера приложений (appserver). Сервер приложений общается с внешними клиентами и основным сервером по протоколу RTLSCP (Real Track Location System Communication Protocol). Клиенты также могут напрямую обращаться к основному серверу по RTLSCP.
RTLSCP реализует архитектуру REST и позволяет в запросах и ответах передавать данные в форматах JSON, KML и PNG. Причем общение по нему может происходить как по HTTP/HTTPS, так и по WS/WSS (Websocket). Этот протокол обеспечивает внешнего клиента обширным функционалом:
- получение различной информации об устройствах — локация, статусы, состояние и т. д.;
- передача управляющих команд на сервер — изменение параметров устройств, настроек сервера, отправка оповещений на устройства, загрузка карты и т. д.;
- получение отчетов по устройствам, статуса работы системы от Quality of Service.
- множество других полезных функций.
Важно, что протокол, со стороны сервера приложений обрастает дополнительным клиент-специфик функционалом от проекта к проекту. Как же это всё тестировать? Вручную получается долго и муторно, тестировщик скорее возненавидит весь мир пока пройдётся по всем командам спецификации RTLSCP API более чем в 120 страниц. Очевидно, этот процесс необходимо автоматизировать.
Тестирование системы проводится под Linux. Изначально мы пытались написать автотесты “на коленке“. Перепробовали несколько вариантов. Генерация запросов со случайными данными и отправка их на вход утилиты для нагрузочного тестирования Siege. В этом случае мы получаем только нагрузочное тестирование без возможности анализа содержимого ответа от сервера. Реализация автотестов на Python и простая отправка запросов через urllib. Тут всё веселее с анализом ответа, но получается громоздкий код, в который сложно вникать стороннему человеку и долго модифицировать.
Решением всех наших проблем стал неожиданно найденный Jmeter от Apache. Хоть на первый взгляд его графический интерфейс вызывает страх у обывателя, на деле этот инструмент помог найти большое количество багов и сэкономить много времени на тестировании RTLSCP API.
Рис. 1. Графический интерфейс Jmeter.
Буквально за месяц удалось покрыть автотестами почти все доступные команды RTLSCP. В процессе создания скриптов, естественно, находились и исправлялись ошибки и неточности как на серверной стороне, так и в самом протоколе. Так как никаких особенных знаний базовая работа в Jmeter не требует, удивительно быстро в автоматизацию тестирования получилось ввести и нового сотрудника.
Об инструменте уже существует некоторое количество статей (стоит обратить внимание на эту) на хабре, поэтому расписывать все его функции подробно не будем. Остановимся лишь на самых интересных моментах, которые запомнились за время использования Jmeter.
Автоматизация проверки сервиса авторизации и разграничений прав доступа для разных пользователей прошла на ура. Без каких-либо сложностей в несколько десятков кликов получилось организовать создание аккаунтов и назначение им прав доступа к случайным ресурсам.
Рис. 2. Так выглядит реализация проверки создания аккаунтов.
С помощью BeanShell PostProcessor (Post тут означает, что скрипт запускается после выполнения запроса) обрабатываем ответ на запрос всех доступных в системе ресурсов. Получаем их количество и генерируем случайные Id ресурсов для последующего присвоения созданным аккаунтам прав доступа к ним. Это осуществляется следующим кодом на BeanShell:
import java.util.regex.*;
import java.util.*;
import java.util.Random;
String response = prev.getResponseDataAsString();
Pattern pattern = Pattern.compile("id");
Matcher matcher = pattern.matcher(response);
int count = 0;
while (matcher.find())
count++;
Random rd=new Random();
Set resSet = new HashSet();
while (resSet.size()<4)
resSet.add(rd.nextInt(count));
int i=1;
Iterator iterator = resSet.iterator();
while (iterator.hasNext()) {
vars.put("resForCombo"+i,iterator.next().toString());
i++;
}
Затем из ответа на запрос информации о ресурсе по его Id получаем его URL с помощью Regular Expression Extractor:
Рис. 3. Использование Regular Expression Extractor.
Тут всё очевидно, в переменную res1Addr помещается содержимое ответа, вырезанное по регулярному выражени. В конце проводим проверку всех созданных аккаунтов и их права доступа к ресурсам. Кстати, обработка Cookies для авторизации в Jmeter реализуется простым добавлением элемента HTTP Cookie Manager.
Элементы типа check AUTH_ACCOUNT_ADDED_INTO_GROUP на рисунке 2 нужны для проверки того, что каждое действие пользователя, совершенное над аккаунтами записалось в соответствующее событие в истории событий (Получаемой также через RTLSCP).
Во время разработки автотестов был крайне полезен встроенный генератор случайных чисел. В любом месте в Jmeter можно использовать эту функцию. Разыграть число в заданном диапазоне:
${__Random(300,180000)}
Или сгенерировать строку определенного размера и случайного содержания:
${__RandomString(${__Random(3,30)},ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,)}
Понравилось, что в Jmeter любое действие можно реализовать как в коде BeanShell, так и с помощью встроенных инструментов. К примеру, получить количество доступных в системе ресурсов (выше мы это делаем через BeanShell PostProcessor ) можно реализовав Regular Expression Extractor, в котором в поле Match No. следует просто указать -1. В этом случае создаётся переменная {Reference Name}_matchNr, содержащая количество найденных в ответе по регулярному выражения строк. Так и ответ на любой запрос можно анализировать в коде BeanShell и выставлять флаги статуса выполнения элемента:
//Get response
response = prev.getResponseDataAsString();
//Check login
if (!response.contains(""login":"${ulogin_g1}"")) {
log.error("### login NOK!");
Failure= true;
//Check timestamp
} else if(!response.contains(""create_ts":${createTS_g1}")) {
log.error("### create_ts NOK!");
Failure= true;
Возможность комментирования каждого элемента делает автотест читабельным и позволяет ссылаться на тикет в багтрекере, например, Redmine:
Рис. 4. Комментирование элементов.
Отключение ресурсоемких проверок и добавление в Thread Group автотеста пользователей в поле Number of Treads (users) превращает наш функциональный автотест в нагрузочный. Теперь проект запускается одновременно из указанного количества потоков и нагружает сервер.
Рис. 5 Нагрузочное тестирование.
Результаты выполнения автотеста можно получить в любом удобном виде, как просмотреть в графической оболочке через View Results Tree, так и файлами логов с различными настройками:
Рис. 6 Получение результатов.
Также стоит отметить возможность в режиме реального времени отправлять результаты или любую другую информацию о статусе автотеста в различные сервисы (JDBC, JMS, Webservice). Например, на Graphite с последующим отображением в Grafana:
Рис. 7 Отправка результатов.
Естественно, у Jmeter существует некоторое количество отрицательных свойств. Например, не всегда удобный графический интерфейс и баги в нём. Но в нашей ситуации, когда срочно (и самое важное, бесплатно) требуется покрыть автоматическими тестами большое количество функций общения клиентов с сервером через протокол, Jmeter оказался незаменимым инструментом тестировщика.
Автор: RTL-Service