Added to the load test script documentation and the new option of verbose mode, which triggers also the load debug, at the time only tracking the php service's rating requests. Rating requests are logged into a log file and formatted into a CSV file

This commit is contained in:
Teresa Noviello
2021-11-01 12:11:58 +00:00
parent b1adf4c650
commit e4ec129e4f
8 changed files with 128 additions and 5 deletions

4
.gitignore vendored
View File

@@ -2,4 +2,6 @@
.DS_Store .DS_Store
*-private.* *-private.*
vendor/ vendor/
Gopkg.lock Gopkg.lock
load-gen/utilities/__pycache__
load-gen/logs/php*

View File

@@ -16,6 +16,7 @@ RUN pip install -r requirements.txt
COPY entrypoint.sh /load/ COPY entrypoint.sh /load/
COPY robot-shop.py /load/ COPY robot-shop.py /load/
COPY utilities /load/
CMD ["./entrypoint.sh"] CMD ["./entrypoint.sh"]

View File

@@ -35,6 +35,8 @@ else
unset TIME unset TIME
fi fi
mkdir -p logs;
echo "Starting $CLIENTS clients for ${RUN_TIME:-ever}" echo "Starting $CLIENTS clients for ${RUN_TIME:-ever}"
if [ "$SILENT" -eq 1 ] if [ "$SILENT" -eq 1 ]
then then

View File

