diff options
author | Devaev Maxim <[email protected]> | 2019-04-14 23:15:06 +0300 |
---|---|---|
committer | Devaev Maxim <[email protected]> | 2019-04-14 23:16:29 +0300 |
commit | bc0deaee5f487ec2bb752a9dbe78ffe51d2559e5 (patch) | |
tree | d14dc029c3ecb57dec1824427cdec479b15a5ddc /testenv | |
parent | 92260645c57689665c1fcd3f65b79a059d99d421 (diff) |
moved tests to testenv
Diffstat (limited to 'testenv')
-rw-r--r-- | testenv/tests/__init__.py | 59 | ||||
-rw-r--r-- | testenv/tests/apps/__init__.py | 20 | ||||
-rw-r--r-- | testenv/tests/apps/test_cleanup.py | 71 | ||||
-rw-r--r-- | testenv/tests/apps/test_htpasswd.py | 170 | ||||
-rw-r--r-- | testenv/tests/auth/__init__.py | 43 | ||||
-rw-r--r-- | testenv/tests/auth/test_service_htpasswd.py | 54 | ||||
-rw-r--r-- | testenv/tests/auth/test_service_http.py | 79 | ||||
-rw-r--r-- | testenv/tests/test_aioregion.py | 113 | ||||
-rw-r--r-- | testenv/tests/test_gpio.py | 58 | ||||
-rw-r--r-- | testenv/tests/test_keymap.py | 36 | ||||
-rw-r--r-- | testenv/tests/test_logging.py | 35 | ||||
-rw-r--r-- | testenv/tests/validators/__init__.py | 20 | ||||
-rw-r--r-- | testenv/tests/validators/test_auth.py | 130 | ||||
-rw-r--r-- | testenv/tests/validators/test_basic.py | 144 | ||||
-rw-r--r-- | testenv/tests/validators/test_hw.py | 72 | ||||
-rw-r--r-- | testenv/tests/validators/test_kvm.py | 169 | ||||
-rw-r--r-- | testenv/tests/validators/test_net.py | 122 | ||||
-rw-r--r-- | testenv/tests/validators/test_os.py | 118 | ||||
-rw-r--r-- | testenv/tox.ini | 12 |
19 files changed, 1520 insertions, 5 deletions
diff --git a/testenv/tests/__init__.py b/testenv/tests/__init__.py new file mode 100644 index 00000000..d1faace6 --- /dev/null +++ b/testenv/tests/__init__.py @@ -0,0 +1,59 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import sys + +from typing import Dict +from typing import Optional + +import fake_rpi.RPi + + +# ===== +class _GPIO(fake_rpi.RPi._GPIO): # pylint: disable=protected-access + def __init__(self) -> None: + super().__init__() + self.__states: Dict[int, int] = {} + + @fake_rpi.RPi.printf + def setup(self, channel: int, state: int, initial: int=0, pull_up_down: Optional[int]=None) -> None: + _ = state # Makes linter happy + _ = pull_up_down # Makes linter happy + self.__states[int(channel)] = int(initial) + + @fake_rpi.RPi.printf + def output(self, channel: int, state: int) -> None: + self.__states[int(channel)] = int(state) + + @fake_rpi.RPi.printf + def input(self, channel: int) -> int: # pylint: disable=arguments-differ + return self.__states[int(channel)] + + @fake_rpi.RPi.printf + def cleanup(self, channel: Optional[int]=None) -> None: # pylint: disable=arguments-differ + _ = channel # Makes linter happy + self.__states = {} + + +# ===== +fake_rpi.RPi.GPIO = _GPIO() +sys.modules["RPi"] = fake_rpi.RPi diff --git a/testenv/tests/apps/__init__.py b/testenv/tests/apps/__init__.py new file mode 100644 index 00000000..1e91f7fa --- /dev/null +++ b/testenv/tests/apps/__init__.py @@ -0,0 +1,20 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # diff --git a/testenv/tests/apps/test_cleanup.py b/testenv/tests/apps/test_cleanup.py new file mode 100644 index 00000000..3e2e4c72 --- /dev/null +++ b/testenv/tests/apps/test_cleanup.py @@ -0,0 +1,71 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import os +import secrets +import multiprocessing +import multiprocessing.queues +import time + +import setproctitle + +from kvmd.apps.cleanup import main + + +# ===== +def test_ok(tmpdir) -> None: # type: ignore + queue: multiprocessing.queues.Queue = multiprocessing.Queue() + + ustreamer_tmp_path = os.path.abspath(str(tmpdir.join("ustr-" + secrets.token_hex(3)))) + os.symlink("/usr/bin/ustreamer", ustreamer_tmp_path) + + ustreamer_sock_path = os.path.abspath(str(tmpdir.join("ustreamer-fake.sock"))) + open(ustreamer_sock_path, "w").close() + kvmd_sock_path = os.path.abspath(str(tmpdir.join("kvmd-fake.sock"))) + open(kvmd_sock_path, "w").close() + + def ustreamer_fake() -> None: + setproctitle.setproctitle(os.path.basename(ustreamer_tmp_path)) + queue.put(True) + while True: + time.sleep(1) + + proc = multiprocessing.Process(target=ustreamer_fake, daemon=True) + proc.start() + assert queue.get(timeout=5) + + assert proc.is_alive() + main([ + "kvmd-cleanup", + "--set-options", + "kvmd/server/port=0", + "kvmd/server/unix=" + kvmd_sock_path, + "kvmd/streamer/port=0", + "kvmd/streamer/unix=" + ustreamer_sock_path, + "kvmd/streamer/cmd=" + ustreamer_tmp_path, + ]) + + assert not os.path.exists(ustreamer_sock_path) + assert not os.path.exists(kvmd_sock_path) + + assert not proc.is_alive() + proc.join() diff --git a/testenv/tests/apps/test_htpasswd.py b/testenv/tests/apps/test_htpasswd.py new file mode 100644 index 00000000..52a38640 --- /dev/null +++ b/testenv/tests/apps/test_htpasswd.py @@ -0,0 +1,170 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import os +import hashlib +import tempfile +import builtins +import getpass + +from typing import List +from typing import Generator +from typing import Any + +import passlib.apache + +import pytest + +from kvmd.apps.htpasswd import main + + +# ===== +def _make_passwd(user: str) -> str: + return hashlib.md5(user.encode()).hexdigest() + + [email protected](name="htpasswd", params=[[], ["admin"], ["admin", "user"]]) +def _htpasswd_fixture(request) -> Generator[passlib.apache.HtpasswdFile, None, None]: # type: ignore + (fd, path) = tempfile.mkstemp() + os.close(fd) + htpasswd = passlib.apache.HtpasswdFile(path) + for user in request.param: + htpasswd.set_password(user, _make_passwd(user)) + htpasswd.save() + yield htpasswd + os.remove(path) + + +def _run_htpasswd(cmd: List[str], htpasswd_path: str, internal_type: str="htpasswd") -> None: + cmd = ["kvmd-htpasswd", *cmd, "--set-options"] + if internal_type != "htpasswd": # By default + cmd.append("kvmd/auth/internal_type=" + internal_type) + if htpasswd_path: + cmd.append("kvmd/auth/internal/file=" + htpasswd_path) + main(cmd) + + +# ===== +def test_ok__list(htpasswd: passlib.apache.HtpasswdFile, capsys) -> None: # type: ignore + _run_htpasswd(["list"], htpasswd.path) + (out, err) = capsys.readouterr() + assert len(err) == 0 + assert sorted(filter(None, out.split("\n"))) == sorted(htpasswd.users()) == sorted(set(htpasswd.users())) + + +# ===== +def test_ok__set_change_stdin(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore + old_users = set(htpasswd.users()) + if old_users: + assert htpasswd.check_password("admin", _make_passwd("admin")) + + mocker.patch.object(builtins, "input", (lambda: " test ")) + _run_htpasswd(["set", "admin", "--read-stdin"], htpasswd.path) + + htpasswd.load(force=True) + assert htpasswd.check_password("admin", " test ") + assert old_users == set(htpasswd.users()) + + +def test_ok__set_add_stdin(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore + old_users = set(htpasswd.users()) + if old_users: + mocker.patch.object(builtins, "input", (lambda: " test ")) + _run_htpasswd(["set", "new", "--read-stdin"], htpasswd.path) + + htpasswd.load(force=True) + assert htpasswd.check_password("new", " test ") + assert old_users.union(["new"]) == set(htpasswd.users()) + + +# ===== +def test_ok__set_change_getpass(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore + old_users = set(htpasswd.users()) + if old_users: + assert htpasswd.check_password("admin", _make_passwd("admin")) + + mocker.patch.object(getpass, "getpass", (lambda *_, **__: " test ")) + _run_htpasswd(["set", "admin"], htpasswd.path) + + htpasswd.load(force=True) + assert htpasswd.check_password("admin", " test ") + assert old_users == set(htpasswd.users()) + + +def test_fail__set_change_getpass(htpasswd: passlib.apache.HtpasswdFile, mocker) -> None: # type: ignore + old_users = set(htpasswd.users()) + if old_users: + assert htpasswd.check_password("admin", _make_passwd("admin")) + + count = 0 + + def fake_getpass(*_: Any, **__: Any) -> str: + nonlocal count + assert count <= 1 + if count == 0: + passwd = " test " + else: + passwd = "test " + count += 1 + return passwd + + mocker.patch.object(getpass, "getpass", fake_getpass) + with pytest.raises(SystemExit, match="Sorry, passwords do not match"): + _run_htpasswd(["set", "admin"], htpasswd.path) + assert count == 2 + + htpasswd.load(force=True) + assert htpasswd.check_password("admin", _make_passwd("admin")) + assert old_users == set(htpasswd.users()) + + +# ===== +def test_ok__del(htpasswd: passlib.apache.HtpasswdFile) -> None: + old_users = set(htpasswd.users()) + + if old_users: + assert htpasswd.check_password("admin", _make_passwd("admin")) + + _run_htpasswd(["del", "admin"], htpasswd.path) + + htpasswd.load(force=True) + assert not htpasswd.check_password("admin", _make_passwd("admin")) + assert old_users.difference(["admin"]) == set(htpasswd.users()) + + +# ===== +def test_fail__not_htpasswd() -> None: + with pytest.raises(SystemExit, match="Error: KVMD internal auth not using 'htpasswd'"): + _run_htpasswd(["list"], "", internal_type="http") + + +def test_fail__unknown_plugin() -> None: + with pytest.raises(SystemExit, match="Config error: Unknown plugin 'auth/foobar'"): + _run_htpasswd(["list"], "", internal_type="foobar") + + +def test_fail__invalid_passwd(mocker, tmpdir) -> None: # type: ignore + path = os.path.abspath(str(tmpdir.join("htpasswd"))) + open(path, "w").close() + mocker.patch.object(builtins, "input", (lambda: "\n")) + with pytest.raises(SystemExit, match="The argument is not a valid passwd characters"): + _run_htpasswd(["set", "admin", "--read-stdin"], path) diff --git a/testenv/tests/auth/__init__.py b/testenv/tests/auth/__init__.py new file mode 100644 index 00000000..cdaa6cfb --- /dev/null +++ b/testenv/tests/auth/__init__.py @@ -0,0 +1,43 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import contextlib + +from typing import AsyncGenerator +from typing import Any + +from kvmd.yamlconf import make_config + +from kvmd.plugins.auth import BaseAuthService +from kvmd.plugins.auth import get_auth_service_class + + +# ===== +async def get_configured_auth_service(name: str, **kwargs: Any) -> AsyncGenerator[BaseAuthService, None]: + service_class = get_auth_service_class(name) + config = make_config(kwargs, service_class.get_options()) + service = service_class(**config._unpack()) # pylint: disable=protected-access + try: + yield service + finally: + await service.cleanup() diff --git a/testenv/tests/auth/test_service_htpasswd.py b/testenv/tests/auth/test_service_htpasswd.py new file mode 100644 index 00000000..6378d896 --- /dev/null +++ b/testenv/tests/auth/test_service_htpasswd.py @@ -0,0 +1,54 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import os + +import passlib.apache + +import pytest + +from . import get_configured_auth_service + + +# ===== +async def test_ok__htpasswd_service(tmpdir) -> None: # type: ignore + path = os.path.abspath(str(tmpdir.join("htpasswd"))) + + htpasswd = passlib.apache.HtpasswdFile(path, new=True) + htpasswd.set_password("admin", "pass") + htpasswd.save() + + async with get_configured_auth_service("htpasswd", file=path) as service: + assert not (await service.login("user", "foo")) + assert not (await service.login("admin", "foo")) + assert not (await service.login("user", "pass")) + assert (await service.login("admin", "pass")) + + htpasswd.set_password("admin", "bar") + htpasswd.set_password("user", "bar") + htpasswd.save() + + assert (await service.login("admin", "bar")) + assert (await service.login("user", "bar")) + assert not (await service.login("admin", "foo")) + assert not (await service.login("user", "foo")) diff --git a/testenv/tests/auth/test_service_http.py b/testenv/tests/auth/test_service_http.py new file mode 100644 index 00000000..c6f2b631 --- /dev/null +++ b/testenv/tests/auth/test_service_http.py @@ -0,0 +1,79 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import Dict +from typing import AsyncGenerator + +import aiohttp.web +import aiohttp_basicauth + +import pytest + +from . import get_configured_auth_service + + +# ===== +async def _handle_auth(request: aiohttp.web.BaseRequest) -> aiohttp.web.Response: + status = 400 + if request.method == "POST": + credentials = (await request.json()) + if credentials["user"] == "admin" and credentials["passwd"] == "pass": + status = 200 + return aiohttp.web.Response(text=str(status), status=status) + + [email protected](name="auth_server_port") +async def _auth_server_port_fixture(aiohttp_server) -> AsyncGenerator[int, None]: # type: ignore + auth = aiohttp_basicauth.BasicAuthMiddleware( + username="server-admin", + password="server-pass", + force=False, + ) + + app = aiohttp.web.Application(middlewares=[auth]) + app.router.add_post("/auth", _handle_auth) + app.router.add_post("/auth_plus_basic", auth.required(_handle_auth)) + + server = await aiohttp_server(app) + try: + yield server.port + finally: + await server.close() + + +# ===== [email protected]("kwargs", [ + {}, + {"verify": False}, + {"user": "server-admin", "passwd": "server-pass"}, +]) +async def test_ok(auth_server_port: int, kwargs: Dict) -> None: + url = "http://localhost:%d/%s" % ( + auth_server_port, + ("auth_plus_basic" if kwargs.get("user") else "auth"), + ) + async with get_configured_auth_service("http", url=url, **kwargs) as service: + assert not (await service.login("user", "foobar")) + assert not (await service.login("admin", "foobar")) + assert not (await service.login("user", "pass")) + assert (await service.login("admin", "pass")) diff --git a/testenv/tests/test_aioregion.py b/testenv/tests/test_aioregion.py new file mode 100644 index 00000000..601f5280 --- /dev/null +++ b/testenv/tests/test_aioregion.py @@ -0,0 +1,113 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import asyncio + +import pytest + +from kvmd.aioregion import RegionIsBusyError +from kvmd.aioregion import AioExclusiveRegion + + +# ===== +async def test_ok__access_one() -> None: + region = AioExclusiveRegion(RegionIsBusyError) + + async def func() -> None: + assert not region.is_busy() + with region: + assert region.is_busy() + assert not region.is_busy() + + await func() + + assert not region.is_busy() + region.exit() + assert not region.is_busy() + + +async def test_fail__access_one() -> None: + region = AioExclusiveRegion(RegionIsBusyError) + + async def func() -> None: + assert not region.is_busy() + with region: + assert region.is_busy() + region.enter() + assert not region.is_busy() + + with pytest.raises(RegionIsBusyError): + await func() + + assert not region.is_busy() + region.exit() + assert not region.is_busy() + + +# ===== +async def test_ok__access_two() -> None: + region = AioExclusiveRegion(RegionIsBusyError) + + async def func1() -> None: + with region: + await asyncio.sleep(1) + print("done func1()") + + async def func2() -> None: + await asyncio.sleep(2) + print("waiking up func2()") + with region: + await asyncio.sleep(1) + print("done func2()") + + await asyncio.gather(func1(), func2()) + + assert not region.is_busy() + region.exit() + assert not region.is_busy() + + +async def test_fail__access_two() -> None: + region = AioExclusiveRegion(RegionIsBusyError) + + async def func1() -> None: + with region: + await asyncio.sleep(2) + print("done func1()") + + async def func2() -> None: + await asyncio.sleep(1) + with region: + await asyncio.sleep(1) + print("done func2()") + + results = await asyncio.gather(func1(), func2(), return_exceptions=True) + assert results[0] is None + assert type(results[1]) == RegionIsBusyError # pylint: disable=unidiomatic-typecheck + + assert not region.is_busy() + region.exit() + assert not region.is_busy() diff --git a/testenv/tests/test_gpio.py b/testenv/tests/test_gpio.py new file mode 100644 index 00000000..6a02816d --- /dev/null +++ b/testenv/tests/test_gpio.py @@ -0,0 +1,58 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import pytest + +from kvmd import gpio + + +# ===== [email protected]("pin", [0, 1, 13]) +def test_ok__loopback_initial_false(pin: int) -> None: + with gpio.bcm(): + assert gpio.set_output(pin) == pin + assert gpio.read(pin) is False + gpio.write(pin, True) + assert gpio.read(pin) is True + + [email protected]("pin", [0, 1, 13]) +def test_ok__loopback_initial_true(pin: int) -> None: + with gpio.bcm(): + assert gpio.set_output(pin, True) == pin + assert gpio.read(pin) is True + gpio.write(pin, False) + assert gpio.read(pin) is False + + [email protected]("pin", [0, 1, 13]) +def test_ok__input(pin: int) -> None: + with gpio.bcm(): + assert gpio.set_input(pin) == pin + assert gpio.read(pin) is False + + +def test_fail__invalid_pin() -> None: + with pytest.raises(AssertionError): + gpio.set_output(-1) + with pytest.raises(AssertionError): + gpio.set_input(-1) diff --git a/testenv/tests/test_keymap.py b/testenv/tests/test_keymap.py new file mode 100644 index 00000000..f69accb1 --- /dev/null +++ b/testenv/tests/test_keymap.py @@ -0,0 +1,36 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import pytest + +from kvmd.keymap import KEYMAP + + +# ===== +def test_ok__keymap() -> None: + assert type(KEYMAP["KeyA"]) == int # pylint: disable=unidiomatic-typecheck + assert KEYMAP["KeyA"] == 1 + + +def test_fail__keymap() -> None: + with pytest.raises(KeyError): + print(KEYMAP["keya"]) diff --git a/testenv/tests/test_logging.py b/testenv/tests/test_logging.py new file mode 100644 index 00000000..e6372e33 --- /dev/null +++ b/testenv/tests/test_logging.py @@ -0,0 +1,35 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import pytest + +from kvmd.logging import get_logger + + +# ===== [email protected]("depth, name", [ + (0, "tests.test_logging"), + (1, "_pytest.python"), + (2, "pluggy.callers"), +]) +def test_ok__get_logger(depth: int, name: str) -> None: + assert get_logger(depth).name == name diff --git a/testenv/tests/validators/__init__.py b/testenv/tests/validators/__init__.py new file mode 100644 index 00000000..1e91f7fa --- /dev/null +++ b/testenv/tests/validators/__init__.py @@ -0,0 +1,20 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # diff --git a/testenv/tests/validators/test_auth.py b/testenv/tests/validators/test_auth.py new file mode 100644 index 00000000..f3cdf939 --- /dev/null +++ b/testenv/tests/validators/test_auth.py @@ -0,0 +1,130 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import List +from typing import Any + +import pytest + +from kvmd.validators import ValidatorError +from kvmd.validators.auth import valid_user +from kvmd.validators.auth import valid_users_list +from kvmd.validators.auth import valid_passwd +from kvmd.validators.auth import valid_auth_token + + +# ===== [email protected]("arg", [ + "test-", + "glados", + "test", + "_", + "_foo_bar_", + " aix", +]) +def test_ok__valid_user(arg: Any) -> None: + assert valid_user(arg) == arg.strip() + + [email protected]("arg", [ + "тест", + "-molestia", + "te~st", + "-", + "-foo_bar", + " ", + "", + None, +]) +def test_fail__valid_user(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_user(arg)) + + +# ===== [email protected]("arg, retval", [ + ("foo, bar, ", ["foo", "bar"]), + ("foo bar", ["foo", "bar"]), + (["foo", "bar"], ["foo", "bar"]), + ("", []), + (" ", []), + (", ", []), + (", foo, ", ["foo"]), + ([], []), +]) +def test_ok__valid_users_list(arg: Any, retval: List) -> None: + assert valid_users_list(arg) == retval + + [email protected]("arg", [None, [None], [""], [" "], ["user,"]]) +def test_fail__valid_users_list(arg: Any) -> None: # pylint: disable=invalid-name + with pytest.raises(ValidatorError): + print(valid_users_list(arg)) + + +# ===== [email protected]("arg", [ + "glados", + "test", + "_", + "_foo_bar_", + " aix", + " ", + "", + " O(*#&@)FD*S)D(F ", +]) +def test_ok__valid_passwd(arg: Any) -> None: + assert valid_passwd(arg) == arg + + [email protected]("arg", [ + "тест", + "\n", + " \n", + "\n\n", + "\r", + None, +]) +def test_fail__valid_passwd(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_passwd(arg)) + + +# ===== [email protected]("arg", [ + ("0" * 64) + " ", + ("f" * 64) + " ", +]) +def test_ok__valid_auth_token(arg: Any) -> None: + assert valid_auth_token(arg) == arg.strip() + + [email protected]("arg", [ + ("F" * 64), + "0" * 63, + "0" * 65, + "", + None, +]) +def test_fail__valid_auth_token(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_auth_token(arg)) diff --git a/testenv/tests/validators/test_basic.py b/testenv/tests/validators/test_basic.py new file mode 100644 index 00000000..96feb666 --- /dev/null +++ b/testenv/tests/validators/test_basic.py @@ -0,0 +1,144 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import List +from typing import Any + +import pytest + +from kvmd.validators import ValidatorError +from kvmd.validators.basic import valid_bool +from kvmd.validators.basic import valid_number +from kvmd.validators.basic import valid_int_f1 +from kvmd.validators.basic import valid_float_f01 +from kvmd.validators.basic import valid_string_list + + +# ===== [email protected]("arg, retval", [ + ("1", True), + ("true", True), + ("TRUE", True), + ("yes ", True), + (1, True), + (True, True), + ("0", False), + ("false", False), + ("FALSE", False), + ("no ", False), + (0, False), + (False, False), +]) +def test_ok__valid_bool(arg: Any, retval: bool) -> None: + assert valid_bool(arg) == retval + + [email protected]("arg", ["test", "", None, -1, "x"]) +def test_fail__valid_bool(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_bool(arg)) + + +# ===== [email protected]("arg", ["1 ", "-1", 1, -1, 0, 100500]) +def test_ok__valid_number(arg: Any) -> None: + assert valid_number(arg) == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, "1x", 100500.0]) +def test_fail__valid_number(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_number(arg)) + + [email protected]("arg", [-5, 0, 5, "-5 ", "0 ", "5 "]) +def test_ok__valid_number__min_max(arg: Any) -> None: + assert valid_number(arg, -5, 5) == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, -6, 6, "-6 ", "6 "]) +def test_fail__valid_number__min_max(arg: Any) -> None: # pylint: disable=invalid-name + with pytest.raises(ValidatorError): + print(valid_number(arg, -5, 5)) + + +# ===== [email protected]("arg", [1, 5, "5 "]) +def test_ok__valid_int_f1(arg: Any) -> None: + value = valid_int_f1(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, -6, "-6 ", 0, "0 ", "5.0"]) +def test_fail__valid_int_f1(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_int_f1(arg)) + + +# ===== [email protected]("arg", [0.1, 1, 5, "5 ", "5.0 "]) +def test_ok__valid_float_f01(arg: Any) -> None: + value = valid_float_f01(arg) + assert type(value) == float # pylint: disable=unidiomatic-typecheck + assert value == float(str(arg).strip()) + + [email protected]("arg", ["test", "", None, 0.0, "0.0", -6, "-6", 0, "0"]) +def test_fail__valid_float_f01(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_float_f01(arg)) + + +# ===== [email protected]("arg, retval", [ + ("a, b, c", ["a", "b", "c"]), + ("a b c", ["a", "b", "c"]), + (["a", "b", "c"], ["a", "b", "c"]), + ("", []), + (" ", []), + (", ", []), + (", a, ", ["a"]), + ([], []), +]) +def test_ok__valid_string_list(arg: Any, retval: List) -> None: + assert valid_string_list(arg) == retval + + [email protected]("arg, retval", [ + ("1, 2, 3", [1, 2, 3]), + ("1 2 3", [1, 2, 3]), + ([1, 2, 3], [1, 2, 3]), + ("", []), + (" ", []), + (", ", []), + (", 1, ", [1]), + ([], []), +]) +def test_ok__valid_string_list__subval(arg: Any, retval: List) -> None: # pylint: disable=invalid-name + assert valid_string_list(arg, subval=int) == retval + + [email protected]("arg", [None, [None]]) +def test_fail__valid_string_list(arg: Any) -> None: # pylint: disable=invalid-name + with pytest.raises(ValidatorError): + print(valid_string_list(arg)) diff --git a/testenv/tests/validators/test_hw.py b/testenv/tests/validators/test_hw.py new file mode 100644 index 00000000..2c93d3eb --- /dev/null +++ b/testenv/tests/validators/test_hw.py @@ -0,0 +1,72 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import Any + +import pytest + +from kvmd.validators import ValidatorError +from kvmd.validators.hw import valid_tty_speed +from kvmd.validators.hw import valid_gpio_pin +from kvmd.validators.hw import valid_gpio_pin_optional + + +# ===== [email protected]("arg", ["1200 ", 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]) +def test_ok__valid_tty_speed(arg: Any) -> None: + value = valid_tty_speed(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, 0, 1200.1]) +def test_fail__valid_tty_speed(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_tty_speed(arg)) + + +# ===== [email protected]("arg", ["0 ", 0, 1, 13]) +def test_ok__valid_gpio_pin(arg: Any) -> None: + value = valid_gpio_pin(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, -1, -13, 1.1]) +def test_fail__valid_gpio_pin(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_gpio_pin(arg)) + + +# ===== [email protected]("arg", ["0 ", -1, 0, 1, 13]) +def test_ok__valid_gpio_pin_optional(arg: Any) -> None: + value = valid_gpio_pin_optional(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, -2, -13, 1.1]) +def test_fail__valid_gpio_pin_optional(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_gpio_pin_optional(arg)) diff --git a/testenv/tests/validators/test_kvm.py b/testenv/tests/validators/test_kvm.py new file mode 100644 index 00000000..f1050b36 --- /dev/null +++ b/testenv/tests/validators/test_kvm.py @@ -0,0 +1,169 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import Any + +import pytest + +from kvmd.keymap import KEYMAP + +from kvmd.validators import ValidatorError +from kvmd.validators.kvm import valid_atx_button +from kvmd.validators.kvm import valid_kvm_target +from kvmd.validators.kvm import valid_log_seek +from kvmd.validators.kvm import valid_stream_quality +from kvmd.validators.kvm import valid_stream_fps +from kvmd.validators.kvm import valid_hid_key +from kvmd.validators.kvm import valid_hid_mouse_move +from kvmd.validators.kvm import valid_hid_mouse_button +from kvmd.validators.kvm import valid_hid_mouse_wheel + + +# ===== [email protected]("arg", ["POWER ", "POWER_LONG ", "RESET "]) +def test_ok__valid_atx_button(arg: Any) -> None: + assert valid_atx_button(arg) == arg.strip().lower() + + [email protected]("arg", ["test", "", None]) +def test_fail__valid_atx_button(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_atx_button(arg)) + + +# ===== [email protected]("arg", ["KVM ", "SERVER "]) +def test_ok__valid_kvm_target(arg: Any) -> None: + assert valid_kvm_target(arg) == arg.strip().lower() + + [email protected]("arg", ["test", "", None]) +def test_fail__valid_kvm_target(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_kvm_target(arg)) + + +# ===== [email protected]("arg", ["0 ", 0, 1, 13]) +def test_ok__valid_log_seek(arg: Any) -> None: + value = valid_log_seek(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, -1, -13, 1.1]) +def test_fail__valid_log_seek(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_log_seek(arg)) + + +# ===== [email protected]("arg", ["1 ", 20, 100]) +def test_ok__valid_stream_quality(arg: Any) -> None: + value = valid_stream_quality(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, 0, 101, 1.1]) +def test_fail__valid_stream_quality(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_stream_quality(arg)) + + +# ===== [email protected]("arg", ["1 ", 30]) +def test_ok__valid_stream_fps(arg: Any) -> None: + value = valid_stream_fps(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, 31, 1.1]) +def test_fail__valid_stream_fps(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_stream_fps(arg)) + + +# ===== +def test_ok__valid_hid_key() -> None: + for key in KEYMAP: + print(valid_hid_key(key)) + print(valid_hid_key(key + " ")) + + [email protected]("arg", ["test", "", None, "keya"]) +def test_fail__valid_hid_key(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_hid_key(arg)) + + +# ===== [email protected]("arg", [-20000, "1 ", "-1", 1, -1, 0, "20000 "]) +def test_ok__valid_hid_mouse_move(arg: Any) -> None: + assert valid_hid_mouse_move(arg) == int(str(arg).strip()) + + +def test_ok__valid_hid_mouse_move__m50000() -> None: + assert valid_hid_mouse_move(-50000) == -32768 + + +def test_ok__valid_hid_mouse_move__p50000() -> None: + assert valid_hid_mouse_move(50000) == 32767 + + [email protected]("arg", ["test", "", None, 1.1]) +def test_fail__valid_hid_mouse_move(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_hid_mouse_move(arg)) + + +# ===== [email protected]("arg", ["LEFT ", "RIGHT "]) +def test_ok__valid_hid_mouse_button(arg: Any) -> None: + assert valid_hid_mouse_button(arg) == arg.strip().lower() + + [email protected]("arg", ["test", "", None]) +def test_fail__valid_hid_mouse_button(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_hid_mouse_button(arg)) + + +# ===== [email protected]("arg", [-100, "1 ", "-1", 1, -1, 0, "100 "]) +def test_ok__valid_hid_mouse_wheel(arg: Any) -> None: + assert valid_hid_mouse_wheel(arg) == int(str(arg).strip()) + + +def test_ok__valid_hid_mouse_wheel__m200() -> None: + assert valid_hid_mouse_wheel(-200) == -128 + + +def test_ok__valid_hid_mouse_wheel__p200() -> None: + assert valid_hid_mouse_wheel(200) == 127 + + [email protected]("arg", ["test", "", None, 1.1]) +def test_fail__valid_hid_mouse_wheel(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_hid_mouse_wheel(arg)) diff --git a/testenv/tests/validators/test_net.py b/testenv/tests/validators/test_net.py new file mode 100644 index 00000000..eab67c9a --- /dev/null +++ b/testenv/tests/validators/test_net.py @@ -0,0 +1,122 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +from typing import Any + +import pytest + +from kvmd.validators import ValidatorError +from kvmd.validators.net import valid_ip_or_host +from kvmd.validators.net import valid_ip +from kvmd.validators.net import valid_rfc_host +from kvmd.validators.net import valid_port + + +# ===== [email protected]("arg", [ + "yandex.ru ", + "foobar", + "foo-bar.ru", + "127.0.0.1", + "8.8.8.8", + "::", + "::1", + "2001:500:2f::f", +]) +def test_ok__valid_ip_or_host(arg: Any) -> None: + assert valid_ip_or_host(arg) == arg.strip() + + [email protected]("arg", [ + "foo_bar.ru", + "1.1.1.", + ":", + "", + None, +]) +def test_fail__valid_ip_or_host(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_ip_or_host(arg)) + + +# ===== [email protected]("arg", [ + "127.0.0.1 ", + "8.8.8.8", + "::", + "::1", + "2001:500:2f::f", +]) +def test_ok__valid_ip(arg: Any) -> None: + assert valid_ip(arg) == arg.strip() + + [email protected]("arg", [ + "ya.ru", + "1", + "1.1.1", + "1.1.1.", + ":", + "", + None, +]) +def test_fail__valid_ip(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_ip(arg)) + + +# ===== [email protected]("arg", [ + "yandex.ru ", + "foobar", + "foo-bar.ru", + "z0r.de", + "11.ru", + "127.0.0.1", +]) +def test_ok__valid_rfc_host(arg: Any) -> None: + assert valid_rfc_host(arg) == arg.strip() + + [email protected]("arg", [ + "foobar.ru.", + "foo_bar.ru", + "", + None, +]) +def test_fail__valid_rfc_host(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_rfc_host(arg)) + + +# ===== [email protected]("arg", ["0 ", 0, "22", 443, 65535]) +def test_ok__valid_port(arg: Any) -> None: + value = valid_port(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(arg).strip()) + + [email protected]("arg", ["test", "", None, 1.1]) +def test_fail__valid_port(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_port(arg)) diff --git a/testenv/tests/validators/test_os.py b/testenv/tests/validators/test_os.py new file mode 100644 index 00000000..b280b4b3 --- /dev/null +++ b/testenv/tests/validators/test_os.py @@ -0,0 +1,118 @@ +# ========================================================================== # +# # +# KVMD - The main Pi-KVM daemon. # +# # +# Copyright (C) 2018 Maxim Devaev <[email protected]> # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <https://www.gnu.org/licenses/>. # +# # +# ========================================================================== # + + +import os + +from typing import List +from typing import Any + +import pytest + +from kvmd.validators import ValidatorError +from kvmd.validators.os import valid_abs_path +from kvmd.validators.os import valid_abs_path_exists +from kvmd.validators.os import valid_unix_mode +from kvmd.validators.os import valid_command + + +# ===== [email protected]("arg, retval", [ + ("/..", "/"), + ("/root/..", "/"), + ("/root", "/root"), + ("/f/o/o/b/a/r", "/f/o/o/b/a/r"), + ("~", os.path.abspath(".") + "/~"), + ("/foo~", "/foo~"), + ("/foo/~", "/foo/~"), + (".", os.path.abspath(".")), +]) +def test_ok__valid_abs_path(arg: Any, retval: str) -> None: + assert valid_abs_path(arg) == retval + + [email protected]("arg", ["", " ", None]) +def test_fail__valid_abs_path(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_abs_path(arg)) + + +# ===== [email protected]("arg, retval", [ + ("/..", "/"), + ("/root/..", "/"), + ("/root", "/root"), + (".", os.path.abspath(".")), +]) +def test_ok__valid_abs_path_exists(arg: Any, retval: str) -> None: + assert valid_abs_path_exists(arg) == retval + + [email protected]("arg", [ + "/f/o/o/b/a/r", + "~", + "/foo~", + "/foo/~", + "", + None, +]) +def test_fail__valid_abs_path_exists(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_abs_path_exists(arg)) + + +# ===== [email protected]("arg", [0, 5, "1000"]) +def test_ok__valid_unix_mode(arg: Any) -> None: + value = valid_unix_mode(arg) + assert type(value) == int # pylint: disable=unidiomatic-typecheck + assert value == int(str(value).strip()) + + [email protected]("arg", ["test", "", None, -6, "-6", "5.0"]) +def test_fail__valid_unix_mode(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_unix_mode(arg)) + + +# ===== [email protected]("arg, retval", [ + (["/bin/true"], ["/bin/true"]), + (["/bin/true", 1, 2, 3], ["/bin/true", "1", "2", "3"]), + ("/bin/true, 1, 2, 3,", ["/bin/true", "1", "2", "3"]), + ("/bin/true", ["/bin/true"]), +]) +def test_ok__valid_command(arg: Any, retval: List[str]) -> None: + assert valid_command(arg) == retval + + [email protected]("arg", [ + ["/bin/blahblahblah"], + ["/bin/blahblahblah", 1, 2, 3], + [" "], + [], + "/bin/blahblahblah, 1, 2, 3,", + "/bin/blahblahblah", + " ", +]) +def test_fail__valid_command(arg: Any) -> None: + with pytest.raises(ValidatorError): + print(valid_command(arg)) diff --git a/testenv/tox.ini b/testenv/tox.ini index 55d51892..b63b5071 100644 --- a/testenv/tox.ini +++ b/testenv/tox.ini @@ -8,14 +8,14 @@ sitepackages = true changedir = /src [testenv:flake8] -commands = flake8 --config=testenv/linters/flake8.ini kvmd genmap.py tests +commands = flake8 --config=testenv/linters/flake8.ini kvmd genmap.py testenv/tests deps = flake8 flake8-double-quotes -rrequirements.txt [testenv:pylint] -commands = pylint --rcfile=testenv/linters/pylint.ini --output-format=colorized --reports=no kvmd genmap.py tests +commands = pylint --rcfile=testenv/linters/pylint.ini --output-format=colorized --reports=no kvmd genmap.py testenv/tests deps = pylint pytest @@ -24,19 +24,21 @@ deps = -rrequirements.txt [testenv:mypy] -commands = mypy --config-file=testenv/linters/mypy.ini --cache-dir=testenv/.mypy_cache kvmd genmap.py tests +commands = mypy --config-file=testenv/linters/mypy.ini --cache-dir=testenv/.mypy_cache kvmd genmap.py testenv/tests deps = mypy -rrequirements.txt [testenv:vulture] -commands = vulture --ignore-names=_format_P,Plugin --ignore-decorators=@_exposed,@_system_task,@pytest.fixture kvmd genmap.py tests testenv/linters/vulture-wl.py +commands = vulture --ignore-names=_format_P,Plugin --ignore-decorators=@_exposed,@_system_task,@pytest.fixture kvmd genmap.py testenv/tests testenv/linters/vulture-wl.py deps = vulture -rrequirements.txt [testenv:pytest] -commands = py.test -vv --cov-config=testenv/linters/coverage.ini --cov-report=term-missing --cov=kvmd tests +commands = py.test -vv --cov-config=testenv/linters/coverage.ini --cov-report=term-missing --cov=kvmd testenv/tests +setenv = + PYTHONPATH=/src deps = pytest pytest-cov |