Locust – testy wydajności w Pythonie

Locust – testy wydajności w Pythonie
Redaktorzy testywydajnosci.pl po raz kolejny przygotowali ciekawy i merytoryczny artykuł, tym razem poświęcony frameworkowi Locust. Poniżej pełen artykuł, zapraszamy do lektury.
 

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:

https://www.rottentomatoes.com/showtimes/ (3.3M potential traffic)
https://www.rottentomatoes.com/browse/opening/ (2.4M)
https://www.rottentomatoes.com/top/bestofrt/ (2.2M)
https://www.rottentomatoes.com/top/ (1.4M)
https://www.rottentomatoes.com/ (1.1M).

 

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ń