Теория.
Практически всегда мы тестируем то как себя будет вести приложение при взаимодействии пользователя с ним.Это правильно с одной стороны - пользователь важен, он приносит нам деньги и то "качество", которое хочет видеть пользователь - оно превыше всего.
Но есть определенные обстоятельства в которых мы тестируем не то как пользователь взаимодействует с приложением, а то как приложение взаимодействует с другими приложениями (если мы гооворим о распределенных системах) или как модули приложения взаимодействуют между собой.
(так выглядят сервисы внутри twitter, источник)
И вот с этого момента нас начинает интересовать, что будет с нашим приложением А если приложение Б от которого оно зависит ляжет или начнет себя неадекватно вести.
Этим аспектам уделяют мало внимания, в лучшем случае - падение одного приложения потянет за собой крэш всей системы (пользовательской).
Это хорошо и правильно - если вы не видите для себя другого способа, то пусть будет хотя бы так.
Однако если вы его не только видите но и используете, то скорее всего вы заинтересованы в проверке работоспособности вашей зашиты от падений сторонних компонентов.
И вот тут начинаются интересности:
- Естественно у вас такая защита должна быть. А вот всунуть ее в legacy-код или продукт дизайн которого таких возможностей не предусматривал не так просто.
- Уровень и с которого "падаем" и глубина падения. Если говорить про стандартную трехзвенную архитектуру, то тут фантазии особо разгуляться негде.
Все намного интереснее - често говоря просто эта задача актуальнее - когда у вас SOA или микросервисы. Здесь и уровней больше, типы и глубина падения тоже могут быть разными. Про типы хочется написать отдельно - это может быть как и просто генерация исключения для тестирования того что приложение стабильно его обрабатывает, проглатывает и снаружи ничего не видно, так и внедрение более изощеренного поведения - эмуляция неправильной конфигурации приложения, изменение диапазна типовых значений для экспериментов над поведением. Про банальности типа потери соединения с БД во время работы - молчу. - Крушение приложения. Отдельная тема для распределенных систем особенно для тех что занимаются in-memory вычислениями (Storm, Kafka, Mesos, Suro). Что произойдет с блоком данных отправленным на in-memory обработку если обработчик сдох? Крушения опять же могут быть разными, но тут очень много специфики у каждого.
Довольно теории, перейдем к практике.
Приложение отзывается на три урла.
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 - падение приложения через указанное время (опционально, если не указано, то упадет сразу).
Код приложения выложен на github.
Хочется более приближенных к реальности примеров - их есть у меня.
Вот например ключи запуска Chromium
Практика.
Для практики я построил на коленке простейшее вэб-приложение на Java (Jetty inside).Приложение отзывается на три урла.
http://127.0.0.1:9090/doWork - отдает рандомное целое число от 0 до 1000.
http://127.0.0.1:9090/fault?mode=disabled - выключает fault-режим
После включения режима падения генератор случайных числе начинает отдавать 0 или 1. Это и есть наше падение.
http://127.0.0.1:9090/crash?time=15 - падение приложения через указанное время (опционально, если не указано, то упадет сразу).
Как оно организовано изнутри.
Внутри все сделал по максимуму просто - интерфейс генератора случайных чисел задекорирован и на уровне декоратора отрабатывает бизнес-логика использования или неиспользования fault-режима.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class GeneratorFaultDecorator implements RandomGenerator{ | |
private final FaultModeManager faultModeManager; | |
private final RandomGenerator delegate; | |
public GeneratorFaultDecorator(FaultModeManager faultModeManager, RandomGenerator delegate) { | |
this.faultModeManager = faultModeManager; | |
this.delegate = delegate; | |
} | |
@Override | |
public int get() { | |
if (faultModeManager.isEnabled()){ | |
return new Random().nextInt(2); | |
} | |
return delegate.get(); | |
} | |
} |
Код приложения выложен на github.
Хочется более приближенных к реальности примеров - их есть у меня.
Вот например ключи запуска Chromium