mirror of
https://github.com/QIDITECH/moonraker.git
synced 2026-01-30 16:18:44 +03:00
QIDI moonraker
This commit is contained in:
244
tests/conftest.py
Normal file
244
tests/conftest.py
Normal file
@@ -0,0 +1,244 @@
|
||||
from __future__ import annotations
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import asyncio
|
||||
import shutil
|
||||
import re
|
||||
import pathlib
|
||||
import sys
|
||||
import shlex
|
||||
import tempfile
|
||||
import subprocess
|
||||
from typing import Iterator, Dict, AsyncIterator, Any
|
||||
from moonraker import Server
|
||||
from eventloop import EventLoop
|
||||
import utils
|
||||
import dbtool
|
||||
from fixtures import KlippyProcess, HttpClient, WebsocketClient
|
||||
|
||||
ASSETS = pathlib.Path(__file__).parent.joinpath("assets")
|
||||
|
||||
need_klippy_restart = pytest.StashKey[bool]()
|
||||
|
||||
def pytest_addoption(parser: pytest.Parser, pluginmanager):
|
||||
parser.addoption("--klipper-path", action="store", dest="klipper_path")
|
||||
parser.addoption("--klipper-exec", action="store", dest="klipper_exec")
|
||||
|
||||
def interpolate_config(source_path: pathlib.Path,
|
||||
dest_path: pathlib.Path,
|
||||
keys: Dict[str, Any]
|
||||
) -> None:
|
||||
def interp(match):
|
||||
return str(keys[match.group(1)])
|
||||
sub_data = re.sub(r"\${([^}]+)}", interp, source_path.read_text())
|
||||
dest_path.write_text(sub_data)
|
||||
|
||||
@pytest.fixture(scope="session", autouse=True)
|
||||
def ssl_certs() -> Iterator[Dict[str, pathlib.Path]]:
|
||||
with tempfile.TemporaryDirectory(prefix="moonraker-certs-") as tmpdir:
|
||||
tmp_path = pathlib.Path(tmpdir)
|
||||
cert_path = tmp_path.joinpath("certificate.pem")
|
||||
key_path = tmp_path.joinpath("privkey.pem")
|
||||
cmd = (
|
||||
f"openssl req -newkey rsa:4096 -nodes -keyout {key_path} "
|
||||
f"-x509 -days 365 -out {cert_path} -sha256 "
|
||||
"-subj '/C=US/ST=NRW/L=Earth/O=Moonraker/OU=IT/"
|
||||
"CN=www.moonraker-test.com/emailAddress=mail@moonraker-test.com'"
|
||||
)
|
||||
args = shlex.split(cmd)
|
||||
subprocess.run(args, check=True)
|
||||
yield {
|
||||
"ssl_certificate_path": cert_path,
|
||||
"ssl_key_path": key_path,
|
||||
}
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def event_loop() -> Iterator[asyncio.AbstractEventLoop]:
|
||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||
yield loop
|
||||
loop.close()
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def session_args(ssl_certs: Dict[str, pathlib.Path]
|
||||
) -> Iterator[Dict[str, pathlib.Path]]:
|
||||
mconf_asset = ASSETS.joinpath(f"moonraker/base_server.conf")
|
||||
secrets_asset = ASSETS.joinpath(f"moonraker/secrets.ini")
|
||||
pcfg_asset = ASSETS.joinpath(f"klipper/base_printer.cfg")
|
||||
with tempfile.TemporaryDirectory(prefix="moonraker-test") as tmpdir:
|
||||
tmp_path = pathlib.Path(tmpdir)
|
||||
secrets_dest = tmp_path.joinpath("secrets.ini")
|
||||
shutil.copy(secrets_asset, secrets_dest)
|
||||
cfg_path = tmp_path.joinpath("config")
|
||||
cfg_path.mkdir()
|
||||
log_path = tmp_path.joinpath("logs")
|
||||
log_path.mkdir()
|
||||
db_path = tmp_path.joinpath("database")
|
||||
db_path.mkdir()
|
||||
gcode_path = tmp_path.joinpath("gcode_files")
|
||||
gcode_path.mkdir()
|
||||
dest_paths = {
|
||||
"temp_path": tmp_path,
|
||||
"asset_path": ASSETS,
|
||||
"config_path": cfg_path,
|
||||
"database_path": db_path,
|
||||
"log_path": log_path,
|
||||
"gcode_path": gcode_path,
|
||||
"secrets_path": secrets_dest,
|
||||
"klippy_uds_path": tmp_path.joinpath("klippy_uds"),
|
||||
"klippy_pty_path": tmp_path.joinpath("klippy_pty"),
|
||||
"klipper.dict": ASSETS.joinpath("klipper/klipper.dict"),
|
||||
"mconf_asset": mconf_asset,
|
||||
"pcfg_asset": pcfg_asset,
|
||||
}
|
||||
dest_paths.update(ssl_certs)
|
||||
mconf_dest = cfg_path.joinpath("moonraker.conf")
|
||||
dest_paths["moonraker.conf"] = mconf_dest
|
||||
interpolate_config(mconf_asset, mconf_dest, dest_paths)
|
||||
pcfg_dest = cfg_path.joinpath("printer.cfg")
|
||||
dest_paths["printer.cfg"] = pcfg_dest
|
||||
interpolate_config(pcfg_asset, pcfg_dest, dest_paths)
|
||||
yield dest_paths
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def klippy_session(session_args: Dict[str, pathlib.Path],
|
||||
pytestconfig: pytest.Config) -> Iterator[KlippyProcess]:
|
||||
pytestconfig.stash[need_klippy_restart] = False
|
||||
kpath = pytestconfig.getoption('klipper_path', "~/klipper")
|
||||
kexec = pytestconfig.getoption('klipper_exec', None)
|
||||
if kexec is None:
|
||||
kexec = sys.executable
|
||||
exec = pathlib.Path(kexec).expanduser()
|
||||
klipper_path = pathlib.Path(kpath).expanduser()
|
||||
base_cmd = f"{exec} {klipper_path}/klippy/klippy.py "
|
||||
kproc = KlippyProcess(base_cmd, session_args)
|
||||
kproc.start()
|
||||
yield kproc
|
||||
kproc.stop()
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def klippy(klippy_session: KlippyProcess,
|
||||
pytestconfig: pytest.Config):
|
||||
if pytestconfig.stash[need_klippy_restart]:
|
||||
pytestconfig.stash[need_klippy_restart] = False
|
||||
klippy_session.restart()
|
||||
return klippy_session
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def path_args(request: pytest.FixtureRequest,
|
||||
session_args: Dict[str, pathlib.Path],
|
||||
pytestconfig: pytest.Config
|
||||
) -> Iterator[Dict[str, pathlib.Path]]:
|
||||
path_marker = request.node.get_closest_marker("run_paths")
|
||||
paths: Dict[str, Any] = {
|
||||
"moonraker_conf": "base_server.conf",
|
||||
"secrets": "secrets.ini",
|
||||
"printer_cfg": "base_printer.cfg",
|
||||
"klippy_uds": None,
|
||||
}
|
||||
if path_marker is not None:
|
||||
paths.update(path_marker.kwargs)
|
||||
tmp_path = session_args["temp_path"]
|
||||
cfg_path = session_args["config_path"]
|
||||
mconf_dest = session_args["moonraker.conf"]
|
||||
mconf_asset = ASSETS.joinpath(f"moonraker/{paths['moonraker_conf']}")
|
||||
pcfg_asset = ASSETS.joinpath(f"klipper/{paths['printer_cfg']}")
|
||||
last_uds = session_args["klippy_uds_path"]
|
||||
if paths["klippy_uds"] is not None:
|
||||
tmp_uds = tmp_path.joinpath(paths["klippy_uds"])
|
||||
session_args["klippy_uds_path"] = tmp_uds
|
||||
if (
|
||||
not mconf_asset.samefile(session_args["mconf_asset"]) or
|
||||
paths["klippy_uds"] is not None
|
||||
):
|
||||
session_args['mconf_asset'] = mconf_asset
|
||||
interpolate_config(mconf_asset, mconf_dest, session_args)
|
||||
if not pcfg_asset.samefile(session_args["pcfg_asset"]):
|
||||
pcfg_dest = session_args["printer.cfg"]
|
||||
session_args["pcfg_asset"] = pcfg_asset
|
||||
interpolate_config(pcfg_asset, pcfg_dest, session_args)
|
||||
pytestconfig.stash[need_klippy_restart] = True
|
||||
if paths["secrets"] != session_args["secrets_path"].name:
|
||||
secrets_asset = ASSETS.joinpath(f"moonraker/{paths['secrets']}")
|
||||
secrets_dest = tmp_path.joinpath(paths['secrets'])
|
||||
shutil.copy(secrets_asset, secrets_dest)
|
||||
session_args["secrets_path"] = secrets_dest
|
||||
if "moonraker_log" in paths:
|
||||
log_path = session_args["log_path"]
|
||||
session_args['moonraker.log'] = log_path.joinpath(
|
||||
paths["moonraker_log"])
|
||||
bkp_dest: pathlib.Path = cfg_path.joinpath(".moonraker.conf.bkp")
|
||||
if "moonraker_bkp" in paths:
|
||||
bkp_source = ASSETS.joinpath("moonraker/base_server.conf")
|
||||
bkp_dest = cfg_path.joinpath(paths["moonraker_bkp"])
|
||||
interpolate_config(bkp_source, bkp_dest, session_args)
|
||||
if "database" in paths:
|
||||
db_source = ASSETS.joinpath(f"moonraker/{paths['database']}")
|
||||
db_dest = session_args["database_path"]
|
||||
db_args = {"input": str(db_source), "destination": db_dest}
|
||||
dbtool.restore(db_args)
|
||||
yield session_args
|
||||
log = session_args.pop("moonraker.log", None)
|
||||
if log is not None and log.is_file():
|
||||
log.unlink()
|
||||
if bkp_dest.is_file():
|
||||
bkp_dest.unlink()
|
||||
for item in session_args["database_path"].iterdir():
|
||||
if item.is_file():
|
||||
item.unlink()
|
||||
session_args["klippy_uds_path"] = last_uds
|
||||
if paths["klippy_uds"] is not None:
|
||||
# restore the original uds path
|
||||
interpolate_config(mconf_asset, mconf_dest, session_args)
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def base_server(path_args: Dict[str, pathlib.Path],
|
||||
event_loop: asyncio.AbstractEventLoop
|
||||
) -> Iterator[Server]:
|
||||
evtloop = EventLoop()
|
||||
args = {
|
||||
'config_file': str(path_args['moonraker.conf']),
|
||||
'log_file': str(path_args.get("moonraker.log", "")),
|
||||
'software_version': "moonraker-pytest"
|
||||
}
|
||||
ql = logger = None
|
||||
if args["log_file"]:
|
||||
ql, logger, warning = utils.setup_logging(args)
|
||||
if warning:
|
||||
args["log_warning"] = warning
|
||||
yield Server(args, logger, evtloop)
|
||||
if ql is not None:
|
||||
ql.stop()
|
||||
|
||||
@pytest_asyncio.fixture(scope="class")
|
||||
async def full_server(base_server: Server) -> AsyncIterator[Server]:
|
||||
base_server.load_components()
|
||||
ret = base_server.server_init(start_server=False)
|
||||
await asyncio.wait_for(ret, 4.)
|
||||
yield base_server
|
||||
if base_server.event_loop.aioloop.is_running():
|
||||
await base_server._stop_server(exit_reason="terminate")
|
||||
|
||||
@pytest_asyncio.fixture(scope="class")
|
||||
async def ready_server(full_server: Server, klippy: KlippyProcess):
|
||||
ret = full_server.start_server(connect_to_klippy=False)
|
||||
await asyncio.wait_for(ret, 4.)
|
||||
ret = full_server.klippy_connection.connect()
|
||||
await asyncio.wait_for(ret, 4.)
|
||||
yield full_server
|
||||
|
||||
@pytest_asyncio.fixture(scope="class")
|
||||
async def http_client() -> AsyncIterator[HttpClient]:
|
||||
client = HttpClient()
|
||||
yield client
|
||||
client.close()
|
||||
|
||||
@pytest_asyncio.fixture(scope="class")
|
||||
async def websocket_client(request: pytest.FixtureRequest
|
||||
) -> AsyncIterator[WebsocketClient]:
|
||||
conn_marker = request.node.get_closest_marker("no_ws_connect")
|
||||
client = WebsocketClient()
|
||||
if conn_marker is None:
|
||||
await client.connect()
|
||||
yield client
|
||||
client.close()
|
||||
Reference in New Issue
Block a user