В нашей небольшой, но очень динамично развивающейся компании каждый день тестируется более сотни задач.
Все они протестированы как в тестовой среде, так и в средах, приближенных к реальным.
Подавляющее большинство веб-задач проверяются автоматическими тестами, которых у нас немало.
Около полугода назад тестов и задач было так много, что наша небольшая Selenium-ферма начала буквально «захлебываться» в час пик запросами на новую сессию Firefox или Chrome. Выглядело это примерно так: Selenium Grid создает очередь сессий, ожидающих свободного браузера.
Пользователи продолжают запускать автотесты, и эта очередь продолжает расти, но браузеры заняты старыми задачами и сессии «отваливаются» с таймаутом.
На тот момент максимальное количество узлов, разделенных между 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 #тестирование веб-сервисов #тестирование мобильных приложений
-
Обзор Apple Macbook Pro Mc373Ll/A
19 Oct, 24 -
Последнее Слово О Редактировании В Photoshop
19 Oct, 24 -
Решение Дилеммы, Нужен Ли Gmail Для Blogger
19 Oct, 24 -
Новая Фишка - Холодильник-Электростанция
19 Oct, 24 -
Автоматическая Блокировка Экрана В Gnu/Linux
19 Oct, 24 -
Apple Macintosh Перформа 475
19 Oct, 24 -
Google И Его Секреты: Чего Нам Ждать Завтра
19 Oct, 24 -
Инициация
19 Oct, 24 -
Цифровая Дорога / Цифровая Дорога
19 Oct, 24