W tym wpisie chcę odpowiedzieć na pytania, jak wygląda konfiguracja Selenium Grid i czym to narzędzie właściwie jest. Selenium Grid jest jednym z gamy produktów Selenium. Jego celem jest dostarczenie rozwiązania, które pozwoli w prosty sposób wykonywać testy równolegle na różnych maszynach i konfiguracjach.
Jak to działa?
Rozwiązanie Selenium Grid składa się z Hub’a, który rozdziela testy i Node’ów, które je wykonują. Testy są kierowane do Hub’a, który posiada listę zarejestrowanych (podpiętych do niego) Node’ów. To do nich właśnie kieruje komendy, które Node’y mają wykonać. Dzięki takiemu rozwiązaniu możemy uruchamiać testy równolegle, na różnych systemach operacyjnych, różnych przeglądarkach czy ich wersjach.
Korzyści i funkcjonalności:
- Skalowalność – zwiększenie wydajności naszego Selenium Grid’a wymaga jedynie dołożenia nowej maszyny i zainstalowania na niej Node’a.
- Load balancing – Hub sam zajmuje się równoważeniem obciążenia i odpowiednio rozkłada je na Node’y.
- Równoległe wykonanie testów – znaczne skrócenie czasu trwania testów poprzez wykonywanie ich na kilku maszynach w tym samym czasie.
- Łatwe zarządzanie środowiskiem testowym – konfiguracja możliwości poszczególnych Node’ów (np. wspierane przeglądarki czy maksymalna liczba ich instancji) jest bardzo prosta.
- Testowanie na różnych środowiskach (cross-platform testing) – możliwość testowania na różnych systemach operacyjnych, różnych przeglądarkach i ich wersjach.
Architektura Selenium Grid:
Selenium Grid składa się z Hub’a i co najmniej jednego Node’a.
Hub to punkt centralny każdego Grida. Miejsce, do którego zostają wysłane nasze testy. Każdy Grid składa się z dokładnie jednego Huba. Instrukcje (testy) najczęściej trafiają do niego z serwera Continuous Integration, który zleca ich wykonanie. Mogą też zostać wysłane z komputera osoby piszącej testy, itp. Hub, po otrzymaniu instrukcji, przekazuje je do Node’ów, którymi zarządza.
Node jest to miejsce, gdzie testy są faktycznie wykonywane. To tutaj uruchamiane są przeglądarki. Każdy node podłączając się do Huba informuje go o swoich możliwościach. Możliwości te (tzw. capabilities) możemy ustawić inne dla każdego z Node’ów. Może to być np. maksymalna liczba otwartych okien przeglądarki, informacja jakie przeglądarki mogą zostać obsłużone, itp. Jest to przydatne szczególnie, gdy maszyny, które wykonują testy mają różną specyfikację.
Konfiguracja Selenium Grid:
Do uruchomienia Grida będzie Ci potrzebny Selenium Server Standalone, który można pobrać z oficjalnej strony Selenium
1. Uruchomienie Hub’a:
Otwieramy wiersz poleceń i uruchamiamy plik poleceniem:
java -jar selenium-server-standalone-3.141.59.jar -role hub
„-role hub” oznacza, że uruchamiamy go w trybie Hub. Po wpisaniu komendy w linii poleceń powinny wyświetlić takie logi:
java -jar selenium-server-standalone-3.141.59.jar -role hub
19:37:20.156 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
19:37:20.278 INFO [GridLauncherV3.lambda$buildLaunchers$5] - Launching Selenium Grid hub on port 4444
2020-03-15 19:37:20.774:INFO::main: Logging initialized @1027ms to org.seleniumhq.jetty9.util.log.StdErrLog
19:37:21.001 INFO [Hub.start] - Selenium Grid hub is up and running
19:37:21.003 INFO [Hub.start] - Nodes should register to http://<<<TWÓJ ADRES IP>>>:4444/grid/register/
19:37:21.004 INFO [Hub.start] - Clients should connect to http://<<<TWÓJ ADRES IP>>>:4444/wd/hub
Od tej pory Hub jest uruchomiony i domyślnie nasłuchuje na porcie 4444. Jak widać w logach, Node’y powinny się rejestrować do Huba pod adresem http://<<<TWÓJ ADRES IP>>>:4444/grid/register/
Klienci (np. serwer CI lub Twój komputer) komunikują się z Hub’em pod adresem http://<<<ADRES IP>>>:4444/wd/hub
2. Uruchomienie Node’a:
Uruchomienie testów omówimy na przykładzie przeglądarki Chrome. Na początek musimy pobrać Chromedriver, czyli sterownik do przeglądarki Chrome. Plik umieszczamy w folderze, gdzie znajduje się Selenium Server i w tej lokalizacji ponownie otwieramy wiersz poleceń. Uruchomienie Node’a przebiega podobnie do Hub’a i robimy to komendą:
java -Dwebdriver.chrome.driver=chromedriver.exe -jar selenium-server-standalone-3.141.59.jar -role node -hub http://localhost:4444/grid/register
Uwaga: Jeśli Node’a uruchamiasz na innej maszynie niż Hub’a, wówczas „localhost” w adresie należy zamienić na adres IP maszyny, na której uruchomiony jest Hub.
java -Dwebdriver.chrome.driver=chromedriver.exe -jar selenium-server-standalone-3.141.59.jar -role node -hub http://localhost:4444/grid/register
20:01:54.207 INFO [GridLauncherV3.parse] - Selenium server version: 3.141.59, revision: e82be7d358
20:01:54.330 INFO [GridLauncherV3.lambda$buildLaunchers$7] - Launching a Selenium Grid node on port 17245
2020-03-15 20:01:54.431:INFO::main: Logging initialized @425ms to org.seleniumhq.jetty9.util.log.StdErrLog
20:01:54.691 INFO [WebDriverServlet.<init>] - Initialising WebDriverServlet
20:01:54.763 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 17245
20:01:54.763 INFO [GridLauncherV3.lambda$buildLaunchers$7] - Selenium Grid node is up and ready to register to the hub
20:01:54.802 INFO [SelfRegisteringRemote$1.run] - Starting auto registration thread. Will try to register every 5000 ms.
20:01:55.200 INFO [SelfRegisteringRemote.registerToHub] - Registering the node to the hub: http://localhost:4444/grid/register
20:01:55.251 INFO [SelfRegisteringRemote.registerToHub] - The node is registered to the hub and ready to use
Grid Console
Status naszego Grida możemy sprawdzić w konsoli dostępnej pod adresem http://localhost:4444/grid/console. Spójrzmy na parametry uruchomionego Node’a. W zakładce „Browsers” wyświetlone są ikonki różnych przeglądarek (w moim przypadku jest to 1x Safari, 5x Firefox i 5x Chrome). Jest to nic innego jak wspomniane wcześniej możliwości Node’a (Capabilities).
Są to wartości domyślne, ale możemy je zmienić – to omówiliśmy w dalszej części artykułu. Liczba ikon oznacza ile instancji danej przeglądarki może obsłużyć nasz Node. Przejdźmy do zakładki „Configuration”, gdzie znajduje się szczegółowa specyfikacja naszego Node’a.
Widzimy tutaj m.in. atrybut „maxSession: 5” oraz różne wartości „maxInstances” dla różnych przeglądarek. Co to oznacza?
- „maxSession” to maksymalna liczba sesji, czyli równolegle wykonujących się testów na tej maszynie.
- „maxInstances” to liczba mówiąca, ile instancji danej przeglądarki może być uruchomione w tym samym czasie.
Co w sytuacji, gdy mamy ustawione maxSession = 5, a maxInstances dla Chrome = 10? Bardziej istotna jest maksymalna liczba sesji, w związku z czym nie uruchomi się ich więcej niż 5.
Pozostałe parametry:
- port – port na którym jest uruchamiany Hub lub Node. Hub domyślnie uruchamiany jest na porcie 4444, a Node losowym, wolnym porcie (w moim przypadku był to 17245).
- timeout – oznacza czas w sekundach, po którym Hub automatycznie zwalnia Node’a, który nie otrzymał w tym czasie żadnego requestu do wykonania. Wówczas Node będzie gotowy by przyjmować kolejny test do wykonania. Parametr ten jest ważny, ponieważ pozwala czyścić naszego Grida bez konieczności ręcznej interwencji.
- maxSession – określa maksymalną liczbę wszystkich przeglądarek, które mogą działać równolegle na danym Node.
- browser – tym parametrem możemy określać maksymalną liczbę instancji, rodzaj oraz wersję przeglądarki, itp.
- registerCycle – czas w milisekundach określający z jaką częstotliwością uruchomiony Node będzie próbował łączyć się z Hub’em. Zmniejszenie tego parametru pozwala przykładowo uruchomić ponownie Huba bez konieczności ponownego uruchamiania Node’ów.
Dodatkowa konfiguracja Selenium Grid na przykładzie zmiany portów
Zacznijmy od Huba. Zamknij okno, w którym jest on uruchomiony, przejdź do wiersza poleceń, do folderu z Selenium Server i wprowadź komendę, która uruchomi Hub na porcie 4445.
java -jar selenium-server-standalone-3.141.59.jar -role hub -port 4445
Spójrzmy w takim razie na naszego Node’a, któremu podaliśmy (w komendzie uruchamiającej), że adres Huba to http://localhost:4444/grid/register. Jak widać pojawiają się na nim logi mówiące, że nie może się połączyć z Hubem.
INFO [SelfRegisteringRemote$1.run] - Couldn't register this node: The hub is down or not responding: Failed to connect to localhost/0:0:0:0:0:0:0:1:4444
Spróbujmy to naprawić. Zamknij okno Node’a i wykonaj komendę, w której zmienimy adres Huba (z nowym portem) oraz ustawiamy port Node’a na 4446.
java -Dwebdriver.chrome.driver=chromedriver.exe -jar selenium-server-standalone-3.141.59.jar -role node -hub http://localhost:4445/grid/register -port 4446
W efekcie Selenium Grid został uruchomiony na wskazanych przez nas portach.
Debugowanie
W sytuacji, gdy potrzebujemy przeanalizować działanie naszego Grida, możemy to zrobić posługując się logami na dwa sposoby:
1. Zapisywanie logów do pliku
Należy do komendy uruchamiającej Hub’a lub Node’a dodać argument „-log” i wskazać plik, do którego logi mają być zapisywane, np.:
java -jar selenium-server-standalone-3.141.59.jar -role hub -log log.txt
2. Wyświetlanie logów w terminalu
Uruchom Hub’a lub Node’a z argumentem „-debug”. Wówczas logi będą wyświetlane na terminalu:
java -jar selenium-server-standalone-3.141.59.jar -role hub -debug
Kiedy warto używać Selenium Grid?
Pierwszym, oczywistym powodem jest sytuacja, w której chcemy uruchamiać testy na różnych przeglądarkach, w różnych środowiskach, itp.
Ponadto użycie Selenium Grid pozwala nam skrócić czas wykonania testów poprzez możliwość rozdzielenia ich na wiele maszyn i równolegle uruchamianie.
Podsumowanie
Mam nadzieję, że teraz już wiesz, nam czym polega konfiguracja Selenium Grid i kiedy warto użyć tego narzędzia. W następnym wpisie dotyczącym Selenium Grid omówimy możliwości konfiguracji przez zewnętrzny plik konfiguracyjny JSON oraz przedstawimy parę sztuczek, które przydają się w celu poprawy stabilności działania naszego Grida oraz zapewnienia działania bez potrzeby naszej ingerencji.
Tematykę Selenium Grid i Continuous Integration dokładnie omawiamy na jednym z naszych kursów – Tester Automatyzujący, na który serdecznie zapraszamy każdego, kto chciałby rozpocząć przygodę z automatyzacją testów.
Linki:
https://www.selenium.dev/documentation/en/grid/setting_up_your_own_grid/
https://github.com/SeleniumHQ/selenium/wiki/Grid2#configuring-the-nodes-by-json