Esempio n. 1
0
def generate_valid_cs(validate_pairs=[]):
    host_name = generate_generic_id()
    shared_access_key = generate_generic_id()
    cs = f"HostName={host_name};"
    input_pairs = dict((k, generate_generic_id()) for k in validate_pairs)
    policy = input_pairs["SharedAccessKeyName"] if "SharedAccessKeyName" in input_pairs else None

    for key, value in input_pairs.items():
        cs += "{}={};".format(
            key, value
        )

    cs = f"{cs}SharedAccessKey={shared_access_key}"
    uri = host_name
    if "DeviceId" in input_pairs:
        uri = f"{uri}/devices/{input_pairs['DeviceId']}"
    if "ModuleId" in input_pairs:
        uri = f"{uri}/modules/{input_pairs['ModuleId']}"

    return {
        "connection_string": cs,
        "uri": uri,
        "policy": policy,
        "key": shared_access_key
    }
Esempio n. 2
0
def generate_twin_result(randomized=False):
    return {
        "$dtId": generate_generic_id() if randomized else twin_id,
        "$etag": generate_generic_id() if randomized else etag,
        "$metadata": {
            "$model": generate_generic_id() if randomized else model_id
        }
    }
Esempio n. 3
0
class TestConfigDelete:
    @pytest.fixture(params=[204])
    def serviceclient(self, mocker, fixture_ghcs, fixture_sas, request):
        service_client = mocker.patch(path_service_client)
        side_effect = [
            build_mock_response(mocker, request.param),
        ]
        service_client.side_effect = side_effect
        return service_client

    @pytest.mark.parametrize(
        "etag",
        [generate_generic_id(), None],
    )
    def test_config_delete(self, serviceclient, fixture_cmd, etag):
        subject.iot_hub_configuration_delete(fixture_cmd,
                                             config_id=config_id,
                                             hub_name=mock_target["entity"],
                                             etag=etag)
        args = serviceclient.call_args
        url = args[0][0].url
        method = args[0][0].method
        headers = args[0][0].headers

        assert method == "DELETE"
        assert "{}/configurations/{}?".format(mock_target["entity"],
                                              config_id) in url
        assert headers["If-Match"] == '"{}"'.format(etag if etag else "*")

    def test_config_delete_error(self, fixture_cmd,
                                 serviceclient_generic_error):
        with pytest.raises(CLIError):
            subject.iot_hub_configuration_delete(
                fixture_cmd,
                config_id=config_id,
                hub_name=mock_target["entity"])
Esempio n. 4
0
import re
import pytest
import responses
import json
from knack.cli import CLIError
from azext_iot.operations import hub as subject
from azext_iot.tests.generators import generate_generic_id
from azext_iot.common.utility import ensure_iothub_sdk_min_version
from azext_iot.constants import IOTHUB_TRACK_2_SDK_MIN_VERSION

hub_name = "HUBNAME"
blob_container_uri = "https://example.com"
resource_group_name = "RESOURCEGROUP"
managed_identity = "EXAMPLEMANAGEDIDENTITY"
generic_job_response = {"JobResponse": generate_generic_id()}
qualified_hostname = "{}.subdomain.domain".format(hub_name)


@pytest.fixture
def get_mgmt_client(mocker, fixture_cmd):
    from azure.mgmt.iothub import IotHubClient

    # discovery call to find iothub
    patch_discovery = mocker.patch(
        "azext_iot.iothub.providers.discovery.IotHubDiscovery.get_target"
    )
    patch_discovery.return_value = {
        "resourcegroup": resource_group_name
    }
Esempio n. 5
0
from azext_iot.tests.generators import generate_generic_id
from azext_iot.common.shared import DeviceAuthApiType

path_iot_hub_service_factory = "azext_iot._factory.iot_hub_service_factory"
path_service_client = "msrest.service_client.ServiceClient.send"
path_ghcs = "azext_iot.iothub.providers.discovery.IotHubDiscovery.get_target"
path_discovery_init = (
    "azext_iot.iothub.providers.discovery.IotHubDiscovery._initialize_client")
