18 сентября 2014

Что такое Fault Injection с картинками и примерами

Теория.

Практически всегда мы тестируем то как себя будет вести приложение при взаимодействии пользователя с ним.
Это правильно с одной стороны - пользователь важен, он приносит нам деньги и то "качество", которое хочет видеть пользователь - оно превыше всего.
Но есть определенные обстоятельства в которых мы тестируем не то как пользователь взаимодействует с приложением, а то как приложение взаимодействует с другими приложениями (если мы гооворим о распределенных системах) или как модули приложения взаимодействуют между собой.
(так выглядят сервисы внутри twitter, источник

И вот с этого момента нас начинает интересовать, что будет с нашим приложением А если приложение Б от которого оно зависит ляжет или начнет себя неадекватно вести.
Этим аспектам уделяют мало внимания, в лучшем случае - падение одного приложения потянет за собой крэш всей системы (пользовательской).
Это хорошо и правильно - если вы не видите для себя  другого способа, то пусть будет хотя бы так.

Однако если вы его не только видите но и используете, то скорее всего вы заинтересованы в проверке работоспособности вашей зашиты от падений сторонних компонентов.
И вот тут начинаются интересности:

  1. Естественно у вас такая защита должна быть. А вот всунуть ее в legacy-код или продукт дизайн которого таких возможностей не предусматривал не так просто.
  2. Уровень и с которого "падаем" и глубина падения. Если говорить про стандартную трехзвенную архитектуру, то тут фантазии особо разгуляться негде.
    Все намного интереснее  - често говоря просто эта задача актуальнее - когда у вас SOA или микросервисы. Здесь и уровней больше, типы и глубина падения тоже могут быть разными. Про типы хочется написать отдельно - это может быть как и просто генерация исключения для тестирования того что приложение стабильно его обрабатывает, проглатывает и снаружи ничего не видно, так и внедрение более изощеренного поведения - эмуляция неправильной конфигурации приложения, изменение диапазна типовых значений для экспериментов над поведением. Про банальности типа потери соединения с БД во время работы  - молчу.
  3. Крушение приложения. Отдельная тема для распределенных систем особенно для тех что занимаются in-memory вычислениями (Storm, Kafka, Mesos, Suro). Что произойдет с блоком данных отправленным на in-memory обработку если обработчик сдох? Крушения опять же могут быть разными, но тут очень много специфики у каждого. 
Довольно теории, перейдем к практике.

Практика.

Для практики я построил на коленке простейшее вэб-приложение на Java (Jetty inside).
Приложение отзывается на три урла.
http://127.0.0.1:9090/doWork - отдает рандомное целое число от 0 до 1000.

http://127.0.0.1:9090/fault?mode=enabled - включает fault-режим
http://127.0.0.1:9090/fault?mode=disabled - выключает fault-режим

После включения режима падения генератор случайных числе начинает отдавать 0 или 1. Это и есть наше падение.
http://127.0.0.1:9090/crash?time=15 - падение приложения через  указанное время (опционально, если не указано, то упадет сразу).

Как оно организовано изнутри.

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


Код приложения выложен на github.

Хочется более приближенных к реальности примеров - их есть у меня.
Вот например ключи запуска Chromium