Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added transfer negotiation tests
- Loading branch information
andamian
committed
Nov 18, 2020
1 parent
66152fd
commit 0b8b2ae
Showing
14 changed files
with
574 additions
and
284 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
FROM locustio/locust:latest | ||
|
||
USER root | ||
|
||
#RUN apk --no-cache add gcc git libffi-dev libxslt-dev make musl-dev openssl-dev | ||
#RUN pip install --pre vos==3.3.a1 | ||
RUN pip install -e 'git+https://github.com/opencadc/vostools@newstorage#egg=vostools&subdirectory=vos' | ||
|
||
# Make requests trust all certificates | ||
ENV CURL_CA_BUNDLE= | ||
|
||
#COPY dev_requirements.txt /tmp/ | ||
COPY locustfile.py . | ||
COPY testers.py . | ||
COPY test_config . | ||
RUN mkdir cert | ||
COPY cert/* cert/ | ||
|
||
COPY entrypoint.sh / | ||
|
||
RUN chmod +x /entrypoint.sh | ||
|
||
#RUN pip install -r /tmp/dev_requirements.txt | ||
|
||
USER locust | ||
|
||
ENTRYPOINT ["/entrypoint.sh"] | ||
#CMD ["./docker_start.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Performance Tests | ||
|
||
Testing was done using a product called [Locust](https://locust.io). It runs Python testing code exercising the transfer negotiation and vcp. | ||
|
||
Locust allows us to scale up Workers (Called Users to Locust) to issue multiple simultaneous requests. Tests are executed through an intuitive UI, which features the ability to ramp up Workers per second to a set maximum. Tests run until they are manually stopped. | ||
|
||
The test_config file contains configuration info used to execute the tests tests. | ||
|
||
## Running it | ||
|
||
The system runs on port 8089 with Docker and requires two volumes to be created and populated first: | ||
|
||
* `cert`: to hold the `cadcproxy.pem` file of the authenticated user that runs the tests. | ||
|
||
|
||
### Docker Run | ||
|
||
The image will need to be built first: | ||
|
||
`$ docker build -t myimage .` | ||
|
||
Foreground run: | ||
`$ docker run -t --rm -p 8089:8089 myimage` | ||
|
||
Background run: | ||
`$ docker run -t -d --name locust -p 8089:8089 myimage` | ||
|
||
Then you can visit http://localhost:8089 to use the UI and start a run. | ||
|
||
IMPORTANT: Make sure that the testing machines are accessible (they are either public or the appropriate VPN is running) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
locust | ||
#exec "${@}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
import os | ||
import sys | ||
import time | ||
import inspect | ||
import logging | ||
|
||
from locust import User, events, task, constant_pacing | ||
from uuid import uuid1 | ||
import vos | ||
from vos.commands import vcp | ||
from random import randrange | ||
from testers import GlobalTester, config | ||
|
||
DEBUG = os.getenv('DEBUG', None) | ||
ONE_KB = 1024 | ||
try: | ||
call_freq = int(config['CALL_FREQ']) | ||
except KeyError: | ||
call_freq = 60 | ||
logger = logging.getLogger('locust.main') | ||
logger.info('Running with {} calls/s'.format(call_freq)) | ||
# TODO Don't know how to do it with a logger | ||
print('Running with {} calls/s'.format(call_freq)) | ||
|
||
|
||
def _touch(path, size=ONE_KB): | ||
with open(path, 'a') as f: | ||
f.truncate(size) | ||
f.close() | ||
return path | ||
|
||
|
||
class VCPClient(object): | ||
|
||
def __init__(self, resource_id, certfile): | ||
self.resource_id = resource_id | ||
self.certfile = certfile | ||
|
||
""" | ||
Simple, sample XML RPC client implementation that wraps storage_inventory.Client and | ||
fires locust events on request_success and request_failure, so that all requests | ||
gets tracked in locust's statistics. | ||
""" | ||
def copy(self, source, destination, name, size): | ||
_args = ['vcp'] | ||
if DEBUG is not None: | ||
_args.append('-d') | ||
|
||
_args.extend(['--certfile={}'.format(self.certfile), | ||
'--resource-id={}'.format(self.resource_id), | ||
source, destination]) | ||
sys.argv = _args | ||
|
||
start_time = time.time() | ||
try: | ||
vcp() | ||
except Exception as e: | ||
total_time = int((time.time() - start_time) * 1000) | ||
events.request_failure.fire(request_type='vcp', name='vcp:{}__{}'.format(source, destination), response_time=total_time, response_length=0, exception=e) | ||
else: | ||
total_time = int((time.time() - start_time) * 1000) | ||
events.request_success.fire(request_type='vcp', name=name, response_time=total_time, response_length=size) | ||
# In this example, we've hardcoded response_length=0. If we would want the response length to be | ||
# reported correctly in the statistics, we would probably need to hook in at a lower level | ||
|
||
|
||
def stopwatch(func): | ||
""" | ||
Wrapper to report a function execution time to locust | ||
:param func: | ||
:return: | ||
""" | ||
def wrapper(*args, **kwargs): | ||
# get task's function name | ||
previous_frame = inspect.currentframe().f_back | ||
_, _, task_name, _, _ = inspect.getframeinfo(previous_frame) | ||
|
||
start = time.time() | ||
result = None | ||
try: | ||
result = func(*args, **kwargs) | ||
except Exception as e: | ||
total = int((time.time() - start) * 1000) | ||
events.request_failure.fire(request_type="TYPE", | ||
name=func.__name__, | ||
response_time=total, | ||
response_length=0, | ||
exception=e) | ||
else: | ||
total = int((time.time() - start) * 1000) | ||
events.request_success.fire(request_type="TYPE", | ||
name=func.__name__, | ||
response_time=total, | ||
response_length=0) | ||
return result | ||
|
||
return wrapper | ||
|
||
class Global(User): | ||
wait_time = constant_pacing(60/call_freq) | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(Global, self).__init__(*args, **kwargs) | ||
self.global_tester = GlobalTester() | ||
|
||
@task | ||
@stopwatch | ||
def anon_get_pub(self): | ||
""" | ||
Negotiate a transfer request for a random public file | ||
:return: | ||
""" | ||
self.global_tester.anon_get_pub() | ||
|
||
@task | ||
@stopwatch | ||
def anon_get_priv(self): | ||
""" | ||
Unauthorized failures | ||
:return: | ||
""" | ||
self.global_tester.anon_get_priv() | ||
|
||
@task | ||
@stopwatch | ||
def auth_get_pub(self): | ||
""" | ||
Negotiate a transfer request for a random public file | ||
:return: | ||
""" | ||
self.global_tester.auth_get_pub() | ||
|
||
@task | ||
@stopwatch | ||
def auth_get_priv(self): | ||
self.global_tester.auth_get_priv() | ||
|
||
@task | ||
@stopwatch | ||
def anon_put(self): | ||
""" | ||
Negotiate a transfer request for pushing a file anon - Failure | ||
:return: | ||
""" | ||
self.global_tester.anon_put() | ||
|
||
@task | ||
@stopwatch | ||
def auth_put(self): | ||
""" | ||
Negotiate a transfer request for pushing a file | ||
:return: | ||
""" | ||
self.global_tester.auth_put() | ||
|
||
|
||
# class ApiUser(VCPLocust): | ||
# wait_time = between(0.1, 1) | ||
# source = '' | ||
# size = int(os.getenv('FILE_SIZE_IN_BYTES', ONE_KB)) | ||
# | ||
# class task_set(TaskSet): | ||
# def setup(self): | ||
# file_dir = os.getenv('FILE_DIR', '/tmp') | ||
# ApiUser.source = _touch('{}/SOURCE_FILE.txt'.format(file_dir), ApiUser.size) | ||
# | ||
# def teardown(self): | ||
# os.remove(ApiUser.source) | ||
# | ||
# @task | ||
# def upload(self): | ||
# file_id = uuid1() | ||
# dest = 'cadc:CADCRegtest1/{}.txt'.format(file_id) | ||
# self.client.copy(ApiUser.source, dest, 'upload_{}'.format(ApiUser.size), ApiUser.size) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
[GENERAL] | ||
REG=mach275.cadc.dao.nrc.ca | ||
CERT_FILE=./cert/cadcproxy.pem | ||
# number of calls/user/sec | ||
CALL_FREQ=120 | ||
#ANON_TESTS_ONLY=True | ||
#AUTH_TESTS_ONLY=True | ||
|
||
|
||
[GLOBAL] | ||
RESOURCE_ID=ivo://cadc.nrc.ca/alpha-global/raven | ||
# luskan sync url | ||
LUSKAN_URL=https://proc5-27.cadc.dao.nrc.ca/luskan/sync | ||
|
||
ARGUS_URL=https://www.cadc-ccda.hia-iha.nrc-cnrc.gc.ca/argus/sync | ||
# number of public/private uris to randomly access in order to avoid the effect of caching on test results. | ||
NUM_URIS = 1000 | ||
|
||
[LOCAL] | ||
RESOURCE_ID=ivo://cadc.nrc.ca/alpha-global/raven |
Oops, something went wrong.