diff --git a/src/charm.py b/src/charm.py index e6f12c3..11935ba 100755 --- a/src/charm.py +++ b/src/charm.py @@ -318,8 +318,6 @@ def _refresh_importer_node(self) -> None: if not node.setup_secondary_node( GIT_UBUNTU_USER_HOME_DIR, - self._node_id, - self._num_workers, GIT_UBUNTU_SYSTEM_USER_USERNAME, self._is_publishing_active, self._controller_port, @@ -335,7 +333,7 @@ def _refresh_importer_node(self) -> None: def _start_services(self) -> None: """Start the services and note the result through status.""" - if node.start(GIT_UBUNTU_USER_HOME_DIR): + if node.start(GIT_UBUNTU_USER_HOME_DIR, self._node_id, self._num_workers): node_type_str = "primary" if self._is_primary else "secondary" self.unit.status = ops.ActiveStatus( f"Running git-ubuntu importer {node_type_str} node." @@ -352,8 +350,10 @@ def _update_git_user_config(self) -> bool: self.unit.status = ops.MaintenanceStatus("Updating git config for git-ubuntu user.") if not usr.update_git_user_name( - GIT_UBUNTU_SYSTEM_USER_USERNAME, GIT_UBUNTU_GIT_USER_NAME - ) or not usr.update_git_email(GIT_UBUNTU_SYSTEM_USER_USERNAME, GIT_UBUNTU_GIT_EMAIL): + GIT_UBUNTU_SYSTEM_USER_USERNAME, GIT_UBUNTU_GIT_USER_NAME, GIT_UBUNTU_USER_HOME_DIR + ) or not usr.update_git_email( + GIT_UBUNTU_SYSTEM_USER_USERNAME, GIT_UBUNTU_GIT_EMAIL, GIT_UBUNTU_USER_HOME_DIR + ): self.unit.status = ops.BlockedStatus("Failed to set git user config.") return False return True @@ -363,7 +363,9 @@ def _update_lpuser_config(self) -> bool: self.unit.status = ops.MaintenanceStatus("Updating lpuser entry for git-ubuntu user.") lpuser = self._lp_username if lp.is_valid_lp_username(lpuser): - if not usr.update_git_ubuntu_lpuser(GIT_UBUNTU_SYSTEM_USER_USERNAME, lpuser): + if not usr.update_git_ubuntu_lpuser( + GIT_UBUNTU_SYSTEM_USER_USERNAME, lpuser, GIT_UBUNTU_USER_HOME_DIR + ): self.unit.status = ops.BlockedStatus("Failed to update lpuser config.") return False else: diff --git a/src/git_ubuntu.py b/src/git_ubuntu.py index 5a9a6ac..cc83b8f 100644 --- a/src/git_ubuntu.py +++ b/src/git_ubuntu.py @@ -53,6 +53,34 @@ def _get_services_list(service_folder: str) -> list[str] | None: return service_list +def _expand_service_list_for_workers( + base_service_list: list[str], + node_id: int, + num_workers: int, +) -> list[str]: + """Expand the base service list to include worker instances. + + Args: + base_service_list: The base list of service names. + node_id: The unique ID of this node. + num_workers: The number of worker instances to set up. + + Returns: + The expanded list of service names including worker instances. + """ + expanded_service_list = [] + + for service in base_service_list: + if "@.service" in service: + for worker_id in range(num_workers): + service_name = service.replace("@.service", f"@w{node_id}-{worker_id}") + expanded_service_list.append(service_name) + else: + expanded_service_list.append(service) + + return expanded_service_list + + def generate_systemd_service_string( description: str, service_user: str, @@ -139,7 +167,7 @@ def generate_systemd_service_string( def setup_broker_service( - local_folder: str, + home_dir: str, user: str, group: str, broker_port: int = 1692, @@ -147,7 +175,7 @@ def setup_broker_service( """Set up broker systemd service file. Args: - local_folder: The local folder to store the service in. + home_dir: The home directory of the user. user: The user to run the service as. group: The permissions group to run the service as. broker_port: The network port to provide tasks to workers on. @@ -170,11 +198,12 @@ def setup_broker_service( wanted_by="multi-user.target", ) - return create_systemd_service_file(filename, local_folder, service_string) + services_folder = pathops.LocalPath(home_dir, "services") + return create_systemd_service_file(filename, services_folder.as_posix(), service_string) def setup_poller_service( - local_folder: str, + home_dir: str, user: str, group: str, denylist: str, @@ -184,7 +213,7 @@ def setup_poller_service( """Set up poller systemd service file. Args: - local_folder: The local folder to store the service in. + home_dir: The home directory of the user. user: The user to run the service as. group: The permissions group to run the service as. denylist: The location of the package denylist. @@ -219,27 +248,26 @@ def setup_poller_service( wanted_by="multi-user.target", ) - return create_systemd_service_file(filename, local_folder, service_string) + services_folder = pathops.LocalPath(home_dir, "services") + return create_systemd_service_file(filename, services_folder.as_posix(), service_string) def setup_worker_service( - local_folder: str, + home_dir: str, user: str, group: str, - worker_name: str = "", push_to_lp: bool = True, broker_ip: str = "127.0.0.1", broker_port: int = 1692, lp_credentials_filename: str = "", https_proxy: str = "", ) -> bool: - """Set up worker systemd file with designated worker name. + """Set up worker systemd file. Args: - local_folder: The local folder to store the service in. + home_dir: The home directory of the user. user: The user to run the service as. group: The permissions group to run the service as. - worker_name: The unique worker ID to add to the service filename. push_to_lp: True if publishing repositories to Launchpad. broker_ip: The IP address of the broker process' node. broker_port: The network port that the broker provides tasks on. @@ -249,13 +277,13 @@ def setup_worker_service( Returns: True if setup succeeded, False otherwise. """ - filename = f"git-ubuntu-importer-service-worker{worker_name}.service" + filename = "git-ubuntu-importer-service-worker@.service" publish_arg = " --no-push" if not push_to_lp else "" broker_url = f"tcp://{broker_ip}:{broker_port}" exec_start = f"/snap/bin/git-ubuntu importer-service-worker{publish_arg} %i {broker_url}" - environment = "PYTHONUNBUFFERED=1" + environment = f"HOME={home_dir} PYTHONUNBUFFERED=1" if lp_credentials_filename != "": environment = f"LP_CREDENTIALS_FILE={lp_credentials_filename} " + environment @@ -279,14 +307,17 @@ def setup_worker_service( wanted_by="multi-user.target", ) - return create_systemd_service_file(filename, local_folder, service_string) + services_folder = pathops.LocalPath(home_dir, "services") + return create_systemd_service_file(filename, services_folder.as_posix(), service_string) -def start_services(service_folder: str) -> bool: +def start_services(service_folder: str, node_id: int, num_workers: int) -> bool: """Start all git-ubuntu services and wait for startup to complete. Args: service_folder: The name of the folder containing the service files. + node_id: The unique ID of this node. + num_workers: The number of worker instances to start if secondary. Returns: True if all services were started successfully, False otherwise. @@ -296,6 +327,8 @@ def start_services(service_folder: str) -> bool: if service_list is None: return False + service_list = _expand_service_list_for_workers(service_list, node_id, num_workers) + services_started = True # Start services @@ -337,6 +370,10 @@ def stop_services(service_folder: str) -> bool: services_stopped = True for service in service_list: + # Glob worker services + if "@.service" in service: + service = f"'{service.replace('@.service', '@*')}'" + if stop_service(service): logger.info("Stopped service %s", service) else: diff --git a/src/importer_node.py b/src/importer_node.py index d52625b..4e9a815 100644 --- a/src/importer_node.py +++ b/src/importer_node.py @@ -15,8 +15,6 @@ def setup_secondary_node( git_ubuntu_user_home: str, - node_id: int, - num_workers: int, system_user: str, push_to_lp: bool, primary_port: int, @@ -28,8 +26,6 @@ def setup_secondary_node( Args: git_ubuntu_user_home: The home directory of the git-ubuntu user. - node_id: The unique ID of this node. - num_workers: The number of worker instances to set up. system_user: The user + group to run the services as. push_to_lp: True if publishing repositories to Launchpad. primary_port: The network port used for worker assignments. @@ -40,23 +36,18 @@ def setup_secondary_node( Returns: True if installation succeeded, False otherwise. """ - services_folder = pathops.LocalPath(git_ubuntu_user_home, "services") - - for i in range(num_workers): - worker_name = f"{node_id}_{i}" - if not git_ubuntu.setup_worker_service( - services_folder.as_posix(), - system_user, - system_user, - worker_name, - push_to_lp, - primary_ip, - primary_port, - lp_credentials_filename, - https_proxy, - ): - logger.error("Failed to setup worker %s service.", worker_name) - return False + if not git_ubuntu.setup_worker_service( + git_ubuntu_user_home, + system_user, + system_user, + push_to_lp, + primary_ip, + primary_port, + lp_credentials_filename, + https_proxy, + ): + logger.error("Failed to setup worker service file.") + return False return True @@ -80,11 +71,9 @@ def setup_primary_node( Returns: True if installation succeeded, False otherwise. """ - services_folder = pathops.LocalPath(git_ubuntu_user_home, "services") - # Setup broker service. if not git_ubuntu.setup_broker_service( - services_folder.as_posix(), + git_ubuntu_user_home, system_user, system_user, primary_port, @@ -99,7 +88,7 @@ def setup_primary_node( # Setup poller service. if not git_ubuntu.setup_poller_service( - services_folder.as_posix(), + git_ubuntu_user_home, system_user, system_user, denylist.as_posix(), @@ -112,18 +101,20 @@ def setup_primary_node( return True -def start(git_ubuntu_user_home: str) -> bool: +def start(git_ubuntu_user_home: str, node_id: int, num_workers: int) -> bool: """Start all git-ubuntu services and wait for their startups to complete. Args: git_ubuntu_user_home: The home directory of the git-ubuntu user. + node_id: The node ID of this node. + num_workers: The number of worker services to start if secondary. Returns: True if all services were started successfully, False otherwise. """ services_folder = pathops.LocalPath(git_ubuntu_user_home, "services") - if not git_ubuntu.start_services(services_folder.as_posix()): + if not git_ubuntu.start_services(services_folder.as_posix(), node_id, num_workers): logger.error("Failed to start all services.") return False diff --git a/src/user_management.py b/src/user_management.py index 4887e84..dbe03dd 100644 --- a/src/user_management.py +++ b/src/user_management.py @@ -5,7 +5,7 @@ """Machine user management functions.""" import logging -from os import system +import subprocess from charmlibs import pathops from charms.operator_libs_linux.v0 import passwd @@ -13,20 +13,41 @@ logger = logging.getLogger(__name__) -def _run_command_as_user(user: str, command: str) -> bool: +def _run_command_as_user(user: str, command: str, env: dict[str, str] | None = None) -> bool: """Run a command as a user. Args: user: The user to run the command as. command: The command to run. + env: Dictionary of environment variables to set for the command. Returns: True if the command was run successfully, False otherwise. """ - command_result = system(f'su - {user} -s /bin/bash -c "{command}"') - if command_result != 0: - logger.error("Command %s exited with result %d.", command, command_result) + try: + result = subprocess.run( + command, + user=user, + env=env, + capture_output=True, + text=True, + check=False, + shell=True, + ) + except OSError: + logger.exception("Failed to execute command %s as user %s", command, user) return False + + if result.returncode != 0: + logger.error( + "Command %s exited with result %d - stdout: %s - stderr: %s", + command, + result.returncode, + result.stdout, + result.stderr, + ) + return False + return True @@ -119,29 +140,31 @@ def refresh_git_ubuntu_source( # Update origin to the current source url if not _run_command_as_user( - user, f"git -C {clone_dir.as_posix()} remote set-url origin {source_url}" + user, + f"git -C {clone_dir.as_posix()} remote set-url origin {source_url}", + {"HOME": home_dir}, ): logger.error("Failed to update git-ubuntu source origin.") return False # Run git pull to get up to date - pull_command = f"git -C {clone_dir.as_posix()} pull" + env = {"HOME": home_dir} if https_proxy != "": - pull_command = f"https_proxy={https_proxy} {pull_command}" + env["HTTPS_PROXY"] = https_proxy - if not _run_command_as_user(user, pull_command): + if not _run_command_as_user(user, f"git -C {clone_dir.as_posix()} pull", env): logger.error("Failed to update existing git-ubuntu source.") return False return True # Clone the repository - clone_command = f"git clone {source_url} {clone_dir.as_posix()}" + env = {"HOME": home_dir} if https_proxy != "": - clone_command = f"https_proxy={https_proxy} {clone_command}" + env["HTTPS_PROXY"] = https_proxy logger.info("Cloning git-ubuntu source to %s", clone_dir.as_posix()) - if not _run_command_as_user(user, clone_command): + if not _run_command_as_user(user, f"git clone {source_url} {clone_dir.as_posix()}", env): logger.error("Failed to clone git-ubuntu source.") return False @@ -290,50 +313,68 @@ def set_snap_homedirs(home_dir: str) -> bool: True if the homedirs update succeeded, False otherwise. """ homedirs_entry = pathops.LocalPath(home_dir).parent.as_posix() - command_result = system(f"snap set system homedirs={homedirs_entry}") - if command_result != 0: + + try: + command_result = subprocess.run( + ["snap", "set", "system", f"homedirs={homedirs_entry}"], check=False + ) + except OSError: + logger.exception("Failed to execute snap homedir setting command.") + return False + + if command_result.returncode != 0: logger.error("snap homedir setting exited with result %d.", command_result) return False + return True -def update_git_user_name(user: str, name: str) -> bool: +def update_git_user_name(user: str, name: str, home_dir: str) -> bool: """Update the git user full name entry. Args: user: The system user to update the config for. name: The full name for the git user. + home_dir: The home directory for the user. Returns: True if config update succeeded, False otherwise. """ logger.info("Setting git user.name to %s for user %s.", name, user) - return _run_command_as_user(user, f"git config --global user.name '{name}'") + return _run_command_as_user( + user, f"git config --global user.name '{name}'", {"HOME": home_dir} + ) -def update_git_email(user: str, email: str) -> bool: +def update_git_email(user: str, email: str, home_dir: str) -> bool: """Update the git user email address entry. Args: user: The system user to update the config for. email: The email address for the git user. + home_dir: The home directory for the user. Returns: True if config update succeeded, False otherwise. """ logger.info("Setting git user.email to %s for user %s.", email, user) - return _run_command_as_user(user, f"git config --global user.email {email}") + return _run_command_as_user( + user, f"git config --global user.email {email}", {"HOME": home_dir} + ) -def update_git_ubuntu_lpuser(user: str, lp_username: str) -> bool: +def update_git_ubuntu_lpuser(user: str, lp_username: str, home_dir: str) -> bool: """Update the launchpad user setting for git. Args: user: The system user to update the config for. lp_username: The launchpad username set in git. + home_dir: The home directory for the user. Returns: True if config update succeeded, False otherwise. """ logger.info("Setting git gitubuntu.lpuser to %s for user %s.", lp_username, user) - return _run_command_as_user(user, f"git config --global gitubuntu.lpuser {lp_username}") + return _run_command_as_user( + user, f"git config --global gitubuntu.lpuser {lp_username}", {"HOME": home_dir} + ) diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py new file mode 100644 index 0000000..c76b988 --- /dev/null +++ b/tests/integration/helpers.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright 2025 Canonical Ltd. +# See LICENSE file for licensing details. + + +"""Integration test utility functions.""" + +import json +import socket + +import jubilant + + +def check_deb_installed(app: str, unit: int, juju: jubilant.Juju, package_name: str) -> bool: + """Check if a deb pkg is installed on a specific unit. + + Args: + app: The app in charge of this unit. + unit: The unit number to check. + juju: The juju model in charge of the app. + package_name: The name of the deb package. + + Returns: + True if the package is installed, False otherwise. + """ + install_status = juju.ssh( + f"{app}/{unit}", f"dpkg-query --show --showformat='${{Status}}' {package_name}" + ) + return "installed" in install_status + + +def get_services_dict(unit_name: str, juju: jubilant.Juju) -> dict[str, dict[str, bool | str]]: + """Get a dictionary of running systemd services on the app's unit. + + Args: + unit_name: The name of the unit to check. + juju: The juju model in charge of the app. + + Returns: + A dict mapping unit name to if the service is active and its description. + """ + service_output = juju.ssh( + unit_name, + "systemctl list-units --type service --full --all --output json --no-pager | cat -v", + "", + ) + service_json = json.loads(service_output) + service_dict = dict() + + for service_entry in service_json: + service_dict[service_entry["unit"]] = { + "active": service_entry["active"] == "active", + "description": service_entry["description"], + } + + return service_dict + + +def is_port_open(host: str, port: int) -> bool: + """Check if a port is opened in a particular host. + + Args: + host: The host network location. + port: The port number to check. + + Returns: True if the port is open, False otherwise. + """ + try: + with socket.create_connection((host, port), timeout=5): + return True + except (ConnectionRefusedError, TimeoutError): + return False + + +def wait_for_all_units_running(app: str, juju: jubilant.Juju) -> None: + """Wait until all units of an application are active and contain the correct running message. + + Args: + app: The application name. + juju: The juju model in charge of the app. + """ + juju.wait( + lambda status: all( + unit_status.is_active + and "Running git-ubuntu importer" in unit_status.workload_status.message + for unit_status in status.apps[app].units.values() + ) + ) diff --git a/tests/integration/test_charm.py b/tests/integration/test_charm.py index 8689810..bfa35e2 100644 --- a/tests/integration/test_charm.py +++ b/tests/integration/test_charm.py @@ -5,83 +5,19 @@ """Integration tests.""" -import json import logging -import socket -from time import sleep import jubilant +from helpers import ( + check_deb_installed, + get_services_dict, + is_port_open, + wait_for_all_units_running, +) logger = logging.getLogger(__name__) -def test_service_status(app: str, juju: jubilant.Juju): - """Test necessary files exist after startup. - - Args: - app: The app in charge of this unit. - juju: The juju model in charge of the app. - """ - # Wait until machine is ready, then wait an extra 60 seconds for services to fully activate. - juju.wait(jubilant.all_active) - sleep(90) - - def get_services_dict(unit_name: str, juju: jubilant.Juju) -> dict[str, dict[str, bool | str]]: - """Get a dictionary of running systemd services on the app's unit. - - Args: - unit_name: The name of the unit to check. - juju: The juju model in charge of the app. - - Returns: - A dict mapping unit name to if the service is active and its description. - """ - service_output = juju.ssh( - unit_name, - "systemctl list-units --type service --full --all --output json --no-pager | cat -v", - "", - ) - service_json = json.loads(service_output) - service_dict = dict() - - for service_entry in service_json: - service_dict[service_entry["unit"]] = { - "active": service_entry["active"] == "active", - "description": service_entry["description"], - } - - return service_dict - - for unit_name, unit in juju.status().get_units(app).items(): - services = get_services_dict(unit_name, juju) - - if unit.leader: - assert services["git-ubuntu-importer-service-broker.service"]["active"] - assert ( - services["git-ubuntu-importer-service-broker.service"]["description"] - == "git-ubuntu importer service broker" - ) - assert services["git-ubuntu-importer-service-poller.service"]["active"] - assert ( - services["git-ubuntu-importer-service-poller.service"]["description"] - == "git-ubuntu importer service poller" - ) - - else: - node_id = int(unit_name.split("/")[-1]) - - assert services[f"git-ubuntu-importer-service-worker{node_id}_0.service"]["active"] - assert ( - services[f"git-ubuntu-importer-service-worker{node_id}_0.service"]["description"] - == "git-ubuntu importer service worker" - ) - assert services[f"git-ubuntu-importer-service-worker{node_id}_1.service"]["active"] - assert ( - services[f"git-ubuntu-importer-service-worker{node_id}_1.service"]["description"] - == "git-ubuntu importer service worker" - ) - - def test_installed_apps(app: str, juju: jubilant.Juju): """Test that all required applications are installed. @@ -89,24 +25,7 @@ def test_installed_apps(app: str, juju: jubilant.Juju): app: The app in charge of this unit. juju: The juju model in charge of the app. """ - juju.wait(jubilant.all_active) - - def check_deb_installed(app: str, unit: int, juju: jubilant.Juju, package_name: str) -> bool: - """Check if a deb pkg is installed on a specific unit. - - Args: - app: The app in charge of this unit. - unit: The unit number to check. - juju: The juju model in charge of the app. - package_name: The name of the deb package. - - Returns: - True if the package is installed, False otherwise. - """ - install_status = juju.ssh( - f"{app}/{unit}", f"dpkg-query --show --showformat='${{Status}}' {package_name}" - ) - return "installed" in install_status + wait_for_all_units_running(app, juju) assert check_deb_installed(app, 0, juju, "git") assert check_deb_installed(app, 0, juju, "sqlite3") @@ -129,7 +48,7 @@ def test_installed_dump_files(app: str, juju: jubilant.Juju): app: The app in charge of this unit. juju: The juju model in charge of the app. """ - juju.wait(jubilant.all_active) + wait_for_all_units_running(app, juju) debian_keyring_status = juju.ssh( f"{app}/leader", "test -f /etc/git-ubuntu/debian-archive-keyring.gpg | echo $?", "" @@ -137,29 +56,33 @@ def test_installed_dump_files(app: str, juju: jubilant.Juju): assert debian_keyring_status == "0" -def test_controller_port_open(app: str, juju: jubilant.Juju): - """Confirm that the git-ubuntu controller leader network port opens. +def test_git_ubuntu_source_denylist_exists(app: str, juju: jubilant.Juju): + """Test that the git-ubuntu source repo has been cloned and contains the denylist. Args: app: The app in charge of this unit. juju: The juju model in charge of the app. """ - juju.wait(jubilant.all_active) + wait_for_all_units_running(app, juju) - def is_port_open(host: str, port: int) -> bool: - """Check if a port is opened in a particular host. + debian_keyring_status = juju.ssh( + f"{app}/leader", + "test -f " + + "/var/local/git-ubuntu/live-allowlist-denylist-source/gitubuntu/" + + "source-package-denylist.txt | echo $?", + "", + ).strip() + assert debian_keyring_status == "0" - Args: - host: The host network location. - port: The port number to check. - Returns: True if the port is open, False otherwise. - """ - try: - with socket.create_connection((host, port), timeout=5): - return True - except (ConnectionRefusedError, TimeoutError): - return False +def test_controller_port_open(app: str, juju: jubilant.Juju): + """Confirm that the git-ubuntu controller leader network port opens. + + Args: + app: The app in charge of this unit. + juju: The juju model in charge of the app. + """ + wait_for_all_units_running(app, juju) address = None for unit in juju.status().get_units(app).values(): @@ -168,3 +91,43 @@ def is_port_open(host: str, port: int) -> bool: assert address is not None assert is_port_open(address, 1692) + + +def test_service_status(app: str, juju: jubilant.Juju): + """Test necessary files exist after startup. + + Args: + app: The app in charge of this unit. + juju: The juju model in charge of the app. + """ + # Wait until machine is ready, then wait an extra 60 seconds for services to fully activate. + wait_for_all_units_running(app, juju) + + for unit_name, unit in juju.status().get_units(app).items(): + services = get_services_dict(unit_name, juju) + + if unit.leader: + assert services["git-ubuntu-importer-service-broker.service"]["active"] + assert ( + services["git-ubuntu-importer-service-broker.service"]["description"] + == "git-ubuntu importer service broker" + ) + assert services["git-ubuntu-importer-service-poller.service"]["active"] + assert ( + services["git-ubuntu-importer-service-poller.service"]["description"] + == "git-ubuntu importer service poller" + ) + + else: + node_id = int(unit_name.split("/")[-1]) + + assert services[f"git-ubuntu-importer-service-worker@w{node_id}-0.service"]["active"] + assert ( + services[f"git-ubuntu-importer-service-worker@w{node_id}-0.service"]["description"] + == "git-ubuntu importer service worker" + ) + assert services[f"git-ubuntu-importer-service-worker@w{node_id}-1.service"]["active"] + assert ( + services[f"git-ubuntu-importer-service-worker@w{node_id}-1.service"]["description"] + == "git-ubuntu importer service worker" + ) diff --git a/tests/unit/test_git_ubuntu.py b/tests/unit/test_git_ubuntu.py index 2b700d8..78992e8 100644 --- a/tests/unit/test_git_ubuntu.py +++ b/tests/unit/test_git_ubuntu.py @@ -478,7 +478,7 @@ def test_git_ubuntu_broker_setup_success(mock_create_file): """Test GitUbuntuBroker setup with default parameters.""" mock_create_file.return_value = True - result = setup_broker_service("test_folder", "ubuntu", "testgroup") + result = setup_broker_service("test_home", "ubuntu", "testgroup") assert result is True mock_create_file.assert_called_once() @@ -489,7 +489,7 @@ def test_git_ubuntu_broker_setup_custom_port(mock_create_file): """Test GitUbuntuBroker setup with custom broker port.""" mock_create_file.return_value = True - result = setup_broker_service("test_folder", "ubuntu", "testgroup", broker_port=8080) + result = setup_broker_service("test_home", "ubuntu", "testgroup", broker_port=8080) assert result is True mock_create_file.assert_called_once() @@ -500,7 +500,7 @@ def test_git_ubuntu_broker_setup_failure(mock_create_file): """Test GitUbuntuBroker setup when file creation fails.""" mock_create_file.return_value = False - result = setup_broker_service("test_folder", "ubuntu", "testgroup") + result = setup_broker_service("test_home", "ubuntu", "testgroup") assert result is False @@ -510,7 +510,7 @@ def test_git_ubuntu_poller_setup_success(mock_create_file): """Test GitUbuntuPoller setup with default parameters.""" mock_create_file.return_value = True - result = setup_poller_service("test_folder", "ubuntu", "testgroup", "denylist.txt") + result = setup_poller_service("test_home", "ubuntu", "testgroup", "denylist.txt") assert result is True mock_create_file.assert_called_once() @@ -522,7 +522,7 @@ def test_git_ubuntu_poller_setup_with_http_proxy(mock_create_file): mock_create_file.return_value = True result = setup_poller_service( - "test_folder", + "test_home", "ubuntu", "testgroup", "denylist.txt", @@ -539,7 +539,7 @@ def test_git_ubuntu_poller_setup_with_https_proxy(mock_create_file): mock_create_file.return_value = True result = setup_poller_service( - "test_folder", + "test_home", "ubuntu", "testgroup", "denylist.txt", @@ -556,7 +556,7 @@ def test_git_ubuntu_poller_setup_with_full_proxy(mock_create_file): mock_create_file.return_value = True result = setup_poller_service( - "test_folder", + "test_home", "ubuntu", "testgroup", "denylist.txt", @@ -573,7 +573,7 @@ def test_git_ubuntu_poller_setup_failure(mock_create_file): """Test GitUbuntuPoller setup when file creation fails.""" mock_create_file.return_value = False - result = setup_poller_service("test_folder", "ubuntu", "testgroup", "denylist.txt") + result = setup_poller_service("test_home", "ubuntu", "testgroup", "denylist.txt") assert result is False @@ -583,7 +583,7 @@ def test_git_ubuntu_worker_setup_success(mock_create_file): """Test GitUbuntuWorker setup with default parameters.""" mock_create_file.return_value = True - result = setup_worker_service("test_folder", "ubuntu", "testgroup") + result = setup_worker_service("test_home", "ubuntu", "testgroup") assert result is True mock_create_file.assert_called_once() @@ -595,10 +595,9 @@ def test_git_ubuntu_worker_setup_custom_params(mock_create_file): mock_create_file.return_value = True result = setup_worker_service( - "test_folder", + "test_home", "ubuntu", "testgroup", - worker_name="1_2", broker_ip="192.168.1.100", broker_port=9000, ) @@ -613,10 +612,9 @@ def test_git_ubuntu_worker_setup_https_proxy(mock_create_file): mock_create_file.return_value = True result = setup_worker_service( - "test_folder", + "test_home", "ubuntu", "testgroup", - worker_name="1_2", broker_ip="192.168.1.100", broker_port=9000, https_proxy="http://proxy.example.com:8080", @@ -631,6 +629,6 @@ def test_git_ubuntu_worker_setup_failure(mock_create_file): """Test GitUbuntuWorker setup when file creation fails.""" mock_create_file.return_value = False - result = setup_worker_service("test_folder", "ubuntu", "testgroup") + result = setup_worker_service("test_home", "ubuntu", "testgroup") assert result is False diff --git a/tests/unit/test_importer_node.py b/tests/unit/test_importer_node.py index ee39618..f1c2bc5 100644 --- a/tests/unit/test_importer_node.py +++ b/tests/unit/test_importer_node.py @@ -16,11 +16,11 @@ def test_setup_secondary_node_success(mock_setup_worker): mock_setup_worker.return_value = True result = importer_node.setup_secondary_node( - "/var/local/git-ubuntu", 1, 2, "git-ubuntu", True, 1692, "192.168.1.1" + "/var/local/git-ubuntu", "git-ubuntu", True, 1692, "192.168.1.1" ) assert result is True - assert mock_setup_worker.call_count == 2 + assert mock_setup_worker.call_count == 1 @patch("importer_node.git_ubuntu.setup_worker_service") @@ -29,7 +29,7 @@ def test_setup_secondary_node_failure(mock_setup_worker): mock_setup_worker.return_value = False result = importer_node.setup_secondary_node( - "/var/local/git-ubuntu", 1, 1, "git-ubuntu", True, 1692, "192.168.1.1" + "/var/local/git-ubuntu", "git-ubuntu", True, 1692, "192.168.1.1" ) assert result is False @@ -90,10 +90,10 @@ def test_start_success(mock_start_services): """Test successful service start.""" mock_start_services.return_value = True - result = importer_node.start("/var/local/git-ubuntu") + result = importer_node.start("/var/local/git-ubuntu", 1, 2) assert result is True - mock_start_services.assert_called_once_with("/var/local/git-ubuntu/services") + mock_start_services.assert_called_once_with("/var/local/git-ubuntu/services", 1, 2) @patch("importer_node.git_ubuntu.start_services") @@ -101,7 +101,7 @@ def test_start_failure(mock_start_services): """Test service start failure.""" mock_start_services.return_value = False - result = importer_node.start("/var/local/git-ubuntu") + result = importer_node.start("/var/local/git-ubuntu", 1, 2) assert result is False diff --git a/tests/unit/test_user_management.py b/tests/unit/test_user_management.py index ed1a51d..dd243ec 100644 --- a/tests/unit/test_user_management.py +++ b/tests/unit/test_user_management.py @@ -15,9 +15,9 @@ def test_git_update_user_name_config_success(mock_run_command_as_user): """Test successful git user name config update.""" mock_run_command_as_user.return_value = True - assert user_management.update_git_user_name("ubuntu", "Test User") + assert user_management.update_git_user_name("ubuntu", "Test User", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global user.name 'Test User'" + "ubuntu", "git config --global user.name 'Test User'", {"HOME": "/home/ubuntu"} ) @@ -26,9 +26,9 @@ def test_git_update_user_name_config_fail(mock_run_command_as_user): """Test failed git user name config update.""" mock_run_command_as_user.return_value = False - assert not user_management.update_git_user_name("ubuntu", "Test User") + assert not user_management.update_git_user_name("ubuntu", "Test User", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global user.name 'Test User'" + "ubuntu", "git config --global user.name 'Test User'", {"HOME": "/home/ubuntu"} ) @@ -37,9 +37,9 @@ def test_git_update_user_email_config_success(mock_run_command_as_user): """Test successful git user email config update.""" mock_run_command_as_user.return_value = True - assert user_management.update_git_email("ubuntu", "test@example.com") + assert user_management.update_git_email("ubuntu", "test@example.com", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global user.email test@example.com" + "ubuntu", "git config --global user.email test@example.com", {"HOME": "/home/ubuntu"} ) @@ -48,9 +48,9 @@ def test_git_update_user_email_config_fail(mock_run_command_as_user): """Test failed git user email config update.""" mock_run_command_as_user.return_value = False - assert not user_management.update_git_email("ubuntu", "test@example.com") + assert not user_management.update_git_email("ubuntu", "test@example.com", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global user.email test@example.com" + "ubuntu", "git config --global user.email test@example.com", {"HOME": "/home/ubuntu"} ) @@ -59,9 +59,9 @@ def test_lp_user_config_success(mock_run_command_as_user): """Test successful launchpad user config update.""" mock_run_command_as_user.return_value = True - assert user_management.update_git_ubuntu_lpuser("ubuntu", "test-lp-user") + assert user_management.update_git_ubuntu_lpuser("ubuntu", "test-lp-user", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global gitubuntu.lpuser test-lp-user" + "ubuntu", "git config --global gitubuntu.lpuser test-lp-user", {"HOME": "/home/ubuntu"} ) @@ -70,7 +70,7 @@ def test_lp_user_config_fail(mock_run_command_as_user): """Test failed launchpad user config update.""" mock_run_command_as_user.return_value = False - assert not user_management.update_git_ubuntu_lpuser("ubuntu", "test-lp-user") + assert not user_management.update_git_ubuntu_lpuser("ubuntu", "test-lp-user", "/home/ubuntu") mock_run_command_as_user.assert_called_once_with( - "ubuntu", "git config --global gitubuntu.lpuser test-lp-user" + "ubuntu", "git config --global gitubuntu.lpuser test-lp-user", {"HOME": "/home/ubuntu"} )