path_sas = "azext_iot._factory.SasTokenAuthentication"
path_mqtt_client = "azext_iot.operations._mqtt.mqtt.Client"
path_iot_hub_monitor_events_entrypoint = (
    "azext_iot.operations.hub._iot_hub_monitor_events")
path_iot_device_show = "azext_iot.operations.hub._iot_device_show"
hub_entity = "myhub.azure-devices.net"

instance_name = generate_generic_id()
hostname = "{}.subdomain.domain".format(instance_name)

mock_target = {}
mock_target["entity"] = hub_entity
mock_target["primarykey"] = "rJx/6rJ6rmG4ak890+eW5MYGH+A0uzRvjGNjg3Ve8sfo="
mock_target["secondarykey"] = "aCd/6rJ6rmG4ak890+eW5MYGH+A0uzRvjGNjg3Ve8sfo="
mock_target["policy"] = "iothubowner"
mock_target["subscription"] = "5952cff8-bcd1-4235-9554-af2c0348bf23"
mock_target["location"] = "westus2"
mock_target["sku_tier"] = "Standard"
mock_target["resourcegroup"] = "myresourcegroup"

generic_cs_template = "HostName={};SharedAccessKeyName={};SharedAccessKey={}"

Esempio n. 6
0
def generate_relationship(relationship_name=None):
    return {
        "$relationshipId": generate_generic_id(),
        "$relationshipName": relationship_name,
        "$sourceId": generate_generic_id()
    }
Esempio n. 7
0
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import re
import pytest
import responses
import json
from azext_iot.digitaltwins.providers.base import DigitalTwinsProvider
from azext_iot.tests.generators import generate_generic_id

resource_group = generate_generic_id()
instance_name = generate_generic_id()
qualified_hostname = "{}.subdomain.domain".format(instance_name)


@pytest.fixture
def get_mgmt_client(mocker, fixture_cmd):
    from azext_iot.sdk.digitaltwins.controlplane import AzureDigitalTwinsManagementClient
    from azext_iot.digitaltwins.providers.auth import DigitalTwinAuthentication

    patched_get_raw_token = mocker.patch(
        "azure.cli.core._profile.Profile.get_raw_token")
    patched_get_raw_token.return_value = (
        mocker.MagicMock(name="creds"),
        mocker.MagicMock(name="subscription"),
        mocker.MagicMock(name="tenant"),
    )
Esempio n. 8
0
def generate_resource_id():
    return "dtcli-{}".format(generate_generic_id())
