mirror of https://github.com/akuker/RASCSI.git
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:
parent
a8ac6a06cf
commit
6514e24770
|
@ -55,3 +55,17 @@ services:
|
||||||
"--log-level=${WEB_LOG_LEVEL:-info}",
|
"--log-level=${WEB_LOG_LEVEL:-info}",
|
||||||
"--dev-mode"
|
"--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"
|
||||||
|
|
|
@ -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
|
|
@ -3,3 +3,4 @@ pytest-httpserver==1.0.6
|
||||||
black==22.8.0
|
black==22.8.0
|
||||||
flake8==5.0.4
|
flake8==5.0.4
|
||||||
watchdog==2.1.9
|
watchdog==2.1.9
|
||||||
|
requests==2.28.1
|
||||||
|
|
|
@ -2,9 +2,6 @@ import pytest
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
CFG_DIR = "/home/pi/.config/rascsi"
|
|
||||||
IMAGES_DIR = "/home/pi/images"
|
|
||||||
AFP_DIR = "/home/pi/afpshare"
|
|
||||||
SCSI_ID = 6
|
SCSI_ID = 6
|
||||||
FILE_SIZE_1_MIB = 1048576
|
FILE_SIZE_1_MIB = 1048576
|
||||||
STATUS_SUCCESS = "success"
|
STATUS_SUCCESS = "success"
|
||||||
|
|
|
@ -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"}),
|
("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["scsi_id"] = SCSI_ID
|
||||||
device_config["unit"] = 0
|
device_config["unit"] = 0
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ import uuid
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from conftest import (
|
from conftest import (
|
||||||
IMAGES_DIR,
|
|
||||||
SCSI_ID,
|
SCSI_ID,
|
||||||
FILE_SIZE_1_MIB,
|
FILE_SIZE_1_MIB,
|
||||||
STATUS_SUCCESS,
|
STATUS_SUCCESS,
|
||||||
|
@ -86,7 +85,7 @@ def test_copy_file(http_client, create_test_image, list_files, delete_file):
|
||||||
|
|
||||||
# route("/files/delete", methods=["POST"])
|
# route("/files/delete", methods=["POST"])
|
||||||
def test_delete_file(http_client, create_test_image, list_files):
|
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})
|
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"])
|
# 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())
|
file_name = str(uuid.uuid4())
|
||||||
http_path = f"/images/{file_name}"
|
http_path = f"/images/{file_name}"
|
||||||
url = httpserver.url_for(http_path)
|
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.status_code == 200
|
||||||
assert response_data["status"] == STATUS_SUCCESS
|
assert response_data["status"] == STATUS_SUCCESS
|
||||||
assert file_name in list_files()
|
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
|
# Cleanup
|
||||||
delete_file(file_name)
|
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"])
|
# route("/files/download_to_iso", methods=["POST"])
|
||||||
def test_download_url_to_iso(
|
def test_download_url_to_iso(
|
||||||
|
env,
|
||||||
httpserver,
|
httpserver,
|
||||||
http_client,
|
http_client,
|
||||||
list_files,
|
list_files,
|
||||||
|
@ -283,7 +285,7 @@ def test_download_url_to_iso(
|
||||||
|
|
||||||
m = response_data["messages"]
|
m = response_data["messages"]
|
||||||
assert m[0]["message"] == 'Created CD-ROM ISO image with arguments "-hfs"'
|
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}"
|
assert m[2]["message"] == f"Attached to SCSI ID {SCSI_ID}"
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from conftest import (
|
from conftest import (
|
||||||
CFG_DIR,
|
|
||||||
FILE_SIZE_1_MIB,
|
FILE_SIZE_1_MIB,
|
||||||
STATUS_SUCCESS,
|
STATUS_SUCCESS,
|
||||||
)
|
)
|
||||||
|
@ -46,7 +45,7 @@ def test_show_named_drive_presets(http_client):
|
||||||
|
|
||||||
|
|
||||||
# route("/drive/cdrom", methods=["POST"])
|
# 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"
|
file_name = f"{uuid.uuid4()}.iso"
|
||||||
|
|
||||||
response = http_client.post(
|
response = http_client.post(
|
||||||
|
@ -62,7 +61,7 @@ def test_create_cdrom_properties_file(http_client):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response_data["status"] == STATUS_SUCCESS
|
assert response_data["status"] == STATUS_SUCCESS
|
||||||
assert response_data["messages"][0]["message"] == (
|
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
|
# Cleanup
|
||||||
delete_file(file_name)
|
delete_file(file_name)
|
||||||
|
|
||||||
|
|
||||||
# route("/sys/manpage", methods=["POST"])
|
# route("/sys/manpage", methods=["POST"])
|
||||||
def test_show_manpage(http_client):
|
def test_show_manpage(http_client):
|
||||||
response = http_client.get("/sys/manpage?app=rascsi")
|
response = http_client.get("/sys/manpage?app=rascsi")
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from conftest import CFG_DIR, STATUS_SUCCESS
|
from conftest import STATUS_SUCCESS
|
||||||
|
|
||||||
|
|
||||||
# route("/language", methods=["POST"])
|
# route("/language", methods=["POST"])
|
||||||
|
@ -74,7 +74,7 @@ def test_show_logs(http_client):
|
||||||
|
|
||||||
# route("/config/save", methods=["POST"])
|
# route("/config/save", methods=["POST"])
|
||||||
# route("/config/load", 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_name = str(uuid.uuid4())
|
||||||
config_json_file = f"{config_name}.json"
|
config_json_file = f"{config_name}.json"
|
||||||
reserved_scsi_id = 0
|
reserved_scsi_id = 0
|
||||||
|
@ -96,7 +96,7 @@ def test_save_load_and_delete_configs(http_client):
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response_data["status"] == STATUS_SUCCESS
|
assert response_data["status"] == STATUS_SUCCESS
|
||||||
assert response_data["messages"][0]["message"] == (
|
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"]
|
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.status_code == 200
|
||||||
assert response_data["status"] == STATUS_SUCCESS
|
assert response_data["status"] == STATUS_SUCCESS
|
||||||
assert response_data["messages"][0]["message"] == (
|
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"]
|
assert config_json_file not in http_client.get("/").json()["data"]["config_files"]
|
||||||
|
|
|
@ -1,15 +1,32 @@
|
||||||
import pytest
|
import pytest
|
||||||
import requests
|
import requests
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption("--base_url", action="store", default="http://localhost:8080")
|
default_base_url = "http://rascsi_web" if os.getenv("DOCKER") else "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")
|
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_username", action="store", default="pi")
|
||||||
parser.addoption("--rascsi_password", action="store", default="rascsi")
|
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")
|
@pytest.fixture(scope="session")
|
||||||
def httpserver_listen_address(pytestconfig):
|
def httpserver_listen_address(pytestconfig):
|
||||||
return (pytestconfig.getoption("httpserver_listen_address"), 0)
|
return (pytestconfig.getoption("httpserver_listen_address"), 0)
|
||||||
|
@ -17,8 +34,7 @@ def httpserver_listen_address(pytestconfig):
|
||||||
|
|
||||||
@pytest.fixture(scope="function", autouse=True)
|
@pytest.fixture(scope="function", autouse=True)
|
||||||
def set_httpserver_hostname(pytestconfig, httpserver):
|
def set_httpserver_hostname(pytestconfig, httpserver):
|
||||||
# The HTTP requests are made by Python from within the container so we need
|
# We need httpserver.url_for() to generate URLs pointing to the correct host
|
||||||
# httpserver.url_for to generate URLs which point to the Docker host
|
|
||||||
httpserver.host = pytestconfig.getoption("httpserver_host")
|
httpserver.host = pytestconfig.getoption("httpserver_host")
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue