Ejemplo n.º 1
0
class TestCentralRoleProvider:
    _roles = [
        central_models.RolePreview(role)
        for role in load_json(FileNames.central_role_file)
    ]

    @mock.patch("azext_iot.central.services.role")
    def test_should_return_roles(self, mock_role_svc):

        # setup
        provider = CentralRoleProviderPreview(cmd=None, app_id=app_id)
        mock_role_svc.list_roles.return_value = self._roles

        # act
        roles = provider.list_roles()
        # verify
        # call counts should be at most 1 since the provider has a cache
        assert mock_role_svc.list_roles.call_count == 1
        assert set(roles) == set(map(lambda x: x.id, self._roles))

    @mock.patch("azext_iot.central.services.role")
    def test_should_return_role(self, mock_role_svc):
        # setup
        provider = CentralRoleProviderPreview(cmd=None, app_id=app_id)
        mock_role_svc.get_role.return_value = self._roles[0]

        # act
        role = provider.get_role(self._roles[0].id)
        # verify
        # call counts should be at most 1 since the provider has a cache
        assert mock_role_svc.get_role.call_count == 1
        assert role.id == self._roles[0].id
class TestCentralDeviceProvider:
    _device = load_json(FileNames.central_device_file)
    _device_template = load_json(FileNames.central_device_template_file)

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_should_return_device(self, mock_device_svc, mock_device_template_svc):
        # setup
        provider = CentralDeviceProvider(cmd=None, app_id=app_id)
        mock_device_svc.get_device.return_value = self._device
        mock_device_template_svc.get_device_template.return_value = (
            self._device_template
        )

        # act
        device = provider.get_device("someDeviceId")
        # check that caching is working
        device = provider.get_device("someDeviceId")

        # verify
        # call counts should be at most 1 since the provider has a cache
        assert mock_device_svc.get_device.call_count == 1
        assert mock_device_svc.get_device_template.call_count == 0
        assert device == self._device

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_should_return_device_template(
        self, mock_device_svc, mock_device_template_svc
    ):
        # setup
        provider = CentralDeviceTemplateProvider(cmd=None, app_id=app_id)
        mock_device_svc.get_device.return_value = self._device
        mock_device_template_svc.get_device_template.return_value = (
            self._device_template
        )

        # act
        template = provider.get_device_template("someDeviceTemplate")
        # check that caching is working
        template = provider.get_device_template("someDeviceTemplate")

        # verify
        # call counts should be at most 1 since the provider has a cache
        assert mock_device_template_svc.get_device_template.call_count == 1
        assert template == self._device_template
    def test_template_component_list(self):
        expected_component_list = [
            "_rpgcmdpo",
            "RS40OccupancySensorV36fy",
        ]
        template = Template(
            load_json(FileNames.central_property_validation_template_file))

        assert collections.Counter(
            template.components.keys()) == collections.Counter(
                expected_component_list)
 def test_extract_schema_type_component(self):
     expected_mapping = {
         "component1Prop": "boolean",
         "testComponent": "boolean",
         "component1PropReadonly": "boolean",
         "component1Prop2": "boolean",
     }
     template = Template(
         load_json(FileNames.central_property_validation_template_file))
     for key, val in expected_mapping.items():
         schema = template.get_schema(key, is_component=True)
         schema_type = extract_schema_type(schema)
         assert schema_type == val
    def test_template_interface_list(self):
        expected_interface_list = [
            "urn:sampleApp:groupOne_bz:_rpgcmdpo:1",
            "urn:sampleApp:groupTwo_bz:myxqftpsr:2",
            "urn:sampleApp:groupThree_bz:myxqftpsr:2",
            "urn:sampleApp:groupOne_bz:2",
        ]
        template = Template(
            load_json(FileNames.central_property_validation_template_file))

        assert collections.Counter(
            template.interfaces.keys()) == collections.Counter(
                expected_interface_list)
