From 3d1705bdcf261018513e648f6895a6206cb16a6f Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Fri, 29 May 2020 18:44:19 -0400 Subject: [PATCH] The tool I used to help validate the solution. --- misc/load-test.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100755 misc/load-test.py diff --git a/misc/load-test.py b/misc/load-test.py new file mode 100755 index 0000000..f952d6c --- /dev/null +++ b/misc/load-test.py @@ -0,0 +1,104 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python -p "python.withPackages (ps: [ ps.treq ])" + +# Apply a very minimal load to a PaymentServer via the redemption endpoint. +# +# This requires a PaymentServer run something like: +# +# $ ./result/bin/PaymentServer-exe --issuer Trivial --http-port 8080 --stripe-key-path ../stripe.secret --database SQLite3 --database-path ./vouchers.db +# +# It also requires some vouchers to be marked as paid somehow. The vouchers +# are aaa0 through aaaN where N is the PARALLELISM you select. You can +# accomplish this by: +# +# $ for n in $(seq 0 30); do sqlite3 vouchers.db "insert into vouchers (name) values ('aaa$n')"; done +# +# Then the test can be run as many times as necessary. Repeated redemptions +# are allowed since the same tokens are used on every run. +# +# Originally written for https://github.com/PrivateStorageio/PaymentServer/issues/60 + +from __future__ import division + +from time import ( + time, +) + +from json import ( + dumps, +) + +from treq.client import ( + HTTPClient, +) + +from twisted.web.client import ( + Agent, + readBody, +) +from twisted.internet.task import ( + react, +) +from twisted.internet.defer import ( + inlineCallbacks, + gatherResults, + returnValue, +) + +PARALLELISM = 30 + +@inlineCallbacks +def redeem(client, index): + times = [] + for i in range(16): + before = time() + response = yield client.post( + url="http://127.0.0.1:8080/v1/redeem", + data=dumps({ + "redeemVoucher": "aaa{}".format(index), + "redeemTokens": ["foo-{}-{}".format(index, i)], + "redeemCounter": i, + }), + headers={"content-type": "application/json"}, + ) + after = time() + duration = int((after - before) * 1000) + print("Request complete in {}ms".format(duration)) + body = yield readBody(response) + assert response.code == 200, (response.code, body) + times.append(duration) + returnValue(times) + + +def mean(xs): + return sum(xs) / len(xs) + + +def percentile(n, xs): + return sorted(xs)[int(len(xs) / 100 * 95)] + + +def median(xs): + return percentile(50, xs) + + +@react +@inlineCallbacks +def main(reactor): + client = HTTPClient(Agent(reactor)) + + ds = list( + redeem(client, i) + for i + in range(PARALLELISM) + ) + + times = [] + for result in (yield gatherResults(ds)): + times.extend(result) + + print("min: {}".format(min(times))) + print("max: {}".format(max(times))) + print("mean: {}".format(mean(times))) + print("median: {}".format(median(times))) + print("95th: {}".format(percentile(95, times))) -- GitLab