Skip to content

Commit

Permalink
Merge pull request #190 from kowalpy/master
Browse files Browse the repository at this point in the history
Locust FTP user plugin
  • Loading branch information
cyberw authored Sep 12, 2024
2 parents 2c6d842 + 3a33056 commit 2baf849
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ locust --help
- Kafka ([example](examples/kafka_ex.py))
- MqttUser ([example](examples/mqtt_ex.py))
- RestUser has been removed, as it is [now part of locust core](https://docs.locust.io/en/stable/increase-performance.html#rest)!
- FtpUser ([example_upload](examples/ftp_upload_ex.py), [example_download](examples/ftp_download_ex.py))

## Readers
- Provide ways to get test data into your tests
Expand Down
38 changes: 38 additions & 0 deletions examples/ftp_download_ex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# This script is an example of testing FTP download performance
# It mimics behavior of JMeter FTP sampler
# Author: Marcin Kowalczyk (github.com/kowalpy)

from locust import task, between
from locust_plugins.users.ftp import FtpUser

local_dir = "<local_dir_to_save_downloaded_files_at_your_pc>"
remote_dir = "<subdir_at_ftp_server_where_files_to_download_are>"


class FtpTestDownload(FtpUser):
wait_time = between(1, 2)

def on_start(self):
# on start, you must connect to ftp server
self.client.connect(user="admin", password="admin")
# optionally, you may want to change your working dir at ftp server
self.client.change_working_dir(remote_dir)

@task
def get_file_1(self):
# testing ftp file download
self.client.download_file("example_file.txt", local_dir)

@task
def get_file_2(self):
# testing ftp file download
self.client.download_file("example_file_2.txt", local_dir)

@task
def get_file_incorrect(self):
# testing ftp file download - failure expected
self.client.download_file("example_not_existing.txt", local_dir)

def on_stop(self):
# it is a good practice to close connection once tests are completed
self.client.disconnect()
40 changes: 40 additions & 0 deletions examples/ftp_upload_ex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# This script is an example of testing FTP download performance
# It mimics behavior of JMeter FTP sampler
# Author: Marcin Kowalczyk (github.com/kowalpy)

import os

from locust import task, between
from locust_plugins.users.ftp import FtpUser

local_dir = "<local_dir_containing_files_for_upload_at_your_pc>"
remote_dir = "<subdir_at_ftp_server_where_files_should_be_uploaded>"


class FtpTestUpload(FtpUser):
wait_time = between(5, 10)

def on_start(self):
# on start, you must connect to ftp server
self.client.connect(user="admin", password="admin")
# optionally, you may want to change your working dir at ftp server
self.client.change_working_dir(remote_dir)

@task
def upload_file_1(self):
# testing ftp file download
self.client.upload_file(os.path.join(local_dir, "example_file.txt"))

@task
def upload_file_2(self):
# testing ftp file download
self.client.upload_file(os.path.join(local_dir, "example_file_2.txt"))

@task
def upload_file_incorrect(self):
# testing ftp file download - failure expected
self.client.upload_file(os.path.join(local_dir, "example_not_existing.txt"))

def on_stop(self):
# it is a good practice to close connection once tests are completed
self.client.disconnect()
90 changes: 90 additions & 0 deletions locust_plugins/users/ftp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# This script can be used for testing FTP upload/download performance
# It mimics behavior of JMeter FTP sampler
# Author: Marcin Kowalczyk (github.com/kowalpy)

import datetime
import ftplib
import os
import time

from locust import User


class FtpUser(User):
abstract = True

def __init__(self, environment):
super().__init__(environment)
self.client = FtpClient(environment=environment)


class FtpClient:
def __init__(self, environment):
self.environment = environment
self.connection = None
self.user = None
self.host = None

def connect(self, user='anonymous', password='anonymous@', port=21, timeout=5, tls=False, passive_mode=False):
self.user = user
if tls:
self.connection = ftplib.FTP_TLS()
else:
self.connection = ftplib.FTP()
self.connection.connect(self.environment.host, port, timeout)
self.connection.login(user, password)
self.connection.set_pasv(passive_mode)

def change_working_dir(self, dir_name):
self.connection.cwd(dir_name)

def download_file(self, remote_file_name, local_dir_path):
local_dir_path = os.path.normpath(local_dir_path)
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")
local_file_path = os.path.join(local_dir_path, timestamp)
start_perf_counter = time.perf_counter()
exception = None
response = ""
try:
with (open(local_file_path, 'wb') as local_file):
response = self.connection.retrbinary("RETR " + remote_file_name, local_file.write)
response_time = (time.perf_counter() - start_perf_counter) * 1000
except ftplib.all_errors as e:
exception = e
response_time = (time.perf_counter() - start_perf_counter) * 1000

if exception:
self.environment.events.request.fire(request_type="FTP download", name=remote_file_name,
exception=exception,
response_time=response_time,
response_length=len(str(exception)))
else:
self.environment.events.request.fire(request_type="FTP download", name=remote_file_name,
response_time=response_time,
response_length=len(response))

def upload_file(self, local_file_path):
local_file_path = os.path.normpath(local_file_path)
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S%f")
remote_dir_file = timestamp
start_perf_counter = time.perf_counter()
exception = None
response = ""
try:
response = self.connection.storbinary("STOR " + remote_dir_file, open(local_file_path, "rb"))
except ftplib.all_errors as e:
exception = e
response_time = (time.perf_counter() - start_perf_counter) * 1000

if exception:
self.environment.events.request.fire(request_type="FTP upload", name=local_file_path,
exception=exception,
response_time=response_time,
response_length=len(str(exception)))
else:
self.environment.events.request.fire(request_type="FTP upload", name=local_file_path,
response_time=response_time,
response_length=len(response))

def disconnect(self):
self.connection.close()

0 comments on commit 2baf849

Please sign in to comment.