Небольшой, Но Очень Полезный Патч В Selenium

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

Все они протестированы как в тестовой среде, так и в средах, приближенных к реальным.

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

Около полугода назад тестов и задач было так много, что наша небольшая Selenium-ферма начала буквально «захлебываться» в час пик запросами на новую сессию Firefox или Chrome. Выглядело это примерно так: Selenium Grid создает очередь сессий, ожидающих свободного браузера.

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



Небольшой, но очень полезный патч в Selenium

На тот момент максимальное количество узлов, разделенных между Firefox, Chrome, Internet Explorer и PhantomJS, составляло около 200. Одним из решений проблемы, которая пришла мне в голову, было отслеживать количество свободных узлов перед запуском теста и «держать » тесты в методе настройки (), пока свободных узлов недостаточно.

В примечаниях к изменениям Selenium В свое время проскочил функционал получения информации из грида с помощью HTTP-запросов.

Доступные команды можно просмотреть непосредственно в коде сервлета HubStatusServlet.java .

Их всего три: конфигурация (конфигурация), slotCounts (количество слотов) и новыйSessionRequestCount (количество сессий в очереди на прием браузера).

Формат запроса довольно хитрый: это GET-запрос, но с телом.

Для экспериментов воспользуемся cURL и проверим, что возвращают эти команды:

  
  
  
  
  
  
  
  
  
   

$ curl -XGET http://selenium1:5555/grid/api/hub -d '{"configuration":[]}'



{ 'success': true, 'port': '5555', 'hubConfig': '/usr/local/selenium-rc/grid.json', 'host': 'selenium1.d3', 'servlets': 'org.openqa.grid.web.servlet.HubStatusServlet', 'cleanUpCycle': 5000, 'browserTimeout': 120000, 'newSessionWaitTimeout': 30000, 'capabilityMatcher': 'org.openqa.grid.internal.utils.DefaultCapabilityMatcher', 'prioritizer': null, 'throwOnCapabilityNotPresent': true, 'nodePolling': 5000, 'maxSession': 5, 'role': 'hub', 'jettyMaxThreads': - 1, 'timeout': 90000 }



$ curl -XGET http://selenium1:5555/grid/api/hub -d '{"configuration":["slotCounts"]}'



{ 'success': true, 'slotCounts': { 'free': 50, 'total': 196 } }



curl -XGET http://selenium1:5555/grid/api/hub -d '{"configuration":["newSessionRequestCount"]}'



{ 'success': true, 'newSessionRequestCount': 3 }

Все наши тесты для Selenium написаны на PHP, на котором аналогичный запрос будет выглядеть так:

<Эphp $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, ' http://selenium1:5555/grid/api/hub '); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($curl, CURLOPT_POSTFIELDS, '{"configuration":["slotCounts"]}'); curl_exec($curl);

В принципе, запросив общее количество слотов и количество сессий ожидания в тестовом методе setUp(), можно начать ожидание.

Но это не очень удобно, если у вас неравномерно выделены ресурсы разным браузерам.

Например, у нас примерно на треть больше узлов для Firefox, чем для Google Chrome. А Internet Explorer и MS Edge занимают всего около 10 узлов (да и то их можно разделить по версиям).

Получается, что свободных нод специально для Chrome уже может не быть, хотя в Selenium Grid говорят, что свободные ноды еще есть.

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

Сам патч не очень большой , вот его код:

