diff --git a/sapient_apex_server/translator/proto_to_proto_translator.py b/sapient_apex_server/translator/proto_to_proto_translator.py index 609d2a1..f93c5af 100644 --- a/sapient_apex_server/translator/proto_to_proto_translator.py +++ b/sapient_apex_server/translator/proto_to_proto_translator.py @@ -166,13 +166,42 @@ def _registration_translate_v2_to_v1(message_dict: dict) -> bool: # value back from CommandType enum instead mode_definitions = registration_dict.get("mode_definition", []) + v2_only_command_types = { + "COMMAND_TYPE_MOVE_TO", + "COMMAND_TYPE_PATROL", + "COMMAND_TYPE_FOLLOW", + } + v2_only_region_types = { + "REGION_TYPE_MOBILE_NODE_NO_GO_AREA", + "REGION_TYPE_MOBILE_NODE_GO_AREA", + } + for mode_definition in mode_definitions: _convert_repeated_to_single(mode_definition, "detection_definition") _convert_single_to_repeated(mode_definition, "task") + # Extensible taxonomy docking was introduced in V2 and has no V1 representation. + detection_definition = mode_definition.get("detection_definition", {}) + detection_classes = detection_definition.get("detection_class_definition", []) + for detection_class in detection_classes: + _remove_fields(detection_class, ["taxonomy_dock_definition"]) + tasks = mode_definition.get("task", []) for task in tasks: + region_definition = task.get("region_definition", {}) + region_types = region_definition.get("region_type", []) + region_types[:] = [ + region_type + for region_type in region_types + if region_type not in v2_only_region_types + ] + commands = task.get("command", []) + # Mobile-node commands were introduced in V2. Drop these capability declarations + # when downgrading because the V1 command enum cannot represent them. + commands[:] = [ + command for command in commands if command.get("type") not in v2_only_command_types + ] for command in commands: if "type" in command: # Get the string representation of the type enum diff --git a/tests/test_proto_to_proto_translator.py b/tests/test_proto_to_proto_translator.py new file mode 100644 index 0000000..459499b --- /dev/null +++ b/tests/test_proto_to_proto_translator.py @@ -0,0 +1,67 @@ +# +# Copyright (c) 2019-2024 Roke Manor Research Ltd +# + +from google.protobuf.json_format import MessageToDict, ParseDict + +from sapient_apex_server.translator.proto_to_proto_translator import translate_v2_to_v1 +from sapient_msg.bsi_flex_335_v2_0.sapient_message_pb2 import SapientMessage + + +def test_v2_registration_downgrade_omits_v2_only_taxonomy_and_commands(): + message = ParseDict( + { + "registration": { + "icd_version": "BSI Flex 335 v2.0", + "mode_definition": [ + { + "detection_definition": [ + { + "detection_class_definition": [ + { + "taxonomy_dock_definition": [ + { + "Dock_class_namespace": "sapient_core", + "Dock_class": "Land Vehicle.2 Wheels.Other", + } + ] + } + ] + } + ], + "task": { + "region_definition": { + "region_type": [ + "REGION_TYPE_AREA_OF_INTEREST", + "REGION_TYPE_MOBILE_NODE_NO_GO_AREA", + "REGION_TYPE_MOBILE_NODE_GO_AREA", + ] + }, + "command": [ + {"type": "COMMAND_TYPE_MOVE_TO"}, + {"type": "COMMAND_TYPE_PATROL"}, + {"type": "COMMAND_TYPE_FOLLOW"}, + {"type": "COMMAND_TYPE_LOOK_AT"}, + ] + }, + } + ], + } + }, + SapientMessage(), + ) + + downgraded = translate_v2_to_v1(message) + registration = MessageToDict(downgraded, preserving_proto_field_name=True)["registration"] + + assert registration["icd_version"] == "BSI Flex 335 v1.0" + detection_definition = registration["mode_definition"][0]["detection_definition"] + detection_class = detection_definition["detection_class_definition"][0] + assert "taxonomy_dock_definition" not in detection_class + + task = registration["mode_definition"][0]["task"][0] + assert task["region_definition"]["region_type"] == ["REGION_TYPE_AREA_OF_INTEREST"] + + commands = task["command"] + assert [command["type"] for command in commands] == ["COMMAND_TYPE_LOOK_AT"] + assert commands[0]["name"] == "LookAt"