Esempio n. 9
0
    def test_iothub_device_identity(self):
        to_remove_device_ids = []
        for auth_phase in DATAPLANE_AUTH_TYPES:
            for device_type in DEVICE_TYPES:
                device_count = 4
                device_ids = self.generate_device_names(
                    device_count, edge=device_type == "edge")
                edge_enabled = "--edge-enabled" if device_type == "edge" else ""

                # Symmetric key device checks
                d0_device_checks = [
                    self.check("deviceId", device_ids[0]),
                    self.check("status", "enabled"),
                    self.check("statusReason", None),
                    self.check("connectionState", "Disconnected"),
                    self.check("capabilities.iotEdge", device_type == "edge"),
                    self.exists("authentication.symmetricKey.primaryKey"),
                    self.exists("authentication.symmetricKey.secondaryKey"),
                ]

                # Symmetric key device creation
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity create -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} {edge_enabled}",
                        auth_type=auth_phase,
                    ),
                    checks=d0_device_checks,
                )
                to_remove_device_ids.append(device_ids[0])

                # x509 thumbprint device checks
                d1_device_checks = [
                    self.check("deviceId", device_ids[1]),
                    self.check("status", "enabled"),
                    self.check("statusReason", None),
                    self.check("capabilities.iotEdge", device_type == "edge"),
                    self.check("connectionState", "Disconnected"),
                    self.check("authentication.symmetricKey.primaryKey", None),
                    self.check("authentication.symmetricKey.secondaryKey",
                               None),
                    self.check(
                        "authentication.x509Thumbprint.primaryThumbprint",
                        PRIMARY_THUMBPRINT,
                    ),
                    self.check(
                        "authentication.x509Thumbprint.secondaryThumbprint",
                        SECONDARY_THUMBPRINT,
                    ),
                ]

                # Create x509 thumbprint device
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity create --device-id {device_ids[1]} "
                        f"--hub-name {LIVE_HUB} --resource-group {LIVE_RG} --auth-method x509_thumbprint "
                        f"--primary-thumbprint {PRIMARY_THUMBPRINT} --secondary-thumbprint {SECONDARY_THUMBPRINT} "
                        f"{edge_enabled}",
                        auth_type=auth_phase,
                    ),
                    checks=d1_device_checks,
                )
                to_remove_device_ids.append(device_ids[1])

                # Create x509 thumbprint device using generated cert for primary thumbprint
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity create --device-id {device_ids[2]} --hub-name {LIVE_HUB} "
                        f"--resource-group {LIVE_RG} --auth-method x509_thumbprint --valid-days 1 {edge_enabled}",
                        auth_type=auth_phase,
                    ),
                    checks=[
                        self.check("deviceId", device_ids[2]),
                        self.check("status", "enabled"),
                        self.check("statusReason", None),
                        self.check("capabilities.iotEdge",
                                   device_type == "edge"),
                        self.check("connectionState", "Disconnected"),
                        self.check("authentication.symmetricKey.primaryKey",
                                   None),
                        self.check("authentication.symmetricKey.secondaryKey",
                                   None),
                        self.exists(
                            "authentication.x509Thumbprint.primaryThumbprint"),
                        self.check(
                            "authentication.x509Thumbprint.secondaryThumbprint",
                            None,
                        ),
                    ],
                )
                to_remove_device_ids.append(device_ids[2])

                # Create x509 CA device, disabled status with reason, auth with connection string
                status_reason = "Test Status Reason"
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity create --device-id {device_ids[3]} --hub-name {LIVE_HUB} "
                        f"--resource-group {LIVE_RG} --auth-method x509_ca --status disabled "
                        f"--status-reason '{status_reason}' {edge_enabled}",
                        auth_type=auth_phase,
                    ),
                    checks=[
                        self.check("deviceId", device_ids[3]),
                        self.check("status", "disabled"),
                        self.check("statusReason", status_reason),
                        self.check("capabilities.iotEdge",
                                   device_type == "edge"),
                        self.check("connectionState", "Disconnected"),
                        self.check("authentication.symmetricKey.primaryKey",
                                   None),
                        self.check("authentication.symmetricKey.secondaryKey",
                                   None),
                        self.check(
                            "authentication.x509Thumbprint.primaryThumbprint",
                            None,
                        ),
                        self.check(
                            "authentication.x509Thumbprint.secondaryThumbprint",
                            None,
                        ),
                    ],
                )

                # Delete device identity
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity delete -d {device_ids[3]} -n {LIVE_HUB} -g {LIVE_RG}",
                        auth_type=auth_phase,
                    ),
                    checks=self.is_empty(),
                )

                # Validate deletion worked
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity show -d {device_ids[3]} -n {LIVE_HUB} -g {LIVE_RG}",
                        auth_type=auth_phase,
                    ),
                    expect_failure=True,
                )

                # Show symmetric key device identity
                d0_show = self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity show -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG}",
                        auth_type=auth_phase,
                    ),
                    checks=d0_device_checks,
                ).get_output_in_json()

                # Reset device symmetric key using device-identity generic update
                d0_updated = self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity update -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                        '--set authentication.symmetricKey.primaryKey="" '
                        'authentication.symmetricKey.secondaryKey=""',
                        auth_type=auth_phase,
                    )).get_output_in_json()
                assert (
                    d0_updated["authentication"]["symmetricKey"]["primaryKey"]
                    != d0_show["authentication"]["symmetricKey"]["primaryKey"])
                assert (
                    d0_updated["authentication"]["symmetricKey"]
                    ["secondaryKey"] !=
                    d0_show["authentication"]["symmetricKey"]["secondaryKey"])

                # Update device identity with higher level update parms
                random_status_reason = generate_generic_id()
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity update -d {device_ids[1]} --ee false "
                        f"--ptp {SECONDARY_THUMBPRINT} --stp {PRIMARY_THUMBPRINT} "
                        f"--status-reason '{random_status_reason}' --status disabled "
                        f"-n {LIVE_HUB} -g {LIVE_RG}",
                        auth_type=auth_phase,
                    ),
                    checks=[
                        self.check("deviceId", device_ids[1]),
                        self.check("status", "disabled"),
                        self.check("capabilities.iotEdge", False),
                        self.check("statusReason", random_status_reason),
                        self.check(
                            "authentication.x509Thumbprint.primaryThumbprint",
                            SECONDARY_THUMBPRINT,
                        ),
                        self.check(
                            "authentication.x509Thumbprint.secondaryThumbprint",
                            PRIMARY_THUMBPRINT,
                        ),
                    ],
                )

                query_checks = [
                    self.check("length([*])", len(to_remove_device_ids))
                ]
                for d in to_remove_device_ids:
                    query_checks.append(self.exists(f"[?deviceId=='{d}']"))

                # By default query has no return cap
                self.cmd(
                    self.set_cmd_auth_type(
                        f'iot hub query --hub-name {LIVE_HUB} -g {LIVE_RG} -q "select * from devices"',
                        auth_type=auth_phase,
                    ),
                    checks=query_checks,
                )

                # -1 Top is equivalent to unlimited
                self.cmd(
                    self.set_cmd_auth_type(
                        f'iot hub query --top -1 --hub-name {LIVE_HUB} -g {LIVE_RG} -q "select * from devices"',
                        auth_type=auth_phase,
                    ),
                    checks=query_checks,
                )

                # Explicit top to constrain records and use connection string
                self.cmd(
                    self.set_cmd_auth_type(
                        f'iot hub query --top 1 --hub-name {LIVE_HUB} -g {LIVE_RG} -q "select * from devices"',
                        auth_type=auth_phase,
                    ),
                    checks=[self.check("length([*])", 1)],
                )
                # List devices
                self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity list -n {LIVE_HUB} -g {LIVE_RG}",
                        auth_type=auth_phase,
                    ),
                    checks=query_checks,
                )

                # List devices filtering for edge devices
                edge_filtered_list = self.cmd(
                    self.set_cmd_auth_type(
                        f"iot hub device-identity list -n {LIVE_HUB} -g {LIVE_RG} --ee",
                        auth_type=auth_phase,
                    )).get_output_in_json()
                assert all((d["capabilities"]["iotEdge"] is True
                            for d in edge_filtered_list))
