Как я уже сказал в Последняя часть , при разработке IoT-проекта протоколы взаимодействия с устройствами были достаточно нестабильными, и шансы потерять связь с тестовыми устройствами после обновления прошивки были достаточно высоки.
В разработке участвовало несколько команд, и было жесткое требование — не потерять возможность протестировать бизнес-уровень приложения, даже если перепрошивка устройств нарушит весь поток работы с датчиками.
Чтобы бизнес-аналитики могли проверить свои гипотезы на данных, более-менее похожих на реальность, мы построили имитационную модель устройства.
Таким образом, если устройство ломалось из-за новой прошивки, и данные нужно было срочно получить, мы запускали в сеть имитационную модель вместо реального устройства, которое обрабатывало данные в старом формате и выдавало результат. Еще одним преимуществом модели было то, что бизнес никогда не стал бы покупать большую партию устройств только для того, чтобы проверить гипотезу.
Например, группа бизнес-анализа решила, что прогнозирование времени наполнения контейнера должно работать по-другому.
И никто не будет спешить покупать 10 000 датчиков, чтобы проверить свою гипотезу.
Разработка имитационной модели
Сама имитационная модель выглядела так:Состояние и поведение мусорного бака описывается обычным конечным автоматом.
Сначала мы инициализируем конечный автомат состоянием `EMPTY (level = 0)` и можем совершать над ним какие-то действия, то есть выбрасывать мусор в контейнер.
Теперь нам нужно решить, остается ли контейнер пустым `(level? MAX_LEVEL)` или заполнен `(level > = MAX_LEVEL)`.
Если последнее, то состояние меняется на «FULL».
Кто-то может выгрузить мусор из полного контейнера, или дворник пришел навести порядок, и нам нужно решить, в какое состояние перейти.
За выбор действия отвечает состояние `CHOICE` — в терминологии конечного автомата это что-то похожее на блок if. Контейнер также может сгореть, и тогда состояние конечного автомата изменится на `FIRE`.
Также контейнер может упасть и его состояние станет `ПАДЕНИЕ` (в докладе я рассказывал о том, какие неожиданные причины могут привести к падению контейнеров).
Но есть еще одно состояние «LOST», которое действует из любого другого состояния — оно устанавливается при потере соединения.
Такой конечный автомат описывает практически все поведение контейнера и датчика на нем.
Но этого недостаточно для создания имитационной модели, поскольку мы знаем о возможных состояниях и переходах из них, но не знаем, какова вероятность этих событий и когда они произойдут. На деле оказалось, что вероятность событий зависела от времени суток, потому что:
- перевозчики не работают в ночное время;
- люди выбрасывают больше мусора в определенное время (утром перед работой и вечером).
Можно было установить вероятность того или иного события в определенное время суток.
Простой и понятный стресс-тест
Моделирование само по себе имеет множество преимуществ, и одно из них — недорогое нагрузочное тестирование.Дешево, потому что симуляция — это по сути отдельный поток, который запускает конечный автомат, применяет к нему события, а сами события отправляются на реальный сервер.
Таким образом, симуляция бэкенда ничем не отличается от реального датчика.
А если нам нужно запустить 1000 датчиков — запускаем 1000 потоков и работаем.
Кроме того, моделирование обладает высокой масштабируемостью.
С одной стороны, тестирование нагрузки таким способом достаточно грубое, но с другой стороны, моделирование позволило прогнать большое количество данных, близких к реальности, на протяжении всего проекта.
И не забывайте о талантливых китайских разработчиках, которые проигнорировали стандартные протоколы вроде MQTT и написали собственный протокол поверх сокетов.
Поэтому нам пришлось сделать собственную реализацию сервера, получающего данные о сокетах по этому проприетарному протоколу.
Такой сервер должен был быть многопоточным, так как входных датчиков много.
и эту часть тоже нужно тестировать отдельно, используя тесты производительности.
Вы можете взять JMeter (написать типовой тестовый скрипт), JMH/JCStress (тестировать изолированные части и сделать более точный тест) или что-то свое.
Когда вы принимаете решение в такой ситуации, советую прислушаться к профессионалам, например, Алексею Шипилеву.
На JPoint 2017 он очень крутой рассказал об этом , как тестировать разные вещи и о чем нужно помнить при тестировании производительности.
Мы выбрали вариант сделать что-то свое, так как в проекте был нетипичный подход к QA — у нас нет отдельной команды тестировщиков, а бэкенд-команда сама тестировала функционал.
То есть человек, написавший сокет-сервер, должен был сам покрыть код обычными модулями, интеграционными и тестами производительности.
У нас был небольшой инструмент, который позволял быстро описать сценарий загрузки и запустить его в необходимом количестве параллельных потоков:
Мы говорим, сколько потоков нужно запустить, сколько сообщений отправить, сколько времени все это должно занять, и в каждом потоке отправляем данные в сокет. Нам остается только ждать, что наш сервер сможет корректно обработать все эти данные.StressTestRunner.test() .
mode(ExecutionMode.EXECUTOR_MODE) .
threads(THREADS_COUNT) .
iterations(MESSAGES_COUNT) .
timeout(5, TimeUnit.SECONDS) .
run(() -> sensor.send(MESSAGE)); Awaitility.await() .
atMost(5, TimeUnit.SECONDS) .
untilAsserted(() -> verifyReceived(MESSAGES_COUNT) );
Любой бэкенд-разработчик мог написать всего несколько строк кода.
Ээмуляция сетевых проблем
С помощью моделирования нам удалось смоделировать как некачественную, так и специфическую работу с сокетами.GSM SIM-карты в датчиках не имеют «белых» IP-адресов, и мы могли получать данные с разных IP-адресов 50 раз в течение суток.
И часто случалось, что открывалось соединение, мы начинали передавать данные, потом менялся IP-адрес, и сервер открывал новое соединение, не закрывая старое.
Если бы мы не учли это, то уже через пару дней у нас бы закончились свободные порты на сервере.
Также была проблема разной скорости работы датчиков.
Медленное устройство может открыть соединение и зависнуть на некоторое время, а быстрое что-то отправит. И все это нужно правильно обработать.
В симуляции подобную ситуацию легко смоделировать с помощью пауз.
Это лишь некоторые из сценариев, которые могут быть включены в модель.
выводы
Мне кажется, именно возможность моделирования сильно отличает IoT от других проектов.Поведение устройств моделировать проще, чем поведение людей.
На вход мы получаем детерминированные значения, которые хорошо коррелируют с нашей моделью, а не случайные действия человека.
Потому что поведение устройств логически легче описать, чем поведение людей, и тестировать систему становится проще.
Мы рассмотрели довольно много различных аспектов разработки Интернета вещей.
Если вы пропустили предыдущие две части этой статьи, вы можете найти их здесь: Интернет вещей там, где не ждали (часть 1) – Предметная область и проблемы Интернет вещей там, где вы не ожидали (часть 2) — Архитектура приложений и тестирование особенностей IoT Github с обсуждаемыми инструментами тестирования.
Немного рекламы.#йотКак видите, на конференции по тестированию Heisenbug очень разные доклады, например, как мой о разработке и тестировании IoT. Надеюсь, вам было интересно! В этой статье я также упомянул конференцию JPoint, где видел доклады по нагрузочному тестированию.
В этот раз можно купить билет и на Heisenbug, и на JPoint, и еще на 6 конференций сразу.
-
Firefox – Будущее Серфинга
19 Oct, 24 -
Выпуск Фреймворка Qt 5.6
19 Oct, 24 -
Печальная История Социальной Сети «Уберлов»
19 Oct, 24 -
Наблюдатель Против Pub-Sub
19 Oct, 24