@@ -15,6 +15,9 @@ HOST="http://localhost:8080"
# Error flag # Error flag
ERROR=0 ERROR=0
# Verbose mode
LOAD_DEBUG=1
# Daemon flag # Daemon flag
DAEMON="-it" DAEMON="-it"
SILENT=0 SILENT=0
@@ -24,7 +27,8 @@ USAGE="\
loadgen.sh loadgen.sh
e - error flag e - error flag
d - run in background v - verbose mode. It implies the setting of LOAD_DEBUG and of error flag
d - run in background. It implies the setting of SILENT mode, so the stdout will not be floaded. If -v is used, the load debug will still be printed in the stdout, even if the stdout is suppressed.
n - number of clients n - number of clients
t - time to run n clients t - time to run n clients
h - target host h - target host
@@ -42,12 +46,16 @@ eval $(egrep '[A-Z]+=' ../.env)
echo "Repo $REPO" echo "Repo $REPO"
echo "Tag $TAG" echo "Tag $TAG"
while getopts 'edn:t:h:' OPT while getopts 'edvn:t:h:' OPT
do do
case $OPT in case $OPT in
e) e)
ERROR=1 ERROR=1
;; ;;
v)
LOAD_DEBUG=1
ERROR=1
;;
d) d)
DAEMON="-d" DAEMON="-d"
SILENT=1 SILENT=1
@@ -92,9 +100,14 @@ do
esac esac
done done
rm -rf logs/*
docker run \ docker run \
$DAEMON \ $DAEMON \
--name loadgen \ --name loadgen \
--volume ${PWD}/robot-shop.py:/load/robot-shop.py \
--volume ${PWD}/entrypoint.sh:/load/entrypoint.sh \
--volume ${PWD}/utilities:/load/utilities \
--volume ${PWD}/logs:/load/logs \
--rm \ --rm \
--network=host \ --network=host \
-e "HOST=$HOST" \ -e "HOST=$HOST" \
@@ -102,5 +115,6 @@ docker run \
-e "RUN_TIME=$RUN_TIME" \ -e "RUN_TIME=$RUN_TIME" \
-e "SILENT=$SILENT" \ -e "SILENT=$SILENT" \
-e "ERROR=$ERROR" \ -e "ERROR=$ERROR" \
-e "LOAD_DEBUG=$LOAD_DEBUG" \
${REPO}/rs-load:${TAG} ${REPO}/rs-load:${TAG}

View File

View File

@@ -2,8 +2,11 @@ import os
import random import random
from locust import HttpUser, task, between from locust import HttpUser, task, between
from utilities.CSVWriter import CSVWriter
from random import choice from random import choice
from random import randint from random import randint
from sys import argv
from datetime import date
class UserBehavior(HttpUser): class UserBehavior(HttpUser):
wait_time = between(2, 10) wait_time = between(2, 10)
@@ -26,9 +29,26 @@ class UserBehavior(HttpUser):
"60.242.161.215" "60.242.161.215"
] ]
phplog = None
php_services_api_prefix = '/api/ratings/api'
php_service_rate = '/rate'
php_service_fetch = '/fetch'
php_fieldnames = ['REQTYPE', 'SERVICE', 'INPUT', 'HEADER']
my_csv_writer = None
def on_start(self): def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """ """ on_start is called when a Locust start before any task is scheduled """
print('Starting') print('Starting')
print('LOAD_DEBUG: ', os.environ.get("LOAD_DEBUG"))
if os.environ.get('LOAD_DEBUG') == '1':
print("ARGS ARE:\n\"")
print("\n".join(argv))
print('End of ARGS printing\n')
print('on start. php_fieldnames:{}', format(self.php_fieldnames))
self.my_csv_writer = CSVWriter("logs/php_services_calls.csv", self.php_fieldnames)
self.phplog = open("logs/phplog.txt", "a")
@task @task
def login(self): def login(self):
@@ -44,6 +64,7 @@ class UserBehavior(HttpUser):
@task @task
def load(self): def load(self):
self.phplog.write('new user, new load task\n')
fake_ip = random.choice(self.fake_ip_addresses) fake_ip = random.choice(self.fake_ip_addresses)
self.client.get('/', headers={'x-forwarded-for': fake_ip}) self.client.get('/', headers={'x-forwarded-for': fake_ip})
@@ -61,12 +82,31 @@ class UserBehavior(HttpUser):
if item['instock'] != 0: if item['instock'] != 0:
break break
self.phplog.write('fake_ip: {}\n'.format(fake_ip))
headers={'x-forwarded-for': fake_ip}
# vote for item # vote for item
if randint(1, 10) <= 3: if randint(1, 10) <= 3:
self.client.put('/api/ratings/api/rate/{}/{}'.format(item['sku'], randint(1, 5)), headers={'x-forwarded-for': fake_ip}) ratevalue = randint(1, 5)
put_rate_api_str = '{}{}/{}/{}'.format(self.php_services_api_prefix, self.php_service_rate, item['sku'], ratevalue )
if os.environ.get('LOAD_DEBUG') == '1':
self.phplog.write('ratevalue: {}\n'.format(ratevalue))
self.phplog.write('item: {}\n'.format(item['sku']))
self.phplog.write('put_rate_api_str: {}\n'.format(put_rate_api_str))
self.phplog.flush()
self.my_csv_writer.writerow({'REQTYPE': 'PUT', 'SERVICE': '{}'.format(self.php_service_rate), 'INPUT': '{}/{}'.format(item['sku'], ratevalue ), 'HEADER': '{}'.format(headers)})
self.client.put(put_rate_api_str, headers)
self.client.get('/api/catalogue/product/{}'.format(item['sku']), headers={'x-forwarded-for': fake_ip}) self.client.get('/api/catalogue/product/{}'.format(item['sku']), headers={'x-forwarded-for': fake_ip})
self.client.get('/api/ratings/api/fetch/{}'.format(item['sku']), headers={'x-forwarded-for': fake_ip})
get_rate_api_str = '{}{}/{}'.format(self.php_services_api_prefix, self.php_service_fetch, item['sku'])
if os.environ.get('LOAD_DEBUG') == '1':
self.phplog.write('item: {}\n'.format(item['sku']))
self.phplog.write('get_rate_api_str: {}\n'.format(get_rate_api_str))
self.phplog.flush()
self.my_csv_writer.writerow({'REQTYPE': 'GET', 'SERVICE': '{}'.format(self.php_service_fetch), 'INPUT': '{}'.format(item['sku']), 'HEADER': '{}'.format(headers) })
self.client.get(get_rate_api_str, headers={'x-forwarded-for': fake_ip})
self.client.get('/api/cart/add/{}/{}/1'.format(uniqueid, item['sku']), headers={'x-forwarded-for': fake_ip}) self.client.get('/api/cart/add/{}/{}/1'.format(uniqueid, item['sku']), headers={'x-forwarded-for': fake_ip})
cart = self.client.get('/api/cart/cart/{}'.format(uniqueid), headers={'x-forwarded-for': fake_ip}).json() cart = self.client.get('/api/cart/cart/{}'.format(uniqueid), headers={'x-forwarded-for': fake_ip}).json()

View File

@@ -0,0 +1,19 @@
import csv
# Refs:
# [Tutorial1] https://rharshad.com/locust-load-test/
class CSVReader:
def __init__(self, filepath):
try:
file = open(filepath)
except TypeError:
pass
self.file = file
self.reader = csv.reader(file)
def __next__(self):
try:
return next(self.reader)
except StopIteration:
self.file.seek(0, 0)
return next(self.reader)

View File

@@ -0,0 +1,45 @@
import os
import csv
from datetime import date
class CSVWriter:
def __init__(self, filepath, custom_fields=[]):
if os.environ.get('LOAD_DEBUG') == '1':
print('CSVWriter init/args: filepath:\'{}\' custom_fields\'{}\''.format(filepath,custom_fields))
try:
file = open(filepath,'a')
except TypeError as typeErr:
print(f"CSVWriter init/Unexpected {err=}, {type(typeErr)=}")
raise
print('CSVWriter init/pass')
self.file = file
if not custom_fields:
print('CSVWriter init/empty params')
else:
self.fieldnames = custom_fields
try:
self.writer = csv.DictWriter(self.file, self.fieldnames)
self.writer.writeheader()
except BaseException as err:
print(f"CSVWriter init/Unexpected {err=}, {type(err)=}")
raise
self.file.flush()
def writerow(self, row: dict):
if os.environ.get('LOAD_DEBUG') == '1':
print('CSVWriter/writerow/args: {}',format(row))
if not row:
print('CSVWriter/writerow/empty arg')
else:
try:
self.writer.writerow(row)
self.file.flush()
except BaseException as err:
print(f"CSVWriter/writerow/Unexpected {err=}, {type(err)=}")
raise