diff --git a/etc/load-testing/README.md b/etc/load-testing/README.md new file mode 100644 index 0000000..8b96c4c --- /dev/null +++ b/etc/load-testing/README.md @@ -0,0 +1,30 @@ +# `stackage-server` load tests + +This directory can be used to test an on-premises instance of `stackage-server` for quality of service metrics. Follow the instructions below to run it. + +We assume you will be using `pyenv` to handle different Python environments in a safe manner. If you prefer installing packages globally (not recommended), jump straight to the line commented with `# install dependencies`. Before doing anything, set an environment variable `STACKAGE_SERVER_REPO` on your shell to this repo’s root folder. Then copy everything and run: + +```shell +cd ~ +curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash + +# add the following lines to your shell initialisation for permanent usage +export PYENV_VIRTUALENV_DISABLE_PROMPT=1 +eval "$(pyenv init -)" +eval "$(pyenv virtualenv-init -)" + +# create an environment for tests +pyenv install 3.6.3 +pyenv virtualenv 3.6.3 stackage-server-py-3.6.3 +cd "${STACKAGE_SERVER_REPO}/etc/load-testing" +pyenv local stackage-server-py-3.6.3 +pyenv activate stackage-server-py-3.6.3 # should happen automatically on previous line, but just to be sure + +# install dependencies +pip install -r requirements.txt + +# execute load tests +locust --host="http://yourlocalinstance.domain" +``` + +Then navigate to [127.0.0.1:8089](http://127.0.0.1:8089), set the number of clients to simulate, spawn rate, start it and wait a few minutes for the results to stabilise. You can then download or analyse directly on Locust’s UI. diff --git a/etc/load-testing/locustfile.py b/etc/load-testing/locustfile.py new file mode 100644 index 0000000..0089702 --- /dev/null +++ b/etc/load-testing/locustfile.py @@ -0,0 +1,159 @@ +from locust import HttpLocust, task, TaskSet +from random import randrange + +def random_element(xs): + return xs[randrange(len(xs))] + +def select_snapshot(): + _snapshots = [ + "lts", + "nightly", + "lts-9.10", + "lts-9.7", + "lts-9.6", + "lts-9.5", + "lts-8.8", + "nightly-2017-07-05", + "nightly-2017-05-30", + "nightly-2017-03-25", + "lts-7.20", + ] + return random_element(_snapshots) + +def select_package(): + _packages = [ + "accelerate", + "adjunctions", + "aeson", + "binary", + "both", + "extensible-effects", + "hamlet", + "hdocs", + "microlens", + "range", + "sort", + "text", + "universe" + ] + return random_element(_packages) + +def select_hoogle_query(): + _hoogle_queries = [ + "Ord", + "Eq", + "Num", + "pack", + "Text -> String", + "fmap", + "a -> a", + "traverse", + "bracket", + "^.", + ">>>", + "<$>", + "bimap", + "inject" + ] + return random_element(_hoogle_queries) + +class HoogleQueries(TaskSet): + @task + def hoogle_queries(self): + _snapshot = select_snapshot() + _query = select_hoogle_query() + self.client.get("/" \ + + _snapshot \ + + "/hoogle?q=" + _query \ + , name="/:snapshot/hoogle?q=[:query]") + + @task + def stop(self): + self.interrupt() + +class Haddock(TaskSet): + @task + def haddock(self): + _snapshot = select_snapshot() + _package = select_package() + self.client.get("/haddock/" \ + + _snapshot + "/" \ + + _package + "/" \ + + "doc-index-All.html" \ + , name="/haddock/:snapshot/:package/doc-index-All.html") + + @task + def stop(self): + self.interrupt() + +class Documentation(TaskSet): + @task + def docs(self): + _snapshot = select_snapshot() + self.client.get("/" \ + + _snapshot \ + + "/docs" \ + , name="/:snapshot/docs") + + @task + def stop(self): + self.interrupt() + +class PackageBrowser(TaskSet): + @task + def browse_package(self): + _snapshot = select_snapshot() + _package = select_package() + self.client.get("/" \ + + _snapshot \ + + "/package/" + _package \ + , name="/:snapshot/package/:package") + + @task + def stop(self): + self.interrupt() + +class Snapshots(TaskSet): + @task + def updateSnapshots(self): + self.client.get("/download/snapshots.json") + + @task + def stop(self): + self.interrupt() + +class TopLevelPages(TaskSet): + @task(20) + def install(self): + self.client.get("/install") + + @task(10) + def lts(self): + self.client.get("/lts") + + @task(5) + def nightly(self): + self.client.get("/nightly") + + @task(2) + def snapshots(self): + self.client.get("/snapshots") + + @task(2) + def stop(self): + self.interrupt() + +class UserBehaviour(TaskSet): + tasks = { + Haddock : 10, + HoogleQueries : 5, + PackageBrowser : 2, + Documentation : 2, + Snapshots : 1, + TopLevelPages : 1, + } + +class WebsiteUser(HttpLocust): + task_set = UserBehaviour + min_wait = 1000 + max_wait = 9000 diff --git a/etc/load-testing/requirements.txt b/etc/load-testing/requirements.txt new file mode 100644 index 0000000..5b1fa01 --- /dev/null +++ b/etc/load-testing/requirements.txt @@ -0,0 +1,17 @@ +certifi==2017.4.17 +chardet==3.0.4 +click==6.7 +Flask==0.12.2 +gevent==1.2.2 +greenlet==0.4.12 +idna==2.5 +itsdangerous==0.24 +Jinja2==2.9.6 +-e git://github.com/locustio/locust.git@072d7752552ff32898253fcd5734c3b64995c17e#egg=locustio +MarkupSafe==1.0 +msgpack-python==0.4.8 +pyzmq==15.2.0 +requests==2.18.1 +six==1.10.0 +urllib3==1.21.1 +Werkzeug==0.12.2