Мониторим и нагружаем приложения Jmix

от автора

Инструменты мониторинга работы приложений могут быть полезны не только DevOps’ам, но и разработчикам для исследования производительности приложения в поиске, например узких мест в его работе, поэтому в данной статье мы не только настроим мониторинг для Jmix-приложения, но и подготовимся к его синтетическому нагрузочному тестированию. Особенностью платформы Jmix в силу того, что на использует фреймворк Vaadin, является тот факт, что работа UI интегрирована с бекендом, но это также значит и то, что и метрики можно использовать прозрачно, т.е. замерять ими работу интерфейсного слоя. 

Создаем проект и включаем метрики

Для разработки вам понадобиться среда разработки IntelliJ IDEA с установленным плагином Jmix.

В качестве примера возьмем jmix-onboarding. Это такой более полноценный Hello World, т.е. демонстрационный проект.

Для его получения себе на компьютер в среде разработки выберем File -> New -> Project from Version Control и в появившемся диалоге укажем адрес репозитория: https://github.com/jmix-framework/jmix-onboarding-2.git

Впрочем, вы можете и создать абсолютно новый проект, он будет сразу готов к запуску и работе.

Для подключения Actuator добавим в build.gradle его зависимости:

    implementation 'org.springframework.boot:spring-boot-starter-actuator'     implementation 'io.micrometer:micrometer-registry-prometheus'

По умолчанию метрики отключены. Чтобы включить их в application.properties добавим следующие строчки:

management.endpoints.web.exposure.include=prometheus,health,info,metrics management.endpoint.health.show-details=always

Настраиваем авторизацию

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

@Configuration public class ActuatorSecurityConfiguration {     @Bean     @Order(JmixSecurityFilterChainOrder.FLOWUI - 10)     public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {         http.securityMatcher("/actuator/**")                 .authorizeHttpRequests((authorize) -> authorize.requestMatchers("/actuator/**").permitAll());         return http.build();     } }

Создадим подкаталог docker и в нем файл docker-compose.yml для проекта с PostgreSQL:

services:   jmix-onboarding-postgres:     container_name: jmix-onboarding-postgres     image: postgres:latest     ports:       - "5432:5432"     volumes:       - postgres:/var/lib/postgresql/data       - storage:/storage     environment:       - POSTGRES_USER=onboarding       - POSTGRES_PASSWORD=onboarding       - POSTGRES_DB=onboarding   Jmix-onboarding:     container_name: jmix-onboarding     image: jmix-onboarding:0.0.1-SNAPSHOT     ports:       - "8080:8080"     environment:       - DB_HOST=jmix-onboarding-postgres       - DB_USER=onboarding       - DB_PASSWORD=onboarding       - DB_PORT=5432       - DB_NAME=onboarding     depends_on:       - jmix-onboarding-postgres volumes:   postgres: {}   storage: {}

Создадим профиль для продуктива в файле application-prod.properties с датасорсом для PostgreSQL из Docker:

main.datasource.url = jdbc:postgresql://${DB_HOST}:${DB_PORT}/${DB_NAME} main.datasource.username = ${DB_USER} main.datasource.password =${DB_PASSWORD} jmix.localfs.storage-dir = /storage

Датасорс для разработки вытащим из application.properties в application-dev.properties

main.datasource.url = jdbc:hsqldb:file:.jmix/hsqldb/onboarding main.datasource.username = sa main.datasource.password =

Для поддержки PostgreSQL также надо добавить драйвер СУБД в секцию dependencies файла build.gradle

    runtimeOnly 'org.postgresql:postgresql'

Для того, чтобы профили включались автоматически добавим в build.gradle передачу параметров профиля:

bootRun {     args = ["--spring.profiles.active=dev"] }  tasks.named("bootBuildImage") {     environment["BPE_APPEND_JAVA_TOOL_OPTIONS"] = " -Dspring.profiles.active=prod" }

Собираем Docker-образ:

./gradlew bootBuildImage -Pvaadin.productionMode=true

Запускаем контейнеры:

 docker compose -f ./docker/docker-compose.yml up -d

Проверяем, что приложение отдает данные для мониторинга:

curl http://localhost:8080/actuator/prometheus

Запускаем мониторинг

Создаем конфигурацию docker/config/grafana/provisioning/datasources/all.yaml с датасорсом прометеуса:

