Тестирование отказоустойчивого кода - PullRequest
5 голосов
/ 03 мая 2010

В настоящее время я работаю над серверным приложением, в котором мы согласились попытаться поддерживать определенный уровень обслуживания. Уровень обслуживания, который мы хотим гарантировать: если сервер принимает запрос и сервер отправляет подтверждение клиенту, мы хотим гарантировать, что запрос произойдет, даже если сервер выйдет из строя. Поскольку запросы могут выполняться долго и время подтверждения должно быть коротким, мы реализуем это, сохраняя запрос, затем отправляя подтверждение клиенту, а затем выполняя различные действия для выполнения запроса. По мере выполнения действий они также сохраняются, поэтому сервер знает состояние запроса при запуске, а также существуют различные механизмы согласования с внешними системами для проверки точности наших журналов.

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

  • Попросите, чтобы внешний процесс наблюдал за кодом сервера, а затем попытался уничтожить его, когда внешний процесс считает его подходящим пунктом в тесте
  • Добавьте код приложения, которое приведет к сбою определенных критических точек

Моя проблема с первой стратегией заключается в том, что внешний процесс не может знать точное состояние приложения, поэтому мы не можем быть уверены, что достигли самых проблемных точек в коде. Моя проблема со второй стратегией, хотя она дает больший контроль над ошибками, заключается в том, что мне не нравится иметь код для вставки ошибок в мое приложение, даже с дополнительной компиляцией и т. Д. и впрысните его в производственную среду.

Ответы [ 4 ]

3 голосов
/ 03 мая 2010

Я думаю, что есть три способа справиться с этим, если таковые имеются, я мог бы предложить полный набор интеграционных тестов для этих различных кусков кода, используя внедрение зависимостей или фабричные объекты для создания неработающих действий во время этих интеграций.

Во-вторых, запуск приложения со случайным уничтожением -9 и отключение сетевых интерфейсов может быть хорошим способом проверки этих вещей.

Я бы также предложил проверить сбой файловой системы. То, как вы это сделаете, зависит от вашей ОС, от Solaris или FreeBSD. Я бы создал файловую систему zfs в файле, а затем запустил файл во время работы приложения.

Если вы используете код базы данных, я бы посоветовал также проверить сбой базы данных.

Другой альтернативой внедрению зависимостей и, вероятно, решением, которое я бы использовал, являются перехватчики, вы можете включить перехватчики краш-тестов в вашем коде, они будут знать состояние приложения и вводить перечисленные выше сбои в нужное время, или любые другие, которые вы можете захотеть создать. Это не потребует изменений в вашем существующем коде, просто некоторый дополнительный код, чтобы обернуть его.

2 голосов
/ 03 мая 2010

Ваша забота о введении неисправности не является фундаментальной проблемой. Вам просто нужен надежный способ предотвратить попадание такого кода в развертывание. Один из способов сделать это - спроектировать инжектор ошибок как отладчик. То есть ошибки вводятся процессом, внешним по отношению к вашему процессу. Это уже обеспечивает уровень изоляции. Кроме того, большинство ОС предоставляют некоторый вид контроля доступа, который предотвращает отладку, если специально не включен. В самой примитивной форме это ограничение на root, в других операционных системах требуется определенная «привилегия отладки». Естественно, на производстве этого не будет ни у кого, и, следовательно, ваш инжектор неисправности не сможет даже работать на производстве.

Практически, инжектор сбоя может устанавливать точки останова по определенным адресам, то есть функции или даже строке кода. Затем вы можете отреагировать на это, например, завершив процесс после того, как определенная точка останова будет достигнута три раза.

2 голосов
/ 03 мая 2010

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

Другим способом является повышение наблюдаемости и / или управляемости за счет сокращения вызовов библиотеки или ядра, т. Е. Без изменения кода приложения.

Некоторые ресурсы можно найти на странице Fault Injection в Википедии, в частности в Программно-реализованном внедрении Fault * .

1 голос
/ 03 мая 2010

Я как раз собирался написать так же, как Джастин :)

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

Также представляется целесообразным убедиться, что код тестирования не запущен в производство. Я бы не одобрил условную компиляцию, а вместо этого выбрал бы файл конфигурации, чтобы выбрать компонент ведения журнала.

Использование «случайных» убийств может помочь обнаружить ошибки, но не подходит для систематического тестирования из-за его недетерминированности. Поэтому я не буду использовать его для автоматических тестов.

...