Locust (z ang. szarańcza) to otwarte oprogramowanie, framework dla języka Python pomocny w przeprowadzaniu testów wydajnościowych. Umożliwia nam wypuszczenie, na stronę internetową, chmary wygłodniałej szarańczy (równolegle symulowanych użytkowników) oraz obserwowanie spustoszenia, jakie ze sobą niesie. Robali (użytkowników) mogą być setki, tysiące, a nawet miliony (uwaga - to niebezpieczne).
Strona domowa projektu: https://locust.io
Locust pozwala na:
- pisanie scenariuszy testów w eleganckim języku Python
- rozproszenie testów na wiele maszyn
- obserwowanie analizy symulacji w uwodzicielskim interfejsie graficznym
- tworzenie własnych klientów w celu testowania różnych systemów.
INSTALACJA
Locust możemy zainstalować w systemie operacyjnym Windows oraz Linuks za pomocą narzędzia PIP.
pip install locustio
Więcej szczegółów na: https://docs.locust.io/en/latest/installation.html
PRZYKŁAD UŻYCIA
Aby uruchomić test, wystarczy napisać scenariusz w pliku *.py wg konwencji opisanych w dokumentacji https://docs.locust.io/en/latest/writing-a-locustfile.html, a następnie uruchomić narzędzie w wierszu poleceń.
Oto przykład prostego scenariusza inwazji portalu filmowego:
from locust import HttpLocust, TaskSet, task class WebsiteTasks(TaskSet): @task(3) def index(self): self.client.get("/") @task(1) def top_movies(self): self.client.get("/top") class WebsiteUser(HttpLocust): task_set = WebsiteTasks host = "http://www.rottentomatoes.com" min_wait = 2 * 1000 max_wait = 6 * 1000
Definiujemy adres strony podjętej testom.
host = "http://www.rottentomatoes.com"
Definiujemy zadanie odwiedzenia strony głównej.
@task(3) def index(self): self.client.get("/")
Definiujemy zadanie odwiedzenia podstrony http://www.rottentomatoes.com/top.
@task(1) def top_movies(self): self.client.get("/top")
Dekoratory @task definiują wagi dla poszczególnych zadań
@task(3) ... @task(1)
Definiujemy minimalny i maksymalny czas (w milisekundach) oczekiwania użytkownika na wykonanie kolejnych zadań. Wartość ta będzie losowana z przedziału 2-6 s.
min_wait = 2 * 1000 max_wait = 6 * 1000
Przygotowany scenariusz należy zapisać jako plik *.py (domyślna nazwa to locustfile.py), a następnie przejść do katalogu, w którym on się znajduje używając wiersza poleceń. Przed uruchomieniem skryptu, warto sprawdzić rozkład procentowy naszych wag poleceniem:
locust --show-task-ratio
Skrypt można uruchomić komendą:
locust
Jeśli nie zdefiniowaliśmy adresu testowanej strony w naszym scenariuszu i nie użyliśmy domyślnej nazwy skryptu, możemy podać te dane uruchamiając narzędzie z parametrami:
locust -f <ścieżka_do_skryptu> -H <adres_strony>
Po zweryfikowaniu skryptu i jego parametryzacji pozostało nam tylko uruchomić interfejs graficzny, rozsiąść się w fotelu i obserwować dzieło zniszczenia z niewzruszoną miną psychopaty. Aby to zrobić należy otworzyć w przeglądarce adres http://127.0.0.1:8089 lub http://localhost:8089, pozostawiając uruchomiony proces Locust w tle:
Po podaniu maksymalnej liczby symulowanych użytkowników oraz "hatch rate" (liczby nowych użytkowników tworzonych w jednej sekundzie), zobaczymy statystyki przebiegu naszych testów. Pamiętajmy, że liczba zapytań nie musi równać się liczbie użytkowników online. Niektórzy użytkownicy są zajęci szacowaniem swojego następnego kroku. UWAGA: Wykonywanie testów, na które nie uzyskaliśmy zgody właściciela strony internetowej, jest co najmniej - w złym tonie. Liczba symulowanych użytkownik równa 30 jest symboliczna, symulacja takich rozmiarów raczej nie wywoła przeciążenia serwera, ale może nam się przydać w analizie innych przypadków testów wydajnościowych. W celach edukacyjnych, najlepszym pomysłem jest skonfigurowanie serwera strony internetowej na własnej maszynie, to pozwoli nam na przeprowadzenie zasobożernych symulacji (tysiące użytkowników) z czystym sumieniem.
Narzędzie można także uruchomić bez trybu graficznego, używając komendy:
locust --no-web -c 30 -r 3
Aby nasz scenariusz przybrał na realizmie, możemy zrobić małe badanie dotyczące popularności zawartości naszej strony (polubień FB, potencjalnego ruchu).
Analiza narzędziem https://serpstat.com dostarcza następujących wyników:
Według ankietowanych, najpopularniejsze odpowiedzi to:
Załóżmy również, że po odwiedzeniu strony z rankingiem filmów (https://www.rottentomatoes.com/top/) użytkownik zdecyduje się na odwiedzenie losowej strony z tej listy.
Rozstanie Brada Pitta z Angeliną Jolie nie przeszło bez echa w społeczności gustującej w skandalach (kinomanach). "Czy rozstanie wpłynie na ich karierę?" - ludzie chcą wiedzieć. Załóżmy, że zalogowani użytkownicy chcą odwiedzić profil Brada lub Angeliny aby się o tym przekonać; nie jest nonsensem podejrzewać, że dostęp do tak smakowitych informacji wymaga zalogowania.
Po wprowadzeniu urozmaiceń, scenariusz wygląda następująco:
from locust import HttpLocust, TaskSet, task from lxml import html import requests import random page = requests.get('https://www.rottentomatoes.com/top/') tree = html.fromstring(page.content) top_movies = tree.xpath('//td[@class="middle_col"]//a/@href') class WebsiteTasks(TaskSet): @task(33) def showtimes(self): self.client.get("/showtimes") @task(24) def opening(self): self.client.get("/browse/opening") @task(22) def bestofrt(self): self.client.get("/top/bestofrt") @task(14) def top(self): self.client.get("/top") self.client.get(random.choice(top_movies)) @task(11) def index(self): self.client.get("/") @task(1) def top_movies(self): self.client.post("/api/private/v1.0/user/login", { "username": "tester.versus.world@gmail.com", "password": "Welcome123$" }) self.client.get("/celebrity/{}".format(random.choice(["angelina_jolie", "brad_pitt"]))) class WebsiteUser(HttpLocust): task_set = WebsiteTasks host = "http://www.rottentomatoes.com" min_wait = 3 * 1000 max_wait = 15 * 1000
"Web scraping" - pobieramy linki do stron z profilami filmów wyświetlonych w rankingu https://www.rottentomatoes.com/top/
from lxml import html import requests import random page = requests.get('https://www.rottentomatoes.com/top/') tree = html.fromstring(page.content) top_movies = tree.xpath('//td[@class="middle_col"]//a/@href')
Odwiedzamy stronę wybraną losowo z wcześniej przygotowanej listy.
self.client.get(random.choice(top_movies))
Logujemy się do portalu wysyłając formularz metodą POST.
self.client.post("/api/private/v1.0/user/login", { "username": "xxx", "password": "xxx" })
Odwiedzamy profil Angeliny lub Brada (wybierany losowo).
self.client.get("/celebrity/{}".format(random.choice(["angelina_jolie", "brad_pitt"])))
Tym razem możemy uruchomić skrypt na kilku maszynach, jedna z nich będzie pełniła rolę MASTER, a pozostałe SLAVE. Na komputerze MASTER, na którym będziemy obserwować analizę testów, należy wykonać polecenie:
locust --master
Na komputerach SLAVE, na których powinniśmy mieć kopię naszego skryptu oraz zainstalowanego Pythona i Locust, powinniśmy wykonać następujące polecenie (wskazując adres IP komputera MASTER)
locust --slave --master-host=
W konsoli komputera MASTER zostaniemy poinformowani o dołączeniu komputerów SLAVE:
A oto przebieg analizy:
Interfejs graficzny umożliwia nam również pobranie statystyk w formacie CSV, a to już tylko jeden krok od stworzenia własnego raportu w Excelu, w którym prężące się wykresy wzbudzą poczucie dobrze wykonanej pracy, a może i nawet przyczynią się do uścisku naszej dłoni przez wysoko postawionego menadżera. Więcej przykładów użycia znajdziecie na: https://github.com/locustio/locust/tree/master/examples
Dokumentacja Locust API: https://docs.locust.io/en/latest/api.html
Autor: Marcin Biedroń