Ejemplo n.º 6
0
    def test_validate_invalid_telmetry_component_template_should_fail(self):
        # setup
        device_template = central_models.TemplateV1(
            load_json(FileNames.central_property_validation_template_file))

        properties = MessageProperties(content_encoding=self.encoding,
                                       content_type=self.content_type)
        message = Message(
            body=json.dumps(self.bad_dcm_payload).encode(),
            properties=properties,
            annotations={
                common_parser.DEVICE_ID_IDENTIFIER:
                self.device_id.encode(),
                common_parser.COMPONENT_NAME_IDENTIFIER:
                list(device_template.components.keys())[1].encode(),
            },
            application_properties=_encode_app_props(self.app_properties),
        )
        args = CommonParserArguments(properties=["all"])
        parser = self._create_parser(device_template=device_template,
                                     message=message,
                                     args=args)

        # act
        parsed_msg = parser.parse_message()

        # verify
        assert parsed_msg["event"]["payload"] == self.bad_dcm_payload
        assert parsed_msg["event"]["origin"] == self.device_id
        device_identifier = str(common_parser.DEVICE_ID_IDENTIFIER, "utf8")
        assert parsed_msg["event"]["annotations"][
            device_identifier] == self.device_id
        component_identifier = str(common_parser.COMPONENT_NAME_IDENTIFIER,
                                   "utf8")
        assert (
            parsed_msg["event"]["annotations"][component_identifier] == list(
                device_template.components.keys())[1])
        properties = parsed_msg["event"]["properties"]
        assert properties["system"]["content_encoding"] == self.encoding
        assert properties["system"]["content_type"] == self.content_type
        assert properties["application"] == self.app_properties

        expected_details = strings.invalid_field_name_component_mismatch_template(
            list(self.bad_dcm_payload.keys()),
            device_template.component_schema_names,
        )

        _validate_issues(parser, Severity.warning, 1, 1, [expected_details])
Ejemplo n.º 7
0
 def test_extract_schema_type_component_identifier(self):
     expected_mapping = {
         "component2prop": "boolean",
         "component2Prop2": "boolean",
         "testComponent": "boolean",
         "component2PropReadonly": "boolean",
     }
     template = central_models.TemplateV1(
         load_json(FileNames.central_property_validation_template_file)
     )
     for key, val in expected_mapping.items():
         schema = template.get_schema(
             key, is_component=True, identifier="RS40OccupancySensorV36fy"
         )
         schema_type = extract_schema_type(schema)
         assert schema_type == val
Ejemplo n.º 8
0
class TestCentralDeviceGroupProvider:
    _device_groups = [
        central_models.DeviceGroupPreview(group)
        for group in load_json(FileNames.central_device_group_file)
    ]

    @mock.patch("azext_iot.central.services.device_group")
    def test_should_return_device_groups(self, mock_device_group_svc):

        # setup
        provider = CentralDeviceGroupProviderPreview(cmd=None, app_id=app_id)
        mock_device_group_svc.list_device_groups.return_value = self._device_groups

        # act
        device_groups = provider.list_device_groups()
        # verify
        # call counts should be at most 1 since the provider has a cache
        assert mock_device_group_svc.list_device_groups.call_count == 1
        assert set(device_groups) == set(
            map(lambda x: x.id, self._device_groups))
 def test_extract_schema_type(self):
     expected_mapping = {
         "Bool": "boolean",
         "Date": "date",
         "DateTime": "dateTime",
         "Double": "double",
         "Duration": "duration",
         "IntEnum": "Enum",
         "StringEnum": "Enum",
         "Float": "float",
         "Geopoint": "geopoint",
         "Long": "long",
         "Object": "Object",
         "String": "string",
         "Time": "time",
         "Vector": "vector",
     }
     template = Template(load_json(FileNames.central_device_template_file))
     for key, val in expected_mapping.items():
         schema = template.get_schema(key)
         schema_type = extract_schema_type(schema)
         assert schema_type == val
 def test_object_deep(self, value, expected_result):
     template = Template(
         load_json(FileNames.central_deeply_nested_device_template_file))
     schema = template.get_schema("RidiculousObject")
     assert validate(schema, value) == expected_result
 def test_str_enum(self, value, expected_result):
     template = Template(load_json(FileNames.central_device_template_file))
     schema = template.get_schema("StringEnum")
     assert validate(schema, value) == expected_result
