diff --git a/ni_measurementlink_service/_internal/discovery_client.py b/ni_measurementlink_service/_internal/discovery_client.py index 614bf7356..02d58c6e1 100644 --- a/ni_measurementlink_service/_internal/discovery_client.py +++ b/ni_measurementlink_service/_internal/discovery_client.py @@ -21,12 +21,10 @@ from ni_measurementlink_service.measurement.info import MeasurementInfo, ServiceInfo if sys.platform == "win32": - import errno import msvcrt import win32con import win32file - import winerror _logger = logging.getLogger(__name__) # Save Popen object to avoid "ResourceWarning: subprocess N is still running" @@ -329,7 +327,7 @@ def _start_service( try: with _open_key_file(str(key_file_path)) as _: return discovery_service_subprocess - except IOError: + except OSError: pass if time.time() >= timeout_time: raise TimeoutError("Timed out waiting for discovery service to start") @@ -339,7 +337,7 @@ def _start_service( def _service_already_running(key_file_path: pathlib.Path) -> bool: try: _delete_existing_key_file(key_file_path) - except IOError: + except OSError: return True return False @@ -390,14 +388,7 @@ def _open_key_file(path: str) -> typing.TextIO: None, ) except win32file.error as e: - if e.winerror == winerror.ERROR_FILE_NOT_FOUND: - raise FileNotFoundError(errno.ENOENT, e.strerror, path) from e - elif ( - e.winerror == winerror.ERROR_ACCESS_DENIED - or e.winerror == winerror.ERROR_SHARING_VIOLATION - ): - raise PermissionError(errno.EACCES, e.strerror, path) from e - raise + raise OSError(None, e.strerror, path, e.winerror) from e # The CRT file descriptor takes ownership of the Win32 file handle. # os.O_TEXT is unnecessary because Python handles newline conversion. diff --git a/tests/unit/test_discovery_client.py b/tests/unit/test_discovery_client.py index 8d3c81cf0..1405f1734 100644 --- a/tests/unit/test_discovery_client.py +++ b/tests/unit/test_discovery_client.py @@ -16,6 +16,7 @@ DiscoveryClient, ServiceLocation, _get_discovery_service_address, + _open_key_file, _start_service, ) from ni_measurementlink_service._internal.stubs.ni.measurementlink.discovery.v1.discovery_service_pb2 import ( @@ -33,6 +34,9 @@ from ni_measurementlink_service.measurement.info import MeasurementInfo, ServiceInfo from tests.utilities.fake_rpc_error import FakeRpcError +if sys.platform == "win32": + import win32file + _PROVIDED_MEASUREMENT_SERVICES = [ "ni.measurementlink.measurement.v1.MeasurementService", "ni.measurementlink.measurement.v2.MeasurementService", @@ -236,7 +240,7 @@ def test___get_discovery_service_address___key_file_not_exist___throws_timeouter "ni_measurementlink_service._internal.discovery_client._START_SERVICE_TIMEOUT", 5.0 ) mocker.patch( - "ni_measurementlink_service._internal.discovery_client._open_key_file", side_effect=IOError + "ni_measurementlink_service._internal.discovery_client._open_key_file", side_effect=OSError ) mocker.patch( "ni_measurementlink_service._internal.discovery_client._get_registration_json_file_path", @@ -244,11 +248,29 @@ def test___get_discovery_service_address___key_file_not_exist___throws_timeouter ) mocker.patch("subprocess.Popen") - with pytest.raises(IOError) as exc_info: + with pytest.raises(OSError) as exc_info: _get_discovery_service_address() assert exc_info.type is TimeoutError +@pytest.mark.parametrize( + "windows_error_code", [2, 3] +) # ERROR_FILE_NOT_FOUND = 2, ERROR_PATH_NOT_FOUND = 3 +def test___key_file_not_exist___open_key_file___raises_file_not_found_error( + mocker: MockerFixture, temp_discovery_key_file_path: pathlib.Path, windows_error_code: int +) -> None: + if sys.platform != "win32": + pytest.skip("Windows-only test") + else: + mocker.patch( + "win32file.CreateFile", + side_effect=win32file.error(windows_error_code, None, None), + ) + + with pytest.raises(FileNotFoundError): + _open_key_file(str(temp_discovery_key_file_path)) + + def test___start_discovery_service___key_file_exist_after_poll___service_start_success( mocker: MockerFixture, temp_directory: pathlib.Path, @@ -259,7 +281,7 @@ def test___start_discovery_service___key_file_exist_after_poll___service_start_s mocker.patch( "ni_measurementlink_service._internal.discovery_client._open_key_file", - side_effect=[IOError, IOError, IOError, temp_discovery_key_file_path], + side_effect=[OSError, OSError, OSError, temp_discovery_key_file_path], ) mock_popen = mocker.patch("subprocess.Popen")