From 428411935265841fa2667efaedfc65f3909d4505 Mon Sep 17 00:00:00 2001 From: Bobby Noelte Date: Tue, 8 Oct 2024 14:29:45 +0200 Subject: [PATCH] Add test for server A test fixture to start the server and a first test case is added. The fixture tries to assure that the server is installed and running. If it is not installed the fixture uses pip to install it. The server and the installation by pip is run bei the same Python executable that also runs pytest. The github workflow for pytest is adapted to install akkudoktor-eos. Signed-off-by: Bobby Noelte --- .github/workflows/pytest.yml | 2 ++ Makefile | 10 ++++++ requirements-dev.txt | 3 ++ tests/conftest.py | 53 ++++++++++++++++++++++++++++++ tests/test_server.py | 63 ++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 tests/conftest.py create mode 100644 tests/test_server.py diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 20a3a27c..ba934c0c 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -23,7 +23,9 @@ jobs: sudo apt install -y libmariadb3 libmariadb-dev python -m pip install --upgrade pip pip install -r requirements.txt + pip install -r requirements-dev.txt - name: Run Pytest run: | + pip install -e . python -m pytest -vs --cov modules --cov-report term-missing tests/ diff --git a/Makefile b/Makefile index a43af140..82df14b5 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ help: @echo "Available targets:" @echo " venv - Set up a Python 3 virtual environment." @echo " pip - Install dependencies from requirements.txt." + @echo " pip-dev - Install dependencies from requirements-dev.txt." @echo " install - Install EOS in editable form (development mode) into virtual environment." @echo " docker-run - Run entire setup on docker @echo " docs - Generate HTML documentation using pdoc." @@ -27,6 +28,11 @@ pip: venv .venv/bin/pip install -r requirements.txt @echo "Dependencies installed from requirements.txt." +# Target to install dependencies from requirements.txt +pip-dev: pip + .venv/bin/pip install -r requirements-dev.txt + @echo "Dependencies installed from requirements-dev.txt." + # Target to install EOS in editable form (development mode) into virtual environment. install: pip .venv/bin/pip install build @@ -54,6 +60,10 @@ run: @echo "Starting flask server, please wait..." .venv/bin/python -m akkudoktoreosserver.flask_server +# Target to setup tests. +test-setup: pip-dev + @echo "Setup tests" + # Target to run tests. test: @echo "Running tests..." diff --git a/requirements-dev.txt b/requirements-dev.txt index f1f109b2..b47030fb 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,2 +1,5 @@ +build==1.2.2.post1 pytest==8.3.3 +pytest-xprocess==1.0.2 +requests==2.32.3 pre-commit diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..2a362c9a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,53 @@ +import os +import subprocess +import sys + +import pytest +from xprocess import ProcessStarter + + +@pytest.fixture +def server(xprocess): + class Starter(ProcessStarter): + # assure server to be installed + try: + subprocess.run( + [sys.executable, "-c", "import akkudoktoreosserver"], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except subprocess.CalledProcessError: + test_dir = os.path.dirname(os.path.realpath(__file__)) + project_dir = os.path.abspath(os.path.join(test_dir, "..")) + subprocess.run( + [sys.executable, "-m", "pip", "install", "-e", project_dir], + check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + + # command to start server process + args = [sys.executable, "-m", "akkudoktoreosserver.flask_server"] + + # startup pattern + pattern = "Serving Flask app 'flask_server'" + # search the first 12 lines for the startup pattern, if not found + # a RuntimeError will be raised informing the user + max_read_lines = 12 + + # will wait for 10 seconds before timing out + timeout = 10 + + # xprocess will now attempt to clean up upon interruptions + terminate_on_interrupt = True + + # ensure process is running and return its logfile + logfile = xprocess.ensure("akkudoktoreosserver", Starter) + + # create url/port info to the server + url = "http://127.0.0.1:8503" + yield url + + # clean up whole process tree afterwards + xprocess.getinfo("akkudoktoreosserver").terminate() diff --git a/tests/test_server.py b/tests/test_server.py new file mode 100644 index 00000000..f30e01f1 --- /dev/null +++ b/tests/test_server.py @@ -0,0 +1,63 @@ +import requests + + +def test_server(server): + """ + Test the server + """ + result = requests.get(f"{server}/gesamtlast_simple?year_energy=2000&") + assert result.status_code == 200 + assert ( + result.text + == """[ + 0.12399409965368197, + 0.12082955072761034, + 0.1186152098599658, + 0.13282048719613798, + 0.16801614895243458, + 0.18833079485066814, + 0.2060958576163904, + 0.23815979421159755, + 0.256794470747979, + 0.2730286944402595, + 0.2837831370699189, + 0.2880791113592318, + 0.27868845536305187, + 0.2593976275300202, + 0.26565341182134644, + 0.2834322084492842, + 0.3385133447353511, + 0.36541124595269503, + 0.33781770981176945, + 0.29218838246014817, + 0.24535542466592053, + 0.19484917288665324, + 0.15634028941335018, + 0.13309410380383394, + 0.1239736903705896, + 0.12074280282759843, + 0.11849705069574769, + 0.1320224904313182, + 0.16699106562771282, + 0.18856343364342354, + 0.20578134176859084, + 0.23760516695843145, + 0.25675411140321175, + 0.2729442256919556, + 0.2837782018548114, + 0.2882881388086184, + 0.2800061651414149, + 0.26039842637914645, + 0.26613497240454587, + 0.28441116400389416, + 0.33941195977626437, + 0.36621100374643395, + 0.3391062422788601, + 0.29391186081171267, + 0.24686897327498972, + 0.19620626090788126, + 0.1570820352949701, + 0.13332596485058107 +] +""" + )