class TestPnPRuntimeInvokeCommand(object):
    @pytest.fixture(params=[201])
    def service_client_root(self, mocked_response, fixture_ghcs, request):
        # Root level device command mock
        mocked_response.add(
            method=responses.POST,
            url="https://{}/digitaltwins/{}/commands/{}".format(
                mock_target["entity"], device_id, command_id
            ),
            body=generic_result,
            headers={"x-ms-command-statuscode": str(request.param)},
            status=200,
            content_type="application/json",
            match_querystring=False,
        )

        mocked_response.metadata = request.param
        yield mocked_response

    @pytest.fixture(params=[201])
    def service_client_component(self, mocked_response, fixture_ghcs, request):
        # Component level device command mock
        mocked_response.add(
            method=responses.POST,
            url="https://{}/digitaltwins/{}/components/{}/commands/{}".format(
                mock_target["entity"], device_id, component_id, command_id
            ),
            body=generic_result,
            headers={"x-ms-command-statuscode": str(request.param)},
            status=200,
            content_type="application/json",
            match_querystring=False,
        )

        mocked_response.metadata = request.param
        yield mocked_response

    @pytest.mark.parametrize(
        "request_payload, arbitrary_timeout",
        [
            ("{}", randint(10, 30)),
            (json.dumps({"key": str(generate_generic_id())}), None),
        ],
    )
    def test_pnp_runtime_invoke_root_command(
        self, fixture_cmd, service_client_root, request_payload, arbitrary_timeout
    ):
        result = subject.invoke_device_command(
            cmd=fixture_cmd,
            device_id=device_id,
            command_name=command_id,
            connect_timeout=arbitrary_timeout,
            response_timeout=arbitrary_timeout,
            payload=request_payload,
            hub_name=mock_target["entity"],
        )

        self._assert_common_attributes(
            request_payload=request_payload,
            executed_client=service_client_root,
            result=result,
            connect_timeout=arbitrary_timeout,
            response_timeout=arbitrary_timeout,
        )

    @pytest.mark.parametrize(
        "request_payload, arbitrary_timeout",
        [
            ("{}", randint(10, 30)),
            (json.dumps({"key": str(generate_generic_id())}), None),
        ],
    )
    def test_pnp_runtime_invoke_component_command(
        self, fixture_cmd, service_client_component, request_payload, arbitrary_timeout
    ):
        result = subject.invoke_device_command(
            cmd=fixture_cmd,
            device_id=device_id,
            command_name=command_id,
            connect_timeout=arbitrary_timeout,
            response_timeout=arbitrary_timeout,
            payload=request_payload,
            hub_name=mock_target["entity"],
            component_path=component_id,
        )

        self._assert_common_attributes(
            request_payload=request_payload,
            executed_client=service_client_component,
            result=result,
            connect_timeout=arbitrary_timeout,
            response_timeout=arbitrary_timeout,
        )

    def test_pnp_runtime_invoke_command_error(
        self,
        fixture_cmd,
        service_client_generic_errors,
    ):
        with pytest.raises(CLIError):
            subject.invoke_device_command(
                cmd=fixture_cmd,
                device_id=device_id,
                command_name=command_id,
                payload=json.dumps({}),
                hub_name=mock_target["entity"],
            )

        with pytest.raises(CLIError):
            subject.invoke_device_command(
                cmd=fixture_cmd,
                device_id=device_id,
                command_name=command_id,
                payload=json.dumps({}),
                hub_name=mock_target["entity"],
                component_path=component_id,
            )

    def _assert_common_attributes(
        self,
        request_payload,
        executed_client,
        result,
        connect_timeout=None,
        response_timeout=None,
    ):
        if connect_timeout:
            assert (
                "connectTimeoutInSeconds={}".format(connect_timeout)
                in executed_client.calls[0].request.url
            )

        if response_timeout:
            assert (
                "responseTimeoutInSeconds={}".format(response_timeout)
                in executed_client.calls[0].request.url
            )

        assert request_payload == executed_client.calls[0].request.body
        assert (
            executed_client.calls[0].request.headers["Content-Type"]
            == "application/json; charset=utf-8"
        )

        assert result["payload"] == json.loads(generic_result)
        assert result["status"] == str(executed_client.metadata)
