diff --git a/pyproject.toml b/pyproject.toml index 4b4d2727..02941bce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,8 +176,8 @@ source = [ ] [tool.coverage.coverage_conditional_plugin.rules] -is-windows = "sys_platform == 'win32'" -is-posix = "sys_platform != 'win32'" +skip-coverage-windows = "sys_platform == 'win32'" +skip-coverage-posix = "sys_platform != 'win32'" [tool.coverage.report] show_missing = true diff --git a/src/openjd/adaptor_runtime/_background/backend_runner.py b/src/openjd/adaptor_runtime/_background/backend_runner.py index a1f7329e..8f692953 100644 --- a/src/openjd/adaptor_runtime/_background/backend_runner.py +++ b/src/openjd/adaptor_runtime/_background/backend_runner.py @@ -10,19 +10,21 @@ from threading import Thread, Event import traceback from types import FrameType -from typing import Callable, List, Optional, Union +from typing import Callable, List, Optional from .server_response import ServerResponseGenerator -from .._osname import OSName from ..adaptors import AdaptorRunner -from .._http import SocketPaths from .._utils import secure_open -if OSName.is_posix(): - from .http_server import BackgroundHTTPServer -if OSName.is_windows(): +if os.name == "nt": # pragma: skip-coverage-posix from ...adaptor_runtime_client.named_pipe.named_pipe_helper import NamedPipeHelper - from .backend_named_pipe_server import WinBackgroundNamedPipeServer + from .backend_named_pipe_server import ( + WinBackgroundNamedPipeServer, + WinBackgroundNamedPipeServer as BackgroundServerType, + ) +else: # pragma: skip-coverage-windows + from .._http import SocketPaths + from .http_server import BackgroundHTTPServer, BackgroundHTTPServer as BackgroundServerType # type: ignore from .log_buffers import LogBuffer from .model import ConnectionSettings from .model import DataclassJSONEncoder @@ -46,12 +48,12 @@ def __init__( self._connection_file_path = connection_file_path self._log_buffer = log_buffer - self._server: Optional[Union[BackgroundHTTPServer, WinBackgroundNamedPipeServer]] = None + self._server: Optional[BackgroundServerType] = None signal.signal(signal.SIGINT, self._sigint_handler) - if OSName.is_posix(): # pragma: is-windows - signal.signal(signal.SIGTERM, self._sigint_handler) - else: # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix signal.signal(signal.SIGBREAK, self._sigint_handler) # type: ignore[attr-defined] + else: # pragma: skip-coverage-windows + signal.signal(signal.SIGTERM, self._sigint_handler) def _sigint_handler(self, signum: int, frame: Optional[FrameType]) -> None: """ @@ -81,24 +83,24 @@ def run(self, *, on_connection_file_written: List[Callable[[], None]] | None = N _logger.info("Running in background daemon mode.") shutdown_event: Event = Event() - if OSName.is_posix(): # pragma: is-windows - server_path = SocketPaths.for_os().get_process_socket_path( + if os.name == "nt": # pragma: skip-coverage-posix + server_path = NamedPipeHelper.generate_pipe_name("AdaptorNamedPipe") + else: # pragma: skip-coverage-windows + server_path = SocketPaths().get_process_socket_path( ".openjd_adaptor_runtime", create_dir=True, ) - else: # pragma: is-posix - server_path = NamedPipeHelper.generate_pipe_name("AdaptorNamedPipe") try: - if OSName.is_windows(): # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix self._server = WinBackgroundNamedPipeServer( server_path, self._adaptor_runner, shutdown_event=shutdown_event, log_buffer=self._log_buffer, ) - else: # pragma: is-windows - self._server = BackgroundHTTPServer( + else: # pragma: skip-coverage-windows + self._server = BackgroundHTTPServer( # type: ignore server_path, self._adaptor_runner, shutdown_event=shutdown_event, @@ -153,8 +155,8 @@ def run(self, *, on_connection_file_written: List[Callable[[], None]] | None = N # NamedPipe servers are managed by Named Pipe File System it is not a regular file. # Once all handles are closed, the system automatically cleans up the named pipe. files_for_deletion = [self._connection_file_path] - if OSName.is_posix(): # pragma: is-windows - files_for_deletion.append(server_path) + if os.name != "nt": # pragma: skip-coverage-windows + files_for_deletion.append(server_path) # type: ignore for path in files_for_deletion: try: os.remove(path) diff --git a/src/openjd/adaptor_runtime/_background/frontend_runner.py b/src/openjd/adaptor_runtime/_background/frontend_runner.py index d9bd8644..e792864c 100644 --- a/src/openjd/adaptor_runtime/_background/frontend_runner.py +++ b/src/openjd/adaptor_runtime/_background/frontend_runner.py @@ -20,7 +20,6 @@ from types import ModuleType from typing import Optional, Callable, Dict -from .._osname import OSName from ..process._logging import _ADAPTOR_OUTPUT_LEVEL from .._utils._constants import _OPENJD_ENV_STDOUT_PREFIX, _OPENJD_ADAPTOR_SOCKET_ENV from .loaders import ConnectionSettingsFileLoader @@ -36,7 +35,7 @@ _FRONTEND_RUNNER_REQUEST_TIMEOUT: float = 5.0 -if OSName.is_windows(): +if os.name == "nt": # pragma: skip-coverage-posix from ...adaptor_runtime_client.named_pipe.named_pipe_helper import NamedPipeHelper import pywintypes @@ -78,10 +77,10 @@ def __init__( self._canceled = Event() signal.signal(signal.SIGINT, self._sigint_handler) - if OSName.is_posix(): # pragma: is-windows - signal.signal(signal.SIGTERM, self._sigint_handler) - else: # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix signal.signal(signal.SIGBREAK, self._sigint_handler) # type: ignore[attr-defined] + else: # pragma: skip-coverage-windows + signal.signal(signal.SIGTERM, self._sigint_handler) def init( self, @@ -270,7 +269,7 @@ def _heartbeat(self, ack_id: str | None = None) -> HeartbeatResponse: """ params: dict[str, str] | None = {"ack_id": ack_id} if ack_id else None response = self._send_request("GET", "/heartbeat", params=params) - body = json.load(response.fp) if OSName.is_posix() else json.loads(response["body"]) # type: ignore + body = json.loads(response["body"]) if os.name == "nt" else json.load(response.fp) # type: ignore return DataclassMapper(HeartbeatResponse).map(body) def _heartbeat_until_state_complete(self, state: AdaptorState) -> None: @@ -330,7 +329,7 @@ def _send_request( "Connection settings are required to send requests, but none were provided" ) - if OSName.is_windows(): # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix if params: # This is used for aligning to the Linux's behavior in order to reuse the code in handler. # In linux, query string params will always be put in a list. @@ -353,7 +352,7 @@ def _send_request( _logger.error(f"Failed to send {path} request: {e}") raise return response - else: # pragma: is-windows + else: # pragma: skip-coverage-windows return self._send_linux_request( method, path, @@ -368,7 +367,7 @@ def _send_linux_request( *, params: dict | None = None, json_body: dict | None = None, - ) -> http_client.HTTPResponse: # pragma: is-windows + ) -> http_client.HTTPResponse: # pragma: skip-coverage-windows if not self.connection_settings: raise ConnectionSettingsNotProvidedError( "Connection settings are required to send requests, but none were provided" diff --git a/src/openjd/adaptor_runtime/_entrypoint.py b/src/openjd/adaptor_runtime/_entrypoint.py index df1a906f..96eb7b46 100644 --- a/src/openjd/adaptor_runtime/_entrypoint.py +++ b/src/openjd/adaptor_runtime/_entrypoint.py @@ -5,6 +5,7 @@ import contextlib import logging import os +import platform import signal import sys import tempfile @@ -40,7 +41,6 @@ RuntimeConfiguration, ConfigurationManager, ) -from ._osname import OSName from ._utils._constants import _OPENJD_ADAPTOR_SOCKET_ENV, _OPENJD_LOG_REGEX from ._utils._logging import ( ConditionalFormatter, @@ -84,7 +84,7 @@ _DIR = os.path.dirname(os.path.realpath(__file__)) # Keyword args to init the ConfigurationManager for the runtime. _ENV_CONFIG_PATH_PREFIX = "RUNTIME_CONFIG_PATH" -_system_config_path_prefix = "/etc" if OSName.is_posix() else os.environ["PROGRAMDATA"] +_system_config_path_prefix = os.environ["PROGRAMDATA"] if os.name == "nt" else "/etc" _system_config_path = os.path.abspath( os.path.join( _system_config_path_prefix, @@ -226,7 +226,7 @@ def _init_config(self) -> None: raise except NotImplementedError as e: _logger.warning( - f"The current system ({OSName()}) is not supported for runtime " + f"The current system ({platform.platform()}) is not supported for runtime " f"configuration. Only the default configuration will be loaded. Full error: {e}" ) # The above call to build_config() would have already successfully retrieved the @@ -354,10 +354,10 @@ def _handle_run( self._adaptor_runner = AdaptorRunner(adaptor=adaptor) # To be able to handle cancelation via signals signal.signal(signal.SIGINT, self._sigint_handler) - if OSName.is_posix(): # pragma: is-windows - signal.signal(signal.SIGTERM, self._sigint_handler) - else: # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix signal.signal(signal.SIGBREAK, self._sigint_handler) # type: ignore[attr-defined] + else: # pragma: skip-coverage-windows + signal.signal(signal.SIGTERM, self._sigint_handler) try: self._adaptor_runner._start() self._adaptor_runner._run(integration_data.run_data) diff --git a/src/openjd/adaptor_runtime/_http/request_handler.py b/src/openjd/adaptor_runtime/_http/request_handler.py index 82489d91..02927ee7 100644 --- a/src/openjd/adaptor_runtime/_http/request_handler.py +++ b/src/openjd/adaptor_runtime/_http/request_handler.py @@ -12,8 +12,8 @@ from dataclasses import dataclass from http import HTTPStatus, server from typing import Any, Callable, Type +import sys -from .._osname import OSName from .exceptions import UnsupportedPlatformException _logger = logging.getLogger(__name__) @@ -125,8 +125,8 @@ def _authenticate(self) -> bool: peercred_opt_level: Any peercred_opt: Any cred_cls: Any - if OSName.is_macos(): # pragma: no cover - # SOL_LOCAL is not defined in Python's socket module, need to hardcode it + if sys.platform == "darwin": + # On MacOS, SOL_LOCAL is not defined in Python's socket module, need to hardcode it # source: https://github.com/apple-oss-distributions/xnu/blob/1031c584a5e37aff177559b9f69dbd3c8c3fd30a/bsd/sys/un.h#L85 peercred_opt_level = 0 # type: ignore[attr-defined] peercred_opt = socket.LOCAL_PEERCRED # type: ignore[attr-defined] diff --git a/src/openjd/adaptor_runtime/_http/sockets.py b/src/openjd/adaptor_runtime/_http/sockets.py index c4c90110..beebb11a 100644 --- a/src/openjd/adaptor_runtime/_http/sockets.py +++ b/src/openjd/adaptor_runtime/_http/sockets.py @@ -5,11 +5,11 @@ import abc import os import stat +import sys import tempfile +from typing import Type -from .._osname import OSName from .exceptions import ( - UnsupportedPlatformException, NonvalidSocketPathException, NoSocketPathFoundException, ) @@ -18,29 +18,11 @@ _PID_MAX_LENGTH = 7 -class SocketPaths(abc.ABC): +class SocketPathsBase(abc.ABC): """ Base class for determining the paths for sockets used in the Adaptor Runtime. """ - @staticmethod - def for_os(osname: OSName = OSName()): # pragma: no cover - """ - Gets the SocketPaths class for a specific OS. - - Args: - osname (OSName, optional): The OS to get socket paths for. - Defaults to the current OS. - - Raises: - UnsupportedPlatformException: Raised when this class is requested for an unsupported - platform. - """ - klass = _get_socket_paths_cls(osname) - if not klass: - raise UnsupportedPlatformException(osname) - return klass() - def get_process_socket_path( self, namespace: str | None = None, @@ -143,7 +125,7 @@ def verify_socket_path(self, path: str) -> None: # pragma: no cover pass -class WindowsSocketPaths(SocketPaths): +class WindowsSocketPaths(SocketPathsBase): """ Specialization for verifying socket paths on Windows systems. """ @@ -153,7 +135,7 @@ def verify_socket_path(self, path: str) -> None: pass -class UnixSocketPaths(SocketPaths): +class UnixSocketPaths(SocketPathsBase): """ Specialization for verifying socket paths on Unix systems. """ @@ -215,14 +197,12 @@ def verify_socket_path(self, path: str) -> None: ) -_os_map: dict[str, type[SocketPaths]] = { - OSName.LINUX: LinuxSocketPaths, - OSName.MACOS: MacOSSocketPaths, - OSName.WINDOWS: WindowsSocketPaths, -} - +SocketPaths: Type -def _get_socket_paths_cls( - osname: OSName, -) -> type[SocketPaths] | None: # pragma: no cover - return _os_map.get(osname, None) +# Make SocketPaths the correct operating-specific subclass of SocketPathsBase +if sys.platform == "darwin": # pragma: skip-coverage-windows + SocketPaths = MacOSSocketPaths +elif os.name == "nt": # pragma: skip-coverage-posix + SocketPaths = WindowsSocketPaths +else: # pragma: skip-coverage-windows + SocketPaths = LinuxSocketPaths diff --git a/src/openjd/adaptor_runtime/_named_pipe/named_pipe_request_handler.py b/src/openjd/adaptor_runtime/_named_pipe/named_pipe_request_handler.py index 742850d8..b24d2b01 100644 --- a/src/openjd/adaptor_runtime/_named_pipe/named_pipe_request_handler.py +++ b/src/openjd/adaptor_runtime/_named_pipe/named_pipe_request_handler.py @@ -1,6 +1,8 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. import json +import os +import platform from typing import TYPE_CHECKING, Dict, List if TYPE_CHECKING: # pragma: no cover because pytest will think we should test for this. @@ -18,8 +20,6 @@ import traceback from abc import ABC, abstractmethod -from openjd.adaptor_runtime._osname import OSName - _logger = logging.getLogger(__name__) @@ -42,10 +42,10 @@ def __init__(self, server: "NamedPipeServer", pipe_handle: HANDLE): Utilized for message read/write operations. """ self._handler_type_name = self.__class__.__name__ - if not OSName.is_windows(): + if os.name != "nt": # pragma: skip-coverage-windows raise OSError( f"{self._handler_type_name} can be only used on Windows Operating Systems. " - f"Current Operating System is {OSName._get_os_name()}" + f"Current Operating System is {platform.platform()}" ) self.server = server self.pipe_handle = pipe_handle diff --git a/src/openjd/adaptor_runtime/_named_pipe/named_pipe_server.py b/src/openjd/adaptor_runtime/_named_pipe/named_pipe_server.py index 5ba430a4..7600a37a 100644 --- a/src/openjd/adaptor_runtime/_named_pipe/named_pipe_server.py +++ b/src/openjd/adaptor_runtime/_named_pipe/named_pipe_server.py @@ -1,8 +1,10 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. from __future__ import annotations -import logging +import logging +import os +import platform import threading from threading import Event @@ -20,7 +22,6 @@ if TYPE_CHECKING: from .._named_pipe import ResourceRequestHandler -from .._osname import OSName import win32pipe import win32file @@ -83,10 +84,10 @@ def __init__(self, pipe_name: str, shutdown_event: Event): # pragma: no cover shutdown_event (Event): An Event used for signaling server shutdown. """ self._server_type_name = self.__class__.__name__ - if not OSName.is_windows(): + if os.name != "nt": # pragma: skip-coverage-windows raise OSError( f"{self._server_type_name} can be only used on Windows Operating Systems. " - f"Current Operating System is {OSName._get_os_name()}" + f"Current Operating System is {platform.platform()}" ) self._named_pipe_instances: List[HANDLE] = [] self._pipe_name = pipe_name diff --git a/src/openjd/adaptor_runtime/_osname.py b/src/openjd/adaptor_runtime/_osname.py index cbe4524e..30287f85 100644 --- a/src/openjd/adaptor_runtime/_osname.py +++ b/src/openjd/adaptor_runtime/_osname.py @@ -2,11 +2,19 @@ import platform from typing import Optional +import warnings class OSName(str): """ - OS Name Utility Class. + OS Name Utility Class. (DEPRECATED) + + This class is deprecated, all code should use Python idioms: + 1. For Windows: os.name == "nt" + 2. For POSIX: os.name != "nt" + 3. For MacOS: sys.platform == "darwin" + 4. For a human-readable OS description: platform.platform() + Calling the constructor without any parameters will create an OSName object initialized with the OS python is running on (one of Linux, macOS, Windows). @@ -28,6 +36,7 @@ class OSName(str): def __init__(self, *args, **kw): super().__init__() + warnings.warn("The OSName class is deprecated.", DeprecationWarning) def __new__(cls, *args, **kw): if len(args) > 0: diff --git a/src/openjd/adaptor_runtime/_utils/_secure_open.py b/src/openjd/adaptor_runtime/_utils/_secure_open.py index 47269de9..6ddd6107 100644 --- a/src/openjd/adaptor_runtime/_utils/_secure_open.py +++ b/src/openjd/adaptor_runtime/_utils/_secure_open.py @@ -6,15 +6,12 @@ import os from contextlib import contextmanager from typing import IO, TYPE_CHECKING, Generator -from .._osname import OSName -if OSName.is_windows(): +if os.name == "nt": # pragma: skip-coverage-posix import ntsecuritycon as con import win32security import win32con -from openjd.adaptor_runtime._osname import OSName - if TYPE_CHECKING: from _typeshed import StrOrBytesPath @@ -52,13 +49,13 @@ def secure_open( "flags": _get_flags_from_mode_str(open_mode), } # not O_RDONLY - if flags != 0 and OSName.is_posix(): # pragma: is-windows + if flags != 0 and os.name != "nt": # pragma: skip-coverage-windows os_open_kwargs["mode"] = stat.S_IWUSR | stat.S_IRUSR | mask fd = os.open(**os_open_kwargs) # type: ignore # not O_RDONLY. Use ACL to set the permission for the file owner. - if flags != 0 and OSName.is_windows(): # pragma: is-posix + if flags != 0 and os.name == "nt": # pragma: skip-coverage-posix if mask != 0: raise NotImplementedError("Additional masks are not supported in Windows.") set_file_permissions_in_windows(path) diff --git a/src/openjd/adaptor_runtime/adaptors/_path_mapping.py b/src/openjd/adaptor_runtime/adaptors/_path_mapping.py index b5a79a5f..c1e06b86 100644 --- a/src/openjd/adaptor_runtime/adaptors/_path_mapping.py +++ b/src/openjd/adaptor_runtime/adaptors/_path_mapping.py @@ -2,10 +2,9 @@ from __future__ import annotations +import os from pathlib import PurePath, PurePosixPath, PureWindowsPath -from .._osname import OSName - __all__ = [ "PathMappingRule", ] @@ -15,6 +14,8 @@ class PathMappingRule: """A PathMappingRule represents how to transform a valid rooted path to another valid rooted path within or across different platforms. + See https://github.com/OpenJobDescription/openjd-specifications/wiki/How-Jobs-Are-Run#path-mapping + This is useful for consolidating environments that refer to physical storage with different paths. Consider the following example: @@ -47,8 +48,8 @@ def __init__( *, source_path_format: str, source_path: str, + destination_os: str = "WINDOWS" if os.name == "nt" else "POSIX", destination_path: str, - destination_os: str = OSName(), ): for label, value in ( ("source_path_format", source_path_format), @@ -60,20 +61,26 @@ def __init__( self.source_path: str = source_path self.destination_path: str = destination_path - self._source_path_format: str = OSName( - source_path_format - ) # Raises ValueError if not valid OS - self._is_windows_source: bool = OSName.is_windows(self._source_path_format) - - self._destination_os: str = OSName(destination_os) # Raises ValueError if not valid OS - self._is_windows_destination: bool = OSName.is_windows(self._destination_os) - - if self._is_windows_source: + source_path_format = source_path_format.upper() + if source_path_format not in ("WINDOWS", "POSIX"): + raise ValueError( + f"The source path format '{source_path_format}' must be 'WINDOWS' or 'POSIX'." + ) + self._source_path_format: str = source_path_format + + destination_os = destination_os.upper() + if destination_os not in ("WINDOWS", "POSIX"): + raise ValueError( + f"The destination path format '{destination_os}' must be 'WINDOWS' or 'POSIX'." + ) + self._destination_os: str = destination_os + + if self._source_path_format == "WINDOWS": self._pure_source_path = PureWindowsPath(self.source_path) else: self._pure_source_path = PurePosixPath(self.source_path) - if self._is_windows_destination: + if self._destination_os == "WINDOWS": self._pure_destination_path = PureWindowsPath(self.destination_path) else: self._pure_destination_path = PurePosixPath(self.destination_path) @@ -82,8 +89,6 @@ def __eq__(self, other): return ( self.source_path == other.source_path and self.destination_path == other.destination_path - and self._is_windows_source == other._is_windows_source - and self._is_windows_destination == other._is_windows_destination ) @staticmethod @@ -124,7 +129,7 @@ def _is_match(self, *, pure_path: PurePath) -> bool: def _get_pure_path(self, path: str) -> PurePath: """Assumes that the path received matches the source os of the rule""" - if self._is_windows_source: + if self._source_path_format == "WINDOWS": return PureWindowsPath(path) else: return PurePosixPath(path) @@ -135,7 +140,7 @@ def _swap_source_for_dest(self, pure_path: PurePath) -> PurePath: new_parts = ( self._pure_destination_path.parts + pure_path.parts[len(self._pure_source_path.parts) :] ) - if self._is_windows_destination: + if self._destination_os == "WINDOWS": return PureWindowsPath(*new_parts) else: return PurePosixPath(*new_parts) diff --git a/src/openjd/adaptor_runtime/adaptors/configuration/_configuration_manager.py b/src/openjd/adaptor_runtime/adaptors/configuration/_configuration_manager.py index 2eb5e5d8..eea1c3b0 100644 --- a/src/openjd/adaptor_runtime/adaptors/configuration/_configuration_manager.py +++ b/src/openjd/adaptor_runtime/adaptors/configuration/_configuration_manager.py @@ -9,7 +9,6 @@ from typing import Generic, List, Type, TypeVar from ..._utils import secure_open -from ..._osname import OSName from ._configuration import AdaptorConfiguration, Configuration __all__ = [ @@ -55,7 +54,7 @@ def create_adaptor_configuration_manager( elif isinstance(schema_path, list): schema_paths.extend(schema_path) - system_config_path_prefix = "/etc" if OSName.is_posix() else os.environ["PROGRAMDATA"] + system_config_path_prefix = os.environ["PROGRAMDATA"] if os.name == "nt" else "/etc" system_config_path = os.path.join( system_config_path_prefix, "openjd", diff --git a/src/openjd/adaptor_runtime/application_ipc/__init__.py b/src/openjd/adaptor_runtime/application_ipc/__init__.py index 33414291..c5ee1653 100644 --- a/src/openjd/adaptor_runtime/application_ipc/__init__.py +++ b/src/openjd/adaptor_runtime/application_ipc/__init__.py @@ -1,11 +1,11 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +import os from ._actions_queue import ActionsQueue -from .._osname import OSName -if OSName.is_posix(): # pragma: is-windows - from ._adaptor_server import AdaptorServer -else: # pragma: is-posix +if os.name == "nt": # pragma: skip-coverage-posix from ._win_adaptor_server import WinAdaptorServer as AdaptorServer # type: ignore +else: # pragma: skip-coverage-windows + from ._adaptor_server import AdaptorServer # type: ignore __all__ = ["ActionsQueue", "AdaptorServer"] diff --git a/src/openjd/adaptor_runtime/application_ipc/_adaptor_server.py b/src/openjd/adaptor_runtime/application_ipc/_adaptor_server.py index d914ad98..76c498f2 100644 --- a/src/openjd/adaptor_runtime/application_ipc/_adaptor_server.py +++ b/src/openjd/adaptor_runtime/application_ipc/_adaptor_server.py @@ -33,7 +33,7 @@ def __init__( actions_queue: ActionsQueue, adaptor: BaseAdaptor, ) -> None: # pragma: no cover - socket_path = SocketPaths.for_os().get_process_socket_path( + socket_path = SocketPaths().get_process_socket_path( ".openjd_adaptor_server", create_dir=True, ) @@ -57,6 +57,6 @@ def shutdown(self) -> None: # pragma: no cover super().shutdown() try: - os.remove(self.socket_path) + os.remove(self.server_path) except FileNotFoundError: pass diff --git a/src/openjd/adaptor_runtime/process/_logging_subprocess.py b/src/openjd/adaptor_runtime/process/_logging_subprocess.py index 5cfd2294..2d90e95b 100644 --- a/src/openjd/adaptor_runtime/process/_logging_subprocess.py +++ b/src/openjd/adaptor_runtime/process/_logging_subprocess.py @@ -4,13 +4,13 @@ from __future__ import annotations import logging +import os import signal import subprocess import uuid from types import TracebackType from typing import Any, Sequence, TypeVar, Dict -from .._osname import OSName from ..app_handlers import RegexHandler from ._logging import _STDERR_LEVEL, _STDOUT_LEVEL from ._stream_logger import StreamLogger @@ -60,7 +60,7 @@ def __init__( encoding=encoding, cwd=startup_directory, ) - if OSName.is_windows(): # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix # In Windows, this is required for signal. SIGBREAK will be sent to the entire process group. # Without this one, current process will also get the SIGBREAK and may react incorrectly. popen_params.update(creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] @@ -178,12 +178,12 @@ def terminate(self, grace_time_s: float = 60) -> None: self._process.wait() else: signal_type: signal.Signals - if OSName.is_windows(): # pragma: is-posix + if os.name == "nt": # pragma: skip-coverage-posix # We use `CREATE_NEW_PROCESS_GROUP` to create the process, # so pid here is also the process group id and SIGBREAK can be only sent to the process group. # Any processes in the process group will receive the SIGBREAK signal. signal_type = signal.CTRL_BREAK_EVENT # type: ignore[attr-defined] - else: # pragma: is-windows + else: # pragma: skip-coverage-windows signal_type = signal.SIGTERM self._logger.info( @@ -198,7 +198,7 @@ def terminate(self, grace_time_s: float = 60) -> None: except subprocess.TimeoutExpired: self._logger.info( f"Process (pid={self._process.pid}) did not complete in the allotted time " - f"after the {'SIGTERM' if OSName.is_posix() else 'SIGBREAK'} signal, " + f"after the {'SIGBREAK' if os.name == 'nt' else 'SIGTERM'} signal, " f"now sending the SIGKILL signal." ) self._process.kill() # SIGKILL, on Windows, this is an alias for terminate diff --git a/src/openjd/adaptor_runtime_client/posix_client_interface.py b/src/openjd/adaptor_runtime_client/posix_client_interface.py index 91a51434..8bb3bc3d 100644 --- a/src/openjd/adaptor_runtime_client/posix_client_interface.py +++ b/src/openjd/adaptor_runtime_client/posix_client_interface.py @@ -74,7 +74,7 @@ def _send_request( headers = { "Content-type": "application/json", } - connection = _UnixHTTPConnection(self.socket_path, timeout=_REQUEST_TIMEOUT) + connection = _UnixHTTPConnection(self.server_path, timeout=_REQUEST_TIMEOUT) if query_string_params: request_path += "?" + _urlencode(query_string_params) connection.request(method, request_path, headers=headers) diff --git a/test/openjd/adaptor_runtime/conftest.py b/test/openjd/adaptor_runtime/conftest.py index 642d94ad..ad9e35d6 100644 --- a/test/openjd/adaptor_runtime/conftest.py +++ b/test/openjd/adaptor_runtime/conftest.py @@ -1,16 +1,17 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. import platform +import os import random import string +import sys from typing import Generator from unittest.mock import MagicMock, patch import pytest -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime._http import sockets -if OSName.is_windows(): +if os.name == "nt": import win32net import win32netcon @@ -97,7 +98,7 @@ def delete_user() -> None: delete_user() -@pytest.fixture(scope="session", autouse=OSName().is_macos()) +@pytest.fixture(scope="session", autouse=(sys.platform == "darwin")) def mock_sockets_py_tempfile_gettempdir_to_slash_tmp() -> Generator[MagicMock, None, None]: """ Mock that is automatically used on Mac to override the tempfile.gettempdir() usages in sockets.py diff --git a/test/openjd/adaptor_runtime/integ/CommandAdaptorExample/adaptor.py b/test/openjd/adaptor_runtime/integ/CommandAdaptorExample/adaptor.py index 156204bd..77d9253d 100644 --- a/test/openjd/adaptor_runtime/integ/CommandAdaptorExample/adaptor.py +++ b/test/openjd/adaptor_runtime/integ/CommandAdaptorExample/adaptor.py @@ -4,7 +4,6 @@ from typing import List from logging import getLogger -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.adaptors import CommandAdaptor, SemanticVersion from openjd.adaptor_runtime.process import ManagedProcess @@ -22,7 +21,7 @@ def get_executable(self) -> str: ManagedProcess. In this example, it returns 'powershell.exe' for Windows to run PowerShell scripts, and '/bin/echo' for other operating systems. """ - if OSName.is_windows(): + if os.name == "nt": # In Windows, we cannot directly run the powershell script. # Need to use PowerShell.exe to run the command. return "powershell.exe" diff --git a/test/openjd/adaptor_runtime/integ/_named_pipe/test_named_pipe_helper.py b/test/openjd/adaptor_runtime/integ/_named_pipe/test_named_pipe_helper.py index 84dcba9f..39cdf280 100644 --- a/test/openjd/adaptor_runtime/integ/_named_pipe/test_named_pipe_helper.py +++ b/test/openjd/adaptor_runtime/integ/_named_pipe/test_named_pipe_helper.py @@ -1,13 +1,12 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. import time -from openjd.adaptor_runtime._osname import OSName import json import os import pytest import threading -if OSName.is_windows(): +if os.name == "nt": import pywintypes import win32file import win32pipe @@ -52,7 +51,7 @@ def start_pipe_server(): server_thread.join() -@pytest.mark.skipif(not OSName.is_windows(), reason="NamedPipe is only implemented in Windows.") +@pytest.mark.skipif(os.name != "nt", reason="NamedPipe is only implemented in Windows.") class TestNamedPipeHelper: def test_named_pipe_communication(self, start_pipe_server): """ diff --git a/test/openjd/adaptor_runtime/integ/_utils/test_secure_open.py b/test/openjd/adaptor_runtime/integ/_utils/test_secure_open.py index 8f28840a..918c49c4 100644 --- a/test/openjd/adaptor_runtime/integ/_utils/test_secure_open.py +++ b/test/openjd/adaptor_runtime/integ/_utils/test_secure_open.py @@ -1,6 +1,5 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -from openjd.adaptor_runtime._osname import OSName import pytest import os import tempfile @@ -9,7 +8,7 @@ from openjd.adaptor_runtime._utils import secure_open -if OSName.is_windows(): +if os.name == "nt": import win32security @@ -40,7 +39,7 @@ def test_secure_open_write_and_read(self, create_file): result = test_file.read() assert result == file_content - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") + @pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") @pytest.mark.skipif( os.getenv("GITHUB_ACTIONS") != "true", reason="Skip this test in local env to avoid user creation with elevated privilege.", diff --git a/test/openjd/adaptor_runtime/integ/adaptors/test_integration_path_mapping.py b/test/openjd/adaptor_runtime/integ/adaptors/test_integration_path_mapping.py index 9a349070..8de9fe52 100644 --- a/test/openjd/adaptor_runtime/integ/adaptors/test_integration_path_mapping.py +++ b/test/openjd/adaptor_runtime/integ/adaptors/test_integration_path_mapping.py @@ -39,9 +39,9 @@ def test_one_rule(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ] @@ -64,15 +64,15 @@ def test_many_rules(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage0", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage0", }, { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", }, ] @@ -89,15 +89,15 @@ def test_many_rules(self) -> None: def test_get_order_is_preserved(self) -> None: # GIVEN rule1 = { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } rule2 = { "source_path_format": "windows", "source_path": "Z:\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\should\\not\\reach\\this", } path_mapping_rules = [rule1, rule2] @@ -125,7 +125,7 @@ def test_rule_list_is_read_only(self) -> None: adaptor = FakeCommandAdaptor(expected) rules = adaptor.path_mapping_rules new_rule = PathMappingRule( - source_path_format="linux", + source_path_format="POSIX", source_path="/mnt/shared/asset_storage1", destination_os="windows", destination_path="Z:\\asset_storage1", @@ -159,9 +159,9 @@ def test_linux_to_windows(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ] @@ -181,7 +181,7 @@ def test_windows_to_linux(self) -> None: { "source_path_format": "windows", "source_path": "Z:\\asset_storage1", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/asset_storage1", } ] @@ -199,9 +199,9 @@ def test_linux_to_linux(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/my_custom_path/asset_storage1", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/asset_storage1", } ] @@ -222,7 +222,7 @@ def test_windows_to_windows(self) -> None: { "source_path_format": "windows", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ] @@ -242,7 +242,7 @@ def test_windows_capitalization_agnostic(self) -> None: { "source_path_format": "windows", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ] @@ -262,7 +262,7 @@ def test_windows_directory_separator_agnostic(self) -> None: { "source_path_format": "windows", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ] @@ -280,15 +280,15 @@ def test_multiple_rules(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage0", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage0", }, { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", }, ] @@ -306,15 +306,15 @@ def test_only_first_applied(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", }, { "source_path_format": "windows", "source_path": "Z:\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\should\\not\\reach\\this", }, ] @@ -332,15 +332,15 @@ def test_apply_order_is_preserved(self) -> None: # GIVEN path_mapping_rules = [ { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", }, { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\should\\not\\reach\\this", }, ] diff --git a/test/openjd/adaptor_runtime/integ/application_ipc/test_integration_adaptor_ipc.py b/test/openjd/adaptor_runtime/integ/application_ipc/test_integration_adaptor_ipc.py index f021dea5..8e77ca8a 100644 --- a/test/openjd/adaptor_runtime/integ/application_ipc/test_integration_adaptor_ipc.py +++ b/test/openjd/adaptor_runtime/integ/application_ipc/test_integration_adaptor_ipc.py @@ -1,5 +1,6 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +import os import threading as _threading import time from time import sleep as _sleep @@ -12,10 +13,9 @@ from openjd.adaptor_runtime.adaptors import Adaptor, SemanticVersion from openjd.adaptor_runtime.application_ipc import ActionsQueue as _ActionsQueue from .fake_app_client import FakeAppClient as _FakeAppClient -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.application_ipc import AdaptorServer as _AdaptorServer -if OSName.is_windows(): +if os.name == "nt": from openjd.adaptor_runtime_client.named_pipe.named_pipe_helper import NamedPipeHelper @@ -36,13 +36,13 @@ def integration_data_interface_version(self) -> SemanticVersion: { "source_path_format": "windows", "source_path": "Z:\\asset_storage1", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/asset_storage1", }, { "source_path_format": "windows", "source_path": "🌚\\🌒\\🌓\\🌔\\🌝\\🌖\\🌗\\🌘\\🌚", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "🌝/🌖/🌗/🌘/🌚/🌒/🌓/🌔/🌝", }, ] @@ -196,7 +196,7 @@ def enqueue_close_action(): # Verifying the test was successful. mocked_close.assert_called_once() - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows named pipe test") + @pytest.mark.skipif(os.name != "nt", reason="Windows named pipe test") def test_adaptor_ipc_with_incorrect_request_path(self, adaptor: Adaptor): # GIVEN # Create a server and pass the actions queue. @@ -216,7 +216,7 @@ def test_adaptor_ipc_with_incorrect_request_path(self, adaptor: Adaptor): assert "Incorrect request path none." == result["body"] assert 404 == result["status"] - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows named pipe test") + @pytest.mark.skipif(os.name != "nt", reason="Windows named pipe test") def test_adaptor_ipc_with_incorrect_request_method(self, adaptor: Adaptor): # GIVEN # Create a server and pass the actions queue. diff --git a/test/openjd/adaptor_runtime/integ/background/test_background_mode.py b/test/openjd/adaptor_runtime/integ/background/test_background_mode.py index 1fdc16ca..25585d02 100644 --- a/test/openjd/adaptor_runtime/integ/background/test_background_mode.py +++ b/test/openjd/adaptor_runtime/integ/background/test_background_mode.py @@ -25,7 +25,6 @@ ConnectionSettingsLoadingError, ConnectionSettingsFileLoader, ) -from openjd.adaptor_runtime._osname import OSName mod_path = (Path(__file__).parent.parent).resolve() sys.path.append(str(mod_path)) @@ -62,7 +61,7 @@ def mock_runtime_logger_level(self, tmpdir: pathlib.Path): def connection_file_path(self, tmp_path: pathlib.Path) -> pathlib.Path: connection_dir = os.path.join(tmp_path.absolute(), "connection_dir") os.mkdir(connection_dir) - if OSName.is_windows(): + if os.name == "nt": # In Windows, to prevent false positives in tests, it's crucial to remove the "Delete subfolders and files" # permission from the parent folder. This step ensures that files cannot be deleted without explicit delete # permissions, addressing an edge case where the same user owns both the parent folder and the file, @@ -101,7 +100,7 @@ def initialized_setup( # We don't need to call the `remove` for the NamedPipe server. # NamedPipe servers are managed by Named Pipe File System it is not a regular file. # Once all handles are closed, the system automatically cleans up the named pipe. - if OSName.is_posix(): + if os.name != "nt": # pragma: skip-coverage-windows try: conn_settings = ConnectionSettingsFileLoader(connection_file_path).load() except ConnectionSettingsLoadingError as e: @@ -127,7 +126,7 @@ def test_init( connection_settings = ConnectionSettingsFileLoader(connection_file_path).load() - if OSName.is_windows(): + if os.name == "nt": import pywintypes import win32file @@ -192,7 +191,7 @@ def test_start( # THEN assert "on_start" in caplog.text - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows named pipe test") + @pytest.mark.skipif(os.name != "nt", reason="Windows named pipe test") def test_incorrect_request_path_in_windows( self, initialized_setup: tuple[FrontendRunner, psutil.Process], @@ -208,7 +207,7 @@ def test_incorrect_request_path_in_windows( ): frontend._send_request("GET", "None") - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows named pipe test") + @pytest.mark.skipif(os.name != "nt", reason="Windows named pipe test") def test_incorrect_request_method_in_windows( self, initialized_setup: tuple[FrontendRunner, psutil.Process], @@ -274,7 +273,7 @@ def test_heartbeat_acks( new_response = frontend._heartbeat(response.output.id) # In Windows, we need to shut down the namedpipe client, # or the connection of the NamedPipe server remains open - if OSName.is_windows(): + if os.name == "nt": frontend.shutdown() # THEN assert f"Received ACK for chunk: {response.output.id}" in new_response.output.output diff --git a/test/openjd/adaptor_runtime/integ/process/scripts/signals_test.py b/test/openjd/adaptor_runtime/integ/process/scripts/signals_test.py index 118f644c..0472c808 100755 --- a/test/openjd/adaptor_runtime/integ/process/scripts/signals_test.py +++ b/test/openjd/adaptor_runtime/integ/process/scripts/signals_test.py @@ -1,11 +1,11 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +import os import signal import sys import time from datetime import datetime import logging -from openjd.adaptor_runtime._osname import OSName logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @@ -24,7 +24,7 @@ def func_trap(signum, frame): def set_signal_handlers(): - signals = [signal.SIGINT, signal.SIGTERM if OSName.is_posix() else signal.SIGBREAK] # type: ignore[attr-defined] + signals = [signal.SIGINT, signal.SIGBREAK if os.name == "nt" else signal.SIGTERM] # type: ignore[attr-defined] for sig in signals: signal.signal(sig, func_trap) diff --git a/test/openjd/adaptor_runtime/integ/process/test_integration_logging_subprocess.py b/test/openjd/adaptor_runtime/integ/process/test_integration_logging_subprocess.py index c524104a..e8ca94af 100644 --- a/test/openjd/adaptor_runtime/integ/process/test_integration_logging_subprocess.py +++ b/test/openjd/adaptor_runtime/integ/process/test_integration_logging_subprocess.py @@ -12,7 +12,6 @@ import pytest -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.app_handlers import RegexCallback, RegexHandler from openjd.adaptor_runtime.process import LoggingSubprocess from openjd.adaptor_runtime.process._logging_subprocess import _STDERR_LEVEL, _STDOUT_LEVEL @@ -26,7 +25,7 @@ class TestIntegrationLoggingSubprocess(object): pytest.param( 2, [ - f"Sending the {'SIGTERM' if OSName.is_posix() else 'CTRL_BREAK_EVENT'} signal to pid=", + f"Sending the {'CTRL_BREAK_EVENT' if os.name == 'nt' else 'SIGTERM'} signal to pid=", "now sending the SIGKILL signal.", ], id="StopProcessWhenSIGTERMFails", @@ -73,11 +72,11 @@ def test_terminate_process(self, caplog): p.terminate(5) # Sometimes, when this is 1 second the process doesn't terminate in time. assert ( - f"Sending the {'SIGTERM' if OSName.is_posix() else 'CTRL_BREAK_EVENT'} signal to pid=" + f"Sending the {'CTRL_BREAK_EVENT' if os.name == 'nt' else 'SIGTERM'} signal to pid=" in caplog.text ) # Asserting the SIGTERM signal was sent to the subprocess assert ( - f"Trapped: {'SIGTERM' if OSName.is_posix() else 'SIGBREAK'}" in caplog.text + f"Trapped: {'SIGBREAK' if os.name == 'nt' else 'SIGTERM'}" in caplog.text ) # Asserting the SIGTERM was received by the subprocess. assert ( "now sending the SIGKILL signal." not in caplog.text @@ -91,7 +90,7 @@ def test_terminate_process(self, caplog): @pytest.mark.parametrize("startup_dir", startup_dir_params) def test_startup_directory(self, startup_dir: str | None, caplog): caplog.set_level(logging.INFO) - if OSName.is_windows(): + if os.name == "nt": args = ["powershell.exe", "pwd"] else: args = ["pwd"] @@ -109,7 +108,7 @@ def test_startup_directory(self, startup_dir: str | None, caplog): if startup_dir is not None: assert startup_dir in caplog.text - @pytest.mark.skipif(not OSName.is_posix(), reason="Only run this test in Linux.") + @pytest.mark.skipif(os.name == "nt", reason="Only run this test in Linux.") def test_startup_directory_empty_posix(self): """When calling LoggingSubprocess with an empty cwd, FileNotFoundError will be raised.""" args = ["pwd"] @@ -117,7 +116,7 @@ def test_startup_directory_empty_posix(self): LoggingSubprocess(args=args, startup_directory="") assert "[Errno 2] No such file or directory: ''" in str(excinfo.value) - @pytest.mark.skipif(not OSName.is_windows(), reason="Only run this test in Windows.") + @pytest.mark.skipif(os.name != "nt", reason="Only run this test in Windows.") def test_startup_directory_empty_windows(self): """When calling LoggingSubprocess with an empty cwd, OSError will be raised.""" args = ["powershell.exe", "pwd"] diff --git a/test/openjd/adaptor_runtime/integ/process/test_integration_managed_process.py b/test/openjd/adaptor_runtime/integ/process/test_integration_managed_process.py index 0020182f..2293083d 100644 --- a/test/openjd/adaptor_runtime/integ/process/test_integration_managed_process.py +++ b/test/openjd/adaptor_runtime/integ/process/test_integration_managed_process.py @@ -12,7 +12,6 @@ import pytest -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.app_handlers import RegexCallback, RegexHandler from openjd.adaptor_runtime.process import ManagedProcess @@ -25,13 +24,13 @@ def test_run(self, caplog): class FakeManagedProcess(ManagedProcess): def get_executable(self) -> str: - if OSName.is_windows(): + if os.name == "nt": return "powershell.exe" else: return "echo" def get_arguments(self) -> List[str]: - if OSName.is_windows(): + if os.name == "nt": return ["echo", "Hello World!"] else: return ["Hello World!"] diff --git a/test/openjd/adaptor_runtime/integ/test_integration_entrypoint.py b/test/openjd/adaptor_runtime/integ/test_integration_entrypoint.py index 22b0d5e3..e4e9f80b 100644 --- a/test/openjd/adaptor_runtime/integ/test_integration_entrypoint.py +++ b/test/openjd/adaptor_runtime/integ/test_integration_entrypoint.py @@ -16,7 +16,6 @@ import openjd.adaptor_runtime._entrypoint as runtime_entrypoint from openjd.adaptor_runtime import EntryPoint -from openjd.adaptor_runtime._osname import OSName mod_path = Path(__file__).parent.resolve() sys.path.append(str(mod_path)) @@ -53,9 +52,7 @@ def test_runs_command_adaptor( } ), "--run-data", - json.dumps( - {"args": ["echo", "hello world"] if OSName.is_windows() else ["hello world"]} - ), + json.dumps({"args": ["hello world"]}), ] entrypoint = EntryPoint(CommandAdaptorExample) @@ -131,9 +128,7 @@ def test_run(self, caplog: pytest.LogCaptureFixture, tmp_path: Path): "--connection-file", str(connection_file), "--run-data", - json.dumps( - {"args": ["echo", "hello world"] if OSName.is_windows() else ["hello world"]} - ), + json.dumps({"args": ["hello world"]}), ] entrypoint = EntryPoint(CommandAdaptorExample) @@ -262,9 +257,7 @@ def get_run_argv(*, connection_file: Path | None = None) -> list[str]: "run", *(["--connection-file", str(connection_file)] if connection_file else []), "--run-data", - json.dumps( - {"args": ["echo", "hello world"] if OSName.is_windows() else ["hello world"]} - ), + json.dumps({"args": ["hello world"]}), ] @staticmethod diff --git a/test/openjd/adaptor_runtime/unit/adaptors/configuration/test_configuration_manager.py b/test/openjd/adaptor_runtime/unit/adaptors/configuration/test_configuration_manager.py index 8146c40c..1b939073 100644 --- a/test/openjd/adaptor_runtime/unit/adaptors/configuration/test_configuration_manager.py +++ b/test/openjd/adaptor_runtime/unit/adaptors/configuration/test_configuration_manager.py @@ -10,7 +10,6 @@ import pytest -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.adaptors.configuration import ( AdaptorConfiguration as _AdaptorConfiguration, Configuration as _Configuration, @@ -128,7 +127,7 @@ def test_create( assert f"Could not write empty configuration to {path}: " in caplog.text -@pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") +@pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") class TestCreateAdaptorConfigurationManagerPosix: def test_creates_config_manager(self): """ @@ -161,7 +160,7 @@ def test_creates_config_manager(self): ) -@pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") +@pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") class TestCreateAdaptorConfigurationManagerWindows: def test_creates_config_manager(self): """ @@ -248,7 +247,7 @@ def test_accepts_multiple_schemas(self): assert result._schema_path[1:] == schema_paths -@pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") +@pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") class TestConfigurationManagerPosix: """ Posix-specific tests for the base ConfigurationManager class @@ -269,7 +268,7 @@ def test_gets_linux_path(self, mock_system: MagicMock): assert result == expected -@pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") +@pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") class TestConfigurationManagerWindows: """ Windows-specific tests for the base ConfigurationManager class diff --git a/test/openjd/adaptor_runtime/unit/adaptors/test_base_adaptor.py b/test/openjd/adaptor_runtime/unit/adaptors/test_base_adaptor.py index f8562cf8..523223a1 100644 --- a/test/openjd/adaptor_runtime/unit/adaptors/test_base_adaptor.py +++ b/test/openjd/adaptor_runtime/unit/adaptors/test_base_adaptor.py @@ -9,7 +9,6 @@ from pytest import param import openjd.adaptor_runtime.adaptors._base_adaptor as base_adaptor -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.adaptors._base_adaptor import ( _ENV_CONFIG_PATH_TEMPLATE, _ENV_CONFIG_SCHEMA_PATH_PREFIX, @@ -169,14 +168,14 @@ def test_loads_config_from_environment_variables( mock_package.return_value = package adaptor = FakeAdaptor({}) adaptor_name = "FakeAdaptor" - if OSName.is_posix(): - additional_config_path = f"/path/to/additional/config/{adaptor_name}.json" - config_path = f"/path/to/config/{adaptor_name}.json" - schema_path = f"/path/to/schema/{adaptor_name}.schema.json" - else: + if os.name == "nt": additional_config_path = rf"C:\path\to\additional\config\{adaptor_name}.json" config_path = rf"C:\path\to\config\{adaptor_name}.json" schema_path = rf"C:\path\to\schema\{adaptor_name}.schema.json" + else: + additional_config_path = f"/path/to/additional/config/{adaptor_name}.json" + config_path = f"/path/to/config/{adaptor_name}.json" + schema_path = f"/path/to/schema/{adaptor_name}.schema.json" mock_file.return_value = config_path diff --git a/test/openjd/adaptor_runtime/unit/adaptors/test_path_mapping.py b/test/openjd/adaptor_runtime/unit/adaptors/test_path_mapping.py index 879d981b..29595e91 100644 --- a/test/openjd/adaptor_runtime/unit/adaptors/test_path_mapping.py +++ b/test/openjd/adaptor_runtime/unit/adaptors/test_path_mapping.py @@ -15,17 +15,17 @@ pytest.param({"source_path_format": "", "source_path": None, "destination_path": ""}), pytest.param({"source_path_format": "", "source_path": "C:/", "destination_path": "/mnt/"}), pytest.param( - {"source_path_format": "windows", "source_path": "", "destination_path": "/mnt/"} + {"source_path_format": "WINDOWS", "source_path": "", "destination_path": "/mnt/"} ), pytest.param( - {"source_path_format": "windows", "source_path": "C:/", "destination_path": ""} + {"source_path_format": "WINDOWS", "source_path": "C:/", "destination_path": ""} ), pytest.param( {"source_path_format": "nonvalid", "source_path": "C:/", "destination_path": "/mnt/"} ), pytest.param( { - "source_path_format": "windows", + "source_path_format": "WINDOWS", "destination_os": "nonvalid", "source_path": "C:/", "destination_path": "/mnt/", @@ -61,8 +61,8 @@ def test_no_args(rule): def test_good_args(): # GIVEN rule = { - "source_path_format": "windows", - "destination_os": "windows", + "source_path_format": "WINDOWS", + "destination_os": "WINDOWS", "source_path": "Y:/movie1", "destination_path": "Z:/movie2", } @@ -86,7 +86,7 @@ def test_good_args(): def test_path_mapping_linux_is_match(path): # GIVEN rule = PathMappingRule( - source_path_format="linux", source_path="/usr", destination_path="/mnt/shared" + source_path_format="POSIX", source_path="/usr", destination_path="/mnt/shared" ) pure_path = PurePosixPath(path) @@ -112,7 +112,7 @@ def test_path_mapping_linux_is_match(path): def test_path_mapping_linux_is_not_match(path): # GIVEN rule = PathMappingRule( - source_path_format="linux", source_path="/usr/Movie1", destination_path="/mnt/shared/Movie1" + source_path_format="POSIX", source_path="/usr/Movie1", destination_path="/mnt/shared/Movie1" ) pure_path = PurePosixPath(path) @@ -138,7 +138,7 @@ def test_path_mapping_linux_is_not_match(path): def test_path_mapping_windows_is_match(path): # GIVEN rule = PathMappingRule( - source_path_format="windows", source_path="Z:\\Movie1", destination_path="/mnt/shared" + source_path_format="WINDOWS", source_path="Z:\\Movie1", destination_path="/mnt/shared" ) pure_path = PureWindowsPath(path) @@ -160,7 +160,7 @@ def test_path_mapping_windows_is_match(path): def test_path_mapping_windows_is_not_match(path): # GIVEN rule = PathMappingRule( - source_path_format="windows", source_path="Z:\\Movie1", destination_path="/mnt/shared" + source_path_format="WINDOWS", source_path="Z:\\Movie1", destination_path="/mnt/shared" ) pure_path = PureWindowsPath(path) @@ -176,9 +176,9 @@ def test_no_change(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage2", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/movie2", } ) @@ -195,9 +195,9 @@ def test_linux_to_windows(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ) @@ -214,9 +214,9 @@ def test_windows_to_linux(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "windows", + "source_path_format": "WINDOWS", "source_path": "Z:\\asset_storage1", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/asset_storage1", } ) @@ -233,9 +233,9 @@ def test_linux_to_linux(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/mnt/shared/my_custom_path/asset_storage1", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/mnt/shared/asset_storage1", } ) @@ -253,9 +253,9 @@ def test_windows_to_windows(self): # GIVEN rule = rule = PathMappingRule.from_dict( rule={ - "source_path_format": "windows", + "source_path_format": "WINDOWS", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ) @@ -272,9 +272,9 @@ def test_windows_capitalization_agnostic(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "windows", + "source_path_format": "WINDOWS", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ) @@ -291,9 +291,9 @@ def test_windows_directory_separator_agnostic(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "windows", + "source_path_format": "WINDOWS", "source_path": "Z:\\my_custom_asset_path\\asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ) @@ -310,9 +310,9 @@ def test_windows_directory_separator_agnostic_inverted(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "windows", + "source_path_format": "WINDOWS", "source_path": "Z:/my_custom_asset_path/asset_storage1", - "destination_os": "windows", + "destination_os": "WINDOWS", "destination_path": "Z:\\asset_storage1", } ) @@ -329,9 +329,9 @@ def test_starts_with_partial_match(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "a/b", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/c", } ) @@ -348,9 +348,9 @@ def test_partial_match(self): # GIVEN rule = PathMappingRule.from_dict( rule={ - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/bar/baz", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/bla", } ) @@ -366,9 +366,9 @@ def test_partial_match(self): def test_to_dict(self): # GIVEN rule_dict = { - "source_path_format": "linux", + "source_path_format": "POSIX", "source_path": "/bar/baz", - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": "/bla", } rule = PathMappingRule.from_dict(rule=rule_dict) diff --git a/test/openjd/adaptor_runtime/unit/application_ipc/test_adaptor_http_request_handler.py b/test/openjd/adaptor_runtime/unit/application_ipc/test_adaptor_http_request_handler.py index d1e80252..30bedd1f 100644 --- a/test/openjd/adaptor_runtime/unit/application_ipc/test_adaptor_http_request_handler.py +++ b/test/openjd/adaptor_runtime/unit/application_ipc/test_adaptor_http_request_handler.py @@ -73,7 +73,7 @@ def test_get_returns_mapped_path(self): { "source_path_format": "windows", "source_path": SOURCE_PATH, - "destination_os": "linux", + "destination_os": "POSIX", "destination_path": DEST_PATH, } ] @@ -104,9 +104,9 @@ def test_get_returns_rules(self): SOURCE_PATH = "Z:\\asset_storage1" DEST_PATH = "/mnt/shared/asset_storage1" rules = { - "source_path_format": "Windows", + "source_path_format": "WINDOWS", "source_path": SOURCE_PATH, - "destination_os": "Linux", + "destination_os": "POSIX", "destination_path": DEST_PATH, } adaptor = FakeAdaptor( diff --git a/test/openjd/adaptor_runtime/unit/background/test_backend_runner.py b/test/openjd/adaptor_runtime/unit/background/test_backend_runner.py index 9b52eede..437b19ee 100644 --- a/test/openjd/adaptor_runtime/unit/background/test_backend_runner.py +++ b/test/openjd/adaptor_runtime/unit/background/test_backend_runner.py @@ -13,7 +13,6 @@ import openjd.adaptor_runtime._background.backend_runner as backend_runner from openjd.adaptor_runtime._background.backend_runner import BackendRunner from openjd.adaptor_runtime._background.model import ConnectionSettings, DataclassJSONEncoder -from openjd.adaptor_runtime._osname import OSName class TestBackendRunner: @@ -23,7 +22,13 @@ class TestBackendRunner: @pytest.fixture(autouse=True) def socket_path(self, tmp_path: pathlib.Path) -> Generator[str, None, None]: - if OSName.is_posix(): + if os.name == "nt": + with patch.object(backend_runner.NamedPipeHelper, "generate_pipe_name") as mock: + path = "\\\\.\\pipe\\AdaptorNamedPipe_1234" + mock.return_value = path + + yield path + else: with patch.object(backend_runner.SocketPaths, "get_process_socket_path") as mock: path = os.path.join(tmp_path, "socket", "1234") mock.return_value = path @@ -34,23 +39,17 @@ def socket_path(self, tmp_path: pathlib.Path) -> Generator[str, None, None]: os.remove(path) except FileNotFoundError: pass - else: - with patch.object(backend_runner.NamedPipeHelper, "generate_pipe_name") as mock: - path = "\\\\.\\pipe\\AdaptorNamedPipe_1234" - mock.return_value = path - - yield path @pytest.fixture(autouse=True) def mock_server_cls(self) -> Generator[MagicMock, None, None]: - if OSName.is_posix(): - with patch.object(backend_runner, "BackgroundHTTPServer", autospec=True) as mock: - yield mock - else: + if os.name == "nt": with patch.object( backend_runner, "WinBackgroundNamedPipeServer", autospec=True ) as mock: yield mock + else: + with patch.object(backend_runner, "BackgroundHTTPServer", autospec=True) as mock: + yield mock @patch.object(backend_runner.json, "dump") @patch.object(backend_runner.os, "remove") @@ -103,10 +102,10 @@ def test_run( cls=DataclassJSONEncoder, ) mock_thread.return_value.join.assert_called_once() - if OSName.is_posix(): - mock_os_remove.assert_has_calls([call(conn_file), call(socket_path)]) - else: + if os.name == "nt": mock_os_remove.assert_has_calls([call(conn_file)]) + else: + mock_os_remove.assert_has_calls([call(conn_file), call(socket_path)]) def test_run_raises_when_http_server_fails_to_start( self, @@ -172,10 +171,10 @@ def test_run_raises_when_writing_connection_file_fails( mock_thread.return_value.start.assert_called_once() open_mock.assert_called_once_with(conn_file, open_mode="w", encoding="utf-8") mock_thread.return_value.join.assert_called_once() - if OSName.is_posix(): - mock_os_remove.assert_has_calls([call(conn_file), call(socket_path)]) - else: + if os.name == "nt": mock_os_remove.assert_has_calls([call(conn_file)]) + else: + mock_os_remove.assert_has_calls([call(conn_file), call(socket_path)]) @patch.object(backend_runner.signal, "signal") @patch.object(backend_runner.ServerResponseGenerator, "submit_task") @@ -197,8 +196,8 @@ def test_signal_hook(self, mock_submit, signal_mock: MagicMock) -> None: # THEN signal_mock.assert_any_call(signal.SIGINT, runner._sigint_handler) - if OSName.is_posix(): - signal_mock.assert_any_call(signal.SIGTERM, runner._sigint_handler) - else: + if os.name == "nt": signal_mock.assert_any_call(signal.SIGBREAK, runner._sigint_handler) # type: ignore[attr-defined] + else: + signal_mock.assert_any_call(signal.SIGTERM, runner._sigint_handler) mock_submit.assert_called_with(server_mock, adaptor_runner._cancel, force_immediate=True) diff --git a/test/openjd/adaptor_runtime/unit/background/test_frontend_runner.py b/test/openjd/adaptor_runtime/unit/background/test_frontend_runner.py index 64736f0a..00f52b19 100644 --- a/test/openjd/adaptor_runtime/unit/background/test_frontend_runner.py +++ b/test/openjd/adaptor_runtime/unit/background/test_frontend_runner.py @@ -18,7 +18,6 @@ import pytest from openjd.adaptor_runtime._background import frontend_runner -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.adaptors import AdaptorState from openjd.adaptor_runtime._background.frontend_runner import ( AdaptorFailedException, @@ -41,7 +40,7 @@ class TestFrontendRunner: @pytest.fixture def server_name(self) -> str: - return "/path/to/socket" if OSName.is_posix() else r"\\.\pipe\TestPipe" + return r"\\.\pipe\TestPipe" if os.name == "nt" else "/path/to/socket" @pytest.fixture def connection_settings(self, server_name: str) -> ConnectionSettings: @@ -395,7 +394,7 @@ def test_sends_heartbeat( mock_json_load: MagicMock, ): # GIVEN - if OSName.is_windows(): + if os.name == "nt": mock_send_request.return_value = {"body": '{"key1": "value1"}'} mock_response = mock_send_request.return_value runner = FrontendRunner() @@ -405,11 +404,11 @@ def test_sends_heartbeat( # THEN assert response is mock_dataclass_mapper_map.return_value - if OSName.is_posix(): + if os.name == "nt": + mock_dataclass_mapper_map.assert_called_once_with({"key1": "value1"}) + else: mock_json_load.assert_called_once_with(mock_response.fp) mock_dataclass_mapper_map.assert_called_once_with(mock_json_load.return_value) - else: - mock_dataclass_mapper_map.assert_called_once_with({"key1": "value1"}) mock_send_request.assert_called_once_with("GET", "/heartbeat", params=None) def test_sends_heartbeat_with_ack_id( @@ -420,7 +419,7 @@ def test_sends_heartbeat_with_ack_id( ): # GIVEN ack_id = "ack_id" - if OSName.is_windows(): + if os.name == "nt": mock_send_request.return_value = {"body": '{"key1": "value1"}'} mock_response = mock_send_request.return_value runner = FrontendRunner() @@ -430,11 +429,11 @@ def test_sends_heartbeat_with_ack_id( # THEN assert response is mock_dataclass_mapper_map.return_value - if OSName.is_posix(): + if os.name == "nt": + mock_dataclass_mapper_map.assert_called_once_with({"key1": "value1"}) + else: mock_json_load.assert_called_once_with(mock_response.fp) mock_dataclass_mapper_map.assert_called_once_with(mock_json_load.return_value) - else: - mock_dataclass_mapper_map.assert_called_once_with({"key1": "value1"}) mock_send_request.assert_called_once_with( "GET", "/heartbeat", params={"ack_id": ack_id} ) @@ -607,7 +606,7 @@ def test_sends_cancel( # THEN mock_send_request.assert_called_once_with("PUT", "/cancel") - @pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") + @pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") class TestSendRequestInLinux: """ Tests for the FrontendRunner._send_request method @@ -760,7 +759,7 @@ def test_sends_body( mock_getresponse.assert_called_once() assert response is mock_getresponse.return_value - @pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") + @pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") class TestSendRequestInWindows: """ Tests for the FrontendRunner._send_request method in Windows @@ -953,10 +952,10 @@ def test_hook(self, signal_mock: MagicMock, cancel_mock: MagicMock) -> None: # THEN signal_mock.assert_any_call(signal.SIGINT, runner._sigint_handler) - if OSName.is_posix(): - signal_mock.assert_any_call(signal.SIGTERM, runner._sigint_handler) - else: + if os.name == "nt": signal_mock.assert_any_call(signal.SIGBREAK, runner._sigint_handler) # type: ignore[attr-defined] + else: + signal_mock.assert_any_call(signal.SIGTERM, runner._sigint_handler) cancel_mock.assert_called_once() diff --git a/test/openjd/adaptor_runtime/unit/background/test_http_server.py b/test/openjd/adaptor_runtime/unit/background/test_http_server.py index aae9c021..c23a77f8 100644 --- a/test/openjd/adaptor_runtime/unit/background/test_http_server.py +++ b/test/openjd/adaptor_runtime/unit/background/test_http_server.py @@ -1,9 +1,9 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -from openjd.adaptor_runtime._osname import OSName +import os import pytest -if OSName.is_windows(): +if os.name == "nt": pytest.skip("Posix-specific tests", allow_module_level=True) import json diff --git a/test/openjd/adaptor_runtime/unit/background/test_server_response.py b/test/openjd/adaptor_runtime/unit/background/test_server_response.py index de5d9826..fb6fe55e 100644 --- a/test/openjd/adaptor_runtime/unit/background/test_server_response.py +++ b/test/openjd/adaptor_runtime/unit/background/test_server_response.py @@ -1,10 +1,10 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +import os from unittest.mock import MagicMock import pytest -from openjd.adaptor_runtime._osname import OSName -if OSName.is_windows(): +if os.name == "nt": from openjd.adaptor_runtime._background.backend_named_pipe_server import ( WinBackgroundNamedPipeServer, ) @@ -25,7 +25,7 @@ def my_fn(): kwargs = {"three": 3, "four": 4} mock_future_runner = MagicMock() - if OSName.is_windows(): + if os.name == "nt": mock_server = MagicMock(spec=WinBackgroundNamedPipeServer) else: mock_server = MagicMock(spec=BackgroundHTTPServer) @@ -52,7 +52,7 @@ def my_fn(): args = ("one", "two") kwargs = {"three": 3, "four": 4} - if OSName.is_windows(): + if os.name == "nt": mock_server = MagicMock(spec=WinBackgroundNamedPipeServer) else: mock_server = MagicMock(spec=BackgroundHTTPServer) diff --git a/test/openjd/adaptor_runtime/unit/http/test_request_handler.py b/test/openjd/adaptor_runtime/unit/http/test_request_handler.py index ac0a117b..137ca6bc 100644 --- a/test/openjd/adaptor_runtime/unit/http/test_request_handler.py +++ b/test/openjd/adaptor_runtime/unit/http/test_request_handler.py @@ -1,9 +1,11 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -from openjd.adaptor_runtime._osname import OSName +import os +import sys + import pytest -if OSName.is_windows(): +if os.name == "nt": pytest.skip("Posix-specific tests", allow_module_level=True) import socket @@ -17,7 +19,6 @@ RequestHandler, UnsupportedPlatformException, ) -from openjd.adaptor_runtime._osname import OSName @pytest.fixture @@ -137,7 +138,7 @@ def test_respond_with_body( mock_wfile.write.assert_called_once_with(body.encode("utf-8")) -@pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") +@pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") class TestAuthentication: """ Tests for the RequestHandler authentication @@ -148,7 +149,7 @@ class TestAuthenticate: Tests for the RequestHandler._authenticate() method """ - cred_cls = request_handler.XUCred if OSName.is_macos() else request_handler.UCred + cred_cls = request_handler.XUCred if sys.platform == "darwin" else request_handler.UCred @pytest.fixture def mock_handler(self) -> MagicMock: diff --git a/test/openjd/adaptor_runtime/unit/http/test_sockets.py b/test/openjd/adaptor_runtime/unit/http/test_sockets.py index 972c4618..c76d7bd6 100644 --- a/test/openjd/adaptor_runtime/unit/http/test_sockets.py +++ b/test/openjd/adaptor_runtime/unit/http/test_sockets.py @@ -15,12 +15,12 @@ MacOSSocketPaths, NonvalidSocketPathException, NoSocketPathFoundException, - SocketPaths, + SocketPathsBase, UnixSocketPaths, ) -class SocketPathsStub(SocketPaths): +class SocketPathsStub(SocketPathsBase): def verify_socket_path(self, path: str) -> None: pass @@ -28,7 +28,7 @@ def verify_socket_path(self, path: str) -> None: class TestSocketPaths: class TestGetProcessSocketPath: """ - Tests for SocketPaths.get_process_socket_path() + Tests for SocketPaths().get_process_socket_path() """ @patch.object(sockets.os, "getpid", return_value=1234) @@ -64,7 +64,7 @@ def test_asserts_max_pid_length(self, mock_getpid: MagicMock): class TestGetSocketPath: """ - Tests for SocketPaths.get_socket_path() + Tests for SocketPaths().get_socket_path() """ @pytest.fixture(autouse=True) diff --git a/test/openjd/adaptor_runtime/unit/named_pipe/test_named_pipe_helper.py b/test/openjd/adaptor_runtime/unit/named_pipe/test_named_pipe_helper.py index d2afae0d..726ad67e 100644 --- a/test/openjd/adaptor_runtime/unit/named_pipe/test_named_pipe_helper.py +++ b/test/openjd/adaptor_runtime/unit/named_pipe/test_named_pipe_helper.py @@ -1,6 +1,5 @@ # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -from openjd.adaptor_runtime._osname import OSName from unittest.mock import patch, MagicMock import pytest import os @@ -22,7 +21,7 @@ def ReadFile(handle: pywintypes.HANDLE, timeout_in_seconds: float): # type: ign return winerror.NO_ERROR, bytes("fake_data", "utf-8") -@pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") +@pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") class TestNamedPipeHelper: def test_named_pipe_read_timeout_exception(self): with pytest.raises( diff --git a/test/openjd/adaptor_runtime/unit/process/test_logging_subprocess.py b/test/openjd/adaptor_runtime/unit/process/test_logging_subprocess.py index 87ea6c07..ee43bde8 100644 --- a/test/openjd/adaptor_runtime/unit/process/test_logging_subprocess.py +++ b/test/openjd/adaptor_runtime/unit/process/test_logging_subprocess.py @@ -3,6 +3,7 @@ """Tests for StreamLogger""" from __future__ import annotations +import os import signal import subprocess from logging import INFO @@ -12,7 +13,6 @@ import pytest import openjd.adaptor_runtime.process._logging_subprocess as logging_subprocess -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime.process import LoggingSubprocess @@ -73,7 +73,7 @@ def test_process_creation(self, mock_popen: mock.Mock, mock_stream_logger: mock. stderr=subprocess.PIPE, cwd=None, ) - if OSName.is_windows(): + if os.name == "nt": popen_params.update(creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] mock_popen.assert_called_with(**popen_params) @@ -187,7 +187,7 @@ def test_terminate(self, mock_popen: mock.Mock, mock_stream_logger: mock.Mock): subject.terminate() # THEN - if OSName.is_windows(): + if os.name == "nt": proc.send_signal.assert_called_once_with(signal.CTRL_BREAK_EVENT) # type: ignore[attr-defined] else: proc.send_signal.assert_called_once_with(signal.SIGTERM) @@ -226,7 +226,7 @@ def test_stop_after_terminate_timeout( subject.terminate(timeout) # THEN - if OSName.is_windows(): + if os.name == "nt": proc.send_signal.assert_called_once_with(signal.CTRL_BREAK_EVENT) # type: ignore[attr-defined] else: proc.send_signal.assert_called_once_with(signal.SIGTERM) @@ -296,7 +296,7 @@ def test_terminate_multiple(self, mock_popen: mock.Mock, mock_stream_logger: moc subject.terminate() - if OSName.is_windows(): + if os.name == "nt": proc.send_signal.assert_called_once_with(signal.CTRL_BREAK_EVENT) # type: ignore[attr-defined] else: proc.send_signal.assert_called_once_with(signal.SIGTERM) @@ -349,7 +349,7 @@ def test_stop_multiple(self, mock_popen: mock.Mock, mock_stream_logger: mock.Moc subject.terminate(timeout) - if OSName.is_windows(): + if os.name == "nt": proc.send_signal.assert_called_once_with(signal.CTRL_BREAK_EVENT) # type: ignore[attr-defined] else: proc.send_signal.assert_called_once_with(signal.SIGTERM) @@ -387,7 +387,7 @@ def test_stop_multiple(self, mock_popen: mock.Mock, mock_stream_logger: mock.Moc def test_context_manager(self): # GIVEN - if OSName.is_windows(): + if os.name == "nt": args = ["powershell", "echo", "foo"] else: args = ["echo", "foo"] @@ -483,7 +483,7 @@ def test_startup_directory_default(self, mock_popen_autospec: mock.Mock): encoding="utf-8", cwd=None, ) - if OSName.is_windows(): + if os.name == "nt": popen_params.update(creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] mock_popen_autospec.assert_called_once_with(**popen_params) @@ -505,7 +505,7 @@ def test_start_directory(self, mock_popen_autospec: mock.Mock): encoding="utf-8", cwd="startup_dir", ) - if OSName.is_windows(): + if os.name == "nt": popen_params.update(creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] mock_popen_autospec.assert_called_once_with(**popen_params) diff --git a/test/openjd/adaptor_runtime/unit/test_entrypoint.py b/test/openjd/adaptor_runtime/unit/test_entrypoint.py index e859ac1d..0698ddff 100644 --- a/test/openjd/adaptor_runtime/unit/test_entrypoint.py +++ b/test/openjd/adaptor_runtime/unit/test_entrypoint.py @@ -24,7 +24,6 @@ from openjd.adaptor_runtime._background import BackendRunner, FrontendRunner from openjd.adaptor_runtime._background.frontend_runner import _FRONTEND_RUNNER_REQUEST_TIMEOUT from openjd.adaptor_runtime._background.model import ConnectionSettings -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime._entrypoint import _load_data from .adaptors.fake_adaptor import FakeAdaptor @@ -361,7 +360,7 @@ def test_uses_default_config_on_unsupported_system( mock_build_config.assert_called_once() mock_get_default_config.assert_called_once() assert entrypoint.config is mock_get_default_config.return_value - assert f"The current system ({OSName()}) is not supported for runtime " + assert " is not supported for runtime " in caplog.text assert ( "configuration. Only the default configuration will be loaded. Full error: " in caplog.text @@ -451,10 +450,10 @@ def test_runmode_signal_hook( # THEN signal_mock.assert_any_call(signal.SIGINT, entrypoint._sigint_handler) - if OSName.is_posix(): - signal_mock.assert_any_call(signal.SIGTERM, entrypoint._sigint_handler) - else: + if os.name == "nt": signal_mock.assert_any_call(signal.SIGBREAK, entrypoint._sigint_handler) # type: ignore[attr-defined] + else: + signal_mock.assert_any_call(signal.SIGTERM, entrypoint._sigint_handler) mock_adaptor_runner.return_value._cancel.assert_called_once() @patch.object(runtime_entrypoint, "InMemoryLogBuffer") diff --git a/test/openjd/adaptor_runtime/unit/utils/test_secure_open.py b/test/openjd/adaptor_runtime/unit/utils/test_secure_open.py index 7e45384b..695fb0e7 100644 --- a/test/openjd/adaptor_runtime/unit/utils/test_secure_open.py +++ b/test/openjd/adaptor_runtime/unit/utils/test_secure_open.py @@ -6,7 +6,6 @@ import pytest -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime._utils import secure_open READ_FLAGS = os.O_RDONLY @@ -44,7 +43,7 @@ ], ) @patch.object(os, "open") -@pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") +@pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") def test_secure_open_in_posix(mock_os_open, path, open_mode, mask, expected_os_open_kwargs): # WHEN with patch("builtins.open", mock_open()) as mocked_open: @@ -76,7 +75,7 @@ def test_secure_open_in_posix(mock_os_open, path, open_mode, mask, expected_os_o ) @patch.object(os, "open") @patch("openjd.adaptor_runtime._utils._secure_open.set_file_permissions_in_windows") -@pytest.mark.skipif(not OSName.is_windows(), reason="Windows-specific tests") +@pytest.mark.skipif(os.name != "nt", reason="Windows-specific tests") def test_secure_open_in_windows( mock_file_permission_setting, mock_os_open, path, open_mode, expected_os_open_kwargs ): diff --git a/test/openjd/adaptor_runtime_client/integ/test_integration_client_interface.py b/test/openjd/adaptor_runtime_client/integ/test_integration_client_interface.py index 98490a73..592d2c2d 100644 --- a/test/openjd/adaptor_runtime_client/integ/test_integration_client_interface.py +++ b/test/openjd/adaptor_runtime_client/integ/test_integration_client_interface.py @@ -2,6 +2,7 @@ from __future__ import annotations +import os import signal import sys import subprocess as _subprocess @@ -9,8 +10,6 @@ from time import sleep as _sleep from typing import Dict, Any -from openjd.adaptor_runtime._osname import OSName - class TestIntegrationClientInterface: """These are the integration tests for the client interface.""" @@ -27,16 +26,16 @@ def test_graceful_shutdown(self) -> None: stdout=_subprocess.PIPE, encoding="utf-8", ) - if OSName.is_windows(): + if os.name == "nt": # In Windows, this is required for signal. SIGBREAK will be sent to the entire process group. # Without this one, current process will also get the SIGBREAK and may react incorrectly. popen_params.update(creationflags=_subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] client_subprocess = _subprocess.Popen(**popen_params) # To avoid a race condition, giving some extra time for the logging subprocess to start. - _sleep(0.5 if OSName.is_posix() else 4) + _sleep(4 if os.name == "nt" else 0.5) signal_type: signal.Signals - if OSName.is_windows(): + if os.name == "nt": signal_type = signal.CTRL_BREAK_EVENT # type: ignore[attr-defined] else: signal_type = signal.SIGTERM @@ -46,11 +45,11 @@ def test_graceful_shutdown(self) -> None: # To avoid a race condition, giving some extra time for the log to be updated after # receiving the signal. - _sleep(0.5 if OSName.is_posix() else 4) + _sleep(4 if os.name == "nt" else 0.5) out, _ = client_subprocess.communicate() - assert f"Received {'SIGBREAK' if OSName.is_windows() else 'SIGTERM'} signal." in out + assert f"Received {'SIGBREAK' if os.name == 'nt' else 'SIGTERM'} signal." in out # Ensure the process actually shutdown assert client_subprocess.returncode is not None @@ -70,16 +69,16 @@ def test_client_in_thread_does_not_do_graceful_shutdown(self) -> None: stdout=_subprocess.PIPE, encoding="utf-8", ) - if OSName.is_windows(): + if os.name == "nt": # In Windows, this is required for signal. SIGBREAK will be sent to the entire process group. # Without this one, current process will also get the SIGBREAK and may react incorrectly. popen_params.update(creationflags=_subprocess.CREATE_NEW_PROCESS_GROUP) # type: ignore[attr-defined] client_subprocess = _subprocess.Popen(**popen_params) # To avoid a race condition, giving some extra time for the logging subprocess to start. - _sleep(0.5 if OSName.is_posix() else 4) + _sleep(4 if os.name == "nt" else 0.5) signal_type: signal.Signals - if OSName.is_windows(): + if os.name == "nt": signal_type = signal.CTRL_BREAK_EVENT # type: ignore[attr-defined] else: signal_type = signal.SIGTERM @@ -90,7 +89,7 @@ def test_client_in_thread_does_not_do_graceful_shutdown(self) -> None: assert client_subprocess.returncode is None out, err = client_subprocess.communicate() assert "ValueError: signal only works in main thread of the main interpreter" not in err - assert f"Received {'SIGBREAK' if OSName.is_windows() else 'SIGTERM'} signal." not in out + assert f"Received {'SIGBREAK' if os.name == 'nt' else 'SIGTERM'} signal." not in out # Ensure the process stops client_subprocess.kill() diff --git a/test/openjd/adaptor_runtime_client/unit/test_client_interface.py b/test/openjd/adaptor_runtime_client/unit/test_client_interface.py index 5cd6e1cf..8abb8ad9 100644 --- a/test/openjd/adaptor_runtime_client/unit/test_client_interface.py +++ b/test/openjd/adaptor_runtime_client/unit/test_client_interface.py @@ -2,6 +2,7 @@ from http import HTTPStatus import json +import os from signal import Signals from types import FrameType as _FrameType from typing import ( @@ -20,7 +21,6 @@ import pytest from _pytest.capture import CaptureFixture as _CaptureFixture -from openjd.adaptor_runtime._osname import OSName from openjd.adaptor_runtime_client import ( Action as _Action, ClientInterface as _ClientInterface, @@ -35,8 +35,8 @@ class FakeClient(_ClientInterface): We are going to use this FakeClient for our testing. """ - def __init__(self, socket_path: str) -> None: - super().__init__(socket_path) + def __init__(self, server_path: str) -> None: + super().__init__(server_path) self.actions.update({"hello_world": self.hello_world}) def hello_world(self, args: _Optional[_Dict[str, _Any]]) -> None: @@ -50,7 +50,7 @@ def close(self, args: _Optional[_Dict[str, _Any]]) -> None: pass -@pytest.mark.skipif(not OSName.is_posix(), reason="Posix-specific tests") +@pytest.mark.skipif(os.name == "nt", reason="Posix-specific tests") class TestPosixClientInterface: @pytest.mark.parametrize( argnames=("original_path", "new_path"), @@ -77,7 +77,7 @@ def test_map_path( mocked_response.length = len(mocked_response.read.return_value) mocked_HTTPConnection_getresponse.return_value = mocked_response - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN mapped = dcc_client.map_path(original_path) @@ -133,7 +133,7 @@ def test_path_mapping_rules( mocked_response.length = len(mocked_response.read.return_value) mocked_HTTPConnection_getresponse.return_value = mocked_response - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN expected = dcc_client.path_mapping_rules() @@ -172,7 +172,7 @@ def test_path_mapping_rules_throws_nonvalid_json( mock_response.status = HTTPStatus.OK mock_response.read.return_value = "bad json".encode("utf-8") mock_getresponse.return_value = mock_response - client = FakeClient(socket_path="socket_path") + client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as raised_err: @@ -203,7 +203,7 @@ def test_path_mapping_rules_throws_not_list( mock_response.status = HTTPStatus.OK mock_response.read.return_value = json.dumps(response_val).encode("utf-8") mock_getresponse.return_value = mock_response - client = FakeClient(socket_path="socket_path") + client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as raised_err: @@ -235,7 +235,7 @@ def test_path_mapping_rules_throws_not_path_mapping_rule( mock_response.status = HTTPStatus.OK mock_response.read.return_value = json.dumps(response_val).encode("utf-8") mock_getresponse.return_value = mock_response - client = FakeClient(socket_path="socket_path") + client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as raised_err: @@ -270,7 +270,7 @@ def test_map_path_error( mocked_response.length = len(mocked_response.read.return_value) mocked_HTTPConnection_getresponse.return_value = mocked_response - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as exc_info: @@ -314,7 +314,7 @@ def test_request_next_action( socket_path = "socket_path" dcc_client = FakeClient(socket_path) - assert dcc_client.socket_path == socket_path + assert dcc_client.server_path == socket_path status, reason, action = dcc_client._request_next_action() assert action is None @@ -383,7 +383,7 @@ def test_map_path( # GIVEN body = json.dumps({"status": 200, "body": json.dumps({"path": new_path})}) mock_read_from_pipe.return_value = body - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN mapped = dcc_client.map_path(original_path) @@ -433,7 +433,7 @@ def test_path_mapping_rules( body = json.dumps({"status": 200, "body": json.dumps({"path_mapping_rules": rules})}) mock_read_from_pipe.return_value = body - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN expected = dcc_client.path_mapping_rules() @@ -472,7 +472,7 @@ def test_path_mapping_rules_throws_nonvalid_json( body = json.dumps({"status": 200, "body": "bad json"}) mock_read_from_pipe.return_value = body - client = FakeClient(socket_path="socket_path") + client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as raised_err: @@ -527,7 +527,7 @@ def test_path_mapping_rules_throws_errors( # GIVEN body = json.dumps({"status": 200, "body": json.dumps(response_val)}) mock_read_from_pipe.return_value = body - client = FakeClient(socket_path="socket_path") + client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as raised_err: @@ -566,7 +566,7 @@ def test_map_path_error( body = json.dumps({"status": 500, "body": REASON}) mock_read_from_pipe.return_value = body - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") # WHEN with pytest.raises(RuntimeError) as exc_info: @@ -666,7 +666,7 @@ def test_poll(self, mocked_perform_action: mock.Mock, capsys: _CaptureFixture) - (200, "OK", a2), ], ): - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") dcc_client.poll() mocked_perform_action.assert_has_calls([mock.call(a1), mock.call(a2)]) @@ -680,14 +680,14 @@ def test_perform_action(self) -> None: a1 = _Action("hello_world", {"arg1": "Hello!", "arg2": "How are you?"}) with mock.patch.object(FakeClient, "hello_world") as mocked_hello_world: - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") dcc_client._perform_action(a1) mocked_hello_world.assert_called_once_with(a1.args) def test_perform_nonvalid_action(self, capsys: _CaptureFixture) -> None: a2 = _Action("nonvalid") - dcc_client = FakeClient(socket_path="socket_path") + dcc_client = FakeClient(server_path="socket_path") dcc_client._perform_action(a2) assert (