# Copyright (C) 2022 Red Hat, Inc. # SPDX-License-Identifier: LGPL-2.1-or-later import os import sys from testlib import Error # pylint: disable=import-error HELPERS_DIR = os.path.dirname(__file__) sys.path.append(HELPERS_DIR) from password import Password from step_logger import log_step from steps import ACCOUNTS USERS_SERVICE = "org.fedoraproject.Anaconda.Modules.Users" USERS_INTERFACE = USERS_SERVICE USERS_OBJECT_PATH = "/org/fedoraproject/Anaconda/Modules/Users" ACCOUNTS_SCREEN = ACCOUNTS CREATE_ACCOUNT_ID_PREFIX = f"{ACCOUNTS_SCREEN}-create-account" ROOT_ACCOUNT_ID_PREFIX = f"{ACCOUNTS_SCREEN}-root-account" # Read-only mode (kickstart-defined users): data-testid selectors ACCOUNTS_READONLY_USERS = "[data-testid='accounts-users-readonly']" ACCOUNTS_READONLY_USER_ROW = "accounts-users-readonly-user" def override_user_interface_conf_keys(test, **kwargs): """Patch `[User Interface]` boolean keys in `/run/anaconda/anaconda.conf` (single restore).""" conf = '/run/anaconda/anaconda.conf' test.restore_file(conf) for key, value in kwargs.items(): text = value if isinstance(value, str) else str(value) if "\n" in text: lines = [line.strip() for line in text.strip().splitlines() if line.strip()] sed_text = "\\\n".join([f"{key} =", *[f" {line}" for line in lines]]) test.machine.execute(f"sed -i '/^{key} =/,/^$/c\\\n{sed_text}' {conf}") else: test.machine.execute(f"sed -i '/^{key} =/c\\{key} = {text}' {conf}") class UsersDBus(): def __init__(self, machine): self.machine = machine self._bus_address = self.machine.execute("cat /run/anaconda/bus.address") def dbus_get_users(self): return self.machine.execute( f'busctl --address="{self._bus_address}" \ get-property \ {USERS_SERVICE} \ {USERS_OBJECT_PATH} \ {USERS_INTERFACE} Users' ) def dbus_clear_users(self): self.machine.execute(f'busctl --address="{self._bus_address}" \ set-property \ {USERS_SERVICE} \ {USERS_OBJECT_PATH} \ {USERS_INTERFACE} Users aa{{sv}} 0') def dbus_get_root_locked(self): ret = self.machine.execute(f'busctl --address="{self._bus_address}" \ get-property \ {USERS_SERVICE} \ {USERS_OBJECT_PATH} \ {USERS_INTERFACE} IsRootAccountLocked') return ret.split()[1].strip() == "true" def dbus_set_root_locked(self, locked): self.machine.execute(f'busctl --address="{self._bus_address}" \ set-property \ {USERS_SERVICE} \ {USERS_OBJECT_PATH} \ {USERS_INTERFACE} IsRootAccountLocked b {"true" if locked else "false"}') def dbus_get_is_root_password_set(self): ret = self.machine.execute(f'busctl --address="{self._bus_address}" \ get-property \ {USERS_SERVICE} \ {USERS_OBJECT_PATH} \ {USERS_INTERFACE} IsRootPasswordSet') return ret.split()[1].strip() == "true" class Users(UsersDBus): def __init__(self, browser, machine): self.browser = browser UsersDBus.__init__(self, machine) @log_step(snapshot_before=True) def set_user_name(self, user_name, append=False, value_check=True): sel = f"#{ACCOUNTS_SCREEN}-create-account-user-name" self.browser.set_input_text(sel, user_name, append=append, value_check=value_check) @log_step(snapshot_before=True) def check_user_name(self, user_name): sel = f"#{ACCOUNTS_SCREEN}-create-account-user-name" self.browser.wait_val(sel, user_name) @log_step(snapshot_before=True) def set_full_name(self, full_name, append=False, value_check=True): sel = f"#{ACCOUNTS_SCREEN}-create-account-full-name" self.browser.set_input_text(sel, full_name, append=append, value_check=value_check) @log_step(snapshot_before=True) def check_full_name(self, full_name): sel = f"#{ACCOUNTS_SCREEN}-create-account-full-name" self.browser.wait_val(sel, full_name) @log_step(snapshot_before=True) def enable_root_account(self, enable): sel = f"#{ACCOUNTS_SCREEN}-root-account-enable-root-account" # FIXME: # Tests are sometimes failing to enable the root account for unknown reasons. # Let's be resilient and try to set the checkbox twice. try: self.browser.set_checked(sel, enable) self.browser.wait_visible(f"{sel}:checked" if enable else f"{sel}:not(:checked)") except Error: self.browser.set_checked(sel, enable) self.browser.wait_visible(f"{sel}:checked" if enable else f"{sel}:not(:checked)") if enable: # Wait that the root password field is visible and focused p = Password(self.browser, ROOT_ACCOUNT_ID_PREFIX) p.check_pw_focused() @log_step(snapshot_before=True) def enable_user_account(self, enable): sel = f"#{ACCOUNTS_SCREEN}-create-account-set-user-account" self.browser.set_checked(sel, enable) def set_valid_root_password(self, valid=True): p = Password(self.browser, ROOT_ACCOUNT_ID_PREFIX) password = "password" p.set_password(password) p.set_password_confirm(password if valid else "X") # Read-only mode (kickstart-defined users) def check_readonly_users_section_visible(self): """Assert the Accounts step shows the read-only user summary (kickstart-defined users).""" self.browser.wait_visible(ACCOUNTS_READONLY_USERS) def check_readonly_user_displayed(self, username, full_name=None): """ Assert a user is listed in the read-only summary. Optionally check the displayed text: 'Full Name (username)' or 'username'. """ sel = f"[data-testid='{ACCOUNTS_READONLY_USER_ROW}-{username}']" self.browser.wait_visible(sel) if full_name is not None: expected = f"{full_name} ({username})" self.browser.wait_text(sel, expected) def create_user(browser, machine): p = Password(browser, CREATE_ACCOUNT_ID_PREFIX) u = Users(browser, machine) password = "password" p.set_password(password) p.set_password_confirm(password) u.set_user_name("tester")