class TestPnPRuntimeUpdateDigitalTwin(object):
    @pytest.fixture
    def service_client(self, mocked_response, fixture_ghcs, request):
        mocked_response.add(
            method=responses.PATCH,
            url="https://{}/digitaltwins/{}".format(
                mock_target["entity"],
                device_id,
            ),
            body=None,
            status=202,
            content_type="application/json",
            match_querystring=False,
        )

        # The command currently will GET a fresh view of the digital twin
        # because the update operation does not return anything.
        mocked_response.add(
            method=responses.GET,
            url="https://{}/digitaltwins/{}".format(
                mock_target["entity"],
                device_id,
            ),
            body=generic_result,
            status=200,
            content_type="application/json",
            match_querystring=False,
        )

        yield mocked_response

    @pytest.mark.parametrize(
        "request_json_patch, etag",
        [
            (
                '[{"op":"remove", "path":"/thermostat1/targetTemperature"}, '
                '{"op":"add", "path":"/thermostat2/targetTemperature", "value": 22}]',
                generate_generic_id(),
            ),
            (
                '{"op":"add", "path":"/thermostat1/targetTemperature", "value": 54}',
                None,
            ),
        ],
    )
    def test_pnp_runtime_update_digital_twin(
        self, fixture_cmd, service_client, request_json_patch, etag
    ):
        json_patch = json.loads(request_json_patch)

        json_patch_collection = []
        if isinstance(json_patch, dict):
            json_patch_collection.append(json_patch)
        if isinstance(json_patch, list):
            json_patch_collection.extend(json_patch)

        expected_request_body = json.dumps(json_patch_collection)

        result = subject.patch_digital_twin(
            cmd=fixture_cmd,
            device_id=device_id,
            hub_name=mock_target["entity"],
            json_patch=request_json_patch,
            etag=etag,
        )

        # First call for patch
        patch_request = service_client.calls[0].request
        assert patch_request.body == expected_request_body
        assert patch_request.headers["If-Match"] == etag if etag else "*"

        # Result from get twin
        assert result == json.loads(generic_result)
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------


