Как заставить Jmeter собирать скриншоты графиков после тестов

Меня зовут Илья Улизко, я занимаюсь нагрузочным тестированием ДБО ЮЛ в блоке Цифровой Трансформации «РСХБ-Интех». В этой статье я поделюсь с вами опытом автоматизации сбора графиков в Grafana при отсутствии установленного grafana-image-render плагина на сервере. Для того, чтобы научить Apache Jmeter делать скриншоты панелей в Grafana, нам понадобится Selenium и Browsermob-proxy.

Начнём со скачивания всех необходимых зависимостей. Сами jar файлы можно скачать с официальных Maven репозиториев. Однако этого будет мало, поэтому нужно рекурсивно скачать зависимости для самих этих jar’ников. В этом нам поможет сервис Jar-Download. Вставляем в окно Maven XML 3 зависимости из selenium, proxy, webdrivermanager.

Нажимаем кнопку Submit, затем Download project.

Нажимаем кнопку Submit, затем Download project.

В итоге получаем архив с более чем 40 jar файлами, которые кладём в apache-jmeter-5.4.3/lib/junit/.

Теперь нам необходимо скачать webdriver’ы под конкретные браузеры: Firefox и Chrome. С версией драйвера для Chrome всё просто: какая версия браузера, такая версия и драйвера. Например, если у вас Google Chrome 111, то и драйвер нужен версии 111. А вот с Firefox задача немного усложняется, но на сайте Mozilla есть таблица с соответствиями, которая поможет разобраться и выбрать нужный драйвер.
Для гибкости рекомендую скачать оба драйвера и установить оба браузера.
После того как всё скачано, складываем драйверы в отдельную папку WebDriver/bin.

Далее нам нужно создать API ключ в Grafana, его мы будем отсылать в заголовке запросов в качестве авторизации. Для этого в Grafana слева нажимаем Configuration => API keys => New API key. Записываем где-нибудь у себя в блокноте, чтобы не забыть API ключ. Его мы будем далее передавать в переменную API_KEY.

Теперь надо прописать в переменных окружения путь до webdriver’ов и API-ключа, чтобы при необходимости всё поменять в одном месте, не затрагивая скрипты Jmeter. Я использую Linux, поэтому привожу пример для этой ОС:
echo 'export PATH=$PATH:/path/to/WebDriver/bin' >> ~/.profile
echo 'export API_GRAFANA=eyJblablablablablablablablabla9' >> ~/.profile
source ~/.profile

Вытаскиваем все id’шники панелей из дашборда. У нас все дашборды для разных микросервисов шаблонизированы, поэтому количество и название панелей везде одинаковое. Заходим на любой дашборд и переходим в Dashboard settings => Json model. С помощью JSONPath $.panels[*].[id,title] и онлайн сервиса получаем список всех id’шников панелей. Этот массив мы далее будем передавать в переменную PANELIDS.

С помощью панели разработчика определяем какой селектор или атрибут отвечает за отображение картинки внутри панели дашборда. Методом проб и ошибок был подобран атрибут class=«panel-container», в отличие от css selector, — он не меняется в разных панелях. Его мы будем передавать в переменную SELECTOR.

Приступаем к написанию скрипта в Jmeter. В начале тест плана создаём setUp Thread Group, внутри которой создаём JSR223 Sampler. В нём мы заводим переменную, которая будет хранить время начала теста и инициализировать переменную FROM:
props.put("TESTSTART",'${__time()}')

