Плавающие баги и как их искать
Заметки о QAВремя чтения ~5 минут
Очень много из текста основано на докладе Анны Васильевой (ныне Куреновой) "Поиск плавающих багов"
Ссылка на ее tg-канал
Что такое плавающие баги

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

- Состояние гонки (Race Condition): ситуация, когда два или более потока (или процесса) пытаются одновременно получить доступ к общему ресурсу.
* эта причина меня особенно заинтересовала, потому что ее тяжело повторить без осознанного действия - Редкие тестовые данные: данные, которые тяжело подобрать.
- Недостаток наблюдения: неочевидные ошибки, которые быстро появляются и быстро пропадают.
- Инфраструктурные проблемы: закончилась память, заблокировалась база данных, не обновился сертификат и прочие типичные проблемы инфраструктуры, которые можно либо словить из-за случайности, либо воспроизводить с помощью мок-северов.
Состояние гонки (Race condition)
Race condition - состояние гонки в системе: ошибка проектирования многопоточной системы или приложения, при которой работа системы или приложения зависит от того, в каком порядке выполняются части кода.
В этом случае дефект зависит от времени и последовательности действий:
- насколько быстро/медленно мы произвели действие
- как конкретно мы это сделали (в какой очередности производились действия)
Часто дефекты появляются на границе работы нескольких потоков: например, один поток положил сущность в базу данных, а второй при попытке сделать то же самое упал с ошибкой из-за отсутствия уникальности. Тут важно одновременное действие потоков: оба практически в один и тот же момент пытались сделать одно и то же. И обработки такого одновременно действия двумя потоками в системе не было, что и привело к ошибке.
Последствия race condition

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

- фаззинг: генерация разных тестовых данных с помощью специальных программ, что позволит решить проблему редких тестовых данных
- поиск ошибок в логах: отслеживание инфраструктурных проблем и их причин в системах логирования, что позволит найти неожиданные ошибки или странную перезагрузку сервера
- отправка большого количества запросов: оценка того, насколько сервер выдерживает разную нагрузку и не выкидывает странные ошибки
- отправка запросов параллельно: отображение корректности работы нескольких потоков с одними и теми же объектами
Почему стоит искать плавающие баги и всегда ли стоит искать их до конца?
Плавающие баги точно стоит искать: они могут выявить критические проблемы, которые могут привести к потери данных или невозможности работы какого-то пользователя.
Иногда причину плавающих багов очень сложно и долго локализовывать и тогда возникает вопрос: как понять, что это критический баг, а не наша попытка зацепиться за нерешаемую проблему и погрязнуть в ней?
Тут точного ответа нет, все очень индивидуально и зависит от бага, который вы ловите: иногда ситуация не может повториться на продакшн среде из-за увеличенного количества памяти, иногда баг можно получить "нереальной" последовательностью действий. Поэтому нужно оценивать риски для бизнеса появившейся проблемы и действовать согласно ситуации, привлекая других участников команды для ускорения поиска.
Личная история пропуска плавающего бага
Иногда одни и те же плавающие баги появляются настолько часто, что мы перестаем их искать: глаз замыливается и начинает воспринимать проблему как норму.
У меня в работе был случай, когда при параллельном запуске автотестов начиналось падение тех тестов, которые отдельно позитивно отрабатывают. Обсудив с разработчиком, который убедил меня в проблеме автотестов, я продолжила перезапускать тесты и убеждаться, что при последовательность запуске все отлично. А значит бага нет (ха-ха).
Все было хорошо до момента, когда не обнаружился баг на продакшене: события терялись при большом количестве документов. И мои тесты отлавливали именно это! Вот так я и пропустила баг, который проявлялся при большом количестве запросов к нескольким потокам...
Так что не повторяйте моих ошибок 🥸
Пост telegram-канала "Заметки о QA"