import pytest
import responses
import json
from random import randint
from knack.cli import CLIError
from azext_iot.iothub import commands_pnp_runtime as subject
from azext_iot.tests.conftest import mock_target
from azext_iot.tests.generators import generate_generic_id


device_id = generate_generic_id()
command_id = generate_generic_id()
component_id = generate_generic_id()
generic_result = json.dumps({"result": generate_generic_id()})


class TestPnPRuntimeInvokeCommand(object):
    @pytest.fixture(params=[201])
    def service_client_root(self, mocked_response, fixture_ghcs, request):
        # Root level device command mock
        mocked_response.add(
            method=responses.POST,
            url="https://{}/digitaltwins/{}/commands/{}".format(
                mock_target["entity"], device_id, command_id
            ),
            body=generic_result,
Esempio n. 13
0
def create_relationship(relationship_name=None):
    return {
        "$relationshipId": generate_generic_id(),
        "relationship_name": relationship_name
    }
Esempio n. 14
0
# coding=utf-8
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import re
import pytest
import responses
import json
from knack.cli import CLIError
from azext_iot.digitaltwins import commands_twins as subject
from azext_iot.tests.generators import generate_generic_id
from msrest.paging import Paged

instance_name = generate_generic_id()
hostname = "{}.subdomain.domain".format(instance_name)
etag = 'AAAA=='
resource_group = 'myrg'

model_id = generate_generic_id()
twin_id = generate_generic_id()
target_twin_id = generate_generic_id()
relationship_id = generate_generic_id()
component_path = generate_generic_id()

generic_result = json.dumps({"result": generate_generic_id()})
generic_query = "select * from digitaltwins"
models_result = json.dumps({"id": model_id})
generic_patch_1 = json.dumps({"a": "b"})
generic_patch_2 = json.dumps({"a": "b", "c": "d"})
Esempio n. 15
0
import urllib
import json
from azext_iot.tests.generators import generate_generic_id

etag = 'AAAA=='
resource_group = 'myrg'


def generate_model_id():
    normal_id = "dtmi:com:{}:{};1".format(generate_generic_id(),
                                          generate_generic_id())
    url_id = urllib.parse.quote_plus(normal_id)
    return normal_id, url_id


generic_result = json.dumps({"result": generate_generic_id()})
model_id, url_model_id = generate_model_id()
twin_id = generate_generic_id()


def generate_model_result(model_id=None):
    model_id = model_id if model_id else generate_model_id()[0]
    return {
        "model": {
            "@context": ["dtmi:com:context;2"],
            "@id": model_id,
            "@type": "Interface"
        },
        "id": model_id
    }
Esempio n. 16
0
class TestConfigUpdate:
    @pytest.fixture(params=[200])
    def serviceclient(self, mocker, fixture_ghcs, fixture_sas, request):
        service_client = mocker.patch(path_service_client)
        service_client.return_value = build_mock_response(
            mocker, request.param, {})
        return service_client

    @pytest.mark.parametrize(
        "etag",
        [generate_generic_id(), None],
    )
    def test_config_update(self, fixture_cmd, serviceclient,
                           sample_config_show, etag):
        subject.iot_hub_configuration_update(cmd=fixture_cmd,
                                             config_id=config_id,
                                             hub_name=mock_target["entity"],
                                             parameters=sample_config_show,
                                             etag=etag)
        args = serviceclient.call_args
        url = args[0][0].url
        method = args[0][0].method
        body = json.loads(args[0][0].body)
        headers = args[0][0].headers

        assert "{}/configurations/{}?".format(mock_target["entity"],
                                              config_id) in url
        assert method == "PUT"

        assert body["id"] == sample_config_show["id"]
        assert body.get("metrics") == sample_config_show.get("metrics")
        assert body.get("targetCondition") == sample_config_show.get(
            "targetCondition")
        assert body.get("priority") == sample_config_show.get("priority")
        assert body.get("labels") == sample_config_show.get("labels")

        headers = args[0][0].headers
        assert headers["If-Match"] == '"{}"'.format(etag if etag else "*")

    def test_config_update_invalid_args(self, fixture_cmd, serviceclient,
                                        sample_config_show):
        from copy import deepcopy

        request = deepcopy(sample_config_show)
        request["labels"] = "not a dictionary"

        with pytest.raises(CLIError) as exc_label:
            subject.iot_hub_configuration_update(
                cmd=fixture_cmd,
                config_id=config_id,
                hub_name=mock_target["entity"],
                parameters=request,
            )

        type_name = "class" if "class" in str(type) else "type"
        assert str(exc_label.value) == (
            "The property \"labels\" must be of <{0} 'dict'> but is <{0} 'str'>. "
            "Input: not a dictionary. Review inline JSON examples here --> "
            "https://github.com/Azure/azure-iot-cli-extension/wiki/Tips".
            format(type_name))

    def test_config_update_error(self, fixture_cmd,
                                 serviceclient_generic_error):
        with pytest.raises(CLIError):
            subject.iot_hub_configuration_update(
                cmd=fixture_cmd,
                config_id=config_id,
                hub_name=mock_target["entity"],
                parameters={},
            )
Esempio n. 17
0
def generate_model_id():
    normal_id = "dtmi:com:{}:{};1".format(generate_generic_id(),
                                          generate_generic_id())
    url_id = urllib.parse.quote_plus(normal_id)
    return normal_id, url_id
Esempio n. 18
0
                          opt_env_set=opt_env_set)

