mirror of
https://github.com/dw-0/kiauh.git
synced 2026-08-03 04:47:56 +05:00
refactor: replace CURRENT_USER with get_current_user in multiple components; add user group utility functions
This commit is contained in:
@@ -23,11 +23,10 @@ from components.klipper import (
|
|||||||
KLIPPER_SERVICE_TEMPLATE,
|
KLIPPER_SERVICE_TEMPLATE,
|
||||||
KLIPPER_UDS_NAME,
|
KLIPPER_UDS_NAME,
|
||||||
)
|
)
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import BaseInstance
|
from core.instance_manager.base_instance import BaseInstance
|
||||||
from core.logger import Logger
|
from core.logger import Logger
|
||||||
from utils.fs_utils import create_folders, get_data_dir
|
from utils.fs_utils import create_folders, get_data_dir
|
||||||
from utils.sys_utils import get_service_file_path
|
from utils.sys_utils import get_current_user, get_service_file_path
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -93,7 +92,7 @@ class Klipper:
|
|||||||
|
|
||||||
service_content = template_content.replace(
|
service_content = template_content.replace(
|
||||||
"%USER%",
|
"%USER%",
|
||||||
CURRENT_USER,
|
get_current_user(),
|
||||||
)
|
)
|
||||||
service_content = service_content.replace(
|
service_content = service_content.replace(
|
||||||
"%KLIPPER_DIR%",
|
"%KLIPPER_DIR%",
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
# ======================================================================= #
|
# ======================================================================= #
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import grp
|
|
||||||
import os
|
|
||||||
import shutil
|
import shutil
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from subprocess import CalledProcessError, run
|
from subprocess import CalledProcessError, run
|
||||||
@@ -28,7 +26,6 @@ from components.klipper.klipper_dialogs import (
|
|||||||
)
|
)
|
||||||
from components.webui_client.base_data import BaseWebClient
|
from components.webui_client.base_data import BaseWebClient
|
||||||
from components.webui_client.client_utils import create_client_config_symlink
|
from components.webui_client.client_utils import create_client_config_symlink
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import SUFFIX_BLACKLIST
|
from core.instance_manager.base_instance import SUFFIX_BLACKLIST
|
||||||
from core.logger import DialogType, Logger
|
from core.logger import DialogType, Logger
|
||||||
from core.services.backup_service import BackupService
|
from core.services.backup_service import BackupService
|
||||||
@@ -42,6 +39,8 @@ from utils.input_utils import get_confirm, get_number_input, get_string_input
|
|||||||
from utils.instance_utils import get_instances
|
from utils.instance_utils import get_instances
|
||||||
from utils.sys_utils import (
|
from utils.sys_utils import (
|
||||||
cmd_sysctl_service,
|
cmd_sysctl_service,
|
||||||
|
get_current_user,
|
||||||
|
get_user_groups,
|
||||||
install_python_packages,
|
install_python_packages,
|
||||||
parse_packages_from_file,
|
parse_packages_from_file,
|
||||||
)
|
)
|
||||||
@@ -93,12 +92,14 @@ def check_user_groups(interactive: bool = True) -> None:
|
|||||||
must confirm before groups are modified. When ``interactive`` is false (the
|
must confirm before groups are modified. When ``interactive`` is false (the
|
||||||
headless CLI path), groups are added automatically without prompting.
|
headless CLI path), groups are added automatically without prompting.
|
||||||
"""
|
"""
|
||||||
user_groups = [grp.getgrgid(gid).gr_name for gid in os.getgroups()]
|
user_groups = get_user_groups()
|
||||||
missing_groups = [g for g in ["tty", "dialout"] if g not in user_groups]
|
missing_groups = [g for g in ["tty", "dialout"] if g not in user_groups]
|
||||||
|
|
||||||
if not missing_groups:
|
if not missing_groups:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
current_user = get_current_user()
|
||||||
|
|
||||||
if interactive:
|
if interactive:
|
||||||
Logger.print_dialog(
|
Logger.print_dialog(
|
||||||
DialogType.ATTENTION,
|
DialogType.ATTENTION,
|
||||||
@@ -116,22 +117,22 @@ def check_user_groups(interactive: bool = True) -> None:
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
if not get_confirm(f"Add user '{CURRENT_USER}' to group(s) now?"):
|
if not get_confirm(f"Add user '{current_user}' to group(s) now?"):
|
||||||
log = "Skipped adding user to required groups. You might encounter issues."
|
log = "Skipped adding user to required groups. You might encounter issues."
|
||||||
Logger.print_warn(log)
|
Logger.print_warn(log)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
Logger.print_info(
|
Logger.print_info(
|
||||||
f"Adding user '{CURRENT_USER}' to required groups: "
|
f"Adding user '{current_user}' to required groups: "
|
||||||
f"{', '.join(missing_groups)}"
|
f"{', '.join(missing_groups)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for group in missing_groups:
|
for group in missing_groups:
|
||||||
Logger.print_status(f"Adding user '{CURRENT_USER}' to group {group} ...")
|
Logger.print_status(f"Adding user '{current_user}' to group {group} ...")
|
||||||
command = ["sudo", "usermod", "-a", "-G", group, CURRENT_USER]
|
command = ["sudo", "usermod", "-a", "-G", group, current_user]
|
||||||
run(command, check=True)
|
run(command, check=True)
|
||||||
Logger.print_ok(f"Group {group} assigned to user '{CURRENT_USER}'.")
|
Logger.print_ok(f"Group {group} assigned to user '{current_user}'.")
|
||||||
except CalledProcessError as e:
|
except CalledProcessError as e:
|
||||||
Logger.print_error(f"Unable to add user to usergroups: {e}")
|
Logger.print_error(f"Unable to add user to usergroups: {e}")
|
||||||
raise
|
raise
|
||||||
|
|||||||
@@ -330,10 +330,11 @@ class TestCheckUserGroups:
|
|||||||
def test_interactive_mode_prompts_before_adding_user(self, monkeypatch) -> None:
|
def test_interactive_mode_prompts_before_adding_user(self, monkeypatch) -> None:
|
||||||
from components.klipper.klipper_utils import check_user_groups
|
from components.klipper.klipper_utils import check_user_groups
|
||||||
|
|
||||||
monkeypatch.setattr("os.getgroups", lambda: [])
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"grp.getgrgid",
|
"components.klipper.klipper_utils.get_user_groups", lambda: []
|
||||||
lambda gid: type("Group", (), {"gr_name": "tty"})(),
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"components.klipper.klipper_utils.get_current_user", lambda: "tester"
|
||||||
)
|
)
|
||||||
|
|
||||||
prompted: List[str] = []
|
prompted: List[str] = []
|
||||||
@@ -357,10 +358,11 @@ class TestCheckUserGroups:
|
|||||||
def test_headless_mode_auto_adds_without_prompt(self, monkeypatch) -> None:
|
def test_headless_mode_auto_adds_without_prompt(self, monkeypatch) -> None:
|
||||||
from components.klipper.klipper_utils import check_user_groups
|
from components.klipper.klipper_utils import check_user_groups
|
||||||
|
|
||||||
monkeypatch.setattr("os.getgroups", lambda: [])
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"grp.getgrgid",
|
"components.klipper.klipper_utils.get_user_groups", lambda: []
|
||||||
lambda gid: type("Group", (), {"gr_name": "tty"})(),
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"components.klipper.klipper_utils.get_current_user", lambda: "tester"
|
||||||
)
|
)
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
|
|||||||
@@ -22,14 +22,13 @@ from components.moonraker import (
|
|||||||
MOONRAKER_LOG_NAME,
|
MOONRAKER_LOG_NAME,
|
||||||
MOONRAKER_SERVICE_TEMPLATE,
|
MOONRAKER_SERVICE_TEMPLATE,
|
||||||
)
|
)
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import BaseInstance
|
from core.instance_manager.base_instance import BaseInstance
|
||||||
from core.logger import Logger
|
from core.logger import Logger
|
||||||
from core.simple_config_parser.simple_config_parser import (
|
from core.simple_config_parser.simple_config_parser import (
|
||||||
SimpleConfigParser,
|
SimpleConfigParser,
|
||||||
)
|
)
|
||||||
from utils.fs_utils import create_folders
|
from utils.fs_utils import create_folders
|
||||||
from utils.sys_utils import get_service_file_path
|
from utils.sys_utils import get_current_user, get_service_file_path
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -98,7 +97,7 @@ class Moonraker:
|
|||||||
|
|
||||||
service_content = template_content.replace(
|
service_content = template_content.replace(
|
||||||
"%USER%",
|
"%USER%",
|
||||||
CURRENT_USER,
|
get_current_user(),
|
||||||
)
|
)
|
||||||
service_content = service_content.replace(
|
service_content = service_content.replace(
|
||||||
"%MOONRAKER_DIR%",
|
"%MOONRAKER_DIR%",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -13,12 +14,14 @@ from utils import fs_utils, sys_utils
|
|||||||
class TestSubprocessRunner:
|
class TestSubprocessRunner:
|
||||||
def test_run_executes_command(self) -> None:
|
def test_run_executes_command(self) -> None:
|
||||||
runner = SubprocessRunner()
|
runner = SubprocessRunner()
|
||||||
result = runner.run(["true"])
|
result = runner.run([sys.executable, "-c", ""])
|
||||||
assert result.returncode == 0
|
assert result.returncode == 0
|
||||||
|
|
||||||
def test_check_output_returns_stdout(self) -> None:
|
def test_check_output_returns_stdout(self) -> None:
|
||||||
runner = SubprocessRunner()
|
runner = SubprocessRunner()
|
||||||
output = runner.check_output(["echo", "hello"], text=True)
|
output = runner.check_output(
|
||||||
|
[sys.executable, "-c", "print('hello')"], text=True
|
||||||
|
)
|
||||||
assert "hello" in output
|
assert "hello" in output
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -507,9 +507,10 @@ class TestPackaging:
|
|||||||
def test_pyproject_metadata_allows_editable_dev_install(self) -> None:
|
def test_pyproject_metadata_allows_editable_dev_install(self) -> None:
|
||||||
project_root = Path(__file__).resolve().parents[4]
|
project_root = Path(__file__).resolve().parents[4]
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
|
import sys
|
||||||
|
|
||||||
result = sp.run(
|
result = sp.run(
|
||||||
["python", "-m", "pip", "install", "--dry-run", "-e", ".[dev]"],
|
[sys.executable, "-m", "pip", "install", "--dry-run", "-e", ".[dev]"],
|
||||||
cwd=project_root,
|
cwd=project_root,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
|
|||||||
@@ -7,8 +7,6 @@
|
|||||||
# This file may be distributed under the terms of the GNU GPLv3 license #
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||||
# ======================================================================= #
|
# ======================================================================= #
|
||||||
|
|
||||||
import os
|
|
||||||
import pwd
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# global dependencies
|
# global dependencies
|
||||||
@@ -17,9 +15,6 @@ GLOBAL_DEPS = ["git", "wget", "curl", "unzip", "dfu-util", "python3-virtualenv"]
|
|||||||
# strings
|
# strings
|
||||||
INVALID_CHOICE = "Invalid choice. Please select a valid value."
|
INVALID_CHOICE = "Invalid choice. Please select a valid value."
|
||||||
|
|
||||||
# current user
|
|
||||||
CURRENT_USER = pwd.getpwuid(os.getuid())[0]
|
|
||||||
|
|
||||||
# dirs
|
# dirs
|
||||||
SYSTEMD = Path("/etc/systemd/system")
|
SYSTEMD = Path("/etc/systemd/system")
|
||||||
NGINX_SITES_AVAILABLE = Path("/etc/nginx/sites-available")
|
NGINX_SITES_AVAILABLE = Path("/etc/nginx/sites-available")
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from pathlib import Path
|
|||||||
from subprocess import CalledProcessError, run
|
from subprocess import CalledProcessError, run
|
||||||
|
|
||||||
from components.moonraker.moonraker import Moonraker
|
from components.moonraker.moonraker import Moonraker
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import BaseInstance
|
from core.instance_manager.base_instance import BaseInstance
|
||||||
from core.logger import Logger
|
from core.logger import Logger
|
||||||
from core.simple_config_parser.simple_config_parser import (
|
from core.simple_config_parser.simple_config_parser import (
|
||||||
@@ -30,7 +29,7 @@ from extensions.obico import (
|
|||||||
OBICO_SERVICE_TEMPLATE,
|
OBICO_SERVICE_TEMPLATE,
|
||||||
)
|
)
|
||||||
from utils.fs_utils import create_folders
|
from utils.fs_utils import create_folders
|
||||||
from utils.sys_utils import get_service_file_path
|
from utils.sys_utils import get_current_user, get_service_file_path
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -105,7 +104,7 @@ class MoonrakerObico:
|
|||||||
|
|
||||||
service_content = template_content.replace(
|
service_content = template_content.replace(
|
||||||
"%USER%",
|
"%USER%",
|
||||||
CURRENT_USER,
|
get_current_user(),
|
||||||
)
|
)
|
||||||
service_content = service_content.replace(
|
service_content = service_content.replace(
|
||||||
"%OBICO_DIR%",
|
"%OBICO_DIR%",
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from pathlib import Path
|
|||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
|
||||||
from components.klipper.klipper import Klipper
|
from components.klipper.klipper import Klipper
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import BaseInstance
|
from core.instance_manager.base_instance import BaseInstance
|
||||||
from core.logger import Logger
|
from core.logger import Logger
|
||||||
from extensions.octoprint import (
|
from extensions.octoprint import (
|
||||||
@@ -22,7 +21,11 @@ from extensions.octoprint import (
|
|||||||
OP_LOG_NAME,
|
OP_LOG_NAME,
|
||||||
)
|
)
|
||||||
from utils.fs_utils import create_folders
|
from utils.fs_utils import create_folders
|
||||||
from utils.sys_utils import create_service_file, get_service_file_path
|
from utils.sys_utils import (
|
||||||
|
create_service_file,
|
||||||
|
get_current_user,
|
||||||
|
get_service_file_path,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -88,7 +91,7 @@ class Octoprint:
|
|||||||
Environment="LC_ALL=C.UTF-8"
|
Environment="LC_ALL=C.UTF-8"
|
||||||
Environment="LANG=C.UTF-8"
|
Environment="LANG=C.UTF-8"
|
||||||
Type=simple
|
Type=simple
|
||||||
User={CURRENT_USER}
|
User={get_current_user()}
|
||||||
ExecStart={octo_exec} --basedir {basedir} --config {cfg} --port={port} serve
|
ExecStart={octo_exec} --basedir {basedir} --config {cfg} --port={port} serve
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ from pathlib import Path
|
|||||||
from subprocess import CalledProcessError
|
from subprocess import CalledProcessError
|
||||||
|
|
||||||
from components.moonraker.moonraker import Moonraker
|
from components.moonraker.moonraker import Moonraker
|
||||||
from core.constants import CURRENT_USER
|
|
||||||
from core.instance_manager.base_instance import BaseInstance
|
from core.instance_manager.base_instance import BaseInstance
|
||||||
from core.logger import Logger
|
from core.logger import Logger
|
||||||
from extensions.telegram_bot import (
|
from extensions.telegram_bot import (
|
||||||
@@ -26,7 +25,7 @@ from extensions.telegram_bot import (
|
|||||||
TG_BOT_SERVICE_TEMPLATE,
|
TG_BOT_SERVICE_TEMPLATE,
|
||||||
)
|
)
|
||||||
from utils.fs_utils import create_folders
|
from utils.fs_utils import create_folders
|
||||||
from utils.sys_utils import get_service_file_path
|
from utils.sys_utils import get_current_user, get_service_file_path
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyMethodMayBeStatic
|
# noinspection PyMethodMayBeStatic
|
||||||
@@ -86,7 +85,7 @@ class MoonrakerTelegramBot:
|
|||||||
|
|
||||||
service_content = template_content.replace(
|
service_content = template_content.replace(
|
||||||
"%USER%",
|
"%USER%",
|
||||||
CURRENT_USER,
|
get_current_user(),
|
||||||
)
|
)
|
||||||
service_content = service_content.replace(
|
service_content = service_content.replace(
|
||||||
"%TELEGRAM_BOT_DIR%",
|
"%TELEGRAM_BOT_DIR%",
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ def get_instances(
|
|||||||
name = convert_camelcase_to_kebabcase(instance_type.__name__)
|
name = convert_camelcase_to_kebabcase(instance_type.__name__)
|
||||||
pattern = re.compile(f"^{name}(-[0-9a-zA-Z]+)?.service$")
|
pattern = re.compile(f"^{name}(-[0-9a-zA-Z]+)?.service$")
|
||||||
|
|
||||||
|
if not SYSTEMD.exists():
|
||||||
|
return []
|
||||||
|
|
||||||
service_list = [
|
service_list = [
|
||||||
Path(SYSTEMD, service)
|
Path(SYSTEMD, service)
|
||||||
for service in SYSTEMD.iterdir()
|
for service in SYSTEMD.iterdir()
|
||||||
|
|||||||
@@ -28,6 +28,29 @@ from core.logger import Logger
|
|||||||
from utils.fs_utils import check_file_exist, remove_with_sudo
|
from utils.fs_utils import check_file_exist, remove_with_sudo
|
||||||
from utils.input_utils import get_confirm
|
from utils.input_utils import get_confirm
|
||||||
|
|
||||||
|
|
||||||
|
def get_current_user() -> str:
|
||||||
|
"""Return the current user's login name (cross-platform)."""
|
||||||
|
if os.name == "posix":
|
||||||
|
import pwd
|
||||||
|
|
||||||
|
return pwd.getpwuid(os.getuid())[0]
|
||||||
|
|
||||||
|
import getpass
|
||||||
|
|
||||||
|
return getpass.getuser()
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_groups() -> List[str]:
|
||||||
|
"""Return the current user's group names (empty on non-Unix)."""
|
||||||
|
if os.name != "posix":
|
||||||
|
return []
|
||||||
|
|
||||||
|
import grp
|
||||||
|
|
||||||
|
return [grp.getgrgid(gid).gr_name for gid in os.getgroups()]
|
||||||
|
|
||||||
|
|
||||||
SysCtlServiceAction = Literal[
|
SysCtlServiceAction = Literal[
|
||||||
"start",
|
"start",
|
||||||
"stop",
|
"stop",
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ class TestRemoveFile:
|
|||||||
with pytest.warns(DeprecationWarning):
|
with pytest.warns(DeprecationWarning):
|
||||||
remove_file(Path("/some/file"), sudo=True)
|
remove_file(Path("/some/file"), sudo=True)
|
||||||
|
|
||||||
assert runs == [("sudo rm -f /some/file", True)]
|
assert runs == [(f"sudo rm -f {Path('/some/file')}", True)]
|
||||||
|
|
||||||
|
|
||||||
class TestRunRemoveRoutines:
|
class TestRunRemoveRoutines:
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ from utils.sys_utils import (
|
|||||||
create_service_file,
|
create_service_file,
|
||||||
download_file,
|
download_file,
|
||||||
download_progress,
|
download_progress,
|
||||||
|
get_current_user,
|
||||||
get_distro_info,
|
get_distro_info,
|
||||||
get_ipv4_addr,
|
get_ipv4_addr,
|
||||||
get_service_file_path,
|
get_service_file_path,
|
||||||
get_system_timezone,
|
get_system_timezone,
|
||||||
get_upgradable_packages,
|
get_upgradable_packages,
|
||||||
|
get_user_groups,
|
||||||
install_python_packages,
|
install_python_packages,
|
||||||
install_python_requirements,
|
install_python_requirements,
|
||||||
install_system_packages,
|
install_system_packages,
|
||||||
@@ -425,7 +427,7 @@ class TestDownloadFile:
|
|||||||
"utils.sys_utils.urllib.request.urlretrieve", fake_urlretrieve
|
"utils.sys_utils.urllib.request.urlretrieve", fake_urlretrieve
|
||||||
)
|
)
|
||||||
download_file("http://x/file", Path("/target"), show_progress=False)
|
download_file("http://x/file", Path("/target"), show_progress=False)
|
||||||
assert calls == [("http://x/file", "/target", None)]
|
assert calls == [("http://x/file", str(Path("/target")), None)]
|
||||||
|
|
||||||
def test_with_progress(self, monkeypatch) -> None:
|
def test_with_progress(self, monkeypatch) -> None:
|
||||||
calls: List[tuple] = []
|
calls: List[tuple] = []
|
||||||
@@ -727,3 +729,44 @@ class TestGetSystemTimezone:
|
|||||||
lambda *a, **k: (_ for _ in ()).throw(CalledProcessError(1, "timedatectl")),
|
lambda *a, **k: (_ for _ in ()).throw(CalledProcessError(1, "timedatectl")),
|
||||||
)
|
)
|
||||||
assert get_system_timezone() == "UTC"
|
assert get_system_timezone() == "UTC"
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetCurrentUser:
|
||||||
|
def test_posix_uses_pwd(self, monkeypatch) -> None:
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
fake_pwd = types.SimpleNamespace(getpwuid=lambda uid: ["alice", "x", uid])
|
||||||
|
monkeypatch.setitem(sys.modules, "pwd", fake_pwd)
|
||||||
|
monkeypatch.setattr("utils.sys_utils.os.name", "posix")
|
||||||
|
monkeypatch.setattr("utils.sys_utils.os.getuid", lambda: 1000, raising=False)
|
||||||
|
|
||||||
|
assert get_current_user() == "alice"
|
||||||
|
|
||||||
|
def test_non_posix_uses_getpass(self, monkeypatch) -> None:
|
||||||
|
monkeypatch.setattr("utils.sys_utils.os.name", "nt")
|
||||||
|
monkeypatch.setattr("getpass.getuser", lambda: "bob")
|
||||||
|
|
||||||
|
assert get_current_user() == "bob"
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetUserGroups:
|
||||||
|
def test_posix_maps_gids_to_names(self, monkeypatch) -> None:
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
|
||||||
|
fake_grp = types.SimpleNamespace(
|
||||||
|
getgrgid=lambda gid: types.SimpleNamespace(gr_name=f"g{gid}")
|
||||||
|
)
|
||||||
|
monkeypatch.setitem(sys.modules, "grp", fake_grp)
|
||||||
|
monkeypatch.setattr("utils.sys_utils.os.name", "posix")
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"utils.sys_utils.os.getgroups", lambda: [10, 20], raising=False
|
||||||
|
)
|
||||||
|
|
||||||
|
assert get_user_groups() == ["g10", "g20"]
|
||||||
|
|
||||||
|
def test_non_posix_returns_empty(self, monkeypatch) -> None:
|
||||||
|
monkeypatch.setattr("utils.sys_utils.os.name", "nt")
|
||||||
|
|
||||||
|
assert get_user_groups() == []
|
||||||
|
|||||||
Reference in New Issue
Block a user