Docker container for Pytest (#901)

* Dockerize Pytest

* Fix auto-delete warning in delete file test

* Allow tests to be executed with a non-default home dir

* Use hostname for Docker container only if tests executed in Docker

* Update container entrypoint to pytest

* Re-format tests with black

* Define if the execution environment is a Docker container in env fixture

* Skip unsupported host bridge attachment test in Docker
This commit is contained in:
nucleogenic 2022-10-15 03:30:08 +01:00 committed by GitHub
parent a8ac6a06cf
commit 6514e24770
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 59 additions and 21 deletions

View File

@ -55,3 +55,17 @@ services:
"--log-level=${WEB_LOG_LEVEL:-info}",
"--dev-mode"
]
pytest:
container_name: pytest
image: rascsi:pytest
pull_policy: never
profiles:
- webui-tests
build:
context: ..
dockerfile: docker/pytest/Dockerfile
volumes:
- ../python/web:/src:delegated
working_dir: /src
entrypoint: "pytest"

5
docker/pytest/Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM python:3.7-bullseye
ENV DOCKER=1
COPY python/web/requirements-dev.txt /requirements-dev.txt
RUN pip install -r /requirements-dev.txt

View File

@ -3,3 +3,4 @@ pytest-httpserver==1.0.6
black==22.8.0
flake8==5.0.4
watchdog==2.1.9
requests==2.28.1

View File

@ -2,9 +2,6 @@ import pytest
import uuid
import warnings
CFG_DIR = "/home/pi/.config/rascsi"
IMAGES_DIR = "/home/pi/images"
AFP_DIR = "/home/pi/afpshare"
SCSI_ID = 6
FILE_SIZE_1_MIB = 1048576
STATUS_SUCCESS = "success"

View File

@ -81,7 +81,10 @@ def test_attach_image(http_client, create_test_image, detach_devices):
("Printer", {"type": "SCLP", "param_timeout": 60, "param_cmd": "lp -fart %f"}),
],
)
def test_attach_device(http_client, detach_devices, device_name, device_config):
def test_attach_device(env, http_client, detach_devices, device_name, device_config):
if env["is_docker"] and device_name == "Host Bridge":
pytest.skip("Test not supported in Docker environment.")
device_config["scsi_id"] = SCSI_ID
device_config["unit"] = 0

View File

