Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions ni_measurementlink_service/_internal/discovery_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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")
Expand All @@ -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

Expand Down Expand Up @@ -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.
Expand Down
28 changes: 25 additions & 3 deletions tests/unit/test_discovery_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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",
Expand Down Expand Up @@ -236,19 +240,37 @@ 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",
return_value=temp_registration_json_file_path,
)
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,
Expand All @@ -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")

Expand Down