-
Notifications
You must be signed in to change notification settings - Fork 46
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #283 from lubosmj/performance-testing-port
Port performance tests
- Loading branch information
Showing
8 changed files
with
510 additions
and
9 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Port performance tests to pulp_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
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,78 @@ | ||
import logging | ||
import requests | ||
import tempfile | ||
import time | ||
|
||
from .utils import measureit, urljoin | ||
|
||
BASE_ADDR = "http://localhost:24817" | ||
CONTENT_ADDR = "http://localhost:24816" | ||
|
||
|
||
def get(url, params={}): | ||
"""Wrapper around requests.get with some simplification in our case.""" | ||
url = BASE_ADDR + url | ||
|
||
r = requests.get(url=url, params=params) | ||
r.raise_for_status() | ||
data = r.json() | ||
return data | ||
|
||
|
||
def get_results(url, params={}): | ||
"""Wrapper around requests.get with some simplification in our case.""" | ||
out = [] | ||
page = 0 | ||
while True: | ||
data = get(url, params) | ||
out += data["results"] | ||
page += 1 | ||
params["page"] = page | ||
if data["next"] is None: | ||
break | ||
return out | ||
|
||
|
||
def post(url, data): | ||
"""Wrapper around requests.post with some simplification in our case.""" | ||
url = BASE_ADDR + url | ||
|
||
r = requests.post(url=url, json=data) | ||
r.raise_for_status() | ||
return r.json() | ||
|
||
|
||
def download(base_url, file_name, file_size): | ||
"""Downlad file with expected size and drop it.""" | ||
with tempfile.TemporaryFile() as downloaded_file: | ||
full_url = urljoin(CONTENT_ADDR, base_url, file_name) | ||
duration, response = measureit(requests.get, full_url) | ||
response.raise_for_status() | ||
downloaded_file.write(response.content) | ||
assert downloaded_file.tell() == file_size | ||
return duration | ||
|
||
|
||
def wait_for_tasks(tasks, timeout=None): | ||
""" | ||
Wait for tasks to finish. | ||
Returns task info. If we time out, list of None is returned. | ||
""" | ||
start = time.time() | ||
out = [] | ||
step = 3 | ||
for t in tasks: | ||
while True: | ||
if timeout is not None: | ||
now = time.time() | ||
if now >= start + timeout: | ||
raise Exception("Task %s timeouted" % t) | ||
response = get(t) | ||
logging.debug("Task status is '%s', full response %s" % (response["state"], response)) | ||
if response["state"] in ("failed", "cancelled", "completed"): | ||
out.append(response) | ||
break | ||
else: | ||
time.sleep(step) | ||
return out |
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,105 @@ | ||
import datetime | ||
import statistics | ||
|
||
DATETIME_FMT = "%Y-%m-%dT%H:%M:%S.%fZ" | ||
|
||
|
||
def parse_date_from_string(s, parse_format="%Y-%m-%dT%H:%M:%S.%fZ"): | ||
"""Parse string to datetime object. | ||
:param s: str like '2018-11-18T21:03:32.493697Z' | ||
:param parse_format: str defaults to %Y-%m-%dT%H:%M:%S.%fZ | ||
:return: datetime.datetime | ||
""" | ||
return datetime.datetime.strptime(s, parse_format) | ||
|
||
|
||
def tasks_table(tasks, performance_task_name): | ||
"""Return overview of tasks.""" | ||
out = [] | ||
for t in tasks: | ||
created_at = parse_date_from_string(t["pulp_created"]) | ||
started_at = parse_date_from_string(t["started_at"]) | ||
finished_at = parse_date_from_string(t["finished_at"]) | ||
task_duration = finished_at - started_at | ||
waiting_time = started_at - created_at | ||
out.append( | ||
"\n-> {task_name} => Waiting time (s): {wait} | Service time (s): {service}".format( | ||
task_name=performance_task_name, | ||
wait=waiting_time.total_seconds(), | ||
service=task_duration.total_seconds(), | ||
) | ||
) | ||
return "\n".join(out) | ||
|
||
|
||
def tasks_min_max_table(tasks): | ||
"""Return overview of tasks dates min and max in a table.""" | ||
""" | ||
out = "\n%11s\t%27s\t%27s\n" % ("field", "min", "max") | ||
for f in ("pulp_created", "started_at", "finished_at"): | ||
sample = [datetime.datetime.strptime(t[f], DATETIME_FMT) for t in tasks] | ||
out += "%11s\t%s\t%s\n" % ( | ||
f, | ||
min(sample).strftime(DATETIME_FMT), | ||
max(sample).strftime(DATETIME_FMT), | ||
) | ||
return out | ||
""" | ||
|
||
|
||
def data_stats(data): | ||
"""Return basic stats fetch from provided data.""" | ||
return { | ||
"samples": len(data), | ||
"min": min(data), | ||
"max": max(data), | ||
"mean": statistics.mean(data), | ||
"stdev": statistics.stdev(data) if len(data) > 1 else 0.0, | ||
} | ||
|
||
|
||
def fmt_data_stats(data): | ||
""" | ||
Format data. | ||
https://stackoverflow.com/questions/455612/limiting-floats-to-two-decimal-points | ||
""" | ||
return { | ||
"samples": data["samples"], | ||
"min": float("%.02f" % round(data["min"], 2)), | ||
"max": float("%.02f" % round(data["max"], 2)), | ||
"mean": float("%.02f" % round(data["mean"], 2)), | ||
"stdev": float("%.02f" % round(data["stdev"], 2)), | ||
} | ||
|
||
|
||
def tasks_waiting_time(tasks): | ||
"""Analyse tasks waiting time (i.e. started_at - _created).""" | ||
durations = [] | ||
for t in tasks: | ||
diff = datetime.datetime.strptime( | ||
t["started_at"], DATETIME_FMT | ||
) - datetime.datetime.strptime(t["pulp_created"], DATETIME_FMT) | ||
durations.append(diff.total_seconds()) | ||
return fmt_data_stats(data_stats(durations)) | ||
|
||
|
||
def tasks_service_time(tasks): | ||
"""Analyse tasks service time (i.e. finished_at - started_at).""" | ||
durations = [] | ||
for t in tasks: | ||
diff = datetime.datetime.strptime( | ||
t["finished_at"], DATETIME_FMT | ||
) - datetime.datetime.strptime(t["started_at"], DATETIME_FMT) | ||
durations.append(diff.total_seconds()) | ||
return fmt_data_stats(data_stats(durations)) | ||
|
||
|
||
def print_fmt_experiment_time(label, start, end): | ||
"""Print formatted label and experiment time.""" | ||
print("\n-> {} => Experiment time (s): {}".format(label, (end - start).total_seconds())) | ||
|
||
|
||
def report_tasks_stats(performance_task_name, tasks): | ||
"""Print out basic stats about received tasks.""" | ||
print(tasks_table(tasks, performance_task_name)) |
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,32 @@ | ||
import logging | ||
import random | ||
import time | ||
import string | ||
import requests | ||
|
||
|
||
def get_random_string(): | ||
"""Return random string.""" | ||
return "".join(random.choice(string.ascii_lowercase) for i in range(5)) | ||
|
||
|
||
def urljoin(*args): | ||
"""This sucks, but works. Better ways welcome.""" | ||
return "/".join([i.lstrip("/").rstrip("/") for i in args]) | ||
|
||
|
||
def measureit(func, *args, **kwargs): | ||
"""Measure execution time of passed function.""" | ||
logging.debug("Measuring duration of %s %s %s" % (func.__name__, args, kwargs)) | ||
before = time.clock() | ||
out = func(*args, **kwargs) | ||
after = time.clock() | ||
return after - before, out | ||
|
||
|
||
def parse_pulp_manifest(url): | ||
"""Parse pulp manifest.""" | ||
response = requests.get(url) | ||
response.text.split("\n") | ||
data = [i.strip().split(",") for i in response.text.split("\n")] | ||
return [(i[0], i[1], int(i[2])) for i in data if i != [""]] |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.