[PATCH] First HTTP functional test of the RPC interface
Filipe Laíns
lains at archlinux.org
Thu Apr 16 21:58:47 UTC 2020
On Sun, 2020-04-12 at 18:55 +0200, Frédéric Mangano-Tarumi wrote:
> Though barely useful in its current state, it shows how to integrate
> pytest with SQLAlchemy and Werkzeug, providing a test framework for the
> potential future Flask port, while actually testing the current PHP
> implementation.
> ---
> aurweb/test/__init__.py | 0
> aurweb/test/conftest.py | 51 +++++++++++++++++++++++++++++++++++++++++
> aurweb/test/test_rpc.py | 21 +++++++++++++++++
> aurweb/test/wsgihttp.py | 38 ++++++++++++++++++++++++++++++
> test/README.md | 3 +++
> test/rpc.t | 2 ++
> 6 files changed, 115 insertions(+)
> create mode 100644 aurweb/test/__init__.py
> create mode 100644 aurweb/test/conftest.py
> create mode 100644 aurweb/test/test_rpc.py
> create mode 100644 aurweb/test/wsgihttp.py
> create mode 100755 test/rpc.t
>
> diff --git a/aurweb/test/__init__.py b/aurweb/test/__init__.py
> new file mode 100644
> index 00000000..e69de29b
> diff --git a/aurweb/test/conftest.py b/aurweb/test/conftest.py
> new file mode 100644
> index 00000000..49cc2f6e
> --- /dev/null
> +++ b/aurweb/test/conftest.py
> @@ -0,0 +1,51 @@
> +"""
> +Fixtures for pytest.
> +
> +This module is automatically loaded by pytest.
> +"""
> +
> +import pytest
> +import sqlalchemy
> +import werkzeug.test
> +import werkzeug.wrappers
> +import werkzeug.wrappers.json
> +
> +import aurweb.config
> +import aurweb.db
> +from aurweb.test.wsgihttp import WsgiHttpProxy
> +
> +
> +class Response(werkzeug.wrappers.CommonResponseDescriptorsMixin,
> + werkzeug.wrappers.json.JSONMixin,
> + werkzeug.wrappers.BaseResponse):
> + """
> + Custom response object to be returned by the test client. More mixins could
> + be added if need be.
> +
> + See https://werkzeug.palletsprojects.com/en/1.0.x/wrappers/#mixin-classes
> + """
> + pass
> +
> +
> + at pytest.fixture
> +def client():
> + """
> + Build a Werkzeug test client for making HTTP requests to AUR. It requires
> + that the AUR test website is already running at `[options] aur_location`,
> + specified in the configuration file.
> +
> + When aurweb becomes a pure Flask application, this should return Flask’s
> + test_client(), which is a Werkzeug test client too.
> + https://flask.palletsprojects.com/en/1.1.x/testing/#the-testing-skeleton
> + """
> + base_uri = aurweb.config.get("options", "aur_location")
> + proxy = WsgiHttpProxy(base_uri)
> + return werkzeug.test.Client(proxy, Response)
> +
> +
> + at pytest.fixture(scope="session")
> +def db_engine():
> + """
> + Return an SQLAlchemy engine to the configured database.
> + """
> + return sqlalchemy.create_engine(aurweb.db.get_sqlalchemy_url())
> diff --git a/aurweb/test/test_rpc.py b/aurweb/test/test_rpc.py
> new file mode 100644
> index 00000000..7079145c
> --- /dev/null
> +++ b/aurweb/test/test_rpc.py
> @@ -0,0 +1,21 @@
> +"""
> +Test suite for the RPC interface.
> +
> +See also `doc/rpc.txt` for the RPC interface documentation.
> +"""
> +
> +import pytest
> +from sqlalchemy.sql import select
> +
> +from aurweb.schema import Packages
> +
> +
> +def test_search_by_name(client, db_engine):
> + """Take a package from the database, and find it through the RPC interface."""
> + with db_engine.connect() as conn:
> + pkg = conn.execute(select([Packages]).limit(1)).fetchone()
> + if pkg is None:
> + pytest.skip("needs at least one package in the database")
> + resp = client.get("/rpc/", query_string={"v": "5", "type": "search", "arg": pkg["Name"]})
> + result = resp.json
> + assert result["resultcount"] >= 1
> diff --git a/aurweb/test/wsgihttp.py b/aurweb/test/wsgihttp.py
> new file mode 100644
> index 00000000..5b9d8040
> --- /dev/null
> +++ b/aurweb/test/wsgihttp.py
> @@ -0,0 +1,38 @@
> +import http.client
> +import urllib.parse
> +
> +
> +class WsgiHttpProxy:
> + """
> + WSGI-to-HTTP proxy, that is to say a WSGI application that forwards every
> + WSGI request to an HTTP server, then the HTTP response back to WSGI.
> +
> + The base URL the constructor takes is something like
> + `http://localhost:8080`. It must not contain a path, a query string or a
> + fragment, as the proxy wouldn’t now what to do with it.
> +
> + Only the HTTP scheme is supported, but HTTPS could probably be easily added.
> + """
> +
> + def __init__(self, base_url):
> + parts = urllib.parse.urlsplit(base_url)
> + self.netloc = parts.netloc
> + # Limitations of this dumb proxy
> + assert parts.scheme == "http"
> + assert parts.path in ("", "/")
Why a tuple?
> + assert parts.query == ""
> + assert parts.fragment == ""
> +
> + def __call__(self, environ, start_response):
> + conn = http.client.HTTPConnection(self.netloc)
> + conn.request(
> + method=environ["REQUEST_METHOD"],
> + url=urllib.parse.urlunsplit((
> + "http", self.netloc,
> + urllib.parse.quote(environ["PATH_INFO"]),
> + environ["QUERY_STRING"], "")),
> + body=environ["wsgi.input"].read(int(environ.get("CONTENT_LENGTH", 0))),
> + )
> + resp = conn.getresponse()
> + start_response(f"{resp.status} {resp.reason}", resp.getheaders())
> + return resp
> diff --git a/test/README.md b/test/README.md
> index de7eff18..cc8baf33 100644
> --- a/test/README.md
> +++ b/test/README.md
> @@ -20,8 +20,11 @@ For all the test to run, the following Arch packages should be installed:
> - python-bleach
> - python-markdown
> - python-pygit2
> +- python-pytest
> +- python-pytest-tap
> - python-sqlalchemy
> - python-srcinfo
> +- python-werkzeug
>
> Writing tests
> -------------
> diff --git a/test/rpc.t b/test/rpc.t
> new file mode 100755
> index 00000000..f950f7df
> --- /dev/null
> +++ b/test/rpc.t
> @@ -0,0 +1,2 @@
> +#!/bin/sh
> +pytest --tap-stream "$(dirname "$0")/../aurweb/test/test_rpc.py"
I think we should be using pytest-runner here. What do you think Lukas?
Otherwise LGTM.
Cheers,
Filipe Laíns
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part
URL: <https://lists.archlinux.org/pipermail/aur-dev/attachments/20200416/0ba99799/attachment.sig>
More information about the aur-dev
mailing list