apiVersion: 1   datasources:   - name: Prometheus     label: Prometheus     type: prometheus     access: proxy     url: http://prometheus:9090     isDefault: true

Создаем Docker-файл для Graphana docker/config/grafana/Dockerfile

FROM grafana/grafana ADD ./provisioning /etc/grafana/provisioning

Создаем docker/config/prometheus.yml

scrape_configs:   - job_name: 'onboarding_monitoring'     scrape_interval: 5s     metrics_path: '/actuator/prometheus'     static_configs:       - targets: ['jmix-onboarding:8080']

Создаем docker/monitoring.yml

services:   grafana:     build: './config/grafana'     user: root     ports:       - 3000:3000     volumes:       - ./grafana:/var/lib/grafana     environment:       - GF_SECURITY_ADMIN_USER=admin       - GF_SECURITY_ADMIN_PASSWORD=admin   prometheus:     image: prom/prometheus     user: root     ports:       - 9090:9090     volumes:       - ./config/prometheus.yml:/etc/prometheus/prometheus.yml       - ./prometheus:/prometheus

Запускаем мониторинг:

docker compose -f ./docker/monitoring.yml start

Для проверки можно зайти веб-интерфейс Prometheus, открыв в браузере http://localhost:9090 и убедиться, что статус работы сборщика метрик там позитивный.

Настраиваем панели и графики