class TestCentralPropertyMonitor:
    _device_twin = load_json(FileNames.central_device_twin_file)
    _duplicate_property_template = load_json(
        FileNames.central_property_validation_template_file
    )

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_should_return_updated_properties(
        self, mock_device_svc, mock_device_template_svc
    ):
        # setup
        device_twin_data = json.dumps(self._device_twin)
        raw_twin = ast.literal_eval(
            device_twin_data.replace("current_time", datetime.now().isoformat())
        )

        twin = DeviceTwin(raw_twin)
        twin_next = DeviceTwin(raw_twin)
        twin_next.reported_property.version = twin.reported_property.version + 1
        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )
        result = monitor._compare_properties(
            twin_next.reported_property, twin.reported_property
        )
        assert len(result) == 3
        assert len(result["$iotin:urn_azureiot_Client_SDKInformation"]) == 3
        assert result["$iotin:urn_azureiot_Client_SDKInformation"]["language"]
        assert result["$iotin:urn_azureiot_Client_SDKInformation"]["version"]
        assert result["$iotin:urn_azureiot_Client_SDKInformation"]["vendor"]

        assert len(result["$iotin:deviceinfo"]) == 8
        assert result["$iotin:deviceinfo"]["manufacturer"]
        assert result["$iotin:deviceinfo"]["model"]
        assert result["$iotin:deviceinfo"]["osName"]
        assert result["$iotin:deviceinfo"]["processorArchitecture"]
        assert result["$iotin:deviceinfo"]["swVersion"]
        assert result["$iotin:deviceinfo"]["processorManufacturer"]
        assert result["$iotin:deviceinfo"]["totalStorage"]
        assert result["$iotin:deviceinfo"]["totalMemory"]

        assert len(result["$iotin:settings"]) == 1
        assert result["$iotin:settings"]["fanSpeed"]

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_should_return_no_properties(
        self, mock_device_svc, mock_device_template_svc
    ):
        # test to check that no property updates are reported when version is not upadted
        # setup
        device_twin_data = json.dumps(self._device_twin)
        raw_twin = ast.literal_eval(
            device_twin_data.replace("current_time", datetime.now().isoformat())
        )
        twin = DeviceTwin(raw_twin)
        twin_next = DeviceTwin(raw_twin)
        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )
        result = monitor._compare_properties(
            twin_next.reported_property, twin.reported_property
        )
        assert result is None

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_validate_properties_declared_multiple_interfaces(
        self, mock_device_svc, mock_device_template_svc
    ):

        # setup
        mock_device_template_svc.get_device_template.return_value = Template(
            self._duplicate_property_template
        )

        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )

        model = {"Model": "test_model"}

        issues = monitor._validate_payload_against_entities(
            model, list(model.keys())[0], Severity.warning,
        )

        assert (
            issues[0].details == "Duplicate property: 'Model' found under following "
            "interfaces ['urn:sampleApp:groupOne_bz:_rpgcmdpo:1', 'urn:sampleApp:groupTwo_bz:myxqftpsr:2', "
            "'urn:sampleApp:groupThree_bz:myxqftpsr:2'] "
            "in the device model. Either provide the interface name as part "
            "of the device payload or make the propery name unique in the device model"
        )

        version = {"OsName": "test_osName"}

        issues = monitor._validate_payload_against_entities(
            version, list(version.keys())[0], Severity.warning,
        )

        assert len(issues) == 0

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_validate_properties_name_miss_under_interface(
        self, mock_device_svc, mock_device_template_svc
    ):

        # setup
        mock_device_template_svc.get_device_template.return_value = Template(
            self._duplicate_property_template
        )

        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )

        # invalid interface / property
        definition = {"definition": "test_definition"}

        issues = monitor._validate_payload_against_entities(
            definition, list(definition.keys())[0], Severity.warning,
        )

        assert (
            issues[0].details
            == "Device is sending data that has not been defined in the device template."
            " Following capabilities have NOT been defined in the device template '['definition']'."
            " Following capabilities have been defined in the device template (grouped by interface)"
            " '{'urn:sampleApp:groupOne_bz:2': ['addRootProperty', 'addRootPropertyReadOnly', 'addRootProperty2'],"
            " 'urn:sampleApp:groupOne_bz:_rpgcmdpo:1': ['Model', 'Version', 'TotalStorage'],"
            " 'urn:sampleApp:groupTwo_bz:myxqftpsr:2': ['Model', 'Manufacturer'],"
            " 'urn:sampleApp:groupThree_bz:myxqftpsr:2': ['Manufacturer', 'Version', 'Model', 'OsName']}'. "
        )

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_validate_properties_severity_level(
        self, mock_device_svc, mock_device_template_svc
    ):

        # setup
        mock_device_template_svc.get_device_template.return_value = Template(
            self._duplicate_property_template
        )

        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )

        # severity level info
        definition = {"definition": "test_definition"}

        issues = monitor._validate_payload_against_entities(
            definition, list(definition.keys())[0], Severity.info,
        )

        assert (
            issues[0].details
            == "Device is sending data that has not been defined in the device template. "
            "Following capabilities have NOT been defined in the device template "
            "'['definition']'. Following capabilities have been defined in the device template "
            "(grouped by interface) '{'urn:sampleApp:groupOne_bz:2': "
            "['addRootProperty', 'addRootPropertyReadOnly', 'addRootProperty2'], "
            "'urn:sampleApp:groupOne_bz:_rpgcmdpo:1': ['Model', 'Version', 'TotalStorage'], "
            "'urn:sampleApp:groupTwo_bz:myxqftpsr:2': ['Model', 'Manufacturer'], "
            "'urn:sampleApp:groupThree_bz:myxqftpsr:2': ['Manufacturer', 'Version', 'Model', 'OsName']}'. "
        )

        # severity level error
        issues = monitor._validate_payload_against_entities(
            definition, list(definition.keys())[0], Severity.error,
        )

        assert len(issues) == 0

    @mock.patch("azext_iot.central.services.device_template")
    @mock.patch("azext_iot.central.services.device")
    def test_validate_properties_name_miss_under_component(
        self, mock_device_svc, mock_device_template_svc
    ):

        # setup
        mock_device_template_svc.get_device_template.return_value = Template(
            self._duplicate_property_template
        )

        monitor = PropertyMonitor(
            cmd=None,
            app_id=app_id,
            device_id=device_id,
            token=None,
            central_dns_suffix=None,
        )

        # invalid component property
        definition = {
            PNP_DTDLV2_COMPONENT_MARKER: "c",
            "data": {"definition": "test_definition"},
        }

        issues = monitor._validate_payload_against_entities(
            definition, list(definition.keys())[0], Severity.warning,
        )

        assert (
            issues[0].details
            == "Device is sending data that has not been defined in the device template. "
            "Following capabilities have NOT been defined in the device template '['data']'. "
            "Following capabilities have been defined in the device template (grouped by components) "
            "'{'_rpgcmdpo': ['component1Prop', 'testComponent', 'component1PropReadonly', 'component1Prop2'], "
            "'RS40OccupancySensorV36fy': ['component2prop', 'testComponent', 'component2PropReadonly', "
            "'component2Prop2', 'component1Telemetry']}'. "
        )
Ejemplo n.º 13
0
 def _get_template(self):
     return central_models.TemplateV1(
         load_json(FileNames.central_device_template_file))
Ejemplo n.º 14
0
 def _get_template(self):
     return Template(load_json(FileNames.central_device_template_file))
Ejemplo n.º 15
0
 def test_object_simple(self, value, expected_result):
     template = central_models.TemplateV1(
         load_json(FileNames.central_device_template_file)
     )
     schema = template.get_schema("Object")
     assert validate(schema, value) == expected_result