From b453e1fb4075c584255232f3c174c664e3b92606 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 14:37:14 +0530 Subject: [PATCH 01/12] Client: Add pin map client measurement plugin sdk service --- .../pin_map/__init__.py | 5 ++ .../pin_map/_client.py | 90 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 packages/service/ni_measurement_plugin_sdk_service/pin_map/__init__.py create mode 100644 packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/__init__.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/__init__.py new file mode 100644 index 000000000..ef52a74a8 --- /dev/null +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/__init__.py @@ -0,0 +1,5 @@ +"""Public API for accessing the NI Pin Map Service.""" + +from ni_measurement_plugin_sdk_service.pin_map._client import PinMapClient + +__all__ = ["PinMapClient"] diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py new file mode 100644 index 000000000..d2185687b --- /dev/null +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -0,0 +1,90 @@ +"""Client for accessing the NI Pin Map Service.""" + +import logging +import pathlib +import threading +from typing import Optional, Union + +import grpc + +from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1 import ( + pin_map_service_pb2, + pin_map_service_pb2_grpc, +) +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient +from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool + +_logger = logging.getLogger(__name__) + +GRPC_SERVICE_INTERFACE_NAME = "ni.measurementlink.pinmap.v1.PinMapService" +GRPC_SERVICE_CLASS = "ni.measurementlink.pinmap.v1.PinMapService" + + +class PinMapClient(object): + """Client for accessing the NI Pin Map Service.""" + + def __init__( + self, + *, + discovery_client: Optional[DiscoveryClient] = None, + grpc_channel: Optional[grpc.Channel] = None, + grpc_channel_pool: Optional[GrpcChannelPool] = None + ) -> None: + """Initialize the pin map client. + + Args: + discovery_client: An optional discovery client (recommended). + + grpc_channel: An optional session management gRPC channel. + + grpc_channel_pool: An optional gRPC channel pool (recommended). + """ + self._initialization_lock = threading.Lock() + self._discovery_client = discovery_client + self._grpc_channel_pool = grpc_channel_pool + self._stub: Optional[pin_map_service_pb2_grpc.PinMapServiceStub] = None + + if grpc_channel is not None: + self._stub = pin_map_service_pb2_grpc.PinMapServiceStub(grpc_channel) + + def _get_stub(self) -> pin_map_service_pb2_grpc.PinMapServiceStub: + if self._stub is None: + with self._initialization_lock: + if self._grpc_channel_pool is None: + _logger.debug("Creating unshared GrpcChannelPool.") + self._grpc_channel_pool = GrpcChannelPool() + if self._discovery_client is None: + _logger.debug("Creating unshared DiscoveryClient.") + self._discovery_client = DiscoveryClient( + grpc_channel_pool=self._grpc_channel_pool + ) + if self._stub is None: + service_location = self._discovery_client.resolve_service( + provided_interface=GRPC_SERVICE_INTERFACE_NAME, + service_class=GRPC_SERVICE_CLASS, + ) + channel = self._grpc_channel_pool.get_channel(service_location.insecure_address) + self._stub = pin_map_service_pb2_grpc.PinMapServiceStub(channel) + return self._stub + + def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: + """Update registered pin map contents. + + Create and register a pin map if a pin map resource for the specified pin map id is not + found. + + Args: + pin_map_path: The file path of the pin map to register as a pin map resource. + + Returns: + The resource id of the pin map that is registered to the pin map service. + """ + # By convention, the pin map id is the .pinmap file path. + with open(pin_map_path, "r", encoding="utf-8-sig") as file: + xml_content = file.read() + request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( + pin_map_id=str(pin_map_path), pin_map_xml=xml_content + ) + + response = self._get_stub().UpdatePinMapFromXml(request) + return response.pin_map_id From ccf296792788aa846176e08976c77e3f9a8eac9f Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 14:37:54 +0530 Subject: [PATCH 02/12] Tests: Remove pin_map_client.py from test utilities --- .../service/tests/utilities/pin_map_client.py | 80 ------------------- 1 file changed, 80 deletions(-) delete mode 100644 packages/service/tests/utilities/pin_map_client.py diff --git a/packages/service/tests/utilities/pin_map_client.py b/packages/service/tests/utilities/pin_map_client.py deleted file mode 100644 index 624516462..000000000 --- a/packages/service/tests/utilities/pin_map_client.py +++ /dev/null @@ -1,80 +0,0 @@ -"""Client for accessing the measurement pin map service.""" - -import logging -import pathlib -import threading -from typing import Optional, Union - -import grpc - -from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1 import ( - pin_map_service_pb2, - pin_map_service_pb2_grpc, -) -from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient -from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool - -_logger = logging.getLogger(__name__) - -GRPC_SERVICE_INTERFACE_NAME = "ni.measurementlink.pinmap.v1.PinMapService" -GRPC_SERVICE_CLASS = "ni.measurementlink.pinmap.v1.PinMapService" - - -class PinMapClient(object): - """Client for accessing the measurement pin map service.""" - - def __init__( - self, - *, - discovery_client: Optional[DiscoveryClient] = None, - grpc_channel: Optional[grpc.Channel] = None, - grpc_channel_pool: Optional[GrpcChannelPool] = None - ) -> None: - """Initialize the pin map client.""" - self._initialization_lock = threading.Lock() - self._discovery_client = discovery_client - self._grpc_channel_pool = grpc_channel_pool - self._stub: Optional[pin_map_service_pb2_grpc.PinMapServiceStub] = None - - if grpc_channel is not None: - self._stub = pin_map_service_pb2_grpc.PinMapServiceStub(grpc_channel) - - def _get_stub(self) -> pin_map_service_pb2_grpc.PinMapServiceStub: - if self._stub is None: - with self._initialization_lock: - if self._grpc_channel_pool is None: - _logger.debug("Creating unshared GrpcChannelPool.") - self._grpc_channel_pool = GrpcChannelPool() - if self._discovery_client is None: - _logger.debug("Creating unshared DiscoveryClient.") - self._discovery_client = DiscoveryClient( - grpc_channel_pool=self._grpc_channel_pool - ) - if self._stub is None: - service_location = self._discovery_client.resolve_service( - provided_interface=GRPC_SERVICE_INTERFACE_NAME, - service_class=GRPC_SERVICE_CLASS, - ) - channel = self._grpc_channel_pool.get_channel(service_location.insecure_address) - self._stub = pin_map_service_pb2_grpc.PinMapServiceStub(channel) - return self._stub - - def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: - """Update registered pin map contents. - - Create and register a pin map if a pin map resource for the specified pin map id is not - found. - - Args: - pin_map_path: The file path of the pin map to register as a pin map resource. - - Returns: - The resource id of the pin map that is registered to the pin map service. - """ - # By convention, the pin map id is the .pinmap file path. - request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( - pin_map_id=str(pin_map_path), - pin_map_xml=pathlib.Path(pin_map_path).read_text(encoding="utf-8"), - ) - response = self._get_stub().UpdatePinMapFromXml(request) - return response.pin_map_id From 4022bd0bcddfd1229ccb8bf1d6f8c43e12e31be8 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 14:38:58 +0530 Subject: [PATCH 03/12] Tests: Import PinMapClient in tests --- packages/service/tests/acceptance/test_nidaqmx_measurement.py | 2 +- packages/service/tests/acceptance/test_nidcpower_measurement.py | 2 +- packages/service/tests/acceptance/test_nidigital_measurement.py | 2 +- packages/service/tests/acceptance/test_nidmm_measurement.py | 2 +- packages/service/tests/acceptance/test_nifgen_measurement.py | 2 +- packages/service/tests/acceptance/test_niscope_measurement.py | 2 +- packages/service/tests/acceptance/test_niswitch_measurement.py | 2 +- .../tests/acceptance/test_niswitch_multiplexer_measurement.py | 2 +- packages/service/tests/acceptance/test_session_management.py | 2 +- packages/service/tests/conftest.py | 2 +- .../integration/session_management/test_nidaqmx_reservation.py | 2 +- .../session_management/test_nidcpower_reservation.py | 2 +- .../session_management/test_nidigital_reservation.py | 2 +- .../integration/session_management/test_nidmm_reservation.py | 2 +- .../integration/session_management/test_nifgen_reservation.py | 2 +- .../integration/session_management/test_niscope_reservation.py | 2 +- .../session_management/test_niswitch_multiplexer_reservation.py | 2 +- .../integration/session_management/test_niswitch_reservation.py | 2 +- .../tests/integration/session_management/test_reservation.py | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/service/tests/acceptance/test_nidaqmx_measurement.py b/packages/service/tests/acceptance/test_nidaqmx_measurement.py index 98938fe19..79bdffe41 100644 --- a/packages/service/tests/acceptance/test_nidaqmx_measurement.py +++ b/packages/service/tests/acceptance/test_nidaqmx_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import nidaqmx_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.nidaqmx.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_nidcpower_measurement.py b/packages/service/tests/acceptance/test_nidcpower_measurement.py index ebffed8ff..86ab5e219 100644 --- a/packages/service/tests/acceptance/test_nidcpower_measurement.py +++ b/packages/service/tests/acceptance/test_nidcpower_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import nidcpower_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.nidcpower.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_nidigital_measurement.py b/packages/service/tests/acceptance/test_nidigital_measurement.py index 7b92fa5d2..1994839df 100644 --- a/packages/service/tests/acceptance/test_nidigital_measurement.py +++ b/packages/service/tests/acceptance/test_nidigital_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import nidigital_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.nidigital.types_pb2 import Configurations, Outputs diff --git a/packages/service/tests/acceptance/test_nidmm_measurement.py b/packages/service/tests/acceptance/test_nidmm_measurement.py index 77bb6b5a8..bb6f12158 100644 --- a/packages/service/tests/acceptance/test_nidmm_measurement.py +++ b/packages/service/tests/acceptance/test_nidmm_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import nidmm_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.nidmm.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_nifgen_measurement.py b/packages/service/tests/acceptance/test_nifgen_measurement.py index a56ba535a..d402896b1 100644 --- a/packages/service/tests/acceptance/test_nifgen_measurement.py +++ b/packages/service/tests/acceptance/test_nifgen_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import nifgen_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.nifgen.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_niscope_measurement.py b/packages/service/tests/acceptance/test_niscope_measurement.py index f05683abf..2dca3c8d2 100644 --- a/packages/service/tests/acceptance/test_niscope_measurement.py +++ b/packages/service/tests/acceptance/test_niscope_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import niscope_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.niscope.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_niswitch_measurement.py b/packages/service/tests/acceptance/test_niswitch_measurement.py index 67a3c1145..746788515 100644 --- a/packages/service/tests/acceptance/test_niswitch_measurement.py +++ b/packages/service/tests/acceptance/test_niswitch_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import niswitch_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.niswitch.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_niswitch_multiplexer_measurement.py b/packages/service/tests/acceptance/test_niswitch_multiplexer_measurement.py index e26f37afb..66f027567 100644 --- a/packages/service/tests/acceptance/test_niswitch_multiplexer_measurement.py +++ b/packages/service/tests/acceptance/test_niswitch_multiplexer_measurement.py @@ -13,8 +13,8 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.measurements import niswitch_multiplexer_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.niswitchmultiplexer.types_pb2 import Configurations, Outputs _SITE = 0 diff --git a/packages/service/tests/acceptance/test_session_management.py b/packages/service/tests/acceptance/test_session_management.py index e63def482..ca679a3e7 100644 --- a/packages/service/tests/acceptance/test_session_management.py +++ b/packages/service/tests/acceptance/test_session_management.py @@ -14,9 +14,9 @@ PinMapContext, ) from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from tests.utilities.discovery_service_process import DiscoveryServiceProcess from tests.utilities.measurements import pin_aware_measurement -from tests.utilities.pin_map_client import PinMapClient from tests.utilities.stubs.pinaware.types_pb2 import Configurations, Outputs diff --git a/packages/service/tests/conftest.py b/packages/service/tests/conftest.py index a18d6cbc5..ef532f8a5 100644 --- a/packages/service/tests/conftest.py +++ b/packages/service/tests/conftest.py @@ -19,13 +19,13 @@ from ni_measurement_plugin_sdk_service.discovery._support import ( _get_registration_json_file_path, ) +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.measurement.service import ( GrpcChannelPool, MeasurementService, ) from ni_measurement_plugin_sdk_service.session_management import SessionManagementClient from tests.utilities.discovery_service_process import DiscoveryServiceProcess -from tests.utilities.pin_map_client import PinMapClient @pytest.fixture(scope="module") diff --git a/packages/service/tests/integration/session_management/test_nidaqmx_reservation.py b/packages/service/tests/integration/session_management/test_nidaqmx_reservation.py index 7dea03ef7..9e9a2bd15 100644 --- a/packages/service/tests/integration/session_management/test_nidaqmx_reservation.py +++ b/packages/service/tests/integration/session_management/test_nidaqmx_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_nidcpower_reservation.py b/packages/service/tests/integration/session_management/test_nidcpower_reservation.py index 2f1e60c90..8d4a9e17c 100644 --- a/packages/service/tests/integration/session_management/test_nidcpower_reservation.py +++ b/packages/service/tests/integration/session_management/test_nidcpower_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_nidigital_reservation.py b/packages/service/tests/integration/session_management/test_nidigital_reservation.py index c45f7d5b2..c99440aea 100644 --- a/packages/service/tests/integration/session_management/test_nidigital_reservation.py +++ b/packages/service/tests/integration/session_management/test_nidigital_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient def test___single_session_reserved___initialize_nidigital_session___creates_single_session( diff --git a/packages/service/tests/integration/session_management/test_nidmm_reservation.py b/packages/service/tests/integration/session_management/test_nidmm_reservation.py index 818fedb75..28795cef7 100644 --- a/packages/service/tests/integration/session_management/test_nidmm_reservation.py +++ b/packages/service/tests/integration/session_management/test_nidmm_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_nifgen_reservation.py b/packages/service/tests/integration/session_management/test_nifgen_reservation.py index 8a39192b2..d2fb003fd 100644 --- a/packages/service/tests/integration/session_management/test_nifgen_reservation.py +++ b/packages/service/tests/integration/session_management/test_nifgen_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_niscope_reservation.py b/packages/service/tests/integration/session_management/test_niscope_reservation.py index 6c6311429..13fc90056 100644 --- a/packages/service/tests/integration/session_management/test_niscope_reservation.py +++ b/packages/service/tests/integration/session_management/test_niscope_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_niswitch_multiplexer_reservation.py b/packages/service/tests/integration/session_management/test_niswitch_multiplexer_reservation.py index a4d745e6b..f3a2fb286 100644 --- a/packages/service/tests/integration/session_management/test_niswitch_multiplexer_reservation.py +++ b/packages/service/tests/integration/session_management/test_niswitch_multiplexer_reservation.py @@ -4,6 +4,7 @@ import niswitch import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, @@ -12,7 +13,6 @@ ConnectionSubset, get_connection_subset_with_multiplexer, ) -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_niswitch_reservation.py b/packages/service/tests/integration/session_management/test_niswitch_reservation.py index fd7c7273f..1e49711db 100644 --- a/packages/service/tests/integration/session_management/test_niswitch_reservation.py +++ b/packages/service/tests/integration/session_management/test_niswitch_reservation.py @@ -3,12 +3,12 @@ import pytest +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( PinMapContext, SessionManagementClient, ) from tests.utilities.connection_subset import ConnectionSubset, get_connection_subset -from tests.utilities.pin_map_client import PinMapClient _SITE = 0 diff --git a/packages/service/tests/integration/session_management/test_reservation.py b/packages/service/tests/integration/session_management/test_reservation.py index 09f5a26ba..19410e1d8 100644 --- a/packages/service/tests/integration/session_management/test_reservation.py +++ b/packages/service/tests/integration/session_management/test_reservation.py @@ -3,6 +3,7 @@ import pathlib from contextlib import ExitStack +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import ( INSTRUMENT_TYPE_NI_DCPOWER, INSTRUMENT_TYPE_NI_RELAY_DRIVER, @@ -15,7 +16,6 @@ get_connection_subset, get_connection_subset_with_multiplexer, ) -from tests.utilities.pin_map_client import PinMapClient _PIN_MAP_A = "PinMapA_3Instruments_3DutPins_2SystemPins_2Sites.pinmap" _PIN_MAP_A_PIN_NAMES = ["A", "B", "C", "S1", "S2"] From 8032546c7a5ce0697f12a660b1d51513138c6546 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 14:39:31 +0530 Subject: [PATCH 04/12] Tests: Add tests for pin map client class --- .../service/tests/acceptance/test_logging.py | 17 ++++ .../pin_map/1Smu1ChannelGroup1Pin1Site.pinmap | 18 +++++ packages/service/tests/unit/conftest.py | 7 ++ .../service/tests/unit/test_pin_map_client.py | 78 +++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 packages/service/tests/assets/unit/pin_map/1Smu1ChannelGroup1Pin1Site.pinmap create mode 100644 packages/service/tests/unit/test_pin_map_client.py diff --git a/packages/service/tests/acceptance/test_logging.py b/packages/service/tests/acceptance/test_logging.py index bc012a493..adcf81309 100644 --- a/packages/service/tests/acceptance/test_logging.py +++ b/packages/service/tests/acceptance/test_logging.py @@ -1,4 +1,5 @@ import logging +import pathlib import re from typing import Generator @@ -12,6 +13,7 @@ ) from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.measurement.service import MeasurementService +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import SessionManagementClient from tests.acceptance.test_streaming_data_measurement import ( _get_configuration_parameters as get_streaming_data_configuration_parameters, @@ -37,6 +39,21 @@ def test___discovery_client___call___client_call_logged( assert f"gRPC client call complete: {method_name}" in debug_messages +def test___pin_map_client___call___client_call_logged( + caplog: LogCaptureFixture, + pin_map_client: PinMapClient, + pin_map_directory: pathlib.Path, +) -> None: + with caplog.at_level(logging.DEBUG): + pin_map_path = pin_map_directory / "1Smu1ChannelGroup2Pin2Site.pinmap" + _ = pin_map_client.update_pin_map(pin_map_path) + + method_name = "/ni.measurementlink.pinmap.v1.PinMapService/UpdatePinMapFromXml" + debug_messages = [r.message for r in caplog.records if r.levelno == logging.DEBUG] + assert f"gRPC client call starting: {method_name}" in debug_messages + assert f"gRPC client call complete: {method_name}" in debug_messages + + def test___session_management_client___call___client_call_logged( caplog: LogCaptureFixture, request: FixtureRequest ) -> None: diff --git a/packages/service/tests/assets/unit/pin_map/1Smu1ChannelGroup1Pin1Site.pinmap b/packages/service/tests/assets/unit/pin_map/1Smu1ChannelGroup1Pin1Site.pinmap new file mode 100644 index 000000000..f16b4fd9e --- /dev/null +++ b/packages/service/tests/assets/unit/pin_map/1Smu1ChannelGroup1Pin1Site.pinmap @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/service/tests/unit/conftest.py b/packages/service/tests/unit/conftest.py index a0e555558..548b9763a 100644 --- a/packages/service/tests/unit/conftest.py +++ b/packages/service/tests/unit/conftest.py @@ -1,5 +1,6 @@ """Test fixtures for unit tests.""" +import pathlib from typing import Generator, cast from unittest.mock import Mock @@ -94,3 +95,9 @@ def session_management_client( def single_session_reservation(mocker: MockerFixture) -> Mock: """Test fixture that creates a mock SingleSessionReservation.""" return mocker.create_autospec(SingleSessionReservation) + + +@pytest.fixture(scope="module") +def pin_map_directory(test_assets_directory: pathlib.Path) -> pathlib.Path: + """Test fixture that returns the pin map directory.""" + return test_assets_directory / "unit" / "pin_map" diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py new file mode 100644 index 000000000..db7eb16ad --- /dev/null +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -0,0 +1,78 @@ +"""Contains tests to validate the pin_map_client.py. +""" + +import pathlib +from typing import cast +from unittest.mock import Mock + +import grpc +import pytest +from pytest_mock import MockerFixture + +from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1.pin_map_service_pb2 import ( + PinMap, + UpdatePinMapFromXmlRequest, +) +from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1.pin_map_service_pb2_grpc import PinMapServiceStub +from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient +from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool +from ni_measurement_plugin_sdk_service.pin_map._client import PinMapClient + + +def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( + pin_map_client: PinMapClient, + pin_map_stub: Mock, + pin_map_directory: pathlib.Path, +) -> None: + pin_map_path = str(pin_map_directory / "1Smu1ChannelGroup1Pin1Site.pinmap") + pin_map_stub.UpdatePinMapFromXml.return_value = PinMap(pin_map_id=pin_map_path) + + registered_pin_map_id = pin_map_client.update_pin_map(pin_map_path) + + pin_map_stub.UpdatePinMapFromXml.assert_called_once() + request: UpdatePinMapFromXmlRequest = pin_map_stub.UpdatePinMapFromXml.call_args.args[0] + assert request.pin_map_id == pin_map_path + assert request.pin_map_xml == _read_pin_map_file(pin_map_path) + assert registered_pin_map_id == pin_map_path + + +def test__invalid_pin_map_file_path__register_pin_map___raises_file_not_found_error( + pin_map_client: PinMapClient +) -> None: + pin_map_path = "InvalidPinmap.pinmap" + + with pytest.raises(FileNotFoundError): + _ = pin_map_client.update_pin_map(pin_map_path) + + +def _read_pin_map_file(pin_map_path: str) -> str: + with open(pin_map_path, "r", encoding="utf-8-sig") as file: + xml_content = file.read() + return xml_content + + +@pytest.fixture +def pin_map_client( + discovery_client: Mock, + grpc_channel_pool: Mock, + mocker: MockerFixture, + pin_map_stub: Mock, +) -> PinMapClient: + """Create a Client with a mock PinMapServiceStub.""" + mocker.patch( + "ni_measurement_plugin_sdk_service.pin_map.PinMapClient._get_stub", + return_value=pin_map_stub, + ) + client = PinMapClient( + discovery_client=cast(DiscoveryClient, discovery_client), + grpc_channel_pool=cast(GrpcChannelPool, grpc_channel_pool), + ) + return client + + +@pytest.fixture +def pin_map_stub(mocker: MockerFixture) -> Mock: + """Create a mock PinMapServiceStub.""" + stub = mocker.create_autospec(PinMapServiceStub) + stub.UpdatePinMapFromXml = mocker.create_autospec(grpc.UnaryUnaryMultiCallable) + return stub \ No newline at end of file From 60e8380247e8a60e63927f8343b04e100b29fce5 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 14:49:25 +0530 Subject: [PATCH 05/12] Fix: Lint errors --- .../pin_map/_client.py | 8 ++++---- .../service/tests/acceptance/test_logging.py | 4 ++-- packages/service/tests/conftest.py | 2 +- .../service/tests/unit/test_pin_map_client.py | 16 +++++++++------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py index d2185687b..9ea531d16 100644 --- a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -31,14 +31,14 @@ def __init__( grpc_channel_pool: Optional[GrpcChannelPool] = None ) -> None: """Initialize the pin map client. - + Args: discovery_client: An optional discovery client (recommended). grpc_channel: An optional session management gRPC channel. - grpc_channel_pool: An optional gRPC channel pool (recommended). - """ + grpc_channel_pool: An optional gRPC channel pool (recommended). + """ self._initialization_lock = threading.Lock() self._discovery_client = discovery_client self._grpc_channel_pool = grpc_channel_pool @@ -85,6 +85,6 @@ def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( pin_map_id=str(pin_map_path), pin_map_xml=xml_content ) - + response = self._get_stub().UpdatePinMapFromXml(request) return response.pin_map_id diff --git a/packages/service/tests/acceptance/test_logging.py b/packages/service/tests/acceptance/test_logging.py index adcf81309..ec5745160 100644 --- a/packages/service/tests/acceptance/test_logging.py +++ b/packages/service/tests/acceptance/test_logging.py @@ -40,8 +40,8 @@ def test___discovery_client___call___client_call_logged( def test___pin_map_client___call___client_call_logged( - caplog: LogCaptureFixture, - pin_map_client: PinMapClient, + caplog: LogCaptureFixture, + pin_map_client: PinMapClient, pin_map_directory: pathlib.Path, ) -> None: with caplog.at_level(logging.DEBUG): diff --git a/packages/service/tests/conftest.py b/packages/service/tests/conftest.py index ef532f8a5..f0a91228f 100644 --- a/packages/service/tests/conftest.py +++ b/packages/service/tests/conftest.py @@ -19,11 +19,11 @@ from ni_measurement_plugin_sdk_service.discovery._support import ( _get_registration_json_file_path, ) -from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.measurement.service import ( GrpcChannelPool, MeasurementService, ) +from ni_measurement_plugin_sdk_service.pin_map import PinMapClient from ni_measurement_plugin_sdk_service.session_management import SessionManagementClient from tests.utilities.discovery_service_process import DiscoveryServiceProcess diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index db7eb16ad..5b5bfa5ed 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -13,14 +13,16 @@ PinMap, UpdatePinMapFromXmlRequest, ) -from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1.pin_map_service_pb2_grpc import PinMapServiceStub +from ni_measurement_plugin_sdk_service._internal.stubs.ni.measurementlink.pinmap.v1.pin_map_service_pb2_grpc import ( + PinMapServiceStub, +) from ni_measurement_plugin_sdk_service.discovery import DiscoveryClient from ni_measurement_plugin_sdk_service.grpc.channelpool import GrpcChannelPool from ni_measurement_plugin_sdk_service.pin_map._client import PinMapClient def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( - pin_map_client: PinMapClient, + pin_map_client: PinMapClient, pin_map_stub: Mock, pin_map_directory: pathlib.Path, ) -> None: @@ -37,7 +39,7 @@ def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( def test__invalid_pin_map_file_path__register_pin_map___raises_file_not_found_error( - pin_map_client: PinMapClient + pin_map_client: PinMapClient, ) -> None: pin_map_path = "InvalidPinmap.pinmap" @@ -46,9 +48,9 @@ def test__invalid_pin_map_file_path__register_pin_map___raises_file_not_found_er def _read_pin_map_file(pin_map_path: str) -> str: - with open(pin_map_path, "r", encoding="utf-8-sig") as file: - xml_content = file.read() - return xml_content + with open(pin_map_path, "r", encoding="utf-8-sig") as file: + xml_content = file.read() + return xml_content @pytest.fixture @@ -75,4 +77,4 @@ def pin_map_stub(mocker: MockerFixture) -> Mock: """Create a mock PinMapServiceStub.""" stub = mocker.create_autospec(PinMapServiceStub) stub.UpdatePinMapFromXml = mocker.create_autospec(grpc.UnaryUnaryMultiCallable) - return stub \ No newline at end of file + return stub From f4071abf62158aa8fa33240b86da1a25af6af0c0 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Thu, 29 Aug 2024 15:47:30 +0530 Subject: [PATCH 06/12] Refractor: Method name changes and spacing --- .../ni_measurement_plugin_sdk_service/pin_map/_client.py | 1 - packages/service/tests/unit/test_pin_map_client.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py index 9ea531d16..efc703f3f 100644 --- a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -85,6 +85,5 @@ def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( pin_map_id=str(pin_map_path), pin_map_xml=xml_content ) - response = self._get_stub().UpdatePinMapFromXml(request) return response.pin_map_id diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index 5b5bfa5ed..9f5fa1c5b 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -34,7 +34,7 @@ def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( pin_map_stub.UpdatePinMapFromXml.assert_called_once() request: UpdatePinMapFromXmlRequest = pin_map_stub.UpdatePinMapFromXml.call_args.args[0] assert request.pin_map_id == pin_map_path - assert request.pin_map_xml == _read_pin_map_file(pin_map_path) + assert request.pin_map_xml == _get_pin_map_file_contents(pin_map_path) assert registered_pin_map_id == pin_map_path @@ -47,7 +47,7 @@ def test__invalid_pin_map_file_path__register_pin_map___raises_file_not_found_er _ = pin_map_client.update_pin_map(pin_map_path) -def _read_pin_map_file(pin_map_path: str) -> str: +def _get_pin_map_file_contents(pin_map_path: str) -> str: with open(pin_map_path, "r", encoding="utf-8-sig") as file: xml_content = file.read() return xml_content From d35015a0b4a29e9ff5291761c1edb2dbbc0b2ced Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 11:56:26 +0530 Subject: [PATCH 07/12] Tests: Test name changes in test_pin_map_client.py --- packages/service/tests/unit/test_pin_map_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index 9f5fa1c5b..f12ebd952 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -21,7 +21,7 @@ from ni_measurement_plugin_sdk_service.pin_map._client import PinMapClient -def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( +def test___valid_pin_map_file___register_pin_map___returns_pin_map_id( pin_map_client: PinMapClient, pin_map_stub: Mock, pin_map_directory: pathlib.Path, @@ -38,7 +38,7 @@ def test__valid_pin_map_file__register_pin_map___sends_request_and_returns_id( assert registered_pin_map_id == pin_map_path -def test__invalid_pin_map_file_path__register_pin_map___raises_file_not_found_error( +def test___invalid_pin_map_file_path___register_pin_map___raises_file_not_found_error( pin_map_client: PinMapClient, ) -> None: pin_map_path = "InvalidPinmap.pinmap" From 13c551b609cbe8432eff3a133770ae2c702569b3 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 11:57:48 +0530 Subject: [PATCH 08/12] Fix: Docstrings correction --- .../ni_measurement_plugin_sdk_service/pin_map/_client.py | 2 +- packages/service/tests/unit/test_pin_map_client.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py index efc703f3f..5eb177047 100644 --- a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -35,7 +35,7 @@ def __init__( Args: discovery_client: An optional discovery client (recommended). - grpc_channel: An optional session management gRPC channel. + grpc_channel: An optional pin map gRPC channel. grpc_channel_pool: An optional gRPC channel pool (recommended). """ diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index f12ebd952..762f85a2e 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -41,7 +41,7 @@ def test___valid_pin_map_file___register_pin_map___returns_pin_map_id( def test___invalid_pin_map_file_path___register_pin_map___raises_file_not_found_error( pin_map_client: PinMapClient, ) -> None: - pin_map_path = "InvalidPinmap.pinmap" + pin_map_path = "InvalidPinMap.pinmap" with pytest.raises(FileNotFoundError): _ = pin_map_client.update_pin_map(pin_map_path) From 5da74bd04f590631e35905111d64800c5e5f334d Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 12:06:32 +0530 Subject: [PATCH 09/12] Client: Use read_text for reading pinmaps --- .../ni_measurement_plugin_sdk_service/pin_map/_client.py | 5 ++--- packages/service/tests/unit/test_pin_map_client.py | 6 ++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py index 5eb177047..0f4590880 100644 --- a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -80,10 +80,9 @@ def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: The resource id of the pin map that is registered to the pin map service. """ # By convention, the pin map id is the .pinmap file path. - with open(pin_map_path, "r", encoding="utf-8-sig") as file: - xml_content = file.read() request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( - pin_map_id=str(pin_map_path), pin_map_xml=xml_content + pin_map_id=str(pin_map_path), + pin_map_xml=pathlib.Path(pin_map_path).read_text(encoding="utf-8-sig"), ) response = self._get_stub().UpdatePinMapFromXml(request) return response.pin_map_id diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index 762f85a2e..4a177866a 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -26,7 +26,7 @@ def test___valid_pin_map_file___register_pin_map___returns_pin_map_id( pin_map_stub: Mock, pin_map_directory: pathlib.Path, ) -> None: - pin_map_path = str(pin_map_directory / "1Smu1ChannelGroup1Pin1Site.pinmap") + pin_map_path = "D:\\measurement-plugin-python\\examples\\nidcpower_source_dc_voltage\\NIDCPowerSourceDCVoltage.pinmap" pin_map_stub.UpdatePinMapFromXml.return_value = PinMap(pin_map_id=pin_map_path) registered_pin_map_id = pin_map_client.update_pin_map(pin_map_path) @@ -48,9 +48,7 @@ def test___invalid_pin_map_file_path___register_pin_map___raises_file_not_found_ def _get_pin_map_file_contents(pin_map_path: str) -> str: - with open(pin_map_path, "r", encoding="utf-8-sig") as file: - xml_content = file.read() - return xml_content + return pathlib.Path(pin_map_path).read_text(encoding="utf-8-sig") @pytest.fixture From 1593d75790d967d74a3e30bf5a24b06c5cdfadf4 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 12:08:08 +0530 Subject: [PATCH 10/12] Revert: Harcoded path --- packages/service/tests/unit/test_pin_map_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/service/tests/unit/test_pin_map_client.py b/packages/service/tests/unit/test_pin_map_client.py index 4a177866a..9555b58c8 100644 --- a/packages/service/tests/unit/test_pin_map_client.py +++ b/packages/service/tests/unit/test_pin_map_client.py @@ -26,7 +26,7 @@ def test___valid_pin_map_file___register_pin_map___returns_pin_map_id( pin_map_stub: Mock, pin_map_directory: pathlib.Path, ) -> None: - pin_map_path = "D:\\measurement-plugin-python\\examples\\nidcpower_source_dc_voltage\\NIDCPowerSourceDCVoltage.pinmap" + pin_map_path = str(pin_map_directory / "1Smu1ChannelGroup1Pin1Site.pinmap") pin_map_stub.UpdatePinMapFromXml.return_value = PinMap(pin_map_id=pin_map_path) registered_pin_map_id = pin_map_client.update_pin_map(pin_map_path) From 7dd3f311c9eb732a9084dc01a2dcb9e8bb3b591f Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 12:09:06 +0530 Subject: [PATCH 11/12] Tests: Update the scope of pin_map_directory to function --- packages/service/tests/unit/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/service/tests/unit/conftest.py b/packages/service/tests/unit/conftest.py index 548b9763a..2456b4da9 100644 --- a/packages/service/tests/unit/conftest.py +++ b/packages/service/tests/unit/conftest.py @@ -97,7 +97,7 @@ def single_session_reservation(mocker: MockerFixture) -> Mock: return mocker.create_autospec(SingleSessionReservation) -@pytest.fixture(scope="module") +@pytest.fixture def pin_map_directory(test_assets_directory: pathlib.Path) -> pathlib.Path: """Test fixture that returns the pin map directory.""" return test_assets_directory / "unit" / "pin_map" From 53e16f1a6934291940b8448b0f82e05fba1ff7a8 Mon Sep 17 00:00:00 2001 From: Mounika Battu Date: Fri, 30 Aug 2024 12:19:07 +0530 Subject: [PATCH 12/12] Fix: Lint errors --- .../ni_measurement_plugin_sdk_service/pin_map/_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py index 0f4590880..6f964e776 100644 --- a/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py +++ b/packages/service/ni_measurement_plugin_sdk_service/pin_map/_client.py @@ -82,7 +82,7 @@ def update_pin_map(self, pin_map_path: Union[str, pathlib.Path]) -> str: # By convention, the pin map id is the .pinmap file path. request = pin_map_service_pb2.UpdatePinMapFromXmlRequest( pin_map_id=str(pin_map_path), - pin_map_xml=pathlib.Path(pin_map_path).read_text(encoding="utf-8-sig"), + pin_map_xml=pathlib.Path(pin_map_path).read_text(encoding="utf-8-sig"), ) response = self._get_stub().UpdatePinMapFromXml(request) return response.pin_map_id