diff --git a/java/server/src/org/openqa/grid/web/servlet/HubStatusServlet.java b/java/server/src/org/openqa/grid/web/servlet/HubStatusServlet.java index 8b9c578.550c5db 100644 --- a/java/server/src/org/openqa/grid/web/servlet/HubStatusServlet.java +++ b/java/server/src/org/openqa/grid/web/servlet/HubStatusServlet.java @@ -29,10 +29,12 @@ import org.openqa.grid.internal.Registry; import org.openqa.grid.internal.RemoteProxy; import org.openqa.grid.internal.TestSlot; +import org.openqa.selenium.remote.CapabilityType; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -128,6 +130,11 @@ private JsonObject getResponse(HttpServletRequest request) throws IOException { paramsToReturn.remove("slotCounts"); } + if (paramsToReturn.contains("browserSlotsCount")) { + res.add("browserSlotsCount", getBrowserSlotsCount()); + paramsToReturn.remove("browserSlotsCount"); + } + for (String key : paramsToReturn) { Object value = allParams.get(key); if (value == null) { @@ -169,6 +176,53 @@ private JsonObject getSlotCounts() { return result; } + private JsonObject getBrowserSlotsCount() { + int freeSlots = 0; + int totalSlots = 0; + + Map<String, Integer> freeBrowserSlots = new HashMap<>(); + Map<String, Integer> totalBrowserSlots = new HashMap<>(); + + for (RemoteProxy proxy : getRegistry().

getAllProxies()) { + for (TestSlot slot : proxy.getTestSlots()) { + String + slot_browser_name = + slot.getCapabilities().

get(CapabilityType.BROWSER_NAME).

toString().

toUpperCase(); + if (slot.getSession() == null) { + if (freeBrowserSlots.containsKey(slot_browser_name)) { + freeBrowserSlots.put(slot_browser_name, freeBrowserSlots.get(slot_browser_name) + 1); + } else { + freeBrowserSlots.put(slot_browser_name, 1); + } + freeSlots += 1; + } + if (totalBrowserSlots.containsKey(slot_browser_name)) { + totalBrowserSlots.put(slot_browser_name, totalBrowserSlots.get(slot_browser_name) + 1); + } else { + totalBrowserSlots.put(slot_browser_name, 1); + } + totalSlots += 1; + } + } + + JsonObject result = new JsonObject(); + + for (String str : totalBrowserSlots.keySet()) { + JsonObject browser = new JsonObject(); + browser.addProperty("total", totalBrowserSlots.get(str)); + if (freeBrowserSlots.containsKey(str)) { + browser.addProperty("free", freeBrowserSlots.get(str)); + } else { + browser.addProperty("free", 0); + } + result.add(str, browser); + } + + result.addProperty("total", totalSlots); + result.addProperty("total_free", freeSlots); + return result; + } + private JsonObject getRequestJSON(HttpServletRequest request) throws IOException { JsonObject requestJSON = null; BufferedReader rd = new BufferedReader(new InputStreamReader(request.getInputStream()));

Мне до сих пор немного стыдно, что я не подготовил его по всем правилам (с тестами и т.п.

) и не отправил в SeleniumHQ. Обещаю, что сделаю это в ближайшее время, если читатели найдут функционал полезным :) Применяем патч к локальной копии исходников Selenium, собираем собственную сборку Selenium-grid ( вот подробная инструкция по сборке ).

Если не хотите заморачиваться со сборкой, можете попробовать то, что я уже собрал: https://github.com/leipreachan/misc_scripts/tree/master/blob/selenium Теперь перезапускаем selenium-grid и смотрим, какие значения он возвращает:

curl -XGET http://selenium1:5555/grid/api/hub -d '{"configuration":["browserSlotsCount"]}'

и результат:

{ 'success': true, 'browserSlotsCount': { 'IEXPLORER': { 'total': 4, 'free': 3 }, 'FIREFOX': { 'total': 95, 'free': 50 }, 'MICROSOFTEDGE': { 'total': 1, 'free': 1 }, 'PHANTOMJS': { 'total': 20, 'free': 20 }, 'CHROME': { 'total': 76, 'free': 75 }, 'total': 196, 'total_free': 149 } }

Итак, теперь мы знаем, какие бесплатные браузеры и в каком количестве есть в Selenium Grid. Осталось немного подкорректировать метод setup() (или аналогичный):

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

Учитывая, что у нас автоматически выполняется несколько сотен тестов, это значительно упростило жизнь всем, кто занимается тестированием.




Артём Солдаткин Ведущий инженер по обеспечению качества, Badoo Теги: #автоматизация тестирования #Selenium #seleniumgrid #тестирование ИТ-систем #java #тестирование веб-сервисов #тестирование мобильных приложений
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.