Тестирование и нагрузочные испытания - как, чем и зачем Александр Сербул Руководитель направления контроля качества интеграции и внедрений @AlexSerbul Рассмотрим частые кейсы, замечаемые Клиентами Что и как лучше тестировать? Чем тестировать? Тест-кейсы и аналитика «Монитор качества» как основа методологии тестирования Приоритетные риски Риск: «Клиент фиксирует многочисленные ошибки: управления, проектирования, разработки, эксплуатации …» Опытный Клиент: В ТЗ Клиентом подробно описан функционал, на выходе – он логически отличается Клиент отмечает много ошибок, используется в роли тестировщика Ошибки исправляются не с первого раза Оценки работы – сильно плавают Детали, подразумеваемые по умолчанию, сделаны небрежно: - сообщения об ошибках – на английском - недостаточно валидируются входные данные - страницы об ошибках на серверах: технические и т.п. Приоритетные риски Риск: «Клиент фиксирует многочисленные ошибки: управления, проектирования, разработки, эксплуатации …» Опытный Клиент: Клиент не может добиться организации эффективного мониторинга и проактивной реакции (пользователи узнают о проблеме первыми) Партнер не может предоставить Клиенту «взрослые» артефакты: - Как провести нагрузочное тестирование и интерпретировать результаты - Обоснованные рекомендации по выбору хостинга/железа серверов - Гарантии SLA с описанием возможных рисков - Рекомендации по созданию отказоустойчивой и масштабируемой архитектуры Сбор и анализ требований Храните требования в удобном для доступа и редактирования виде – напр. wiki В требовании пропишите, как его проверять на языке Клиента Посмотрите формат User Stories, Use Cases Не утоните в деталях – замучаетесь актуализировать документы Ведите логическую модель данных, схемы и описания алгоритмов. Повесьте их на стены. Ведите модель инфоблоков Ведите прототип в Axure Ведите Глоссарий, изучите его с менеджером ТЗ и требования в wiki – далеко не одно и то же. Test Cases Нужно объяснить тестировщику, как проверять каждый кейс: Описываем шаги в виде Test Case (аналитик) Поддерживаем их в актуальном состоянии в wiki Программист создает скрипты для тестировщика Организуем тестовые сервера с тестовыми данными Да, после изменения в веб-проекте – нужно заново проходить по связанным TestCases Иногда полезна матрица зависимостей Test Cases Матрица зависимостей. Лучше сделать «попроще» Модульные тесты - UnitTests Полезны в ряде случаев: Когда пишите свой кастомный технически сложный функционал Когда тестировать вручную очень долго и сложно Когда создаете низкоуровневые утилиты/библиотеки Когда пишите ООП-код в модулях Битрикс Инструменты: PHPUnit, SimpleTest. Можно написать свой попроще. Модульные тесты - UnitTests Опасны в ряде случаев: «Овчинка выделки не стоит», Клиент не хочет платить Наличие в команде «фанатиков» 100% UnitTests + DependencyInjection Не ООП код, а простые скрипты компонентов Объем кода UnitTests может превысить объем кода проекта. Любое изменение функционала – нужно переписывать тесты. Пишите просто и модульно. Проектируйте просто: высокая связность, низкая связанность. Модульные тесты - UnitTests Слабо-связанная (loose coupling), высоко-связная (high cohesion) удачная архитектура интеграции Ядро Битрикс Правим тут Класс Класс Компонент Шаблон Компонент Шаблон Шаблон Компонент Шаблон Шаблон Шаблон Модульные тесты - UnitTests Добро пожаловать в АД! Модульные тесты - UnitTests Так лучше не делать Ядро Битрикс Правим тут Класс Класс Класс Класс Компонент Шаблон Компонент Шаблон Шаблон Компонент Шаблон Шаблон Шаблон Функциональные тесты - Selenium Можно автоматизировать часть ручных тестов - Selenium: Пишите на javascript «бот», эмулирующий Клиентов Тесты составляются просто Можно постить формы, нажимать ссылки, обходить DOM Значительно ускоряется «перетестирование» проекта Систематизируется верстка Функциональные тесты - Selenium Поддерживать большой объем тестов Selenium – непросто Интерфейсы очень часто меняются Верстка иногда серьезно усложняется под Selenium Сложные сценарии трудно автоматизировать Попробуйте на практике, определите золотую середину. Beta-тестирование Попробуйте привлечь сотрудников Клиента к тестированию Попробуйте продать идею запуска решения в качестве Beta Объясните, что лучше опередить конкурентов, чем быть … совсем без багов Бардак в производстве <> BETA Пользователи не спасут веб-решение, кишащее багами Невозможно и ненужно отлавливать все некритичные ошибки. Монитор качества Структурированная методика управления качеством внедрения Система тестов для веб-разработчиков, набор рекомендаций для клиентов Состоит из 26 обязательных тестов и 40 необязательных Включает более 10 автоматических проверок, их число будет постоянно увеличиваться Цель – обеспечить прозрачный и гибкий процесс сдачи веб-проекта клиенту Монитор качества Используем системный подход – снижая риски и стоимость внедрения и его поддержки Прислушиваемся к «best practices» и советам экспертов BitrixFramework Заставляем систему выполнять сложные/рутинные проверки: автотесты Алгоритм тестирования До … После … Текущие инструменты безопасности Проактивный фильтр (WAF) и веб-антивирус – защищают снаружи от имеющихся уязвимостей в коде, допущенных интегратором Панель безопасности, журнал вторжений, одноразовые пароли, защита сессий и контроль активности – позволяют выстроить инфраструктуру защиты Текущие инструменты страхуют разработчика, значительно снижают последствия ошибок и усложняют взлом Причины появления «дырявого» кода Разработчик мыслит «креативно», хакер – «деструктивно». Программисту не хватает опыта аудита и «взлома» кода. Написание устойчивого к взлому кода требует не только глубоких теоретических знаний, но и многолетней практики. API Bitrix Framework – взломоустойчива. «Дырявый» код возникает при интеграции, в кастомных страницах, компонентах и модулях. Инструмент для аудита безопасности PHP-кода Инструмент для аудита безопасности PHP-кода Инструмент для аудита безопасности PHP-кода Технология – статический taint-анализ. Инструмент идентифицирует следующие возможные уязвимости: XSS (Cross-site scripting) SQL инъекции Выполнение произвольного php кода Выполнение произвольных системных команд Инъекции в заголовок ответа (HTTP Response Splitting) File Inclusion Подробности в блоге Андрея Красичкова: http://dev.1c-bitrix.ru/community/blogs/information_security/static_taint_analysis_tool.php Инструмент для аудита безопасности PHP-кода Данные HTTP-запроса (GET, POST, PUT, COOKIE, SERVER) Environment, argv, argc Файл php или подключение компонента в публичной части Ядро компонента (component.php) result_modifier.php Шаблон компонента (template.php) Автоматически отслеживается иерархия подключения (переопределения) файлов и ресурсов компонента: /bitrix/components/… /bitrix/templates/… и т.п. Произвольный подключаемый Произвольный подключаемый файл (include) Произвольный подключаемый файл (include) файл (include) Движение опасных данных «по файлам» 1 2 3 4 Отчет инструмента Отчет по возможным проблемам безопасности достаточно краток и точен, предназначен для разработчика или аудитора кода Эффективно определяются наиболее распространенные ошибки безопасности. Рекомендуется включить как ключевой этап в производство веб-проекта Инструмент постоянно развивается! Для его нужно нагружать систему? Чем лучше нагружать и как? Кейсы нагрузки для разных видов проектов Целевые показатели – мифы и реальность Как интерпретировать результаты нагрузки? Какие выводы можно делать? Для чего нагружать систему? Невозможно заранее точно спрогнозировать поведение системы MySQL плохо масштабируется при нагрузке Агенты Битрикс и cron-скрипты могут «спутать все карты» Ошибки в конфигурации – выявляются долго и не сразу Конкуренция потоков Клиентов за ресурсы – файлы и т.п. Синхронное обращение к внешним сокетам/сервисам Баги состыковки nginx + apache/php-fpm + mysql + memcached Перегрузка сетевого стека nginx + apache/php-fpm Перегрузка сокета nginx + php-fpm «Рассыпания» прекомпилятора php И много других чудес. Критерии оценки Какие цифры нужны Клиенту? Ставьте разумные и достижимые Пример 1: Гистограмма времени хитов, хитов менее 0.5 сек – 95%, хитов дольше 10 сек – 0,01%. Число ошибок < 0,01% Пример 2: Среднее время хита – 0.3 сек Пиковое использование памяти скриптами– менее 128М Время тестирования – 48 часов Нужны графики munin по CPU, памяти, диску, трафику, детальные по mysql Каждый 0 после запятой чреват большими издержками: агенты, импорты, баги прекомпилятора, фоновый своп, кэширование внешних ресурсов и т.п. Тестируем на реальных объемах Важно «прикинуть» и воссоздать ожидаемый объем данных в БД Тестируем на выборках, похожих на реальных Компоненты могут отъедать много памяти на реальных выборках Запросы к БД становятся тяжелыми Запросы-убийцы и их влияние на веб-приложение Уход системы в swap Мониторинг: ps, top, free – память, процессор iostat, atop - диски «Утечка» контента Nginx apachetop –f /var/log/nginx/access.log apachetop –f /var/log/httpd/access.log Apache file.php Слот apache file.php Слот apache file.php Слот apache file.php Слот apache file.php Слот apache file.php Слот apache image.gif Слот apache image.png Слот apache style.css Слот apache script.js Слот apache «Зависания» стека tcp/ip На графике числа обращений к apache - провал Резкий рост числа соединений между nginx-apache: netstat –ntop Логируйте состояние БД – «show engine innodb status» Логируйте «netstat» Смотрите лог медленных запросов MySQL Ищите причину в запросах к БД. «Зависания» стека tcp/ip «Зависания» memcached Резкий рост числа соединений к memcached: netstat –ntop | grep 11211 Можно потюнить ядро: echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle echo 15 > /proc/sys/net/ipv4/tcp_fin_timeout И опции запуска memcached: memcached -d -p 11211 -u memcached -m 384 -c 10240 -P /var/run/memcached/memcached.pid А еще можно увеличить число memcached-серверов (вебкластерные редакции). Готовимся к нагрузочному тестированию Устанавливаем инструменты анализа – munin, cacti Настраиваем логгер состояния системы. Например atop. Настраиваем опции логирования nginx, apache, phpfpm, медленных запросов mysql Для nginx – логируем тайминги на апстримы/бэкэнды Для apache/php-fpm – объем памяти Для php-fpm – включаем лог медленных запросов с backtrace Готовимся к нагрузочному тестированию Полезно написать несколько скриптов обработки логов: - Гистограмма времени запросов - Гистограмма ошибок - Гистограмма расхода памяти Технологии: awk, bash, php. Скрипты - в блоге Битрикс на Хабре или пишите нам. cat /var/log/www.access.log | awk -F# '{ zone = int($10/100)*100; hits[zone]++; } \ END { for (z in hits) {printf("%8s ms: %8s,%6.2f% ",z,hits[z],hits[z]/total*100);{s="";a=0;while(a++<int(hits[z]/total*100)) s=s"*";print s} } }' \ total="$TOTAL" - | sort -n Jmeter - для создания нагрузки http://jmeter.apache.org Можно грузить в несколько потоков Можно грузить с кластера машин Можно эмулировать авторизованных юзеров Можно также грузить статику Можно использовать тестовые данные из файлов и др. Много строить сложные сценарии Можно грузить по имеющимся лог-файлам Обязательно прочитать документацию. Jmeter – подводные камни Java ;-) Нужна машина с достаточным ОЗУ Нужно настроить виртуальную память java: java –Xms512m –Xmx2048m : индивидуально Возможны короткие зависания java: - Потюньте сборщик мусора java - Попробуйте JRockit JRE Jmeter – запуск из консоли Можно запускать без графического интерфейса Для начала «готовим» тест-план – “mytest.jmx” XML можно править и ручками Данные по хитам пишутся в лог Обработка лога – awk Лучше запускать внутри ДЦ по локальной сети jmeter –n –t mytest.jmx –o hits.log –j jmeter_run.log Jmeter – цепочки Пример цепочки Jmeter – важные сущности Переменные и заголовки Jmeter – важные сущности Настройка цепочки – группы потоков Jmeter – важные сущности Пауза и куки Jmeter – важные сущности Случайные значения, чтение данных из файлов Jmeter – важные сущности Использование динамических параметров Трактуем результаты Строим гистограммы хитов Считаем средние значения Считаем процент ошибок Смотрим на графики munin/cacti – не должно быть провалов Смотрим на поведение системы каждые 5 минут: atop –r /var/log/atop.log вперед: «t», назад: «T» Составляем отчет для Клиента. Спасибо за внимание! Вопросы? Александр Сербул serbul@1c-bitrix.ru @AlexSerbul