Для Grafana есть готовый JVM-дашборд (https://grafana.com/grafana/dashboards/4701-jvm-micrometer/.), который сразу выглядит красиво. Но мы пойдем немного дальше и будем делать дашборды с только специфичными для работы подсистем фреймворка Jmix данными.

В Jmix уже встроен сбор метрик для основных структурных единиц — представлений (Views) и загрузчиков данных(Data Loaders) и когда вы добавляется свои экраны и пишете в них логику для работы с данными, то автоматически получаете возможность отслеживать их производительность отдельно.

Для представлений название метрики jmix.ui.views

Поддерживаются тэги: lifeCycle, view мониторятся следующие фазы жизненного цикла:

  • Create

  • Load

  • Init

  • Before show

  • Ready

  • Inject

  • Before close

  • After close

Результат для Prometheus будет выглядеть примерно так:

jmix_ui_views_seconds_max{lifeCycle="load",view="User.list",} 0.0412709

Для загрузчиков данных название метрики jmix.ui.data

Поддерживаются тэги: lifeCycle, view, dataLoader мониторятся следующие фазы жизненного цикла:

  • Pre-load

  • Load

  • Post-load

Запись метрик работает только для загрузчиков данных у которых определен Id

Пример метрики даталоадера для Prometheus:

jmix_ui_data_seconds_max{dataLoader="usersDl",lifeCycle="load",view="User.list",} 0.005668899

Заходим на http://localhost:3000 добавляем дашборд и в него метрики из датасорса Prometheus

jmix_ui_data_seconds_max{dataLoader="usersDl"} -> dashboards

Также это можно сделать через Explore выбрав соответствующий датасорс и вводя имя метрики и ее параметры вы элементы выбора. По нажатию Run query должен построиться предпросмотр графика. Но это произойдет только если уже есть какие-то данные, т.е. надо авторизоваться в приложении, и хотя бы зайти на управление пользователями.

Добавляем свои метрики

При помощи API Micrometer вы можете добавлять свои метрики: таймеры, счетчики. Добавим такой в слушатель для событий сущности.

И добавим счетчик сохранений сущности User, при помощи следующего кода:

package com.company.onboarding.listener;  import com.company.onboarding.entity.User; import io.jmix.core.event.EntitySavingEvent; import io.micrometer.core.instrument.MeterRegistry; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;  @Component public class UserEventListener {      @Autowired     MeterRegistry meterRegistry;      @EventListener     public void onUserLoading(final EntitySavingEvent<User> event) {         meterRegistry.counter("onboarding_on_user_save").increment();     } }

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

Включаем отображение в REST для проекта

Для Jmix есть аддон, который позволяет автоматически отображать сущности, интерфейсы к ним и другие сервисные методы в веб-сервисы, с автоматическим документированием в OpenAPI. Такой подход позволяет использовать фреймворк как основу для разработки сервисов с минимальными затратами на генерацию интерфейса управления данными (backoffice) и достаточно развитыми возможностями кастомизации как интерфейсной части, так и связанной с ними бизнес-логики.

Для включения аддона добавим в build.properties зависимости модулей:

implementation 'io.jmix.authserver:jmix-authserver-starter'  implementation 'io.jmix.rest:jmix-rest-starter'

Добавим минимальную конфигурацию безопасности для сервиса, в файле application.properties:

# The client id is my-client  spring.security.oauth2.authorizationserver.client.myclient.registration.client-id=my-client # The client secret (password) is my-secret  spring.security.oauth2.authorizationserver.client.myclient.registration.client-secret={noop}my-secret  # Enable Client Credential grant for the my-client  spring.security.oauth2.authorizationserver.client.myclient.registration.authorization-grant-types=client_credentials  # Client credentials must be passed in the Authorization header using the HTTP Basic authentication scheme  spring.security.oauth2.authorizationserver.client.myclient.registration.client-authentication_methods=client_secret_basic  # Use opaque tokens instead of JWT  spring.security.oauth2.authorizationserver.client.myclient.token.access-token-format=reference  # access token time-to-live  spring.security.oauth2.authorizationserver.client.myclient.token.access-token-time-to-live=24h jmix.authserver.client.myclient.client-id = my-client  jmix.authserver.client.myclient.resource-roles = user-management, rest-minimal

Также надо создать класс роли доступа в пакете com.company.onboarding.security:

@ResourceRole(name = "User management", code = UserManagementRole.CODE, scope = "API") public interface UserManagementRole {      String CODE = "user-management";      @EntityAttributePolicy(entityClass = User.class, attributes = "*", action = EntityAttributePolicyAction.MODIFY)     @EntityPolicy(entityClass = User.class, actions = EntityPolicyAction.ALL)     void user(); }

Перезапускаем проект и проверяем, что ендпоинты заработали, выполняя сначала запрос на получения токена доступа:

curl -X POST http://localhost:8080/oauth2/token --basic --user my-client:my-secret -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=client_credentials"

И получим список пользователей подставив полученный токен в новый запрос:

curl -X GET http://localhost:8080/rest/entities/User -H "Authorization: Bearer <access_token>"

Устанавливаем JMeter

JMeter — инструмент нагрузочного тестирования, который позволял проектировать тесты в режиме no/low-code еще до того как это стало мейнстримом.

Для запуска JMeter потребуется установить JDK 11 и сделать так, чтобы она использовалась при запуске.
Мне для этого потребовалось сделать небольшой шелл-скрипт запуска в /usr/local/bin c таким содержанием:

#!/bin/bash export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64/ /opt/apache-jmeter-5.6.3/bin/jmeter

Запускаем тесты

Добавим переменные

Создадим Thread Group с названием, например, REST Users

Уберем галочку с Infinite и определим 20 повторений для 10и параллельных пользователей

Аутентификация

Поскольку наш сервис закрыт на авторизацию, тредгруппам JMeter понадобиться проходить эту процедуру хотя бы однажды за сеанс. Для реализации этого элемент If Controller из группы Logic Controller. Назовем его Authenticate.

Добавим в него HTTP семплер для POST-запроса выполняемого на адрес /oauth2/token

Из параметров потребуется передавать только grant_type=client_credentials

Параметры подключения оформим из переменных, которые указывали ранее на уровне Thread Group’ы, подстановка которых оформляется как ${__V(имя_переменной)}

Нам также потребуется передавать значение логина и пароля в заголовке запроса Authorization. Для этого в Authenticate добавим элемент HTTP Header Manager и зададим ему значение заголовка Authorization Basic bXktY2xpZW50Om15LXNlY3JldA==.

Это значение получается из строк логина и пароля соединенных символом “:” и закодированным в Base64. Я воспользовался онлайн сервисом-конвертором чтобы получить строку для моих значений. И встроенным HTTP клиентом IntelliJ IDEA чтобы отладить параметры запроса.

Для выполнения условия только при первом запросе в параметрах If Controller зададим соответствующее условие:

${__groovy(ctx.getThreadNum() == 0 &&  vars.getIteration() == 1,)}

Также добавим в него JSON Extractor из Post Processors получающий токен с помощью выражения

$.access_token

В переменную access_token

И сохранялку значения BeanShell Assertation с выражением:

${__setProperty(access_token, ${access_token})};

Запрос для списка пользователей

В группу добавим HTTP сэмплер Users List для получения пользователей с ресурса rest/entities/User

Также надо добавить HTTP Header Manager

И BeanShell PreProcessor для установки заголовка с токеном в таким коде:

import org.apache.jmeter.protocol.http.control.Header;  var authHeader = sampler.getHeaderManager().getFirstHeaderNamed("Authorization"); if (authHeader == null) {     sampler.getHeaderManager().add(new Header("Authorization", "Bearer" + props.get("access_token"))); } else {     authHeader.setValue("Bearer" + props.get("access_token")); }

В родительскую группу добавим HTTP Cookie Manager из подменю Add -> Config Element.

Также добавим Summary Report из подменю Add -> Listener.

Запуск тестов

Теперь можно запустить тестирование.

После запуска самое время посмотреть в мониторинг.

Остановив выполнение запросов кнопкой “Стоп”, в секции Summary Report появятся данные по выполненным запросам.

Тестирование пользовательских интерфейсов

Разработка UI-тестов

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

На момент написания статьи ChromeDriver требовал достаточно устаревшей версии 114, совмещать которую на компьютере разработчика с актуальной представлялось достаточно нетривиальным, поэтому сработал альтернативный вариант с использованием GeckoDriver и дистрибутивом Firefox ESR

В основе тестов та же логика: аутентификация и выполнение. Но ключевыми единицами являются компоненты WebDriver Sampler, в которых пишется код скриптующий действия пользователя.

Например, скрипт входа в систему для Jmix 2.x может иметь такой код:

var props = WDS.vars  WDS.sampleResult.sampleStart() WDS.browser.get(props.get('jmix_proto') + '://' + props.get('jmix_host') + ':' + props.get('jmix_port'))  var pkg = JavaImporter(org.openqa.selenium, org.openqa.selenium.support.ui) var wait = new pkg.WebDriverWait(WDS.browser, java.time.Duration.ofSeconds(100))  // wait for login screen wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('input[name=username]')))  var login = WDS.browser.findElement(pkg.By.cssSelector('input[name=username]')) var password = WDS.browser.findElement(pkg.By.cssSelector('input[name=password]')) var submit = WDS.browser.findElement(pkg.By.cssSelector('vaadin-button[slot=submit]'))  login.clear() login.sendKeys(['admin']) password.clear() password.sendKeys(['admin']) submit.click()  // wait main app screen  wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('vaadin-app-layout[id="MainView"]')))  var appMenu = WDS.browser.findElement(pkg.By.cssSelector('a[href=users]')) appMenu.click()  wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('[id="usersDataGrid"]')))  WDS.sampleResult.sampleEnd()

Скрипт основных действий в панели управления, будут выглядеть так:

var props = WDS.vars var pkg = JavaImporter(org.openqa.selenium, org.openqa.selenium.support.ui) var wait = new pkg.WebDriverWait(WDS.browser, java.time.Duration.ofSeconds(120)) var tu = JavaImporter(java.util.concurrent.TimeUnit)  WDS.sampleResult.sampleStart() WDS.browser.manage().window().setPosition(new pkg.Point(0, 0)) WDS.browser.manage().window().setSize(new pkg.Dimension(1280, 1024)) WDS.browser.get(props.get('jmix_proto') + '://' + props.get('jmix_host') + ':' + props.get('jmix_port')) wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('vaadin-app-layout[id="MainView"]'))) var usersMenu = WDS.browser.findElement(pkg.By.cssSelector('a[href="users"]'))  usersMenu.click()  wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('[id="usersDataGrid"]')))  var tableRow  = WDS.browser.findElement(pkg.By.cssSelector('[id="usersDataGrid"]')).getShadowRoot().findElements(pkg.By.cssSelector('table tbody tr td')).get(0) tableRow.click()  wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('[id="editBtn"]:not(.v-disabled)')))  var editButton = WDS.browser.findElement(pkg.By.cssSelector('[id="editBtn"]')) editButton.click()  wait.until(pkg.ExpectedConditions.presenceOfElementLocated(pkg.By.cssSelector('[id="closeBtn"]')))  var closeButton = WDS.browser.findElement(pkg.By.cssSelector('[id="closeBtn"]')) closeButton.click()  WDS.sampleResult.sampleEnd() WDS.sampleResult.setSuccessful(true)