@ -3,7 +3,6 @@ import uuid
import os
from conftest import (
IMAGES_DIR,
SCSI_ID,
FILE_SIZE_1_MIB,
STATUS_SUCCESS,
@ -86,7 +85,7 @@ def test_copy_file(http_client, create_test_image, list_files, delete_file):
# route("/files/delete", methods=["POST"])
def test_delete_file(http_client, create_test_image, list_files):
file_name = create_test_image()
file_name = create_test_image(auto_delete=False)
response = http_client.post("/files/delete", data={"file_name": file_name})
@ -210,7 +209,7 @@ def test_download_file(http_client, create_test_image):
# route("/files/download_url", methods=["POST"])
def test_download_url_to_dir(httpserver, http_client, list_files, delete_file):
def test_download_url_to_dir(env, httpserver, http_client, list_files, delete_file):
file_name = str(uuid.uuid4())
http_path = f"/images/{file_name}"
url = httpserver.url_for(http_path)
@ -236,7 +235,9 @@ def test_download_url_to_dir(httpserver, http_client, list_files, delete_file):
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert file_name in list_files()
assert response_data["messages"][0]["message"] == f"{file_name} downloaded to {IMAGES_DIR}"
assert (
response_data["messages"][0]["message"] == f"{file_name} downloaded to {env['images_dir']}"
)
# Cleanup
delete_file(file_name)
@ -244,6 +245,7 @@ def test_download_url_to_dir(httpserver, http_client, list_files, delete_file):
# route("/files/download_to_iso", methods=["POST"])
def test_download_url_to_iso(
env,
httpserver,
http_client,
list_files,
@ -283,7 +285,7 @@ def test_download_url_to_iso(
m = response_data["messages"]
assert m[0]["message"] == 'Created CD-ROM ISO image with arguments "-hfs"'
assert m[1]["message"] == f"Saved image as: {IMAGES_DIR}/{iso_file_name}"
assert m[1]["message"] == f"Saved image as: {env['images_dir']}/{iso_file_name}"
assert m[2]["message"] == f"Attached to SCSI ID {SCSI_ID}"
# Cleanup

View File

@ -1,7 +1,6 @@
import uuid
from conftest import (
CFG_DIR,
FILE_SIZE_1_MIB,
STATUS_SUCCESS,
)
@ -46,7 +45,7 @@ def test_show_named_drive_presets(http_client):
# route("/drive/cdrom", methods=["POST"])
def test_create_cdrom_properties_file(http_client):
def test_create_cdrom_properties_file(env, http_client):
file_name = f"{uuid.uuid4()}.iso"
response = http_client.post(
@ -62,7 +61,7 @@ def test_create_cdrom_properties_file(http_client):
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert response_data["messages"][0]["message"] == (
f"File created: {CFG_DIR}/{file_name}.properties"
f"File created: {env['cfg_dir']}/{file_name}.properties"
)
@ -89,6 +88,7 @@ def test_create_image_with_properties_file(http_client, delete_file):
# Cleanup
delete_file(file_name)
# route("/sys/manpage", methods=["POST"])
def test_show_manpage(http_client):
response = http_client.get("/sys/manpage?app=rascsi")

View File

@ -1,7 +1,7 @@
import pytest
import uuid
from conftest import CFG_DIR, STATUS_SUCCESS
from conftest import STATUS_SUCCESS
# route("/language", methods=["POST"])
@ -74,7 +74,7 @@ def test_show_logs(http_client):
# route("/config/save", methods=["POST"])
# route("/config/load", methods=["POST"])
def test_save_load_and_delete_configs(http_client):
def test_save_load_and_delete_configs(env, http_client):
config_name = str(uuid.uuid4())
config_json_file = f"{config_name}.json"
reserved_scsi_id = 0
@ -96,7 +96,7 @@ def test_save_load_and_delete_configs(http_client):
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert response_data["messages"][0]["message"] == (
f"File created: {CFG_DIR}/{config_json_file}"
f"File created: {env['cfg_dir']}/{config_json_file}"
)
assert config_json_file in http_client.get("/").json()["data"]["config_files"]
@ -146,7 +146,7 @@ def test_save_load_and_delete_configs(http_client):
assert response.status_code == 200
assert response_data["status"] == STATUS_SUCCESS
assert response_data["messages"][0]["message"] == (
f"File deleted: {CFG_DIR}/{config_json_file}"
f"File deleted: {env['cfg_dir']}/{config_json_file}"
)
assert config_json_file not in http_client.get("/").json()["data"]["config_files"]

View File

@ -1,15 +1,32 @@
import pytest
import requests
import socket
import os
def pytest_addoption(parser):
parser.addoption("--base_url", action="store", default="http://localhost:8080")
parser.addoption("--httpserver_host", action="store", default="host.docker.internal")
parser.addoption("--httpserver_listen_address", action="store", default="127.0.0.1")
default_base_url = "http://rascsi_web" if os.getenv("DOCKER") else "http://localhost:8080"
parser.addoption("--home_dir", action="store", default="/home/pi")
parser.addoption("--base_url", action="store", default=default_base_url)
parser.addoption("--httpserver_host", action="store", default=socket.gethostname())
parser.addoption("--httpserver_listen_address", action="store", default="0.0.0.0")
parser.addoption("--rascsi_username", action="store", default="pi")
parser.addoption("--rascsi_password", action="store", default="rascsi")
@pytest.fixture(scope="session")
def env(pytestconfig):
home_dir = pytestconfig.getoption("home_dir")
return {
"is_docker": bool(os.getenv("DOCKER")),
"home_dir": home_dir,
"cfg_dir": f"{home_dir}/.config/rascsi",
"images_dir": f"{home_dir}/images",
"afp_dir": f"{home_dir}/afpshare",
}
@pytest.fixture(scope="session")
def httpserver_listen_address(pytestconfig):
return (pytestconfig.getoption("httpserver_listen_address"), 0)
@ -17,8 +34,7 @@ def httpserver_listen_address(pytestconfig):
@pytest.fixture(scope="function", autouse=True)
def set_httpserver_hostname(pytestconfig, httpserver):
# The HTTP requests are made by Python from within the container so we need
# httpserver.url_for to generate URLs which point to the Docker host
# We need httpserver.url_for() to generate URLs pointing to the correct host
httpserver.host = pytestconfig.getoption("httpserver_host")