В конце тест плана создаём tearDown Thread Group, внутри которой формируем JSR223 Sampler. В нём пишем весь основной код.
Затем заводим параметризованные переменные:
final String URL = "http://10.10.10.10:3000/d/";
final String DASHBOARD = "VQB0x5pVz/settings";
final int[] PANELIDS = new int[]{26,28,38,37,29,4,2,23,39,40,36,25,27}; final String FROM = '${__P(TESTSTART)}';
final String TO = '${__time()}';
final String SELECTOR = "panel-container";
final String API_KEY = System.getenv("API_GRAFANA");
final double SCALE_MONITOR = 1;
final SimpleDateFormat formatter = new SimpleDateFormat("'_'dd.MM.yyyy");
Обратите внимание на переменную SCALE_MONITOR, она нужна, чтобы нивелировать масштабирование мониторов с высоким разрешением. Например, если у вас монитор с разрешением 4K и в настройках параметров экрана выставлен масштаб в 150%, то значение этой переменной будет 1.5, для масштаб в 125% нужно выставить — 1.25, ну и т.д.

Создадим и настроим объект BrowserMobProxy, он нужен для того, чтобы к запросам из Selenium добавлялся заголовок с авторизацией по API ключу:
BrowserMobProxy proxy = new BrowserMobProxyServer();
proxy.setTrustAllServers(true);
proxy.start();
proxy.addHeader("Authorization", "Bearer ".concat(API_KEY));

Теперь создадим веб драйвер с конкретной реализацией Firefox и передадим в него наш прокси с добавленным заголовком, а также добавим несколько настроек:
WebDriver driver;
DesiredCapabilities caps = new DesiredCapabilities();
Proxy seleniumProxy = ClientUtil.createSeleniumProxy(proxy);
System.setProperty("sun.java2d.uiScale", "1");
System.setProperty(FirefoxDriver.SystemProperty.BROWSER_LOGFILE, "null");
FirefoxOptions firefoxOptions = new FirefoxOptions();
firefoxOptions.addArguments("-private");
caps.setCapability("moz:firefoxOptions", firefoxOptions);
caps.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
caps.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
caps.setCapability(CapabilityType.PROXY, seleniumProxy);
driver = new FirefoxDriver(caps);

Через веб драйвер открываем браузер, разворачиваем на весь экран, делаем авторизованный запрос на URL адрес Grafana. Затем снимаем скриншоты всех панелей, id которых мы собрали в п. 5.
Далее сохраняем каждый скриншот под собственным названием в указанную директорию:
driver.manage().window().maximize();
for (int i = 0; i < PANELIDS.length; i++) {
driver.navigate().to(URL
.concat(DASHBOARD)
.concat("?orgId=1&viewPanel=")
.concat(String.valueOf(PANELIDS[i]))
.concat("&from=")
.concat(FROM)
.concat("&to=")
.concat(TO));
Thread.sleep(2000);
WebElement elem = new WebDriverWait(driver, 5)
.until(ExpectedConditions
.visibilityOfElementLocated(By.className(SELECTOR)));
File screenshot = ((org.openqa.selenium.TakesScreenshot) driver)
.getScreenshotAs(org.openqa.selenium.OutputType.FILE);
BufferedImage image = ImageIO.read(screenshot);
int x = (int) (elem.getLocation().getX() * SCALE_MONITOR);
int y = (int) (elem.getLocation().getY() * SCALE_MONITOR);
int width = (int) (elem.getSize().getWidth() * SCALE_MONITOR);
int height = (int) (elem.getSize().getHeight() * SCALE_MONITOR);
BufferedImage elemScreenshot = image.getSubimage(x, y, width, height);
ImageIO.write(elemScreenshot, "png", new File("/path/GrafanaScreenshots/"
.concat(elem.getAttribute("aria-label")
.substring(0,elem.getAttribute("aria-label").length()-6))
.concat(formatter.format(System.currentTimeMillis()))
.concat(".png")));
}

Закрываем браузер и останавливаем прокси:
driver.quit();
proxy.stop();

В итоге JSR223 Sampler будет выглядеть следующим образом:

Таким образом у нас получилось автоматизировать процесс сбора графиков из дашборда Grafana после проведения НТ.

Надеюсь, что это материал был полезен тем, кто занимается нагрузочным тестированием и работает с Apache Jmeter. Буду рад ответить на ваши вопросы в комментариях.

© Habrahabr.ru