LIVE_HUB = settings.env.azext_iot_testhub
LIVE_RG = settings.env.azext_iot_testrg

# Set this environment variable to your empty blob container sas uri to test device export and enable file upload test.
# For file upload, you will need to have configured your IoT Hub before running.
LIVE_STORAGE_URI = settings.env.azext_iot_teststorageuri

# Set this environment variable to enable identity-based integration tests
# You will need permissions to add and remove role assignments for this storage account
LIVE_STORAGE_RESOURCE_ID = settings.env.azext_iot_identity_teststorageid

CWD = os.path.dirname(os.path.abspath(__file__))

user_managed_identity_name = generate_generic_id()


class TestIoTStorage(IoTLiveScenarioTest):
    def __init__(self, test_case):
        super(TestIoTStorage, self).__init__(test_case, LIVE_HUB, LIVE_RG)
        self.managed_identity = None

    def get_managed_identity(self):
        # Check if there is a managed identity already
        if self.managed_identity:
            return self.managed_identity

        # Create managed identity
        result = self.cmd("identity create -n {} -g {}".format(
            user_managed_identity_name, LIVE_RG)).get_output_in_json()
Esempio n. 19
0
    def test_iothub_module_twin(self):
        for auth_phase in DATAPLANE_AUTH_TYPES:
            device_count = 1
            device_ids = self.generate_device_names(device_count)
            module_count = 1
            module_ids = self.generate_device_names(module_count)

            patch_desired = {
                generate_generic_id(): generate_generic_id(),
                generate_generic_id(): generate_generic_id(),
            }
            patch_tags = {
                generate_generic_id(): generate_generic_id(),
                generate_generic_id(): generate_generic_id(),
            }

            self.kwargs["patch_desired"] = json.dumps(patch_desired)
            self.kwargs["patch_tags"] = json.dumps(patch_tags)

            self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub device-identity create -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG}",
                    auth_type=auth_phase,
                )
            )

            self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-identity create -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG}",
                    auth_type=auth_phase,
                )
            )

            # Initial twin state
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin show -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG}",
                    auth_type=auth_phase,
                ),
                checks=[
                    self.check("moduleId", module_ids[0]),
                    self.check("deviceId", device_ids[0]),
                    self.exists("properties.desired"),
                    self.exists("properties.reported"),
                ],
            ).get_output_in_json()

            assert d0_twin["properties"]["desired"]["$version"] == 1
            assert d0_twin["properties"]["reported"]["$version"] == 1

            # Patch based twin update of desired props
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--desired '{patch_desired}'",  # Not f-string due to CLI TestFramework self.kwargs application :(
                    auth_type=auth_phase,
                )
            ).get_output_in_json()

            assert d0_twin["properties"]["desired"]["$version"] == 2

            for key in patch_desired:
                assert d0_twin["properties"]["desired"][key] == patch_desired[key]

            # Patch based twin update of tag props
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--tags '{patch_tags}'",  # Not f-string due to CLI TestFramework self.kwargs application :(
                    auth_type=auth_phase,
                )
            ).get_output_in_json()

            for key in patch_tags:
                assert d0_twin["tags"][key] == patch_tags[key]

            for key in patch_desired:
                assert d0_twin["properties"]["desired"][key] == patch_desired[key]

            assert d0_twin["properties"]["desired"]["$version"] == 2

            # Patch based twin update of tag and desired props
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--tags '{patch_tags}' --desired '{patch_desired}'",
                    auth_type=auth_phase,
                )
            ).get_output_in_json()

            for key in patch_tags:
                assert d0_twin["tags"][key] == patch_tags[key]

            for key in patch_desired:
                assert d0_twin["properties"]["desired"][key] == patch_desired[key]

            assert d0_twin["properties"]["desired"]["$version"] == 3

            # Prepare removal of all twin tag properties
            for key in patch_tags:
                patch_tags[key] = None
            self.kwargs["patch_tags"] = json.dumps(patch_tags)

            # Remove all twin tag properties
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--tags '{patch_tags}'",
                    auth_type=auth_phase,
                )
            ).get_output_in_json()
            assert d0_twin["tags"] is None

            # Prepare removal of single desired twin property
            target_key = list(patch_desired.keys())[0]
            patch_desired[target_key] = None
            self.kwargs["patch_desired"] = json.dumps(patch_desired)

            # Remove single desired property
            d0_twin = self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--desired '{patch_desired}'",
                    auth_type=auth_phase,
                )
            ).get_output_in_json()

            assert d0_twin["properties"]["desired"].get(target_key) is None
            assert d0_twin["properties"]["desired"]["$version"] == 4

            # Validation error --desired is not an object
            self.cmd(
                self.set_cmd_auth_type(
                    f"iot hub module-twin update -m {module_ids[0]} -d {device_ids[0]} -n {LIVE_HUB} -g {LIVE_RG} "
                    "--desired 'badinput'",
                    auth_type=auth_phase,
                ),
                expect_failure=True,
            )