diff --git a/tests/conftest.py b/tests/conftest.py index 5037244d6ab..422917420f2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -722,11 +722,14 @@ def pytest_runtest_setup(item): entropy_generator.generate_entropy() if salt.utils.platform.is_windows(): - unit_tests_paths = ( + auto_whitelisted_paths = ( str(TESTS_DIR / "unit"), str(PYTESTS_DIR / "unit"), + str(PYTESTS_DIR / "pkg"), ) - if not str(pathlib.Path(item.fspath).resolve()).startswith(unit_tests_paths): + if not str(pathlib.Path(item.fspath).resolve()).startswith( + auto_whitelisted_paths + ): # Unit tests are whitelisted on windows by default, so, we're only # after all other tests windows_whitelisted_marker = item.get_closest_marker("windows_whitelisted") diff --git a/tests/pytests/pkg/download/test_pkg_download.py b/tests/pytests/pkg/download/test_pkg_download.py index b774d9fa047..9a0fbd76bad 100644 --- a/tests/pytests/pkg/download/test_pkg_download.py +++ b/tests/pytests/pkg/download/test_pkg_download.py @@ -464,7 +464,7 @@ def setup_windows( try: arch = os.environ.get("SALT_REPO_ARCH") or "amd64" if package_type != "onedir": - root_dir = pathlib.Path(r"C:\Program Files\Salt Project\Salt") + root_dir = pathlib.Path(os.getenv("ProgramFiles"), "Salt Project", "Salt") if packaging.version.parse(salt_release) > packaging.version.parse("3005"): if package_type.lower() == "nsis": diff --git a/tests/pytests/pkg/integration/test_salt_state_file.py b/tests/pytests/pkg/integration/test_salt_state_file.py index 7b71fcb2365..1aadf3dbddb 100644 --- a/tests/pytests/pkg/integration/test_salt_state_file.py +++ b/tests/pytests/pkg/integration/test_salt_state_file.py @@ -5,6 +5,10 @@ import pytest from pytestskipmarkers.utils import platform from saltfactories.utils.functional import MultiStateResult +pytestmark = [ + pytest.mark.skip_on_windows, +] + @pytest.fixture def files(tmp_path): diff --git a/tests/support/pkg.py b/tests/support/pkg.py index 6df2dac0f63..e01bebc7594 100644 --- a/tests/support/pkg.py +++ b/tests/support/pkg.py @@ -199,7 +199,7 @@ class SaltPkgInstall: Default location for salt configurations """ if platform.is_windows(): - config_path = pathlib.Path("C://salt", "etc", "salt") + config_path = pathlib.Path("C:\\salt", "etc", "salt") else: config_path = pathlib.Path("/etc", "salt") return config_path @@ -237,7 +237,7 @@ class SaltPkgInstall: break if not version: pytest.fail( - f"Failed to package artifacts in '{ARTIFACTS_DIR}'. " + f"Failed to find package artifacts in '{ARTIFACTS_DIR}'. " f"Directory Contents:\n{pprint.pformat(artifacts)}" ) return version @@ -295,6 +295,10 @@ class SaltPkgInstall: self.run_root = self.bin_dir / "run" else: log.error("Unexpected file extension: %s", self.file_ext) + log.debug("root: %s", self.root) + log.debug("bin_dir: %s", self.bin_dir) + log.debug("ssm_bin: %s", self.ssm_bin) + log.debug("run_root: %s", self.run_root) if not self.pkgs: pytest.fail("Could not find Salt Artifacts") @@ -400,21 +404,24 @@ class SaltPkgInstall: self.binary_paths["spm"] = [shutil.which("salt-spm")] else: self.binary_paths["pip"] = [shutil.which("salt-pip")] + log.debug("python_bin: %s", python_bin) + log.debug("binary_paths: %s", self.binary_paths) + log.debug("install_dir: %s", self.install_dir) @staticmethod def salt_factories_root_dir(system_service: bool = False) -> pathlib.Path: if system_service is False: return None if platform.is_windows(): - return pathlib.Path("C:/salt") + return pathlib.Path("C:\\salt") if platform.is_darwin(): return pathlib.Path("/opt/salt") return pathlib.Path("/") def _check_retcode(self, ret): """ - helper function ot check subprocess.run - returncode equals 0, if not raise assertionerror + Helper function to check subprocess.run returncode equals 0 + If not raise AssertionError """ if ret.returncode != 0: log.error(ret) @@ -462,8 +469,14 @@ class SaltPkgInstall: # Remove the service installed by the installer log.debug("Removing installed salt-minion service") self.proc.run(str(self.ssm_bin), "remove", "salt-minion", "confirm") + + # Add installation to the path self.update_process_path() + # Install the service using our config + if self.pkg_system_service: + self._install_ssm_service() + elif platform.is_darwin(): daemons_dir = pathlib.Path("/Library", "LaunchDaemons") service_name = "com.saltstack.salt.minion" @@ -510,6 +523,54 @@ class SaltPkgInstall: log.info(ret) self._check_retcode(ret) + def _install_ssm_service(self, service="minion"): + """ + This function installs the service on Windows using SSM but does not + start it. + + Args: + + service (str): + The name of the service. Default is ``minion`` + """ + service_name = f"salt-{service}" + binary = self.install_dir / f"{service_name}.exe" + ret = self.proc.run( + str(self.ssm_bin), + "install", + service_name, + binary, + "-c", + f'"{str(self.conf_dir)}"', + ) + self._check_retcode(ret) + ret = self.proc.run( + str(self.ssm_bin), + "set", + service_name, + "Description", + "Salt Minion for testing", + ) + self._check_retcode(ret) + # This doesn't start the service. It will start automatically on reboot + # It is set here to make it the same as what the installer does + ret = self.proc.run( + str(self.ssm_bin), "set", service_name, "Start", "SERVICE_AUTO_START" + ) + self._check_retcode(ret) + ret = self.proc.run( + str(self.ssm_bin), "set", service_name, "AppStopMethodConsole", "24000" + ) + self._check_retcode(ret) + ret = self.proc.run( + str(self.ssm_bin), "set", service_name, "AppStopMethodWindow", "2000" + ) + self._check_retcode(ret) + ret = self.proc.run( + str(self.ssm_bin), "set", service_name, "AppRestartDelay", "60000" + ) + self._check_retcode(ret) + def package_python_version(self): return self.proc.run( str(self.binary_paths["python"][0]), @@ -762,7 +823,7 @@ class SaltPkgInstall: self._check_retcode(ret) if self.pkg_system_service: - self._install_system_service() + self._install_ssm_service() elif platform.is_darwin(): if self.classic: @@ -1229,8 +1290,8 @@ class PkgSsmSaltDaemonImpl(PkgSystemdSaltDaemonImpl): # Dereference the internal _process attribute self._process = None - # Lets log and kill any child processes left behind, including the main subprocess - # if it failed to properly stop + # Let's log and kill any child processes left behind, including the main + # subprocess if it failed to properly stop terminate_process( pid=pid, kill_children=True,