Тут еще важно не забыть, что переменная jmix.host должна указывать на внешний адрес хост-машины либо на Docker-хост 172.17.0.1. В этом случае приложение должно быть запущено в контейнере. Делается это просто, в каталоге с проектом выполняем:

./gradlew -Pvaadin.productionMode=true bootBuildImage

А затем запускаем интерактивно:

docker run -it docker.io/library/jmix-onboarding:0.0.1-SNAPSHOT

где jmix-onboarding:0.0.1-SNAPSHOT это имя образа, которое вам выведет команда сборки.

Есть у вас не получается работать с DockerHub, инструкцию для запуска простого реестра Docker-образов можно найти в нашей предыдущей статье “Настройка конвейерной сборки Java-проектов в GitLab” (https://habr.com/ru/companies/haulmont/articles/810151/).

Для реальных кейсов потребуется развить скрипты тестирования так, чтобы они покрывали весь основной функционал приложения.

Благодаря тому, что подсистема интерфейса Jmix Flow UI производит стандартный HTML код, у вас не будет проблем с выборкой элементов селекторами. Однако, надо учитывать, что “внутрянка” многих компонентов спрятана в теневое дерево (Shadow DOM), в которое поиск элемента заходит только через вызов метода getShadowRoot(), как вот в этом примере:

var tableRow  = WDS.browser.findElement(pkg.By.cssSelector('[id="usersDataGrid"]')).getShadowRoot().findElements(pkg.By.cssSelector('table tbody tr td')).get(0)

Также при разработке тестов следует учитывать, что между имитацией действия пользователя и результатом может существовать временная задержка, вызванная обработкой его запросов и отображением результата, поэтому чтобы тесты не заваливались понапрасну следует везде в таких моментах расставлять вызов ожидания результатов при помощи wail.until (WebDriverWait) и аналогов.

В некоторых случаях макросы тестирования можно также попробовать генерировать при помощи записи с расширениями для браузера такими как Selenium IDE.

Автоматизация

Сложность настройки окружения для тестирования, а также необходимость запускать тесты в автоматическом режиме приводит нас к мысли о запуске их в Docker-контейнерах. Как минимум, это поможет нам не даунгрейдить основной браузер до совместимых с тестовой оснасткой версий. Для запуска тестов нам потребуется Docker-файл, который мы разместим в отдельном каталоге-проекте, например ffjmeter.

FROM ubuntu:22.04  ARG JMETER_VERSION="5.6.3" ENV JMETER_HOME /opt/apache-jmeter-${JMETER_VERSION} ENV JMETER_BIN ${JMETER_HOME}/bin ENV JMETER_PLUGINS_MANAGER_VERSION 1.3 ENV CMDRUNNER_VERSION 2.2 ARG GECKODRIVER_VERSION=0.34.0  ENV JMETER_DOWNLOAD_URL https://archive.apache.org/dist/jmeter/binaries/apache-jmeter-${JMETER_VERSION}.tgz  RUN apt-get -qq update RUN apt-get -qq -y install software-properties-common RUN add-apt-repository ppa:mozillateam/ppa RUN apt install wget gnupg unzip curl openjdk-11-jdk-headless firefox-esr -y RUN mkdir -p /tmp/dependencies && \   curl -L --silent ${JMETER_DOWNLOAD_URL} > /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz && \   mkdir -p /opt && \   tar -xzf /tmp/dependencies/apache-jmeter-${JMETER_VERSION}.tgz -C /opt && \   rm -rf /tmp/dependencies  ENV PATH $PATH:$JMETER_BIN  WORKDIR ${JMETER_HOME}/bin  RUN curl --location --silent --show-error --output ${JMETER_HOME}/lib/ext/jmeter-plugins-manager-${JMETER_PLUGINS_MANAGER_VERSION}.jar \     http://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-manager/${JMETER_PLUGINS_MANAGER_VERSION}/jmeter-plugins-manager-${JMETER_PLUGINS_MANAGER_VERSION}.jar \  && curl --location --silent --show-error --output ${JMETER_HOME}/lib/cmdrunner-${CMDRUNNER_VERSION}.jar \     http://search.maven.org/remotecontent?filepath=kg/apc/cmdrunner/${CMDRUNNER_VERSION}/cmdrunner-${CMDRUNNER_VERSION}.jar \  && curl --location --silent --show-error --output ${JMETER_HOME}/lib/jmeter-plugins-webdriver-4.9.1.0.jar \     https://repo1.maven.org/maven2/kg/apc/jmeter-plugins-webdriver/4.9.1.0/jmeter-plugins-webdriver-4.9.1.0.jar \  && curl --location --silent --show-error --output ${JMETER_HOME}/lib/selenium-remote-driver-4.9.1.jar \     https://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-remote-driver/4.9.1/selenium-remote-driver-4.9.1.jar \  && curl --location --silent --show-error --output ${JMETER_HOME}/lib/selenium-api-4.21.0.jar \     https://repo1.maven.org/maven2/org/seleniumhq/selenium/selenium-api/4.21.0/selenium-api-4.21.0.jar  RUN ln -sf /usr/bin/firefox-esr /usr/bin/firefox  RUN java -cp ${JMETER_HOME}/lib/ext/jmeter-plugins-manager-${JMETER_PLUGINS_MANAGER_VERSION}.jar org.jmeterplugins.repository.PluginManagerCMDInstaller  RUN curl -fL -o /tmp/geckodriver.tar.gz \          https://github.com/mozilla/geckodriver/releases/download/v${GECKODRIVER_VERSION}/geckodriver-v${GECKODRIVER_VERSION}-linux64.tar.gz \  && tar -xzf /tmp/geckodriver.tar.gz -C /tmp/ \  && chmod +x /tmp/geckodriver \  && mv /tmp/geckodriver ${JMETER_HOME}/bin  RUN ./PluginsManagerCMD.sh install jpgc-webdriver webdriver-sampler jmeter-plugins-webdriver selenium-remote  COPY launch.sh /usr/local/bin RUN chmod +x /usr/local/bin/launch.sh    ENTRYPOINT ["/usr/local/bin/launch.sh"] 

Скрипт использует запускалку launch.sh, ее мы создаем рядом с таким содержимым:

#!/bin/bash  export JVM_ARGS="-Xms1024m -Xmx8G -XX:MaxMetaspaceSize=1024m" echo "JVM_ARGS=${JVM_ARGS}" echo "/opt/apache-jmeter-5.6.3/bin/jmeter args=$@"  jmeter $@

Меняя параметры JVM_ARGS можно подкрутить лимиты выполнения тестов.

Собрать контейнер в образ с меткой ffjmeter можно командой:

docker build -t docker/ffjmeter .

А для запуска тестов удобно сделать еще один скриптик run_tests.sh:

#!/bin/bash  NOW=$(date '+%Y-%m-%d_%H_%M'); JMX_FILENAME="jmix-benchmark.jmx"; VOLUME_PATH="/home/${USER}/projects/testjmix-jmeter"; JMETER_PATH="/root/jmeter";  docker run --name "jmeter_${NOW}" --volume "${VOLUME_PATH}":"${JMETER_PATH}" docker/ffjmeter -n -t "${JMETER_PATH}/${JMX_FILENAME}" -l "${JMETER_PATH}/result_${NOW}.jtl" -j "${JMETER_PATH}/jmeter_${NOW}.log"  docker rm jmeter_${NOW}

VOLUME_PATH указывает на каталог хостового компьютера в котором мы разрабатываем JMeter-тесты, а JMX_FILENAME определяет какой именно тест-кейс запускать.

После прогона тестов контейнер будет удаляться, а логи и отчет оставаться в каталоге с проектом.

Используя JTL-файл отчета можно построить HTML-страничку с наглядно представленными результатами.

Для этого в первом поле формы надо выбрать оставшийся от работы тестового контейнера CSV/JTL-файл отчета, во второй можно указать пустой(но существующий) файл и в третьем — пустой каталог.

Таким образом, у теперь нас есть контейнер, который подойдет как для разработки тестов, так и для их выполнения в среде неприрывной доставки CI/CD. Разработку можно вести не выходя из сред разработки тестов JMeter и браузера. А при помощи настроенного мониторинга мы можем вживую наблюдать изменения показателей происходящие при работе тестов. Сочетая использование среды разработки тестов с графическим интерфейсом и их запускалок в контейнерах мы можем как разделить нагрузку между компьютером разработки и серверами, так и решить проблему установки различных версий браузеров и другого необходимого программного обеспечения на компьютере разработчика.


ссылка на оригинал статьи https://habr.com/ru/articles/825402/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *