BastionSSO/user_manage_api/tests/test_service_unit.py

110 lines
4.0 KiB
Python

import pytest
from typing import List, Optional
from app.core.errors import ApiError, map_command_error
from app.core.models import UserCreateRequest
import app.providers.cli_provider as cli_provider
from app.providers.cli_provider import CliSystemProvider
from app.providers.base import SystemProvider
from app.services.user_group_service import UserGroupService
class NoopProvider(SystemProvider):
def __init__(self) -> None:
self.created_home_dir: Optional[str] = None
self.created_linked_home_dir: Optional[str] = None
def create_user(self, username: str, password_hash: str, home_dir: Optional[str], linked_home_dir: Optional[str], shell: str, primary_group: Optional[str], groups: List[str]) -> None:
self.created_home_dir = home_dir
self.created_linked_home_dir = linked_home_dir
return None
def delete_user(self, username: str) -> None:
return None
def change_user_password(self, username: str, password_hash: str) -> None:
return None
def list_users(self):
return []
def get_user(self, username: str):
raise ApiError(404, "not_found", "not found")
def create_group(self, groupname: str) -> None:
return None
def delete_group(self, groupname: str) -> None:
return None
def list_groups(self):
return []
def get_group(self, groupname: str):
raise ApiError(404, "not_found", "not found")
def add_user_groups(self, username: str, groups: List[str], replace: bool) -> None:
return None
def remove_user_groups(self, username: str, groups: List[str]) -> None:
return None
def get_user_groups(self, username: str):
return []
def test_home_dir_out_of_base_rejected() -> None:
service = UserGroupService(provider=NoopProvider(), home_base_dir="/home")
payload = UserCreateRequest(username="alice", password_hash="$6$rounds=5000$abcdefghij", home_dir="/tmp/alice", groups=[])
with pytest.raises(ApiError) as raised:
service.create_user(payload)
assert raised.value.status_code == 400
def test_link_home_dir_uses_home_base_symlink_path_and_external_storage() -> None:
provider = NoopProvider()
service = UserGroupService(provider=provider, home_base_dir="/home", link_home_dir="/data/home")
payload = UserCreateRequest(username="alice", password_hash="$6$rounds=5000$abcdefghij", groups=[])
service.create_user(payload)
assert provider.created_home_dir == "/home/alice"
assert provider.created_linked_home_dir == "/data/home/alice"
def test_command_error_mapping_conflict() -> None:
error = map_command_error("user already exists", 9)
assert error.status_code == 409
class RecordingExecutor:
def __init__(self, home_dir: str) -> None:
self.home_dir = home_dir
self.commands: List[List[str]] = []
def run(self, args: List[str], use_sudo: bool = True) -> str:
self.commands.append(args)
if args == ["getent", "passwd", "alice"]:
return f"alice:x:1000:1000::%s:/bin/bash" % self.home_dir
return ""
class FakePath:
def __init__(self, path: str) -> None:
self.path = path
def is_symlink(self) -> bool:
return self.path == "/home/alice"
def test_delete_user_unlinks_home_when_it_is_symlink(monkeypatch) -> None:
monkeypatch.setattr(cli_provider, "Path", FakePath)
executor = RecordingExecutor("/home/alice")
provider = CliSystemProvider(executor=executor)
provider.delete_user("alice")
assert ["userdel", "alice"] in executor.commands
assert ["unlink", "/home/alice"] in executor.commands
def test_delete_user_does_not_unlink_home_when_it_is_directory(monkeypatch) -> None:
monkeypatch.setattr(cli_provider, "Path", FakePath)
executor = RecordingExecutor("/home/old-alice")
provider = CliSystemProvider(executor=executor)
provider.delete_user("alice")
assert ["userdel", "alice"] in executor.commands
assert ["unlink", "/home/old-alice"] not in executor.commands